tracechild.cc revision 8108
1/*
2 * Copyright (c) 2006-2007 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
57bool
58SparcTraceChild::sendState(int socket)
59{
60    uint64_t regVal = 0;
61    for (int x = 0; x <= I7; x++) {
62        regVal = getRegVal(x);
63        if (write(socket, &regVal, sizeof(regVal)) == -1) {
64            cerr << "Write failed! " << strerror(errno) << endl;
65            tracing = false;
66            return false;
67        }
68    }
69    regVal = getRegVal(PC);
70    if (write(socket, &regVal, sizeof(regVal)) == -1) {
71        cerr << "Write failed! " << strerror(errno) << endl;
72        tracing = false;
73        return false;
74    }
75    regVal = getRegVal(NPC);
76    if (write(socket, &regVal, sizeof(regVal)) == -1) {
77        cerr << "Write failed! " << strerror(errno) << endl;
78        tracing = false;
79        return false;
80    }
81    regVal = getRegVal(CCR);
82    if (write(socket, &regVal, sizeof(regVal)) == -1) {
83        cerr << "Write failed! " << strerror(errno) << endl;
84        tracing = false;
85        return false;
86    }
87    return true;
88}
89
90int64_t
91getRegs(regs & myregs, fpu & myfpu, uint64_t * locals,
92        uint64_t * inputs, int num)
93{
94    assert(num < SparcTraceChild::numregs && num >= 0);
95    switch (num) {
96      //Global registers
97      case SparcTraceChild::G0: return 0;
98      case SparcTraceChild::G1: return myregs.r_g1;
99      case SparcTraceChild::G2: return myregs.r_g2;
100      case SparcTraceChild::G3: return myregs.r_g3;
101      case SparcTraceChild::G4: return myregs.r_g4;
102      case SparcTraceChild::G5: return myregs.r_g5;
103      case SparcTraceChild::G6: return myregs.r_g6;
104      case SparcTraceChild::G7: return myregs.r_g7;
105      //Output registers
106      case SparcTraceChild::O0: return myregs.r_o0;
107      case SparcTraceChild::O1: return myregs.r_o1;
108      case SparcTraceChild::O2: return myregs.r_o2;
109      case SparcTraceChild::O3: return myregs.r_o3;
110      case SparcTraceChild::O4: return myregs.r_o4;
111      case SparcTraceChild::O5: return myregs.r_o5;
112      case SparcTraceChild::O6: return myregs.r_o6;
113      case SparcTraceChild::O7: return myregs.r_o7;
114      //Local registers
115      case SparcTraceChild::L0: return locals[0];
116      case SparcTraceChild::L1: return locals[1];
117      case SparcTraceChild::L2: return locals[2];
118      case SparcTraceChild::L3: return locals[3];
119      case SparcTraceChild::L4: return locals[4];
120      case SparcTraceChild::L5: return locals[5];
121      case SparcTraceChild::L6: return locals[6];
122      case SparcTraceChild::L7: return locals[7];
123      //Input registers
124      case SparcTraceChild::I0: return inputs[0];
125      case SparcTraceChild::I1: return inputs[1];
126      case SparcTraceChild::I2: return inputs[2];
127      case SparcTraceChild::I3: return inputs[3];
128      case SparcTraceChild::I4: return inputs[4];
129      case SparcTraceChild::I5: return inputs[5];
130      case SparcTraceChild::I6: return inputs[6];
131      case SparcTraceChild::I7: return inputs[7];
132      //Floating point
133      case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0];
134      case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1];
135      case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2];
136      case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3];
137      case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4];
138      case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5];
139      case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6];
140      case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7];
141      case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8];
142      case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9];
143      case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10];
144      case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11];
145      case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12];
146      case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13];
147      case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14];
148      case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15];
149      case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16];
150      case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17];
151      case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18];
152      case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19];
153      case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20];
154      case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21];
155      case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22];
156      case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23];
157      case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24];
158      case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25];
159      case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26];
160      case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27];
161      case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28];
162      case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29];
163      case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30];
164      case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31];
165      //Miscelaneous
166      case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr;
167      case SparcTraceChild::FPRS: return myregs.r_fprs;
168      case SparcTraceChild::PC: return myregs.r_tpc;
169      case SparcTraceChild::NPC: return myregs.r_tnpc;
170      case SparcTraceChild::Y: return myregs.r_y;
171      case SparcTraceChild::CWP:
172        return (myregs.r_tstate >> 0) & ((1 << 5) - 1);
173      case SparcTraceChild::PSTATE:
174        return (myregs.r_tstate >> 8) & ((1 << 13) - 1);
175      case SparcTraceChild::ASI:
176        return (myregs.r_tstate >> 24) & ((1 << 8) - 1);
177      case SparcTraceChild::CCR:
178        return (myregs.r_tstate >> 32) & ((1 << 8) - 1);
179      default:
180        assert(0);
181        return 0;
182    }
183}
184
185bool
186SparcTraceChild::update(int pid)
187{
188    memcpy(&oldregs, &theregs, sizeof(regs));
189    memcpy(&oldfpregs, &thefpregs, sizeof(fpu));
190    memcpy(oldLocals, locals, 8 * sizeof(uint64_t));
191    memcpy(oldInputs, inputs, 8 * sizeof(uint64_t));
192    if (ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) {
193        cerr << "Update failed" << endl;
194        return false;
195    }
196    uint64_t stackPointer = getSP();
197    uint64_t stackBias = 2047;
198    bool v9 = stackPointer % 2;
199    for (unsigned int x = 0; x < 8; x++) {
200        uint64_t localAddr = stackPointer +
201            (v9 ? (stackBias + x * 8) : (x * 4));
202        locals[x] = ptrace(PTRACE_PEEKTEXT, pid, localAddr, 0);
203        if (!v9) locals[x] >>= 32;
204        uint64_t inputAddr = stackPointer +
205            (v9 ? (stackBias + x * 8 + (8 * 8)) : (x * 4 + 8 * 4));
206        inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, inputAddr, 0);
207        if (!v9) inputs[x] >>= 32;
208    }
209    if (ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0)
210        return false;
211    for (unsigned int x = 0; x < numregs; x++)
212        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
213    return true;
214}
215
216SparcTraceChild::SparcTraceChild()
217{
218    for (unsigned int x = 0; x < numregs; x++)
219        regDiffSinceUpdate[x] = false;
220}
221
222int
223SparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
224                            uint64_t &target1, uint64_t &target2)
225{
226    //We can identify the instruction categories we care about using the top
227    //10 bits of the instruction, excluding the annul bit in the 3rd most
228    //significant bit position and the condition field. We'll call these
229    //bits the "sig" for signature.
230    uint32_t sig = (inst >> 22) & 0x307;
231    uint32_t cond = (inst >> 25) & 0xf;
232    bool annul = (inst & (1 << 29));
233
234    //Check if it's a ba...
235    bool ba = (cond == 0x8) &&
236        (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
237    //or a bn...
238    bool bn = (cond == 0x0) &&
239        (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
240    //or a bcc
241    bool bcc = (cond & 0x7) &&
242        (sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6);
243
244    if (annul) {
245        if (bcc) {
246            target1 = npc;
247            target2 = npc + 4;
248            return 2;
249        } else if(ba) {
250            //This branches immediately to the effective address of the branch
251            //which we'll have to calculate.
252            uint64_t disp = 0;
253            int64_t extender = 0;
254            //Figure out how big the displacement field is, and grab the bits
255            if (sig == 0x1 || sig == 0x5) {
256                disp = inst & ((1 << 19) - 1);
257                extender = 1 << 18;
258            } else {
259                disp = inst & ((1 << 22) - 1);
260                extender = 1 << 21;
261            }
262            //This does sign extension, believe it or not.
263            disp = (disp ^ extender) - extender;
264            //Multiply the displacement by 4. I'm assuming the compiler is
265            //smart enough to turn this into a shift.
266            disp *= 4;
267            target1 = pc + disp;
268        } else if(bn)
269            target1 = npc + 4;
270        else
271            target1 = npc;
272        return 1;
273    } else {
274        target1 = npc;
275        return 1;
276    }
277}
278
279bool
280SparcTraceChild::step()
281{
282    //Increment the count of the number of instructions executed
283    instructions++;
284    //Two important considerations are that the address of the instruction
285    //being breakpointed should be word (64bit) aligned, and that both the
286    //next instruction and the instruction after that need to be breakpointed
287    //so that annulled branches will still stop as well.
288
289    /*
290     * Useful constants
291     */
292    const static uint64_t breakInst = 0x91d02001;
293    const static uint64_t lowBreakInst = breakInst;
294    const static uint64_t highBreakInst = breakInst << 32;
295    const static uint64_t breakWord = breakInst | (breakInst << 32);
296    const static uint64_t lowMask = 0xFFFFFFFFULL;
297    const static uint64_t highMask = lowMask << 32;
298
299    /*
300     * storage for the original contents of the child process's memory
301     */
302    uint64_t originalInst, originalAnnulInst;
303
304    /*
305     * Get information about where the process is and is headed next.
306     */
307    uint64_t currentPC = getRegVal(PC);
308    bool unalignedPC = currentPC & 7;
309    uint64_t alignedPC = currentPC & (~7);
310    uint64_t nextPC = getRegVal(NPC);
311    bool unalignedNPC = nextPC & 7;
312    uint64_t alignedNPC = nextPC & (~7);
313
314    //Get the current instruction
315    uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC);
316    curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32);
317
318    uint64_t bp1, bp2;
319    int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2);
320    assert(numTargets == 1 || numTargets == 2);
321
322    bool unalignedBp1 = bp1 & 7;
323    uint64_t alignedBp1 = bp1 & (~7);
324    bool unalignedBp2 = bp2 & 7;
325    uint64_t alignedBp2 = bp2 & (~7);
326    uint64_t origBp1, origBp2;
327
328    /*
329     * Set the first breakpoint
330     */
331    origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0);
332    uint64_t newBp1 = origBp1;
333    newBp1 &= unalignedBp1 ? highMask : lowMask;
334    newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst;
335    if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0)
336        cerr << "Poke failed" << endl;
337    /*
338     * Set the second breakpoint if necessary
339     */
340    if (numTargets == 2) {
341        origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0);
342        uint64_t newBp2 = origBp2;
343        newBp2 &= unalignedBp2 ? highMask : lowMask;
344        newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst;
345        if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0)
346            cerr << "Poke failed" << endl;
347    }
348
349    /*
350     * Restart the child process
351     */
352    //Note that the "addr" parameter is supposed to be ignored, but in at
353    //least one version of the kernel, it must be 1 or it will set what
354    //pc to continue from
355    if (ptrace(PTRACE_CONT, pid, 1, 0) != 0)
356        cerr << "Cont failed" << endl;
357    doWait();
358
359    /*
360     * Update our record of the child's state
361     */
362    update(pid);
363
364    /*
365     * Put back the original contents of the childs address space in the
366     * reverse order.
367     */
368    if (numTargets == 2) {
369        if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0)
370            cerr << "Poke failed" << endl;
371    }
372    if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0)
373        cerr << "Poke failed" << endl;
374}
375
376int64_t
377SparcTraceChild::getRegVal(int num)
378{
379    return getRegs(theregs, thefpregs, locals, inputs, num);
380}
381
382int64_t
383SparcTraceChild::getOldRegVal(int num)
384{
385    return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
386}
387
388char *
389SparcTraceChild::printReg(int num)
390{
391    sprintf(printBuffer, "0x%016llx", getRegVal(num));
392    return printBuffer;
393}
394
395ostream &
396SparcTraceChild::outputStartState(ostream & os)
397{
398    bool v8 = false;
399    uint64_t sp = getSP();
400    if (sp % 2) {
401        os << "Detected a 64 bit executable.\n";
402        v8 = false;
403    } else {
404        os << "Detected a 32 bit executable.\n";
405        v8 = true;
406    }
407    uint64_t pc = getPC();
408    char obuf[1024];
409    sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
410    os << obuf;
411    sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
412    os << obuf;
413    if (!v8) {
414        //Take out the stack bias
415        sp += 2047;
416    }
417    //Output the window save area
418    for (unsigned int x = 0; x < 16; x++) {
419        uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
420        if (v8) regspot = regspot >> 32;
421        sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
422                sp, x+1, regspot);
423        os << obuf;
424        sp += v8 ? 4 : 8;
425    }
426    //Output the argument count
427    uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
428    if (v8) cargc = cargc >> 32;
429    sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
430    os << obuf;
431    sp += v8 ? 4 : 8;
432    //Output argv pointers
433    int argCount = 0;
434    uint64_t cargv;
435    do {
436        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
437        if (v8) cargv = cargv >> 32;
438        sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
439                sp, argCount++, cargv);
440        os << obuf;
441        sp += v8 ? 4 : 8;
442    } while(cargv);
443    //Output the envp pointers
444    int envCount = 0;
445    uint64_t cenvp;
446    do {
447        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
448        if (v8) cenvp = cenvp >> 32;
449        sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
450                sp, envCount++, cenvp);
451        os << obuf;
452        sp += v8 ? 4 : 8;
453    } while (cenvp);
454    uint64_t auxType, auxVal;
455    do {
456        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
457        if (v8) auxType = auxType >> 32;
458        sp += (v8 ? 4 : 8);
459        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
460        if (v8) auxVal = auxVal >> 32;
461        sp += (v8 ? 4 : 8);
462        sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
463                sp - 8, auxType, auxVal);
464        os << obuf;
465    } while (auxType != 0 || auxVal != 0);
466    //Print out the argument strings, environment strings, and file name.
467    string current;
468    uint64_t buf;
469    uint64_t currentStart = sp;
470    bool clearedInitialPadding = false;
471    do {
472        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
473        char * cbuf = (char *)&buf;
474        for (int x = 0; x < sizeof(uint32_t); x++) {
475            if (cbuf[x])
476                current += cbuf[x];
477            else {
478                sprintf(obuf, "0x%016llx: \"%s\"\n",
479                        currentStart, current.c_str());
480                os << obuf;
481                current = "";
482                currentStart = sp + x + 1;
483            }
484        }
485        sp += (v8 ? 4 : 8);
486        clearedInitialPadding = clearedInitialPadding || buf != 0;
487    } while (!clearedInitialPadding || buf != 0);
488    return os;
489}
490
491TraceChild *
492genTraceChild()
493{
494    return new SparcTraceChild;
495}
496
497