tracechild.cc revision 4843
13096SN/A/*
23096SN/A * Copyright (c) 2007 The Regents of The University of Michigan
311680SCurtis.Dunham@arm.com * All rights reserved.
411680SCurtis.Dunham@arm.com *
511680SCurtis.Dunham@arm.com * Redistribution and use in source and binary forms, with or without
68428SN/A * modification, are permitted provided that the following conditions are
711860Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
811860Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
911860Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
1011860Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
1111860Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
1211390Ssteve.reinhardt@amd.com * neither the name of the copyright holders nor the names of its
1311390Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from
1410036SAli.Saidi@ARM.com * this software without specific prior written permission.
1510036SAli.Saidi@ARM.com *
1611680SCurtis.Dunham@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711860Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811390Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911860Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011860Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111860Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211860Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311390Ssteve.reinhardt@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411860Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511860Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611680SCurtis.Dunham@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711860Sandreas.hansson@arm.com *
2811860Sandreas.hansson@arm.com * Authors: Gabe Black
2911860Sandreas.hansson@arm.com */
3011860Sandreas.hansson@arm.com
3111680SCurtis.Dunham@arm.com#include <iostream>
3211860Sandreas.hansson@arm.com#include <iomanip>
3311860Sandreas.hansson@arm.com#include <errno.h>
349978Sandreas.hansson@arm.com#include <sys/ptrace.h>
3511860Sandreas.hansson@arm.com#include <stdint.h>
369978Sandreas.hansson@arm.com
3711860Sandreas.hansson@arm.com#include "tracechild_amd64.hh"
389978Sandreas.hansson@arm.com
399978Sandreas.hansson@arm.comusing namespace std;
4011860Sandreas.hansson@arm.com
419978Sandreas.hansson@arm.comchar * AMD64TraceChild::regNames[numregs] = {
429978Sandreas.hansson@arm.com                //GPRs
439978Sandreas.hansson@arm.com                "rax", "rbx", "rcx", "rdx",
449978Sandreas.hansson@arm.com                //Index registers
4511440SCurtis.Dunham@arm.com                "rsi", "rdi",
4611103Snilay@cs.wisc.edu                //Base pointer and stack pointer
4711860Sandreas.hansson@arm.com                "rbp", "rsp",
489978Sandreas.hansson@arm.com                //New 64 bit mode registers
4911390Ssteve.reinhardt@amd.com                "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
5010352Sandreas.hansson@arm.com                //Segmentation registers
519978Sandreas.hansson@arm.com                "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base",
529978Sandreas.hansson@arm.com                //PC
539978Sandreas.hansson@arm.com                "rip",
549978Sandreas.hansson@arm.com                //Flags
5510726Sandreas.hansson@arm.com                "eflags"};
5610352Sandreas.hansson@arm.com
579978Sandreas.hansson@arm.combool AMD64TraceChild::sendState(int socket)
5811103Snilay@cs.wisc.edu{
599978Sandreas.hansson@arm.com    uint64_t regVal = 0;
6011390Ssteve.reinhardt@amd.com    for(int x = 0; x <= R15; x++)
619978Sandreas.hansson@arm.com    {
629978Sandreas.hansson@arm.com        regVal = getRegVal(x);
639978Sandreas.hansson@arm.com        if(write(socket, &regVal, sizeof(regVal)) == -1)
649978Sandreas.hansson@arm.com        {
659978Sandreas.hansson@arm.com            cerr << "Write failed! " << strerror(errno) << endl;
669978Sandreas.hansson@arm.com            tracing = false;
679978Sandreas.hansson@arm.com            return false;
689978Sandreas.hansson@arm.com        }
699978Sandreas.hansson@arm.com    }
709978Sandreas.hansson@arm.com    regVal = getRegVal(RIP);
719978Sandreas.hansson@arm.com    if(write(socket, &regVal, sizeof(regVal)) == -1)
729978Sandreas.hansson@arm.com    {
739978Sandreas.hansson@arm.com        cerr << "Write failed! " << strerror(errno) << endl;
749978Sandreas.hansson@arm.com        tracing = false;
759978Sandreas.hansson@arm.com        return false;
769978Sandreas.hansson@arm.com    }
779978Sandreas.hansson@arm.com    return true;
789978Sandreas.hansson@arm.com}
7911680SCurtis.Dunham@arm.com
809978Sandreas.hansson@arm.comint64_t AMD64TraceChild::getRegs(user_regs_struct & myregs, int num)
819978Sandreas.hansson@arm.com{
829978Sandreas.hansson@arm.com        assert(num < numregs && num >= 0);
839978Sandreas.hansson@arm.com        switch(num)
849978Sandreas.hansson@arm.com        {
859978Sandreas.hansson@arm.com                //GPRs
8611860Sandreas.hansson@arm.com                case RAX: return myregs.rax;
879978Sandreas.hansson@arm.com                case RBX: return myregs.rbx;
889978Sandreas.hansson@arm.com                case RCX: return myregs.rcx;
899978Sandreas.hansson@arm.com                case RDX: return myregs.rdx;
909978Sandreas.hansson@arm.com                //Index registers
919978Sandreas.hansson@arm.com                case RSI: return myregs.rsi;
929978Sandreas.hansson@arm.com                case RDI: return myregs.rdi;
939978Sandreas.hansson@arm.com                //Base pointer and stack pointer
9411680SCurtis.Dunham@arm.com                case RBP: return myregs.rbp;
9511860Sandreas.hansson@arm.com                case RSP: return myregs.rsp;
9611680SCurtis.Dunham@arm.com                //New 64 bit mode registers
9711680SCurtis.Dunham@arm.com                case R8: return myregs.r8;
9811680SCurtis.Dunham@arm.com                case R9: return myregs.r9;
999322Sandreas.hansson@arm.com                case R10: return myregs.r10;
1009312Sandreas.hansson@arm.com                case R11: return myregs.r11;
1019312Sandreas.hansson@arm.com                case R12: return myregs.r12;
1029312Sandreas.hansson@arm.com                case R13: return myregs.r13;
1039312Sandreas.hansson@arm.com                case R14: return myregs.r14;
1049312Sandreas.hansson@arm.com                case R15: return myregs.r15;
1059312Sandreas.hansson@arm.com                //Segmentation registers
1069312Sandreas.hansson@arm.com                case CS: return myregs.cs;
1079312Sandreas.hansson@arm.com                case DS: return myregs.ds;
1089312Sandreas.hansson@arm.com                case ES: return myregs.es;
1099312Sandreas.hansson@arm.com                case FS: return myregs.fs;
1109312Sandreas.hansson@arm.com                case GS: return myregs.gs;
1119312Sandreas.hansson@arm.com                case SS: return myregs.ss;
1129312Sandreas.hansson@arm.com                case FS_BASE: return myregs.fs_base;
1139312Sandreas.hansson@arm.com                case GS_BASE: return myregs.gs_base;
1149312Sandreas.hansson@arm.com                //PC
1159312Sandreas.hansson@arm.com                case RIP: return myregs.rip;
1169312Sandreas.hansson@arm.com                //Flags
1179312Sandreas.hansson@arm.com                case EFLAGS: return myregs.eflags;
1189312Sandreas.hansson@arm.com                default:
1199312Sandreas.hansson@arm.com                        assert(0);
1209312Sandreas.hansson@arm.com                        return 0;
1219312Sandreas.hansson@arm.com        }
1229312Sandreas.hansson@arm.com}
1239312Sandreas.hansson@arm.com
1249312Sandreas.hansson@arm.combool AMD64TraceChild::update(int pid)
1259312Sandreas.hansson@arm.com{
1269312Sandreas.hansson@arm.com    oldregs = regs;
1279312Sandreas.hansson@arm.com    if(ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0)
1289312Sandreas.hansson@arm.com    {
1299312Sandreas.hansson@arm.com        cerr << "update: " << strerror(errno) << endl;
1309312Sandreas.hansson@arm.com        return false;
1319312Sandreas.hansson@arm.com    }
1329312Sandreas.hansson@arm.com    for(unsigned int x = 0; x < numregs; x++)
1339312Sandreas.hansson@arm.com        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
1349312Sandreas.hansson@arm.com    return true;
1359312Sandreas.hansson@arm.com}
1369312Sandreas.hansson@arm.com
1379312Sandreas.hansson@arm.comAMD64TraceChild::AMD64TraceChild()
1389312Sandreas.hansson@arm.com{
1399312Sandreas.hansson@arm.com    for(unsigned int x = 0; x < numregs; x++)
1409312Sandreas.hansson@arm.com        regDiffSinceUpdate[x] = false;
1419312Sandreas.hansson@arm.com}
1429312Sandreas.hansson@arm.com
1439312Sandreas.hansson@arm.comint64_t AMD64TraceChild::getRegVal(int num)
1449312Sandreas.hansson@arm.com{
1459312Sandreas.hansson@arm.com        return getRegs(regs, num);
1469312Sandreas.hansson@arm.com}
1479312Sandreas.hansson@arm.com
1489312Sandreas.hansson@arm.comint64_t AMD64TraceChild::getOldRegVal(int num)
1499312Sandreas.hansson@arm.com{
1509312Sandreas.hansson@arm.com        return getRegs(oldregs, num);
1519312Sandreas.hansson@arm.com}
1529312Sandreas.hansson@arm.com
1539312Sandreas.hansson@arm.comchar * AMD64TraceChild::printReg(int num)
1549312Sandreas.hansson@arm.com{
1559312Sandreas.hansson@arm.com        sprintf(printBuffer, "0x%08X", getRegVal(num));
1569312Sandreas.hansson@arm.com        return printBuffer;
1579312Sandreas.hansson@arm.com}
15810148Sandreas.hansson@arm.com
15910148Sandreas.hansson@arm.comostream & AMD64TraceChild::outputStartState(ostream & os)
16010148Sandreas.hansson@arm.com{
16110148Sandreas.hansson@arm.com    uint64_t sp = getSP();
16210148Sandreas.hansson@arm.com    uint64_t pc = getPC();
16310148Sandreas.hansson@arm.com    uint64_t highestInfo = 0;
16410148Sandreas.hansson@arm.com    char obuf[1024];
16510148Sandreas.hansson@arm.com    sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
16610148Sandreas.hansson@arm.com    os << obuf;
16710148Sandreas.hansson@arm.com    sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
16810148Sandreas.hansson@arm.com    os << obuf;
16910148Sandreas.hansson@arm.com
17010148Sandreas.hansson@arm.com    //Output the argument count
17110148Sandreas.hansson@arm.com    uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
17210148Sandreas.hansson@arm.com    sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
17310148Sandreas.hansson@arm.com    os << obuf;
17410148Sandreas.hansson@arm.com    sp += 8;
17510148Sandreas.hansson@arm.com
17610148Sandreas.hansson@arm.com    //Output argv pointers
17710148Sandreas.hansson@arm.com    int argCount = 0;
17810148Sandreas.hansson@arm.com    uint64_t cargv;
17910148Sandreas.hansson@arm.com    do
18010148Sandreas.hansson@arm.com    {
18110148Sandreas.hansson@arm.com        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
18210148Sandreas.hansson@arm.com        sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
18310148Sandreas.hansson@arm.com                sp, argCount++, cargv);
18410148Sandreas.hansson@arm.com        if(cargv)
18510148Sandreas.hansson@arm.com            if(highestInfo < cargv)
18610148Sandreas.hansson@arm.com                highestInfo = cargv;
18710148Sandreas.hansson@arm.com        os << obuf;
18810148Sandreas.hansson@arm.com        sp += 8;
18910148Sandreas.hansson@arm.com    } while(cargv);
19011680SCurtis.Dunham@arm.com
19111860Sandreas.hansson@arm.com    //Output the envp pointers
19211860Sandreas.hansson@arm.com    int envCount = 0;
19311860Sandreas.hansson@arm.com    uint64_t cenvp;
19411680SCurtis.Dunham@arm.com    do
19511680SCurtis.Dunham@arm.com    {
19611680SCurtis.Dunham@arm.com        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
19711680SCurtis.Dunham@arm.com        sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
19811680SCurtis.Dunham@arm.com                sp, envCount++, cenvp);
19911680SCurtis.Dunham@arm.com        os << obuf;
20011680SCurtis.Dunham@arm.com        sp += 8;
20111680SCurtis.Dunham@arm.com    } while(cenvp);
20211680SCurtis.Dunham@arm.com    uint64_t auxType, auxVal;
20311680SCurtis.Dunham@arm.com    do
20411860Sandreas.hansson@arm.com    {
20511860Sandreas.hansson@arm.com        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
20611860Sandreas.hansson@arm.com        sp += 8;
20711860Sandreas.hansson@arm.com        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
2089978Sandreas.hansson@arm.com        sp += 8;
20911860Sandreas.hansson@arm.com        sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
21011860Sandreas.hansson@arm.com                sp - 16, auxType, auxVal);
2119978Sandreas.hansson@arm.com        os << obuf;
21211860Sandreas.hansson@arm.com    } while(auxType != 0 || auxVal != 0);
2139978Sandreas.hansson@arm.com    //Print out the argument strings, environment strings, and file name.
2149978Sandreas.hansson@arm.com    string current;
21511860Sandreas.hansson@arm.com    uint64_t buf;
21611860Sandreas.hansson@arm.com    uint64_t currentStart = sp;
2179978Sandreas.hansson@arm.com    bool clearedInitialPadding = false;
21811680SCurtis.Dunham@arm.com    do
2199978Sandreas.hansson@arm.com    {
22011860Sandreas.hansson@arm.com        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
2219312Sandreas.hansson@arm.com        char * cbuf = (char *)&buf;
22211860Sandreas.hansson@arm.com        for(int x = 0; x < sizeof(uint64_t); x++)
2239312Sandreas.hansson@arm.com        {
22411860Sandreas.hansson@arm.com            if(cbuf[x])
22511860Sandreas.hansson@arm.com                current += cbuf[x];
22611680SCurtis.Dunham@arm.com            else
22711680SCurtis.Dunham@arm.com            {
22811860Sandreas.hansson@arm.com                sprintf(obuf, "0x%016llx: \"%s\"\n",
22910628Sandreas.hansson@arm.com                        currentStart, current.c_str());
23011680SCurtis.Dunham@arm.com                os << obuf;
23111860Sandreas.hansson@arm.com                current = "";
23211860Sandreas.hansson@arm.com                currentStart = sp + x + 1;
23311860Sandreas.hansson@arm.com            }
23411860Sandreas.hansson@arm.com        }
23511680SCurtis.Dunham@arm.com        sp += 8;
23611860Sandreas.hansson@arm.com        clearedInitialPadding = clearedInitialPadding || buf != 0;
23711860Sandreas.hansson@arm.com    } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo);
23811860Sandreas.hansson@arm.com    return os;
23911680SCurtis.Dunham@arm.com}
24011680SCurtis.Dunham@arm.com
24111680SCurtis.Dunham@arm.comuint64_t AMD64TraceChild::findSyscall()
24211860Sandreas.hansson@arm.com{
24311860Sandreas.hansson@arm.com    uint64_t rip = getPC();
24411860Sandreas.hansson@arm.com    bool foundOpcode = false;
24511680SCurtis.Dunham@arm.com    bool twoByteOpcode = false;
24611680SCurtis.Dunham@arm.com    for(;;)
24711680SCurtis.Dunham@arm.com    {
24810628Sandreas.hansson@arm.com        uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0);
24911680SCurtis.Dunham@arm.com        for(int i = 0; i < sizeof(uint64_t); i++)
25011860Sandreas.hansson@arm.com        {
25111680SCurtis.Dunham@arm.com            unsigned char byte = buf & 0xFF;
25211860Sandreas.hansson@arm.com            if(!foundOpcode)
25311860Sandreas.hansson@arm.com            {
25411680SCurtis.Dunham@arm.com                if(!(byte == 0x66 || //operand override
25511860Sandreas.hansson@arm.com                     byte == 0x67 || //address override
25611860Sandreas.hansson@arm.com                     byte == 0x2E || //cs
25711860Sandreas.hansson@arm.com                     byte == 0x3E || //ds
25811680SCurtis.Dunham@arm.com                     byte == 0x26 || //es
25911680SCurtis.Dunham@arm.com                     byte == 0x64 || //fs
26011680SCurtis.Dunham@arm.com                     byte == 0x65 || //gs
26111680SCurtis.Dunham@arm.com                     byte == 0x36 || //ss
26211860Sandreas.hansson@arm.com                     byte == 0xF0 || //lock
26311860Sandreas.hansson@arm.com                     byte == 0xF2 || //repe
26411680SCurtis.Dunham@arm.com                     byte == 0xF3 || //repne
26511860Sandreas.hansson@arm.com                     (byte >= 0x40 && byte <= 0x4F) // REX
26611860Sandreas.hansson@arm.com                    ))
26711860Sandreas.hansson@arm.com                {
26811860Sandreas.hansson@arm.com                    foundOpcode = true;
26911860Sandreas.hansson@arm.com                }
2709481Snilay@cs.wisc.edu            }
27111860Sandreas.hansson@arm.com            if(foundOpcode)
27211860Sandreas.hansson@arm.com            {
27311680SCurtis.Dunham@arm.com                if(twoByteOpcode)
27411860Sandreas.hansson@arm.com                {
27511440SCurtis.Dunham@arm.com                    //SYSCALL or SYSENTER
27611860Sandreas.hansson@arm.com                    if(byte == 0x05 || byte == 0x34)
27711440SCurtis.Dunham@arm.com                        return rip + 1;
27810628Sandreas.hansson@arm.com                    else
2798428SN/A                        return 0;
2808428SN/A                }
2818428SN/A                if(!twoByteOpcode)
2828428SN/A                {
28311860Sandreas.hansson@arm.com                    if(byte == 0xCC) // INT3
28411440SCurtis.Dunham@arm.com                        return rip + 1;
2858428SN/A                    else if(byte == 0xCD) // INT with byte immediate
28611860Sandreas.hansson@arm.com                        return rip + 2;
28711860Sandreas.hansson@arm.com                    else if(byte == 0x0F) // two byte opcode prefix
28811103Snilay@cs.wisc.edu                        twoByteOpcode = true;
2898428SN/A                    else
29011860Sandreas.hansson@arm.com                        return 0;
29111860Sandreas.hansson@arm.com                }
29211440SCurtis.Dunham@arm.com            }
2938428SN/A            buf >>= 8;
29411860Sandreas.hansson@arm.com            rip++;
29511860Sandreas.hansson@arm.com        }
29611440SCurtis.Dunham@arm.com    }
2978428SN/A}
29811860Sandreas.hansson@arm.com
2998428SN/Abool AMD64TraceChild::step()
3008428SN/A{
3018428SN/A    uint64_t ripAfterSyscall = findSyscall();
3028428SN/A    if(ripAfterSyscall)
3038428SN/A    {
3048428SN/A        //Get the original contents of memory
3058428SN/A        uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0);
3068428SN/A        //Patch the first two bytes of the memory immediately after this with
3078428SN/A        //jmp -2. Either single stepping will take over before this
3088428SN/A        //instruction, leaving the rip where it should be, or it will take
3098428SN/A        //over after this instruction, -still- leaving the rip where it should
3108428SN/A        //be.
31111955Sgabeblack@google.com        uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB;
31211680SCurtis.Dunham@arm.com        //Write the patched memory to the processes address space
31311680SCurtis.Dunham@arm.com        ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf);
3148428SN/A        //Step and hit it
3158428SN/A        ptraceSingleStep();
31611860Sandreas.hansson@arm.com        //Put things back to the way they started
31711860Sandreas.hansson@arm.com        ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf);
31811860Sandreas.hansson@arm.com    }
31911860Sandreas.hansson@arm.com    else
32011860Sandreas.hansson@arm.com        ptraceSingleStep();
32111860Sandreas.hansson@arm.com}
32211440SCurtis.Dunham@arm.com
32311606Sandreas.sandberg@arm.comTraceChild * genTraceChild()
32411860Sandreas.hansson@arm.com{
32511860Sandreas.hansson@arm.com        return new AMD64TraceChild;
32611860Sandreas.hansson@arm.com}
32711860Sandreas.hansson@arm.com