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 <sys/ptrace.h>
323115SN/A#include <stdint.h>
333115SN/A
348229Snate@binkert.org#include <cerrno>
358229Snate@binkert.org#include <iostream>
368229Snate@binkert.org
378113Sgblack@eecs.umich.edu#include "arch/sparc/tracechild.hh"
383115SN/A
393115SN/Ausing namespace std;
403115SN/A
418108SN/Abool
428108SN/ASparcTraceChild::sendState(int socket)
434245SN/A{
444245SN/A    uint64_t regVal = 0;
458108SN/A    for (int x = 0; x <= I7; x++) {
464245SN/A        regVal = getRegVal(x);
478108SN/A        if (write(socket, &regVal, sizeof(regVal)) == -1) {
484245SN/A            cerr << "Write failed! " << strerror(errno) << endl;
494245SN/A            tracing = false;
504245SN/A            return false;
514245SN/A        }
524245SN/A    }
534245SN/A    regVal = getRegVal(PC);
548108SN/A    if (write(socket, &regVal, sizeof(regVal)) == -1) {
554245SN/A        cerr << "Write failed! " << strerror(errno) << endl;
564245SN/A        tracing = false;
574245SN/A        return false;
584245SN/A    }
594245SN/A    regVal = getRegVal(NPC);
608108SN/A    if (write(socket, &regVal, sizeof(regVal)) == -1) {
614245SN/A        cerr << "Write failed! " << strerror(errno) << endl;
624245SN/A        tracing = false;
634245SN/A        return false;
644245SN/A    }
654245SN/A    regVal = getRegVal(CCR);
668108SN/A    if (write(socket, &regVal, sizeof(regVal)) == -1) {
674245SN/A        cerr << "Write failed! " << strerror(errno) << endl;
684245SN/A        tracing = false;
694245SN/A        return false;
704245SN/A    }
714245SN/A    return true;
724245SN/A}
734245SN/A
748108SN/Aint64_t
758108SN/AgetRegs(regs & myregs, fpu & myfpu, uint64_t * locals,
768108SN/A        uint64_t * inputs, int num)
773115SN/A{
783115SN/A    assert(num < SparcTraceChild::numregs && num >= 0);
798108SN/A    switch (num) {
808108SN/A      //Global registers
818108SN/A      case SparcTraceChild::G0: return 0;
828108SN/A      case SparcTraceChild::G1: return myregs.r_g1;
838108SN/A      case SparcTraceChild::G2: return myregs.r_g2;
848108SN/A      case SparcTraceChild::G3: return myregs.r_g3;
858108SN/A      case SparcTraceChild::G4: return myregs.r_g4;
868108SN/A      case SparcTraceChild::G5: return myregs.r_g5;
878108SN/A      case SparcTraceChild::G6: return myregs.r_g6;
888108SN/A      case SparcTraceChild::G7: return myregs.r_g7;
898108SN/A      //Output registers
908108SN/A      case SparcTraceChild::O0: return myregs.r_o0;
918108SN/A      case SparcTraceChild::O1: return myregs.r_o1;
928108SN/A      case SparcTraceChild::O2: return myregs.r_o2;
938108SN/A      case SparcTraceChild::O3: return myregs.r_o3;
948108SN/A      case SparcTraceChild::O4: return myregs.r_o4;
958108SN/A      case SparcTraceChild::O5: return myregs.r_o5;
968108SN/A      case SparcTraceChild::O6: return myregs.r_o6;
978108SN/A      case SparcTraceChild::O7: return myregs.r_o7;
988108SN/A      //Local registers
998108SN/A      case SparcTraceChild::L0: return locals[0];
1008108SN/A      case SparcTraceChild::L1: return locals[1];
1018108SN/A      case SparcTraceChild::L2: return locals[2];
1028108SN/A      case SparcTraceChild::L3: return locals[3];
1038108SN/A      case SparcTraceChild::L4: return locals[4];
1048108SN/A      case SparcTraceChild::L5: return locals[5];
1058108SN/A      case SparcTraceChild::L6: return locals[6];
1068108SN/A      case SparcTraceChild::L7: return locals[7];
1078108SN/A      //Input registers
1088108SN/A      case SparcTraceChild::I0: return inputs[0];
1098108SN/A      case SparcTraceChild::I1: return inputs[1];
1108108SN/A      case SparcTraceChild::I2: return inputs[2];
1118108SN/A      case SparcTraceChild::I3: return inputs[3];
1128108SN/A      case SparcTraceChild::I4: return inputs[4];
1138108SN/A      case SparcTraceChild::I5: return inputs[5];
1148108SN/A      case SparcTraceChild::I6: return inputs[6];
1158108SN/A      case SparcTraceChild::I7: return inputs[7];
1168108SN/A      //Floating point
1178108SN/A      case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0];
1188108SN/A      case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1];
1198108SN/A      case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2];
1208108SN/A      case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3];
1218108SN/A      case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4];
1228108SN/A      case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5];
1238108SN/A      case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6];
1248108SN/A      case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7];
1258108SN/A      case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8];
1268108SN/A      case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9];
1278108SN/A      case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10];
1288108SN/A      case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11];
1298108SN/A      case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12];
1308108SN/A      case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13];
1318108SN/A      case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14];
1328108SN/A      case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15];
1338108SN/A      case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16];
1348108SN/A      case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17];
1358108SN/A      case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18];
1368108SN/A      case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19];
1378108SN/A      case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20];
1388108SN/A      case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21];
1398108SN/A      case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22];
1408108SN/A      case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23];
1418108SN/A      case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24];
1428108SN/A      case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25];
1438108SN/A      case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26];
1448108SN/A      case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27];
1458108SN/A      case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28];
1468108SN/A      case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29];
1478108SN/A      case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30];
1488108SN/A      case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31];
1498108SN/A      //Miscelaneous
1508108SN/A      case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr;
1518108SN/A      case SparcTraceChild::FPRS: return myregs.r_fprs;
1528108SN/A      case SparcTraceChild::PC: return myregs.r_tpc;
1538108SN/A      case SparcTraceChild::NPC: return myregs.r_tnpc;
1548108SN/A      case SparcTraceChild::Y: return myregs.r_y;
1558108SN/A      case SparcTraceChild::CWP:
1568108SN/A        return (myregs.r_tstate >> 0) & ((1 << 5) - 1);
1578108SN/A      case SparcTraceChild::PSTATE:
1588108SN/A        return (myregs.r_tstate >> 8) & ((1 << 13) - 1);
1598108SN/A      case SparcTraceChild::ASI:
1608108SN/A        return (myregs.r_tstate >> 24) & ((1 << 8) - 1);
1618108SN/A      case SparcTraceChild::CCR:
1628108SN/A        return (myregs.r_tstate >> 32) & ((1 << 8) - 1);
1638108SN/A      default:
1648108SN/A        assert(0);
1658108SN/A        return 0;
1663115SN/A    }
1673115SN/A}
1683115SN/A
1698108SN/Abool
1708108SN/ASparcTraceChild::update(int pid)
1713115SN/A{
1723115SN/A    memcpy(&oldregs, &theregs, sizeof(regs));
1733115SN/A    memcpy(&oldfpregs, &thefpregs, sizeof(fpu));
1743115SN/A    memcpy(oldLocals, locals, 8 * sizeof(uint64_t));
1753115SN/A    memcpy(oldInputs, inputs, 8 * sizeof(uint64_t));
1768108SN/A    if (ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) {
1773115SN/A        cerr << "Update failed" << endl;
1783115SN/A        return false;
1793115SN/A    }
1804245SN/A    uint64_t stackPointer = getSP();
1814245SN/A    uint64_t stackBias = 2047;
1824245SN/A    bool v9 = stackPointer % 2;
1838108SN/A    for (unsigned int x = 0; x < 8; x++) {
1844245SN/A        uint64_t localAddr = stackPointer +
1854245SN/A            (v9 ? (stackBias + x * 8) : (x * 4));
1864245SN/A        locals[x] = ptrace(PTRACE_PEEKTEXT, pid, localAddr, 0);
1878108SN/A        if (!v9) locals[x] >>= 32;
1884245SN/A        uint64_t inputAddr = stackPointer +
1894245SN/A            (v9 ? (stackBias + x * 8 + (8 * 8)) : (x * 4 + 8 * 4));
1904245SN/A        inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, inputAddr, 0);
1918108SN/A        if (!v9) inputs[x] >>= 32;
1923115SN/A    }
1938108SN/A    if (ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0)
1943115SN/A        return false;
1958108SN/A    for (unsigned int x = 0; x < numregs; x++)
1963115SN/A        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
1973115SN/A    return true;
1983115SN/A}
1993115SN/A
2003115SN/ASparcTraceChild::SparcTraceChild()
2013115SN/A{
2028108SN/A    for (unsigned int x = 0; x < numregs; x++)
2033115SN/A        regDiffSinceUpdate[x] = false;
2043115SN/A}
2053115SN/A
2068108SN/Aint
2078108SN/ASparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
2088108SN/A                            uint64_t &target1, uint64_t &target2)
2094125SN/A{
2104125SN/A    //We can identify the instruction categories we care about using the top
2114125SN/A    //10 bits of the instruction, excluding the annul bit in the 3rd most
2124125SN/A    //significant bit position and the condition field. We'll call these
2134125SN/A    //bits the "sig" for signature.
2144125SN/A    uint32_t sig = (inst >> 22) & 0x307;
2154125SN/A    uint32_t cond = (inst >> 25) & 0xf;
2164125SN/A    bool annul = (inst & (1 << 29));
2174125SN/A
2184125SN/A    //Check if it's a ba...
2194125SN/A    bool ba = (cond == 0x8) &&
2204125SN/A        (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
2214125SN/A    //or a bn...
2224125SN/A    bool bn = (cond == 0x0) &&
2234125SN/A        (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
2244125SN/A    //or a bcc
2254125SN/A    bool bcc = (cond & 0x7) &&
2264125SN/A        (sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6);
2274125SN/A
2288108SN/A    if (annul) {
2298108SN/A        if (bcc) {
2304125SN/A            target1 = npc;
2314125SN/A            target2 = npc + 4;
2324125SN/A            return 2;
23311321Ssteve.reinhardt@amd.com        } else if (ba) {
2344125SN/A            //This branches immediately to the effective address of the branch
2354125SN/A            //which we'll have to calculate.
2364125SN/A            uint64_t disp = 0;
2374125SN/A            int64_t extender = 0;
2384125SN/A            //Figure out how big the displacement field is, and grab the bits
2398108SN/A            if (sig == 0x1 || sig == 0x5) {
2404125SN/A                disp = inst & ((1 << 19) - 1);
2414125SN/A                extender = 1 << 18;
2428108SN/A            } else {
2434125SN/A                disp = inst & ((1 << 22) - 1);
2444125SN/A                extender = 1 << 21;
2454125SN/A            }
2464125SN/A            //This does sign extension, believe it or not.
2474125SN/A            disp = (disp ^ extender) - extender;
2484125SN/A            //Multiply the displacement by 4. I'm assuming the compiler is
2494125SN/A            //smart enough to turn this into a shift.
2504125SN/A            disp *= 4;
2514125SN/A            target1 = pc + disp;
25211321Ssteve.reinhardt@amd.com        } else if (bn)
2534125SN/A            target1 = npc + 4;
2544125SN/A        else
2554125SN/A            target1 = npc;
2564125SN/A        return 1;
2578108SN/A    } else {
2584125SN/A        target1 = npc;
2594125SN/A        return 1;
2604125SN/A    }
2614125SN/A}
2624125SN/A
2638108SN/Abool
2648108SN/ASparcTraceChild::step()
2653115SN/A{
2664125SN/A    //Increment the count of the number of instructions executed
2674125SN/A    instructions++;
2683115SN/A    //Two important considerations are that the address of the instruction
2693115SN/A    //being breakpointed should be word (64bit) aligned, and that both the
2703115SN/A    //next instruction and the instruction after that need to be breakpointed
2713115SN/A    //so that annulled branches will still stop as well.
2723382SN/A
2733382SN/A    /*
2743382SN/A     * Useful constants
2753382SN/A     */
2763115SN/A    const static uint64_t breakInst = 0x91d02001;
2774125SN/A    const static uint64_t lowBreakInst = breakInst;
2784125SN/A    const static uint64_t highBreakInst = breakInst << 32;
2793115SN/A    const static uint64_t breakWord = breakInst | (breakInst << 32);
2803382SN/A    const static uint64_t lowMask = 0xFFFFFFFFULL;
2813115SN/A    const static uint64_t highMask = lowMask << 32;
2823382SN/A
2833382SN/A    /*
2843382SN/A     * storage for the original contents of the child process's memory
2853382SN/A     */
2863115SN/A    uint64_t originalInst, originalAnnulInst;
2873382SN/A
2883382SN/A    /*
2893382SN/A     * Get information about where the process is and is headed next.
2903382SN/A     */
2913382SN/A    uint64_t currentPC = getRegVal(PC);
2923382SN/A    bool unalignedPC = currentPC & 7;
2933382SN/A    uint64_t alignedPC = currentPC & (~7);
2943115SN/A    uint64_t nextPC = getRegVal(NPC);
2953382SN/A    bool unalignedNPC = nextPC & 7;
2963382SN/A    uint64_t alignedNPC = nextPC & (~7);
2973382SN/A
2984125SN/A    //Get the current instruction
2994125SN/A    uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC);
3004125SN/A    curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32);
3014125SN/A
3024125SN/A    uint64_t bp1, bp2;
3034125SN/A    int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2);
3044125SN/A    assert(numTargets == 1 || numTargets == 2);
3054125SN/A
3064125SN/A    bool unalignedBp1 = bp1 & 7;
3074125SN/A    uint64_t alignedBp1 = bp1 & (~7);
3084125SN/A    bool unalignedBp2 = bp2 & 7;
3094125SN/A    uint64_t alignedBp2 = bp2 & (~7);
3104125SN/A    uint64_t origBp1, origBp2;
3113382SN/A
3123382SN/A    /*
3134125SN/A     * Set the first breakpoint
3143382SN/A     */
3154125SN/A    origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0);
3164125SN/A    uint64_t newBp1 = origBp1;
3174125SN/A    newBp1 &= unalignedBp1 ? highMask : lowMask;
3184125SN/A    newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst;
3198108SN/A    if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0)
3204125SN/A        cerr << "Poke failed" << endl;
3214125SN/A    /*
3224125SN/A     * Set the second breakpoint if necessary
3234125SN/A     */
3248108SN/A    if (numTargets == 2) {
3254125SN/A        origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0);
3264125SN/A        uint64_t newBp2 = origBp2;
3274125SN/A        newBp2 &= unalignedBp2 ? highMask : lowMask;
3284125SN/A        newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst;
3298108SN/A        if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0)
3303115SN/A            cerr << "Poke failed" << endl;
3313115SN/A    }
3323382SN/A
3333382SN/A    /*
3343382SN/A     * Restart the child process
3353382SN/A     */
3363115SN/A    //Note that the "addr" parameter is supposed to be ignored, but in at
3373115SN/A    //least one version of the kernel, it must be 1 or it will set what
3383115SN/A    //pc to continue from
3398108SN/A    if (ptrace(PTRACE_CONT, pid, 1, 0) != 0)
3403115SN/A        cerr << "Cont failed" << endl;
3413115SN/A    doWait();
3423382SN/A
3433382SN/A    /*
3443382SN/A     * Update our record of the child's state
3453382SN/A     */
3463115SN/A    update(pid);
3473382SN/A
3483382SN/A    /*
3494125SN/A     * Put back the original contents of the childs address space in the
3504125SN/A     * reverse order.
3513382SN/A     */
3528108SN/A    if (numTargets == 2) {
3538108SN/A        if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0)
3544125SN/A            cerr << "Poke failed" << endl;
3553115SN/A    }
3568108SN/A    if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0)
3574125SN/A        cerr << "Poke failed" << endl;
3583115SN/A}
3593115SN/A
3608108SN/Aint64_t
3618108SN/ASparcTraceChild::getRegVal(int num)
3623115SN/A{
3633115SN/A    return getRegs(theregs, thefpregs, locals, inputs, num);
3643115SN/A}
3653115SN/A
3668108SN/Aint64_t
3678108SN/ASparcTraceChild::getOldRegVal(int num)
3683115SN/A{
3693115SN/A    return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
3703115SN/A}
3713115SN/A
3728108SN/Aostream &
3738108SN/ASparcTraceChild::outputStartState(ostream & os)
3743115SN/A{
3754125SN/A    bool v8 = false;
3763115SN/A    uint64_t sp = getSP();
3778108SN/A    if (sp % 2) {
3784125SN/A        os << "Detected a 64 bit executable.\n";
3794125SN/A        v8 = false;
3808108SN/A    } else {
3814125SN/A        os << "Detected a 32 bit executable.\n";
3824125SN/A        v8 = true;
3834125SN/A    }
3843115SN/A    uint64_t pc = getPC();
3853115SN/A    char obuf[1024];
3863115SN/A    sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
3873115SN/A    os << obuf;
3883115SN/A    sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
3893115SN/A    os << obuf;
3908108SN/A    if (!v8) {
3914125SN/A        //Take out the stack bias
3924125SN/A        sp += 2047;
3934125SN/A    }
3943115SN/A    //Output the window save area
3958108SN/A    for (unsigned int x = 0; x < 16; x++) {
3963115SN/A        uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
3978108SN/A        if (v8) regspot = regspot >> 32;
3983115SN/A        sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
3993115SN/A                sp, x+1, regspot);
4003115SN/A        os << obuf;
4014125SN/A        sp += v8 ? 4 : 8;
4023115SN/A    }
4033115SN/A    //Output the argument count
4043115SN/A    uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
4058108SN/A    if (v8) cargc = cargc >> 32;
4063115SN/A    sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
4073115SN/A    os << obuf;
4084125SN/A    sp += v8 ? 4 : 8;
4093115SN/A    //Output argv pointers
4103115SN/A    int argCount = 0;
4113115SN/A    uint64_t cargv;
4128108SN/A    do {
4133115SN/A        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
4148108SN/A        if (v8) cargv = cargv >> 32;
4153115SN/A        sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
4163115SN/A                sp, argCount++, cargv);
4173115SN/A        os << obuf;
4184125SN/A        sp += v8 ? 4 : 8;
41911321Ssteve.reinhardt@amd.com    } while (cargv);
4203115SN/A    //Output the envp pointers
4213115SN/A    int envCount = 0;
4223115SN/A    uint64_t cenvp;
4238108SN/A    do {
4243115SN/A        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
4258108SN/A        if (v8) cenvp = cenvp >> 32;
4263115SN/A        sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
4273115SN/A                sp, envCount++, cenvp);
4283115SN/A        os << obuf;
4294125SN/A        sp += v8 ? 4 : 8;
4308108SN/A    } while (cenvp);
4313115SN/A    uint64_t auxType, auxVal;
4328108SN/A    do {
4333115SN/A        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
4348108SN/A        if (v8) auxType = auxType >> 32;
4354125SN/A        sp += (v8 ? 4 : 8);
4363115SN/A        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
4378108SN/A        if (v8) auxVal = auxVal >> 32;
4384125SN/A        sp += (v8 ? 4 : 8);
4393115SN/A        sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
4404125SN/A                sp - 8, auxType, auxVal);
4413115SN/A        os << obuf;
4428108SN/A    } while (auxType != 0 || auxVal != 0);
4433115SN/A    //Print out the argument strings, environment strings, and file name.
4443115SN/A    string current;
4453115SN/A    uint64_t buf;
4463115SN/A    uint64_t currentStart = sp;
4473115SN/A    bool clearedInitialPadding = false;
4488108SN/A    do {
4493115SN/A        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
4503115SN/A        char * cbuf = (char *)&buf;
4518108SN/A        for (int x = 0; x < sizeof(uint32_t); x++) {
4528108SN/A            if (cbuf[x])
4533115SN/A                current += cbuf[x];
4548108SN/A            else {
4553115SN/A                sprintf(obuf, "0x%016llx: \"%s\"\n",
4563115SN/A                        currentStart, current.c_str());
4573115SN/A                os << obuf;
4583115SN/A                current = "";
4593115SN/A                currentStart = sp + x + 1;
4603115SN/A            }
4613115SN/A        }
4624125SN/A        sp += (v8 ? 4 : 8);
4633115SN/A        clearedInitialPadding = clearedInitialPadding || buf != 0;
4648108SN/A    } while (!clearedInitialPadding || buf != 0);
4653115SN/A    return os;
4663115SN/A}
4673115SN/A
4688108SN/ATraceChild *
4698108SN/AgenTraceChild()
4703115SN/A{
4713115SN/A    return new SparcTraceChild;
4723115SN/A}
4733115SN/A
474