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