tracechild.cc revision 8113
13115SN/A/* 24125SN/A * Copyright (c) 2006-2007 The Regents of The University of Michigan 33115SN/A * All rights reserved. 43115SN/A * 53115SN/A * Redistribution and use in source and binary forms, with or without 63115SN/A * modification, are permitted provided that the following conditions are 73115SN/A * met: redistributions of source code must retain the above copyright 83115SN/A * notice, this list of conditions and the following disclaimer; 93115SN/A * redistributions in binary form must reproduce the above copyright 103115SN/A * notice, this list of conditions and the following disclaimer in the 113115SN/A * documentation and/or other materials provided with the distribution; 123115SN/A * neither the name of the copyright holders nor the names of its 133115SN/A * contributors may be used to endorse or promote products derived from 143115SN/A * this software without specific prior written permission. 153115SN/A * 163115SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173115SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183115SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193115SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203115SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213115SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223115SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233115SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243115SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253115SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263115SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273115SN/A * 283115SN/A * Authors: Gabe Black 293115SN/A */ 303115SN/A 313115SN/A#include <iostream> 323115SN/A#include <errno.h> 333115SN/A#include <sys/ptrace.h> 343115SN/A#include <stdint.h> 353115SN/A 368113Sgblack@eecs.umich.edu#include "arch/sparc/tracechild.hh" 373115SN/A 383115SN/Ausing namespace std; 393115SN/A 408108SN/Abool 418108SN/ASparcTraceChild::sendState(int socket) 424245SN/A{ 434245SN/A uint64_t regVal = 0; 448108SN/A for (int x = 0; x <= I7; x++) { 454245SN/A regVal = getRegVal(x); 468108SN/A if (write(socket, ®Val, sizeof(regVal)) == -1) { 474245SN/A cerr << "Write failed! " << strerror(errno) << endl; 484245SN/A tracing = false; 494245SN/A return false; 504245SN/A } 514245SN/A } 524245SN/A regVal = getRegVal(PC); 538108SN/A if (write(socket, ®Val, sizeof(regVal)) == -1) { 544245SN/A cerr << "Write failed! " << strerror(errno) << endl; 554245SN/A tracing = false; 564245SN/A return false; 574245SN/A } 584245SN/A regVal = getRegVal(NPC); 598108SN/A if (write(socket, ®Val, sizeof(regVal)) == -1) { 604245SN/A cerr << "Write failed! " << strerror(errno) << endl; 614245SN/A tracing = false; 624245SN/A return false; 634245SN/A } 644245SN/A regVal = getRegVal(CCR); 658108SN/A if (write(socket, ®Val, sizeof(regVal)) == -1) { 664245SN/A cerr << "Write failed! " << strerror(errno) << endl; 674245SN/A tracing = false; 684245SN/A return false; 694245SN/A } 704245SN/A return true; 714245SN/A} 724245SN/A 738108SN/Aint64_t 748108SN/AgetRegs(regs & myregs, fpu & myfpu, uint64_t * locals, 758108SN/A uint64_t * inputs, int num) 763115SN/A{ 773115SN/A assert(num < SparcTraceChild::numregs && num >= 0); 788108SN/A switch (num) { 798108SN/A //Global registers 808108SN/A case SparcTraceChild::G0: return 0; 818108SN/A case SparcTraceChild::G1: return myregs.r_g1; 828108SN/A case SparcTraceChild::G2: return myregs.r_g2; 838108SN/A case SparcTraceChild::G3: return myregs.r_g3; 848108SN/A case SparcTraceChild::G4: return myregs.r_g4; 858108SN/A case SparcTraceChild::G5: return myregs.r_g5; 868108SN/A case SparcTraceChild::G6: return myregs.r_g6; 878108SN/A case SparcTraceChild::G7: return myregs.r_g7; 888108SN/A //Output registers 898108SN/A case SparcTraceChild::O0: return myregs.r_o0; 908108SN/A case SparcTraceChild::O1: return myregs.r_o1; 918108SN/A case SparcTraceChild::O2: return myregs.r_o2; 928108SN/A case SparcTraceChild::O3: return myregs.r_o3; 938108SN/A case SparcTraceChild::O4: return myregs.r_o4; 948108SN/A case SparcTraceChild::O5: return myregs.r_o5; 958108SN/A case SparcTraceChild::O6: return myregs.r_o6; 968108SN/A case SparcTraceChild::O7: return myregs.r_o7; 978108SN/A //Local registers 988108SN/A case SparcTraceChild::L0: return locals[0]; 998108SN/A case SparcTraceChild::L1: return locals[1]; 1008108SN/A case SparcTraceChild::L2: return locals[2]; 1018108SN/A case SparcTraceChild::L3: return locals[3]; 1028108SN/A case SparcTraceChild::L4: return locals[4]; 1038108SN/A case SparcTraceChild::L5: return locals[5]; 1048108SN/A case SparcTraceChild::L6: return locals[6]; 1058108SN/A case SparcTraceChild::L7: return locals[7]; 1068108SN/A //Input registers 1078108SN/A case SparcTraceChild::I0: return inputs[0]; 1088108SN/A case SparcTraceChild::I1: return inputs[1]; 1098108SN/A case SparcTraceChild::I2: return inputs[2]; 1108108SN/A case SparcTraceChild::I3: return inputs[3]; 1118108SN/A case SparcTraceChild::I4: return inputs[4]; 1128108SN/A case SparcTraceChild::I5: return inputs[5]; 1138108SN/A case SparcTraceChild::I6: return inputs[6]; 1148108SN/A case SparcTraceChild::I7: return inputs[7]; 1158108SN/A //Floating point 1168108SN/A case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0]; 1178108SN/A case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1]; 1188108SN/A case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2]; 1198108SN/A case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3]; 1208108SN/A case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4]; 1218108SN/A case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5]; 1228108SN/A case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6]; 1238108SN/A case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7]; 1248108SN/A case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8]; 1258108SN/A case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9]; 1268108SN/A case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10]; 1278108SN/A case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11]; 1288108SN/A case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12]; 1298108SN/A case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13]; 1308108SN/A case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14]; 1318108SN/A case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15]; 1328108SN/A case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16]; 1338108SN/A case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17]; 1348108SN/A case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18]; 1358108SN/A case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19]; 1368108SN/A case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20]; 1378108SN/A case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21]; 1388108SN/A case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22]; 1398108SN/A case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23]; 1408108SN/A case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24]; 1418108SN/A case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25]; 1428108SN/A case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26]; 1438108SN/A case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27]; 1448108SN/A case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28]; 1458108SN/A case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29]; 1468108SN/A case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30]; 1478108SN/A case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31]; 1488108SN/A //Miscelaneous 1498108SN/A case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr; 1508108SN/A case SparcTraceChild::FPRS: return myregs.r_fprs; 1518108SN/A case SparcTraceChild::PC: return myregs.r_tpc; 1528108SN/A case SparcTraceChild::NPC: return myregs.r_tnpc; 1538108SN/A case SparcTraceChild::Y: return myregs.r_y; 1548108SN/A case SparcTraceChild::CWP: 1558108SN/A return (myregs.r_tstate >> 0) & ((1 << 5) - 1); 1568108SN/A case SparcTraceChild::PSTATE: 1578108SN/A return (myregs.r_tstate >> 8) & ((1 << 13) - 1); 1588108SN/A case SparcTraceChild::ASI: 1598108SN/A return (myregs.r_tstate >> 24) & ((1 << 8) - 1); 1608108SN/A case SparcTraceChild::CCR: 1618108SN/A return (myregs.r_tstate >> 32) & ((1 << 8) - 1); 1628108SN/A default: 1638108SN/A assert(0); 1648108SN/A return 0; 1653115SN/A } 1663115SN/A} 1673115SN/A 1688108SN/Abool 1698108SN/ASparcTraceChild::update(int pid) 1703115SN/A{ 1713115SN/A memcpy(&oldregs, &theregs, sizeof(regs)); 1723115SN/A memcpy(&oldfpregs, &thefpregs, sizeof(fpu)); 1733115SN/A memcpy(oldLocals, locals, 8 * sizeof(uint64_t)); 1743115SN/A memcpy(oldInputs, inputs, 8 * sizeof(uint64_t)); 1758108SN/A if (ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) { 1763115SN/A cerr << "Update failed" << endl; 1773115SN/A return false; 1783115SN/A } 1794245SN/A uint64_t stackPointer = getSP(); 1804245SN/A uint64_t stackBias = 2047; 1814245SN/A bool v9 = stackPointer % 2; 1828108SN/A for (unsigned int x = 0; x < 8; x++) { 1834245SN/A uint64_t localAddr = stackPointer + 1844245SN/A (v9 ? (stackBias + x * 8) : (x * 4)); 1854245SN/A locals[x] = ptrace(PTRACE_PEEKTEXT, pid, localAddr, 0); 1868108SN/A if (!v9) locals[x] >>= 32; 1874245SN/A uint64_t inputAddr = stackPointer + 1884245SN/A (v9 ? (stackBias + x * 8 + (8 * 8)) : (x * 4 + 8 * 4)); 1894245SN/A inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, inputAddr, 0); 1908108SN/A if (!v9) inputs[x] >>= 32; 1913115SN/A } 1928108SN/A if (ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0) 1933115SN/A return false; 1948108SN/A for (unsigned int x = 0; x < numregs; x++) 1953115SN/A regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 1963115SN/A return true; 1973115SN/A} 1983115SN/A 1993115SN/ASparcTraceChild::SparcTraceChild() 2003115SN/A{ 2018108SN/A for (unsigned int x = 0; x < numregs; x++) 2023115SN/A regDiffSinceUpdate[x] = false; 2033115SN/A} 2043115SN/A 2058108SN/Aint 2068108SN/ASparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc, 2078108SN/A uint64_t &target1, uint64_t &target2) 2084125SN/A{ 2094125SN/A //We can identify the instruction categories we care about using the top 2104125SN/A //10 bits of the instruction, excluding the annul bit in the 3rd most 2114125SN/A //significant bit position and the condition field. We'll call these 2124125SN/A //bits the "sig" for signature. 2134125SN/A uint32_t sig = (inst >> 22) & 0x307; 2144125SN/A uint32_t cond = (inst >> 25) & 0xf; 2154125SN/A bool annul = (inst & (1 << 29)); 2164125SN/A 2174125SN/A //Check if it's a ba... 2184125SN/A bool ba = (cond == 0x8) && 2194125SN/A (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6); 2204125SN/A //or a bn... 2214125SN/A bool bn = (cond == 0x0) && 2224125SN/A (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6); 2234125SN/A //or a bcc 2244125SN/A bool bcc = (cond & 0x7) && 2254125SN/A (sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6); 2264125SN/A 2278108SN/A if (annul) { 2288108SN/A if (bcc) { 2294125SN/A target1 = npc; 2304125SN/A target2 = npc + 4; 2314125SN/A return 2; 2328108SN/A } else if(ba) { 2334125SN/A //This branches immediately to the effective address of the branch 2344125SN/A //which we'll have to calculate. 2354125SN/A uint64_t disp = 0; 2364125SN/A int64_t extender = 0; 2374125SN/A //Figure out how big the displacement field is, and grab the bits 2388108SN/A if (sig == 0x1 || sig == 0x5) { 2394125SN/A disp = inst & ((1 << 19) - 1); 2404125SN/A extender = 1 << 18; 2418108SN/A } else { 2424125SN/A disp = inst & ((1 << 22) - 1); 2434125SN/A extender = 1 << 21; 2444125SN/A } 2454125SN/A //This does sign extension, believe it or not. 2464125SN/A disp = (disp ^ extender) - extender; 2474125SN/A //Multiply the displacement by 4. I'm assuming the compiler is 2484125SN/A //smart enough to turn this into a shift. 2494125SN/A disp *= 4; 2504125SN/A target1 = pc + disp; 2518108SN/A } else if(bn) 2524125SN/A target1 = npc + 4; 2534125SN/A else 2544125SN/A target1 = npc; 2554125SN/A return 1; 2568108SN/A } else { 2574125SN/A target1 = npc; 2584125SN/A return 1; 2594125SN/A } 2604125SN/A} 2614125SN/A 2628108SN/Abool 2638108SN/ASparcTraceChild::step() 2643115SN/A{ 2654125SN/A //Increment the count of the number of instructions executed 2664125SN/A instructions++; 2673115SN/A //Two important considerations are that the address of the instruction 2683115SN/A //being breakpointed should be word (64bit) aligned, and that both the 2693115SN/A //next instruction and the instruction after that need to be breakpointed 2703115SN/A //so that annulled branches will still stop as well. 2713382SN/A 2723382SN/A /* 2733382SN/A * Useful constants 2743382SN/A */ 2753115SN/A const static uint64_t breakInst = 0x91d02001; 2764125SN/A const static uint64_t lowBreakInst = breakInst; 2774125SN/A const static uint64_t highBreakInst = breakInst << 32; 2783115SN/A const static uint64_t breakWord = breakInst | (breakInst << 32); 2793382SN/A const static uint64_t lowMask = 0xFFFFFFFFULL; 2803115SN/A const static uint64_t highMask = lowMask << 32; 2813382SN/A 2823382SN/A /* 2833382SN/A * storage for the original contents of the child process's memory 2843382SN/A */ 2853115SN/A uint64_t originalInst, originalAnnulInst; 2863382SN/A 2873382SN/A /* 2883382SN/A * Get information about where the process is and is headed next. 2893382SN/A */ 2903382SN/A uint64_t currentPC = getRegVal(PC); 2913382SN/A bool unalignedPC = currentPC & 7; 2923382SN/A uint64_t alignedPC = currentPC & (~7); 2933115SN/A uint64_t nextPC = getRegVal(NPC); 2943382SN/A bool unalignedNPC = nextPC & 7; 2953382SN/A uint64_t alignedNPC = nextPC & (~7); 2963382SN/A 2974125SN/A //Get the current instruction 2984125SN/A uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC); 2994125SN/A curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32); 3004125SN/A 3014125SN/A uint64_t bp1, bp2; 3024125SN/A int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2); 3034125SN/A assert(numTargets == 1 || numTargets == 2); 3044125SN/A 3054125SN/A bool unalignedBp1 = bp1 & 7; 3064125SN/A uint64_t alignedBp1 = bp1 & (~7); 3074125SN/A bool unalignedBp2 = bp2 & 7; 3084125SN/A uint64_t alignedBp2 = bp2 & (~7); 3094125SN/A uint64_t origBp1, origBp2; 3103382SN/A 3113382SN/A /* 3124125SN/A * Set the first breakpoint 3133382SN/A */ 3144125SN/A origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0); 3154125SN/A uint64_t newBp1 = origBp1; 3164125SN/A newBp1 &= unalignedBp1 ? highMask : lowMask; 3174125SN/A newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst; 3188108SN/A if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0) 3194125SN/A cerr << "Poke failed" << endl; 3204125SN/A /* 3214125SN/A * Set the second breakpoint if necessary 3224125SN/A */ 3238108SN/A if (numTargets == 2) { 3244125SN/A origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0); 3254125SN/A uint64_t newBp2 = origBp2; 3264125SN/A newBp2 &= unalignedBp2 ? highMask : lowMask; 3274125SN/A newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst; 3288108SN/A if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0) 3293115SN/A cerr << "Poke failed" << endl; 3303115SN/A } 3313382SN/A 3323382SN/A /* 3333382SN/A * Restart the child process 3343382SN/A */ 3353115SN/A //Note that the "addr" parameter is supposed to be ignored, but in at 3363115SN/A //least one version of the kernel, it must be 1 or it will set what 3373115SN/A //pc to continue from 3388108SN/A if (ptrace(PTRACE_CONT, pid, 1, 0) != 0) 3393115SN/A cerr << "Cont failed" << endl; 3403115SN/A doWait(); 3413382SN/A 3423382SN/A /* 3433382SN/A * Update our record of the child's state 3443382SN/A */ 3453115SN/A update(pid); 3463382SN/A 3473382SN/A /* 3484125SN/A * Put back the original contents of the childs address space in the 3494125SN/A * reverse order. 3503382SN/A */ 3518108SN/A if (numTargets == 2) { 3528108SN/A if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0) 3534125SN/A cerr << "Poke failed" << endl; 3543115SN/A } 3558108SN/A if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0) 3564125SN/A cerr << "Poke failed" << endl; 3573115SN/A} 3583115SN/A 3598108SN/Aint64_t 3608108SN/ASparcTraceChild::getRegVal(int num) 3613115SN/A{ 3623115SN/A return getRegs(theregs, thefpregs, locals, inputs, num); 3633115SN/A} 3643115SN/A 3658108SN/Aint64_t 3668108SN/ASparcTraceChild::getOldRegVal(int num) 3673115SN/A{ 3683115SN/A return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num); 3693115SN/A} 3703115SN/A 3718108SN/Aostream & 3728108SN/ASparcTraceChild::outputStartState(ostream & os) 3733115SN/A{ 3744125SN/A bool v8 = false; 3753115SN/A uint64_t sp = getSP(); 3768108SN/A if (sp % 2) { 3774125SN/A os << "Detected a 64 bit executable.\n"; 3784125SN/A v8 = false; 3798108SN/A } else { 3804125SN/A os << "Detected a 32 bit executable.\n"; 3814125SN/A v8 = true; 3824125SN/A } 3833115SN/A uint64_t pc = getPC(); 3843115SN/A char obuf[1024]; 3853115SN/A sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp); 3863115SN/A os << obuf; 3873115SN/A sprintf(obuf, "Initial program counter = 0x%016llx\n", pc); 3883115SN/A os << obuf; 3898108SN/A if (!v8) { 3904125SN/A //Take out the stack bias 3914125SN/A sp += 2047; 3924125SN/A } 3933115SN/A //Output the window save area 3948108SN/A for (unsigned int x = 0; x < 16; x++) { 3953115SN/A uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 3968108SN/A if (v8) regspot = regspot >> 32; 3973115SN/A sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n", 3983115SN/A sp, x+1, regspot); 3993115SN/A os << obuf; 4004125SN/A sp += v8 ? 4 : 8; 4013115SN/A } 4023115SN/A //Output the argument count 4033115SN/A uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 4048108SN/A if (v8) cargc = cargc >> 32; 4053115SN/A sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc); 4063115SN/A os << obuf; 4074125SN/A sp += v8 ? 4 : 8; 4083115SN/A //Output argv pointers 4093115SN/A int argCount = 0; 4103115SN/A uint64_t cargv; 4118108SN/A do { 4123115SN/A cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 4138108SN/A if (v8) cargv = cargv >> 32; 4143115SN/A sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n", 4153115SN/A sp, argCount++, cargv); 4163115SN/A os << obuf; 4174125SN/A sp += v8 ? 4 : 8; 4183115SN/A } while(cargv); 4193115SN/A //Output the envp pointers 4203115SN/A int envCount = 0; 4213115SN/A uint64_t cenvp; 4228108SN/A do { 4233115SN/A cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 4248108SN/A if (v8) cenvp = cenvp >> 32; 4253115SN/A sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n", 4263115SN/A sp, envCount++, cenvp); 4273115SN/A os << obuf; 4284125SN/A sp += v8 ? 4 : 8; 4298108SN/A } while (cenvp); 4303115SN/A uint64_t auxType, auxVal; 4318108SN/A do { 4323115SN/A auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 4338108SN/A if (v8) auxType = auxType >> 32; 4344125SN/A sp += (v8 ? 4 : 8); 4353115SN/A auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 4368108SN/A if (v8) auxVal = auxVal >> 32; 4374125SN/A sp += (v8 ? 4 : 8); 4383115SN/A sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", 4394125SN/A sp - 8, auxType, auxVal); 4403115SN/A os << obuf; 4418108SN/A } while (auxType != 0 || auxVal != 0); 4423115SN/A //Print out the argument strings, environment strings, and file name. 4433115SN/A string current; 4443115SN/A uint64_t buf; 4453115SN/A uint64_t currentStart = sp; 4463115SN/A bool clearedInitialPadding = false; 4478108SN/A do { 4483115SN/A buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 4493115SN/A char * cbuf = (char *)&buf; 4508108SN/A for (int x = 0; x < sizeof(uint32_t); x++) { 4518108SN/A if (cbuf[x]) 4523115SN/A current += cbuf[x]; 4538108SN/A else { 4543115SN/A sprintf(obuf, "0x%016llx: \"%s\"\n", 4553115SN/A currentStart, current.c_str()); 4563115SN/A os << obuf; 4573115SN/A current = ""; 4583115SN/A currentStart = sp + x + 1; 4593115SN/A } 4603115SN/A } 4614125SN/A sp += (v8 ? 4 : 8); 4623115SN/A clearedInitialPadding = clearedInitialPadding || buf != 0; 4638108SN/A } while (!clearedInitialPadding || buf != 0); 4643115SN/A return os; 4653115SN/A} 4663115SN/A 4678108SN/ATraceChild * 4688108SN/AgenTraceChild() 4693115SN/A{ 4703115SN/A return new SparcTraceChild; 4713115SN/A} 4723115SN/A 473