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, ®Val, 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, ®Val, 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, ®s) != 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