tracechild.cc revision 3382
1/*
2 * Copyright (c) 2006 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: Gabe Black
29 */
30
31#include <iostream>
32#include <errno.h>
33#include <sys/ptrace.h>
34#include <stdint.h>
35
36#include "tracechild_sparc.hh"
37
38using namespace std;
39
40string SparcTraceChild::regNames[numregs] = {
41    //Global registers
42    "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
43    //Output registers
44    "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
45    //Local registers
46    "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
47    //Input registers
48    "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
49    //Floating point
50    "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
51    "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
52    "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
53    "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
54    //Miscelaneous
55    "fsr", "fprs", "pc", "npc", "y", "cwp", "pstate", "asi", "ccr"};
56
57int64_t getRegs(regs & myregs, fpu & myfpu,
58        int64_t * locals, int64_t * inputs, int num)
59{
60    assert(num < SparcTraceChild::numregs && num >= 0);
61    switch(num)
62    {
63        //Global registers
64        case SparcTraceChild::G0: return 0;
65        case SparcTraceChild::G1: return myregs.r_g1;
66        case SparcTraceChild::G2: return myregs.r_g2;
67        case SparcTraceChild::G3: return myregs.r_g3;
68        case SparcTraceChild::G4: return myregs.r_g4;
69        case SparcTraceChild::G5: return myregs.r_g5;
70        case SparcTraceChild::G6: return myregs.r_g6;
71        case SparcTraceChild::G7: return myregs.r_g7;
72        //Output registers
73        case SparcTraceChild::O0: return myregs.r_o0;
74        case SparcTraceChild::O1: return myregs.r_o1;
75        case SparcTraceChild::O2: return myregs.r_o2;
76        case SparcTraceChild::O3: return myregs.r_o3;
77        case SparcTraceChild::O4: return myregs.r_o4;
78        case SparcTraceChild::O5: return myregs.r_o5;
79        case SparcTraceChild::O6: return myregs.r_o6;
80        case SparcTraceChild::O7: return myregs.r_o7;
81        //Local registers
82        case SparcTraceChild::L0: return locals[0];
83        case SparcTraceChild::L1: return locals[1];
84        case SparcTraceChild::L2: return locals[2];
85        case SparcTraceChild::L3: return locals[3];
86        case SparcTraceChild::L4: return locals[4];
87        case SparcTraceChild::L5: return locals[5];
88        case SparcTraceChild::L6: return locals[6];
89        case SparcTraceChild::L7: return locals[7];
90        //Input registers
91        case SparcTraceChild::I0: return inputs[0];
92        case SparcTraceChild::I1: return inputs[1];
93        case SparcTraceChild::I2: return inputs[2];
94        case SparcTraceChild::I3: return inputs[3];
95        case SparcTraceChild::I4: return inputs[4];
96        case SparcTraceChild::I5: return inputs[5];
97        case SparcTraceChild::I6: return inputs[6];
98        case SparcTraceChild::I7: return inputs[7];
99        //Floating point
100        case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0];
101        case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1];
102        case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2];
103        case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3];
104        case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4];
105        case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5];
106        case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6];
107        case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7];
108        case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8];
109        case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9];
110        case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10];
111        case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11];
112        case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12];
113        case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13];
114        case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14];
115        case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15];
116        case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16];
117        case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17];
118        case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18];
119        case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19];
120        case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20];
121        case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21];
122        case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22];
123        case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23];
124        case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24];
125        case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25];
126        case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26];
127        case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27];
128        case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28];
129        case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29];
130        case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30];
131        case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31];
132        //Miscelaneous
133        case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr;
134        case SparcTraceChild::FPRS: return myregs.r_fprs;
135        case SparcTraceChild::PC: return myregs.r_tpc;
136        case SparcTraceChild::NPC: return myregs.r_tnpc;
137        case SparcTraceChild::Y: return myregs.r_y;
138        case SparcTraceChild::CWP:
139            return (myregs.r_tstate >> 0) & ((1 << 5) - 1);
140        case SparcTraceChild::PSTATE:
141            return (myregs.r_tstate >> 8) & ((1 << 13) - 1);
142        case SparcTraceChild::ASI:
143            return (myregs.r_tstate >> 24) & ((1 << 8) - 1);
144        case SparcTraceChild::CCR:
145            return (myregs.r_tstate >> 32) & ((1 << 8) - 1);
146        default:
147            assert(0);
148            return 0;
149    }
150}
151
152bool SparcTraceChild::update(int pid)
153{
154    static const int stackBias = 2047;
155    memcpy(&oldregs, &theregs, sizeof(regs));
156    memcpy(&oldfpregs, &thefpregs, sizeof(fpu));
157    memcpy(oldLocals, locals, 8 * sizeof(uint64_t));
158    memcpy(oldInputs, inputs, 8 * sizeof(uint64_t));
159    if(ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0)
160    {
161        cerr << "Update failed" << endl;
162        return false;
163    }
164    uint64_t StackPointer = getRegVal(O6);
165    for(unsigned int x = 0; x < 8; x++)
166    {
167        locals[x] = ptrace(PTRACE_PEEKTEXT, pid,
168            StackPointer + stackBias + x * 8, 0);
169        inputs[x] = ptrace(PTRACE_PEEKTEXT, pid,
170            StackPointer + stackBias + x * 8 + (8 * 8), 0);
171    }
172    if(ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0)
173        return false;
174    for(unsigned int x = 0; x < numregs; x++)
175        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
176    return true;
177}
178
179SparcTraceChild::SparcTraceChild()
180{
181    for(unsigned int x = 0; x < numregs; x++)
182        regDiffSinceUpdate[x] = false;
183}
184
185bool SparcTraceChild::step()
186{
187    //Two important considerations are that the address of the instruction
188    //being breakpointed should be word (64bit) aligned, and that both the
189    //next instruction and the instruction after that need to be breakpointed
190    //so that annulled branches will still stop as well.
191
192    /*
193     * Useful constants
194     */
195    const static uint64_t breakInst = 0x91d02001;
196    const static uint64_t breakWord = breakInst | (breakInst << 32);
197    const static uint64_t lowMask = 0xFFFFFFFFULL;
198    const static uint64_t highMask = lowMask << 32;
199
200    /*
201     * storage for the original contents of the child process's memory
202     */
203    uint64_t originalInst, originalAnnulInst;
204
205    /*
206     * Get information about where the process is and is headed next.
207     */
208    uint64_t currentPC = getRegVal(PC);
209    bool unalignedPC = currentPC & 7;
210    uint64_t alignedPC = currentPC & (~7);
211    uint64_t nextPC = getRegVal(NPC);
212    bool unalignedNPC = nextPC & 7;
213    uint64_t alignedNPC = nextPC & (~7);
214
215    /*
216     * Store the original contents of the child process's memory
217     */
218    originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC, 0);
219    //Save a ptrace call if we can
220    if(unalignedNPC)
221    {
222        originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC+8, 0);
223    }
224
225    /*
226     * Prepare breakpointed copies of child processes memory
227     */
228    uint64_t newInst, newAnnulInst;
229    //If the current instruction is in the same word as the npc
230    if(alignedPC == alignedNPC)
231    {
232        //Make sure we only replace the other part
233        if(unalignedPC)
234            newInst = (originalInst & lowMask) | (breakWord & highMask);
235        else
236            newInst = (originalInst & highMask) | (breakWord & lowMask);
237    }
238    else
239    {
240        //otherwise replace the whole thing
241        newInst = breakWord;
242    }
243    //If the current instruction is in the same word as the word after
244    //the npc
245    if(alignedPC == alignedNPC+8)
246    {
247        //Make sure we only replace the other part
248        if(unalignedPC)
249            newAnnulInst = (originalAnnulInst & lowMask) | (breakWord & highMask);
250        else
251            newAnnulInst = (originalAnnulInst & highMask) | (breakWord & lowMask);
252    }
253    else
254    {
255        //otherwise replace the whole thing
256        newAnnulInst = breakWord;
257    }
258
259    /*
260     * Stuff the breakpoint instructions into the child's address space.
261     */
262    //Replace the word at npc
263    if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, newInst) != 0)
264        cerr << "Poke failed" << endl;
265    //Replace the next word, if necessary
266    if(unalignedNPC)
267    {
268        if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, newAnnulInst) != 0)
269            cerr << "Poke failed" << endl;
270    }
271
272    /*
273     * Restart the child process
274     */
275    //Note that the "addr" parameter is supposed to be ignored, but in at
276    //least one version of the kernel, it must be 1 or it will set what
277    //pc to continue from
278    if(ptrace(PTRACE_CONT, pid, 1, 0) != 0)
279        cerr << "Cont failed" << endl;
280    doWait();
281
282    /*
283     * Update our record of the child's state
284     */
285    update(pid);
286
287    /*
288     * Put back the original contents of the childs address space
289     */
290    if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, originalInst) != 0)
291        cerr << "Repoke failed" << endl;
292    if(unalignedNPC)
293    {
294        if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, originalAnnulInst) != 0)
295            cerr << "Repoke failed" << endl;
296    }
297    return true;
298}
299
300int64_t SparcTraceChild::getRegVal(int num)
301{
302    return getRegs(theregs, thefpregs, locals, inputs, num);
303}
304
305int64_t SparcTraceChild::getOldRegVal(int num)
306{
307    return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
308}
309
310char * SparcTraceChild::printReg(int num)
311{
312    sprintf(printBuffer, "0x%016llx", getRegVal(num));
313    return printBuffer;
314}
315
316ostream & SparcTraceChild::outputStartState(ostream & os)
317{
318    uint64_t sp = getSP();
319    uint64_t pc = getPC();
320    char obuf[1024];
321    sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
322    os << obuf;
323    sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
324    os << obuf;
325    //Take out the stack bias
326    sp += 2047;
327    //Output the window save area
328    for(unsigned int x = 0; x < 16; x++)
329    {
330        uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
331        sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
332                sp, x+1, regspot);
333        os << obuf;
334        sp += 8;
335    }
336    //Output the argument count
337    uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
338    sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
339    os << obuf;
340    sp += 8;
341    //Output argv pointers
342    int argCount = 0;
343    uint64_t cargv;
344    do
345    {
346        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
347        sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
348                sp, argCount++, cargv);
349        os << obuf;
350        sp += 8;
351    } while(cargv);
352    //Output the envp pointers
353    int envCount = 0;
354    uint64_t cenvp;
355    do
356    {
357        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
358        sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
359                sp, envCount++, cenvp);
360        os << obuf;
361        sp += 8;
362    } while(cenvp);
363    uint64_t auxType, auxVal;
364    do
365    {
366        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
367        sp += 8;
368        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
369        sp += 8;
370        sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
371                sp - 16, auxType, auxVal);
372        os << obuf;
373    } while(auxType != 0 || auxVal != 0);
374    //Print out the argument strings, environment strings, and file name.
375    string current;
376    uint64_t buf;
377    uint64_t currentStart = sp;
378    bool clearedInitialPadding = false;
379    do
380    {
381        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
382        char * cbuf = (char *)&buf;
383        for(int x = 0; x < sizeof(uint64_t); x++)
384        {
385            if(cbuf[x])
386                current += cbuf[x];
387            else
388            {
389                sprintf(obuf, "0x%016llx: \"%s\"\n",
390                        currentStart, current.c_str());
391                os << obuf;
392                current = "";
393                currentStart = sp + x + 1;
394            }
395        }
396        sp += 8;
397        clearedInitialPadding = clearedInitialPadding || buf != 0;
398    } while(!clearedInitialPadding || buf != 0);
399    return os;
400}
401
402TraceChild * genTraceChild()
403{
404    return new SparcTraceChild;
405}
406
407