tracechild.cc revision 8229
16407SN/A/*
27414SN/A * Copyright (c) 2010 ARM Limited
37414SN/A * All rights reserved
47414SN/A *
57414SN/A * The license below extends only to copyright in the software and shall
67414SN/A * not be construed as granting a license to any other intellectual
77414SN/A * property including but not limited to intellectual property relating
87414SN/A * to a hardware implementation of the functionality of the software
97414SN/A * licensed hereunder.  You may use the software subject to the license
107414SN/A * terms below provided that you ensure that this notice is replicated
117414SN/A * unmodified and in its entirety in all distributions of the software,
127414SN/A * modified or unmodified, in source code or in binary form.
137414SN/A *
146407SN/A * Copyright (c) 2006-2009 The Regents of The University of Michigan
156407SN/A * All rights reserved.
166407SN/A *
176407SN/A * Redistribution and use in source and binary forms, with or without
186407SN/A * modification, are permitted provided that the following conditions are
196407SN/A * met: redistributions of source code must retain the above copyright
206407SN/A * notice, this list of conditions and the following disclaimer;
216407SN/A * redistributions in binary form must reproduce the above copyright
226407SN/A * notice, this list of conditions and the following disclaimer in the
236407SN/A * documentation and/or other materials provided with the distribution;
246407SN/A * neither the name of the copyright holders nor the names of its
256407SN/A * contributors may be used to endorse or promote products derived from
266407SN/A * this software without specific prior written permission.
276407SN/A *
286407SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
296407SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
306407SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
316407SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
326407SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
336407SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
346407SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
356407SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
366407SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
376407SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
386407SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
396407SN/A *
406407SN/A * Authors: Ali Saidi
416407SN/A *          Gabe Black
426407SN/A */
436407SN/A
448229Snate@binkert.org#include <stdint.h>
458229Snate@binkert.org
468229Snate@binkert.org#include <cerrno>
478229Snate@binkert.org#include <cstdio>
488229Snate@binkert.org#include <cstring>
496407SN/A#include <iostream>
506407SN/A
518113Sgblack@eecs.umich.edu#include "arch/arm/tracechild.hh"
526407SN/A
536407SN/Ausing namespace std;
546407SN/A
556407SN/AARMTraceChild::ARMTraceChild()
566407SN/A{
577414SN/A    foundMvn = false;
587414SN/A
596411SN/A    for (int x = 0; x < numregs; x++) {
606411SN/A        memset(&regs, 0, sizeof(regs));
616411SN/A        memset(&oldregs, 0, sizeof(regs));
626407SN/A        regDiffSinceUpdate[x] = false;
636411SN/A    }
646407SN/A}
656407SN/A
668108SN/Abool
678108SN/AARMTraceChild::sendState(int socket)
686407SN/A{
696407SN/A    uint32_t regVal = 0;
706411SN/A    uint32_t message[numregs + 1];
716411SN/A    int pos = 1;
726411SN/A    message[0] = 0;
736411SN/A    for (int x = 0; x < numregs; x++) {
746411SN/A        if (regDiffSinceUpdate[x]) {
756411SN/A            message[0] = message[0] | (1 << x);
766411SN/A            message[pos++] = getRegVal(x);
776411SN/A        }
786411SN/A    }
796411SN/A
806411SN/A    size_t sent = 0;
816411SN/A    size_t toSend = pos * sizeof(message[0]);
826411SN/A    uint8_t *messagePtr = (uint8_t *)message;
836411SN/A    while (toSend != 0) {
846411SN/A        sent = write(socket, messagePtr, toSend);
856411SN/A        if (sent == -1) {
866407SN/A            cerr << "Write failed! " << strerror(errno) << endl;
876407SN/A            tracing = false;
886407SN/A            return false;
896407SN/A        }
906411SN/A        toSend -= sent;
916411SN/A        messagePtr += sent;
926407SN/A    }
937414SN/A
946407SN/A    return true;
956407SN/A}
966407SN/A
978108SN/Auint32_t
988108SN/AARMTraceChild::getRegs(user_regs &myregs, int num)
996407SN/A{
1006407SN/A    assert(num < numregs && num >= 0);
1016407SN/A    return myregs.uregs[num];
1026407SN/A}
1036407SN/A
1048108SN/Abool
1058108SN/AARMTraceChild::update(int pid)
1066407SN/A{
1076407SN/A    oldregs = regs;
1088108SN/A    if (ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0) {
1096407SN/A        cerr << "update: " << strerror(errno) << endl;
1106407SN/A        return false;
1116407SN/A    }
1127414SN/A
1138108SN/A    for (unsigned int x = 0; x < numregs; x++)
1146407SN/A        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
1156407SN/A    return true;
1166407SN/A}
1176407SN/A
1188108SN/Aint64_t
1198108SN/AARMTraceChild::getRegVal(int num)
1206407SN/A{
1218108SN/A    return getRegs(regs, num);
1226407SN/A}
1236407SN/A
1248108SN/Aint64_t
1258108SN/AARMTraceChild::getOldRegVal(int num)
1266407SN/A{
1278108SN/A    return getRegs(oldregs,  num);
1286407SN/A}
1296407SN/A
1308108SN/Aostream &
1318108SN/AARMTraceChild::outputStartState(ostream & os)
1326407SN/A{
1336407SN/A    uint32_t sp = getSP();
1346407SN/A    uint32_t pc = getPC();
1356407SN/A    uint32_t highestInfo = 0;
1366407SN/A    char obuf[1024];
1376407SN/A    sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp);
1386407SN/A    os << obuf;
1396407SN/A    sprintf(obuf, "Initial program counter = 0x%08x\n", pc);
1406407SN/A    os << obuf;
1416407SN/A
1426407SN/A    //Output the argument count
1436407SN/A    int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
1446407SN/A    sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc);
1456407SN/A    os << obuf;
1466407SN/A    sp += 4;
1476407SN/A
1486407SN/A    //Output argv pointers
1496407SN/A    int argCount = 0;
1506407SN/A    int32_t cargv;
1518108SN/A    do {
1526407SN/A        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
1536407SN/A        sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n",
1546407SN/A                sp, argCount++, cargv);
1556407SN/A        if(cargv)
1566407SN/A            if(highestInfo < cargv)
1576407SN/A                highestInfo = cargv;
1586407SN/A        os << obuf;
1596407SN/A        sp += 4;
1606407SN/A    } while(cargv);
1616407SN/A
1626407SN/A    //Output the envp pointers
1636407SN/A    int envCount = 0;
1646407SN/A    uint32_t cenvp;
1658108SN/A    do {
1666407SN/A        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
1676407SN/A        sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n",
1686407SN/A                sp, envCount++, cenvp);
1696407SN/A        os << obuf;
1706407SN/A        sp += 4;
1716407SN/A    } while(cenvp);
1726407SN/A    uint32_t auxType, auxVal;
1738108SN/A    do {
1746407SN/A        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
1756407SN/A        sp += 4;
1766407SN/A        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
1776407SN/A        sp += 4;
1786407SN/A        sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n",
1796407SN/A                sp - 8, auxType, auxVal);
1806407SN/A        os << obuf;
1816407SN/A    } while(auxType != 0 || auxVal != 0);
1826407SN/A    //Print out the argument strings, environment strings, and file name.
1836407SN/A    string current;
1846407SN/A    uint32_t buf;
1856407SN/A    uint32_t currentStart = sp;
1866407SN/A    bool clearedInitialPadding = false;
1878108SN/A    do {
1886407SN/A        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
1896407SN/A        char * cbuf = (char *)&buf;
1908108SN/A        for (int x = 0; x < sizeof(uint32_t); x++) {
1918108SN/A            if (cbuf[x])
1926407SN/A                current += cbuf[x];
1938108SN/A            else {
1946407SN/A                sprintf(obuf, "0x%08x: \"%s\"\n",
1956407SN/A                        currentStart, current.c_str());
1966407SN/A                os << obuf;
1976407SN/A                current = "";
1986407SN/A                currentStart = sp + x + 1;
1996407SN/A            }
2006407SN/A        }
2016407SN/A        sp += 4;
2026407SN/A        clearedInitialPadding = clearedInitialPadding || buf != 0;
2036407SN/A    } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo);
2046407SN/A    return os;
2056407SN/A}
2066407SN/A
2078108SN/Abool
2088108SN/AARMTraceChild::step()
2096407SN/A{
2106417SN/A    const uint32_t bkpt_inst = 0xe7f001f0;
2116407SN/A
2126417SN/A    uint32_t lr = getRegVal(14);
2136417SN/A    uint32_t pc = getPC();
2147414SN/A    uint32_t lrOp, subsOp;
2157414SN/A    char obuf[128];
2167414SN/A    bool patch = false;
2176407SN/A
2186417SN/A    // Since ARM uses software breakpoints behind the scenes, they don't work
2196417SN/A    // in read only areas like the page of routines provided by the kernel. The
2206417SN/A    // link register generally holds the address the process wants to the
2216417SN/A    // kernel to return to after it's done, so we'll install a software
2227414SN/A    // breakpoint there.
2237414SN/A    //
2247414SN/A    // Calls into the kernel user page always follow the form:
2257414SN/A    //  MVN ...
2267414SN/A    //  <possible MOV lr,...>
2277414SN/A    //  SUB PC, ...
2287414SN/A    //
2297414SN/A    //  So we look for this pattern and set a breakpoint on the LR at the SUB
2307414SN/A    //  instruction.
2316407SN/A
2327414SN/A
2337414SN/A    subsOp = ptrace(PTRACE_PEEKDATA, pid, pc, 0);
2347414SN/A    if ((subsOp & 0xFFFF0FFF) == 0xe3e00a0f)
2357414SN/A        foundMvn = true;
2367414SN/A
2377414SN/A    if (foundMvn && ((subsOp & 0xFFF0F000) == 0xe240f000)) {
2387414SN/A        foundMvn = false;
2396417SN/A        lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0);
2406417SN/A        ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst);
2417414SN/A        patch = true;
2426417SN/A    }
2436417SN/A    ptraceSingleStep();
2447414SN/A
2457414SN/A    if (patch)
2466417SN/A        ptrace(PTRACE_POKEDATA, pid, lr, lrOp);
2476407SN/A}
2486407SN/A
2496407SN/A
2508108SN/ATraceChild *
2518108SN/AgenTraceChild()
2526407SN/A{
2536407SN/A    return new ARMTraceChild;
2546407SN/A}
2556407SN/A
256