diff options
Diffstat (limited to 'util/statetrace')
-rw-r--r-- | util/statetrace/arch/tracechild_amd64.cc | 322 | ||||
-rw-r--r-- | util/statetrace/arch/tracechild_amd64.hh | 110 | ||||
-rw-r--r-- | util/statetrace/printer.cc | 10 | ||||
-rw-r--r-- | util/statetrace/statetrace.cc | 184 | ||||
-rw-r--r-- | util/statetrace/tracechild_arch.cc | 5 |
5 files changed, 532 insertions, 99 deletions
diff --git a/util/statetrace/arch/tracechild_amd64.cc b/util/statetrace/arch/tracechild_amd64.cc new file mode 100644 index 000000000..088e547e4 --- /dev/null +++ b/util/statetrace/arch/tracechild_amd64.cc @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2007 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include <iostream> +#include <iomanip> +#include <errno.h> +#include <sys/ptrace.h> +#include <stdint.h> + +#include "tracechild_amd64.hh" + +using namespace std; + +char * AMD64TraceChild::regNames[numregs] = { + //GPRs + "rax", "rbx", "rcx", "rdx", + //Index registers + "rsi", "rdi", + //Base pointer and stack pointer + "rbp", "rsp", + //New 64 bit mode registers + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + //Segmentation registers + "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base", + //PC + "rip", + //Flags + "eflags"}; + +bool AMD64TraceChild::sendState(int socket) +{ + uint64_t regVal = 0; + for(int x = 0; x <= R15; x++) + { + regVal = getRegVal(x); + if(write(socket, ®Val, sizeof(regVal)) == -1) + { + cerr << "Write failed! " << strerror(errno) << endl; + tracing = false; + return false; + } + } + regVal = getRegVal(RIP); + if(write(socket, ®Val, sizeof(regVal)) == -1) + { + cerr << "Write failed! " << strerror(errno) << endl; + tracing = false; + return false; + } + return true; +} + +int64_t AMD64TraceChild::getRegs(user_regs_struct & myregs, int num) +{ + assert(num < numregs && num >= 0); + switch(num) + { + //GPRs + case RAX: return myregs.rax; + case RBX: return myregs.rbx; + case RCX: return myregs.rcx; + case RDX: return myregs.rdx; + //Index registers + case RSI: return myregs.rsi; + case RDI: return myregs.rdi; + //Base pointer and stack pointer + case RBP: return myregs.rbp; + case RSP: return myregs.rsp; + //New 64 bit mode registers + case R8: return myregs.r8; + case R9: return myregs.r9; + case R10: return myregs.r10; + case R11: return myregs.r11; + case R12: return myregs.r12; + case R13: return myregs.r13; + case R14: return myregs.r14; + case R15: return myregs.r15; + //Segmentation registers + case CS: return myregs.cs; + case DS: return myregs.ds; + case ES: return myregs.es; + case FS: return myregs.fs; + case GS: return myregs.gs; + case SS: return myregs.ss; + case FS_BASE: return myregs.fs_base; + case GS_BASE: return myregs.gs_base; + //PC + case RIP: return myregs.rip; + //Flags + case EFLAGS: return myregs.eflags; + default: + assert(0); + return 0; + } +} + +bool AMD64TraceChild::update(int pid) +{ + oldregs = regs; + if(ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) + { + cerr << "update: " << strerror(errno) << endl; + return false; + } + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); + return true; +} + +AMD64TraceChild::AMD64TraceChild() +{ + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = false; +} + +int64_t AMD64TraceChild::getRegVal(int num) +{ + return getRegs(regs, num); +} + +int64_t AMD64TraceChild::getOldRegVal(int num) +{ + return getRegs(oldregs, num); +} + +char * AMD64TraceChild::printReg(int num) +{ + sprintf(printBuffer, "0x%08X", getRegVal(num)); + return printBuffer; +} + +ostream & AMD64TraceChild::outputStartState(ostream & os) +{ + uint64_t sp = getSP(); + uint64_t pc = getPC(); + char obuf[1024]; + sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp); + os << obuf; + sprintf(obuf, "Initial program counter = 0x%016llx\n", pc); + os << obuf; + + //Output the argument count + uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc); + os << obuf; + sp += 8; + + //Output argv pointers + int argCount = 0; + uint64_t cargv; + do + { + cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n", + sp, argCount++, cargv); + os << obuf; + sp += 8; + } while(cargv); + + //Output the envp pointers + int envCount = 0; + uint64_t cenvp; + do + { + cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n", + sp, envCount++, cenvp); + os << obuf; + sp += 8; + } while(cenvp); + uint64_t auxType, auxVal; + do + { + auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sp += 8; + auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sp += 8; + sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", + sp - 16, auxType, auxVal); + os << obuf; + } while(auxType != 0 || auxVal != 0); + //Print out the argument strings, environment strings, and file name. + string current; + uint64_t buf; + uint64_t currentStart = sp; + bool clearedInitialPadding = false; + do + { + buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + char * cbuf = (char *)&buf; + for(int x = 0; x < sizeof(uint64_t); x++) + { + if(cbuf[x]) + current += cbuf[x]; + else + { + sprintf(obuf, "0x%016llx: \"%s\"\n", + currentStart, current.c_str()); + os << obuf; + current = ""; + currentStart = sp + x + 1; + } + } + sp += 8; + clearedInitialPadding = clearedInitialPadding || buf != 0; + } while(!clearedInitialPadding || buf != 0); + return os; +} + +uint64_t AMD64TraceChild::findSyscall() +{ + uint64_t rip = getPC(); + bool foundOpcode = false; + bool twoByteOpcode = false; + for(;;) + { + uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0); + for(int i = 0; i < sizeof(uint64_t); i++) + { + unsigned char byte = buf & 0xFF; + if(!foundOpcode) + { + if(!(byte == 0x66 || //operand override + byte == 0x67 || //address override + byte == 0x2E || //cs + byte == 0x3E || //ds + byte == 0x26 || //es + byte == 0x64 || //fs + byte == 0x65 || //gs + byte == 0x36 || //ss + byte == 0xF0 || //lock + byte == 0xF2 || //repe + byte == 0xF3 || //repne + (byte >= 0x40 && byte <= 0x4F) // REX + )) + { + foundOpcode = true; + } + } + if(foundOpcode) + { + if(twoByteOpcode) + { + //SYSCALL or SYSENTER + if(byte == 0x05 || byte == 0x34) + return rip + 1; + else + return 0; + } + if(!twoByteOpcode) + { + if(byte == 0xCC) // INT3 + return rip + 1; + else if(byte == 0xCD) // INT with byte immediate + return rip + 2; + else if(byte == 0x0F) // two byte opcode prefix + twoByteOpcode = true; + else + return 0; + } + } + buf >>= 8; + rip++; + } + } +} + +bool AMD64TraceChild::step() +{ + uint64_t ripAfterSyscall = findSyscall(); + if(ripAfterSyscall) + { + //Get the original contents of memory + uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0); + //Patch the first two bytes of the memory immediately after this with + //jmp -2. Either single stepping will take over before this + //instruction, leaving the rip where it should be, or it will take + //over after this instruction, -still- leaving the rip where it should + //be. + uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB; + //Write the patched memory to the processes address space + ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf); + //Step and hit it + ptraceSingleStep(); + //Put things back to the way they started + ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf); + } + else + ptraceSingleStep(); +} + +TraceChild * genTraceChild() +{ + return new AMD64TraceChild; +} diff --git a/util/statetrace/arch/tracechild_amd64.hh b/util/statetrace/arch/tracechild_amd64.hh new file mode 100644 index 000000000..e7457f677 --- /dev/null +++ b/util/statetrace/arch/tracechild_amd64.hh @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2007 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef REGSTATE_AMD64_HH +#define REGSTATE_AMD64_HH + +#include <sys/user.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <assert.h> +#include <string> + +#include "tracechild.hh" + +class AMD64TraceChild : public TraceChild +{ + public: + enum RegNum + { + //GPRs + RAX, RCX, RDX, RBX, + //Base pointer and stack pointer + RSP, RBP, + //Index registers + RSI, RDI, + //New 64 bit mode registers + R8, R9, R10, R11, R12, R13, R14, R15, + //Segmentation registers + CS, DS, ES, FS, GS, SS, FS_BASE, GS_BASE, + //PC + RIP, + //Flags + EFLAGS, + numregs + }; + private: + char printBuffer [256]; + static char * regNames[numregs]; + int64_t getRegs(user_regs_struct & myregs, int num); + user_regs_struct regs; + user_regs_struct oldregs; + bool regDiffSinceUpdate[numregs]; + + uint64_t findSyscall(); + + protected: + bool update(int pid); + + public: + + AMD64TraceChild(); + + bool sendState(int socket); + + int getNumRegs() + { + return numregs; + } + + bool diffSinceUpdate(int num) + { + assert(num < numregs && num >= 0); + return regDiffSinceUpdate[num]; + } + + std::string getRegName(int num) + { + assert(num < numregs && num >= 0); + return regNames[num]; + } + + int64_t getRegVal(int num); + int64_t getOldRegVal(int num); + uint64_t getPC() {return getRegVal(RIP);} + uint64_t getSP() {return getRegVal(RSP);} + std::ostream & outputStartState(std::ostream & output); + + char * printReg(int num); + + bool step(); +}; + +#endif diff --git a/util/statetrace/printer.cc b/util/statetrace/printer.cc index b14671f2c..178972ea8 100644 --- a/util/statetrace/printer.cc +++ b/util/statetrace/printer.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2006-2007 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -181,7 +181,10 @@ bool NestingPrinter::configure(string config) lastEndPos = endPos; constStrings.push_back(prefix); string subConfig, subString; - int commaPos, lastCommaPos, childSwitchVar; + long int commaPos, lastCommaPos, childSwitchVar; + //Set up the register printer + RegPrinter * regPrinter = new RegPrinter(child); + NestingPrinter * nestingPrinter = new NestingPrinter(child); switch(type) { //If we found a plain register printer @@ -189,8 +192,6 @@ bool NestingPrinter::configure(string config) numPrinters++; //Get the register name subConfig = config.substr(startPos + 2, endPos - startPos - 2); - //Set up the register printer - RegPrinter * regPrinter = new RegPrinter(child); if(!regPrinter->configure(subConfig)) { delete regPrinter; @@ -203,7 +204,6 @@ bool NestingPrinter::configure(string config) case PRINTER_NESTING: numPrinters++; //Punt on reading in all the parameters of the nesting printer - NestingPrinter * nestingPrinter = new NestingPrinter(child); subConfig = config.substr(startPos + 2, endPos - startPos - 2); lastCommaPos = string::npos; commaPos = subConfig.find(","); diff --git a/util/statetrace/statetrace.cc b/util/statetrace/statetrace.cc index 4fe47dc02..5f7224b25 100644 --- a/util/statetrace/statetrace.cc +++ b/util/statetrace/statetrace.cc @@ -49,115 +49,115 @@ using namespace std; void printUsage(const char * execName) { - cout << execName << " -h | -r -- <command> <arguments>" << endl; + cout << execName << " -h | -r -- <command> <arguments>" << endl; } int main(int argc, char * argv[], char * envp[]) { - TraceChild * child = genTraceChild(); - string args; - int startProgramArgs; + TraceChild * child = genTraceChild(); + string args; + int startProgramArgs; - //Parse the command line arguments - bool printInitial = false; - bool printTrace = true; - for(int x = 1; x < argc; x++) + //Parse the command line arguments + bool printInitial = false; + bool printTrace = true; + for(int x = 1; x < argc; x++) + { + if(!strcmp(argv[x], "-h")) { - if(!strcmp(argv[x], "-h")) - { - printUsage(argv[0]); - return 0; - } - else if(!strcmp(argv[x], "-r")) - { - cout << "Legal register names:" << endl; - int numRegs = child->getNumRegs(); - for(unsigned int x = 0; x < numRegs; x++) - { - cout << "\t" << child->getRegName(x) << endl; - } - return 0; - } - else if(!strcmp(argv[x], "-i")) - { - printInitial = true; - } - else if(!strcmp(argv[x], "-nt")) - { - printTrace = false; - } - else if(!strcmp(argv[x], "--")) - { - x++; - if(x >= argc) - { - cerr << "Incorrect usage.\n" << endl; - printUsage(argv[0]); - return 1; - } - startProgramArgs = x; - break; - } - else - { - cerr << "Incorrect usage.\n" << endl; - printUsage(argv[0]); - return 1; - } + printUsage(argv[0]); + return 0; } - if(!child->startTracing(argv[startProgramArgs], - argv + startProgramArgs)) + else if(!strcmp(argv[x], "-r")) { - cerr << "Couldn't start target program" << endl; - return 1; + cout << "Legal register names:" << endl; + int numRegs = child->getNumRegs(); + for(unsigned int x = 0; x < numRegs; x++) + { + cout << "\t" << child->getRegName(x) << endl; + } + return 0; } - if(printInitial) + else if(!strcmp(argv[x], "-i")) { - child->outputStartState(cout); + printInitial = true; } - if(printTrace) + else if(!strcmp(argv[x], "-nt")) { - // Connect to m5 - bool portSet = false; - int port; - int sock = socket(AF_INET, SOCK_STREAM, 0); - if(sock < 0) - { - cerr << "Error opening socket! " << strerror(errno) << endl; - return 1; - } - struct hostent *server; - server = gethostbyname("zower.eecs.umich.edu"); - if(!server) - { - cerr << "Couldn't get host ip! " << strerror(errno) << endl; - return 1; - } - struct sockaddr_in serv_addr; - bzero((char *)&serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - bcopy((char *)server->h_addr, - (char *)&serv_addr.sin_addr.s_addr, - server->h_length); - serv_addr.sin_port = htons(8000); - if(connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + printTrace = false; + } + else if(!strcmp(argv[x], "--")) + { + x++; + if(x >= argc) { - cerr << "Couldn't connect to server! " << strerror(errno) << endl; + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); return 1; } - child->step(); - while(child->isTracing()) - { - if(!child->sendState(sock)) - break; - child->step(); - } + startProgramArgs = x; + break; } - if(!child->stopTracing()) + else { - cerr << "Couldn't stop child" << endl; - return 1; + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); + return 1; + } + } + if(!child->startTracing(argv[startProgramArgs], + argv + startProgramArgs)) + { + cerr << "Couldn't start target program" << endl; + return 1; + } + if(printInitial) + { + child->outputStartState(cout); + } + if(printTrace) + { + // Connect to m5 + bool portSet = false; + int port; + int sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock < 0) + { + cerr << "Error opening socket! " << strerror(errno) << endl; + return 1; + } + struct hostent *server; + server = gethostbyname("localhost"); + if(!server) + { + cerr << "Couldn't get host ip! " << strerror(errno) << endl; + return 1; + } + struct sockaddr_in serv_addr; + bzero((char *)&serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy((char *)server->h_addr, + (char *)&serv_addr.sin_addr.s_addr, + server->h_length); + serv_addr.sin_port = htons(8000); + if(connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + cerr << "Couldn't connect to server! " << strerror(errno) << endl; + return 1; + } + child->step(); + while(child->isTracing()) + { + if(!child->sendState(sock)) + break; + child->step(); } - return 0; + } + if(!child->stopTracing()) + { + cerr << "Couldn't stop child" << endl; + return 1; + } + return 0; } diff --git a/util/statetrace/tracechild_arch.cc b/util/statetrace/tracechild_arch.cc index 603ccb12c..570a12b54 100644 --- a/util/statetrace/tracechild_arch.cc +++ b/util/statetrace/tracechild_arch.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2006-2007 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,8 @@ #if defined __alpha__ #error "Alpha architecture not implemented" #elif defined __amd64__ - #error "AMD64 architecture not implemented" +// #error "AMD64 architecture not implemented" + #include "arch/tracechild_amd64.cc" #elif defined __hppa__ #error "Hppa architecture not implemented" #elif defined __i386__ || defined __i486__ || \ |