tracechild.cc revision 6417
1/*
2 * Copyright (c) 2006-2009 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 *          Gabe Black
30 */
31
32#include <iostream>
33#include <errno.h>
34#include <stdint.h>
35#include <cstring>
36
37#include "tracechild_arm.hh"
38
39using namespace std;
40
41const char* ARMTraceChild::regNames[numregs] = {
42    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
43    "r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc",
44    "cpsr" };
45
46
47ARMTraceChild::ARMTraceChild()
48{
49    for (int x = 0; x < numregs; x++) {
50        memset(&regs, 0, sizeof(regs));
51        memset(&oldregs, 0, sizeof(regs));
52        regDiffSinceUpdate[x] = false;
53    }
54}
55
56bool ARMTraceChild::sendState(int socket)
57{
58    uint32_t regVal = 0;
59    uint32_t message[numregs + 1];
60    int pos = 1;
61    message[0] = 0;
62    for (int x = 0; x < numregs; x++) {
63        if (regDiffSinceUpdate[x]) {
64            message[0] = message[0] | (1 << x);
65            message[pos++] = getRegVal(x);
66        }
67    }
68
69    size_t sent = 0;
70    size_t toSend = pos * sizeof(message[0]);
71    uint8_t *messagePtr = (uint8_t *)message;
72    while (toSend != 0) {
73        sent = write(socket, messagePtr, toSend);
74        if (sent == -1) {
75            cerr << "Write failed! " << strerror(errno) << endl;
76            tracing = false;
77            return false;
78        }
79        toSend -= sent;
80        messagePtr += sent;
81    }
82
83    return true;
84}
85
86uint32_t ARMTraceChild::getRegs(user_regs &myregs, int num)
87{
88    assert(num < numregs && num >= 0);
89    return myregs.uregs[num];
90}
91
92bool ARMTraceChild::update(int pid)
93{
94    oldregs = regs;
95    if(ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0)
96    {
97        cerr << "update: " << strerror(errno) << endl;
98        return false;
99    }
100
101    for(unsigned int x = 0; x < numregs; x++)
102        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
103    return true;
104}
105
106int64_t ARMTraceChild::getRegVal(int num)
107{
108        return getRegs(regs, num);
109}
110
111int64_t ARMTraceChild::getOldRegVal(int num)
112{
113        return getRegs(oldregs,  num);
114}
115
116char * ARMTraceChild::printReg(int num)
117{
118        sprintf(printBuffer, "0x%08X", (uint32_t)getRegVal(num));
119        return printBuffer;
120}
121
122ostream & ARMTraceChild::outputStartState(ostream & os)
123{
124    uint32_t sp = getSP();
125    uint32_t pc = getPC();
126    uint32_t highestInfo = 0;
127    char obuf[1024];
128    sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp);
129    os << obuf;
130    sprintf(obuf, "Initial program counter = 0x%08x\n", pc);
131    os << obuf;
132
133    //Output the argument count
134    int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
135    sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc);
136    os << obuf;
137    sp += 4;
138
139    //Output argv pointers
140    int argCount = 0;
141    int32_t cargv;
142    do
143    {
144        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
145        sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n",
146                sp, argCount++, cargv);
147        if(cargv)
148            if(highestInfo < cargv)
149                highestInfo = cargv;
150        os << obuf;
151        sp += 4;
152    } while(cargv);
153
154    //Output the envp pointers
155    int envCount = 0;
156    uint32_t cenvp;
157    do
158    {
159        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
160        sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n",
161                sp, envCount++, cenvp);
162        os << obuf;
163        sp += 4;
164    } while(cenvp);
165    uint32_t auxType, auxVal;
166    do
167    {
168        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
169        sp += 4;
170        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
171        sp += 4;
172        sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n",
173                sp - 8, auxType, auxVal);
174        os << obuf;
175    } while(auxType != 0 || auxVal != 0);
176    //Print out the argument strings, environment strings, and file name.
177    string current;
178    uint32_t buf;
179    uint32_t currentStart = sp;
180    bool clearedInitialPadding = false;
181    do
182    {
183        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
184        char * cbuf = (char *)&buf;
185        for(int x = 0; x < sizeof(uint32_t); x++)
186        {
187            if(cbuf[x])
188                current += cbuf[x];
189            else
190            {
191                sprintf(obuf, "0x%08x: \"%s\"\n",
192                        currentStart, current.c_str());
193                os << obuf;
194                current = "";
195                currentStart = sp + x + 1;
196            }
197        }
198        sp += 4;
199        clearedInitialPadding = clearedInitialPadding || buf != 0;
200    } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo);
201    return os;
202}
203
204bool ARMTraceChild::step()
205{
206    const uint32_t bkpt_inst = 0xe7f001f0;
207
208    uint32_t lr = getRegVal(14);
209    uint32_t pc = getPC();
210    uint32_t lrOp;
211
212    // Since ARM uses software breakpoints behind the scenes, they don't work
213    // in read only areas like the page of routines provided by the kernel. The
214    // link register generally holds the address the process wants to the
215    // kernel to return to after it's done, so we'll install a software
216    // breakpoint there. If the lr happens to point to the next instruction
217    // we'll leave out our breakpoint to avoid an infinite loop. This isn't a
218    // fool proof strategy, but it should work well in all the reasonable
219    // scenarios I can think of right now.
220
221    if (pc != lr) {
222        lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0);
223        ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst);
224    }
225    ptraceSingleStep();
226    if (pc != lr) {
227        ptrace(PTRACE_POKEDATA, pid, lr, lrOp);
228    }
229}
230
231
232TraceChild * genTraceChild()
233{
234    return new ARMTraceChild;
235}
236
237