tracechild.cc revision 11321
14780SN/A/* 24780SN/A * Copyright (c) 2007 The Regents of The University of Michigan 34780SN/A * All rights reserved. 44780SN/A * 54780SN/A * Redistribution and use in source and binary forms, with or without 64780SN/A * modification, are permitted provided that the following conditions are 74780SN/A * met: redistributions of source code must retain the above copyright 84780SN/A * notice, this list of conditions and the following disclaimer; 94780SN/A * redistributions in binary form must reproduce the above copyright 104780SN/A * notice, this list of conditions and the following disclaimer in the 114780SN/A * documentation and/or other materials provided with the distribution; 124780SN/A * neither the name of the copyright holders nor the names of its 134780SN/A * contributors may be used to endorse or promote products derived from 144780SN/A * this software without specific prior written permission. 154780SN/A * 164780SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 174780SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 184780SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 194780SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 204780SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 214780SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 224780SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234780SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244780SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254780SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 264780SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274780SN/A * 284780SN/A * Authors: Gabe Black 294780SN/A */ 304780SN/A 314780SN/A#include <sys/ptrace.h> 324780SN/A#include <stdint.h> 338229Snate@binkert.org 348229Snate@binkert.org#include <cerrno> 358229Snate@binkert.org#include <cstring> 368229Snate@binkert.org#include <iomanip> 378229Snate@binkert.org#include <iostream> 384780SN/A 398113Sgblack@eecs.umich.edu#include "arch/amd64/tracechild.hh" 404780SN/A 414780SN/Ausing namespace std; 424780SN/A 438108SN/Abool 448108SN/AAMD64TraceChild::sendState(int socket) 454780SN/A{ 465049SN/A uint64_t regVal64 = 0; 475049SN/A uint32_t regVal32 = 0; 488108SN/A for (int x = 0; x <= R15; x++) { 495049SN/A regVal64 = getRegVal(x); 508108SN/A if (write(socket, ®Val64, sizeof(regVal64)) == -1) { 514780SN/A cerr << "Write failed! " << strerror(errno) << endl; 524780SN/A tracing = false; 534780SN/A return false; 544780SN/A } 554780SN/A } 565049SN/A regVal64 = getRegVal(RIP); 578108SN/A if (write(socket, ®Val64, sizeof(regVal64)) == -1) { 584780SN/A cerr << "Write failed! " << strerror(errno) << endl; 594780SN/A tracing = false; 604780SN/A return false; 614780SN/A } 628108SN/A for (int x = MMX0_0; x <= MMX7_1; x++) { 635049SN/A regVal32 = getRegVal(x); 648108SN/A if (write(socket, ®Val32, sizeof(regVal32)) == -1) { 655049SN/A cerr << "Write failed! " << strerror(errno) << endl; 665049SN/A tracing = false; 675049SN/A return false; 685049SN/A } 695049SN/A } 708108SN/A for (int x = XMM0_0; x <= XMM15_3; x++) { 715049SN/A regVal32 = getRegVal(x); 728108SN/A if (write(socket, ®Val32, sizeof(regVal32)) == -1) { 735049SN/A cerr << "Write failed! " << strerror(errno) << endl; 745049SN/A tracing = false; 755049SN/A return false; 765049SN/A } 775049SN/A } 784780SN/A return true; 794780SN/A} 804780SN/A 818108SN/Aint64_t 828108SN/AAMD64TraceChild::getRegs(user_regs_struct & myregs, 835049SN/A user_fpregs_struct & myfpregs, int num) 844780SN/A{ 855049SN/A assert(num < numregs && num >= 0); 868108SN/A switch (num) { 878108SN/A //GPRs 888108SN/A case RAX: return myregs.rax; 898108SN/A case RBX: return myregs.rbx; 908108SN/A case RCX: return myregs.rcx; 918108SN/A case RDX: return myregs.rdx; 928108SN/A //Index registers 938108SN/A case RSI: return myregs.rsi; 948108SN/A case RDI: return myregs.rdi; 958108SN/A //Base pointer and stack pointer 968108SN/A case RBP: return myregs.rbp; 978108SN/A case RSP: return myregs.rsp; 988108SN/A //New 64 bit mode registers 998108SN/A case R8: return myregs.r8; 1008108SN/A case R9: return myregs.r9; 1018108SN/A case R10: return myregs.r10; 1028108SN/A case R11: return myregs.r11; 1038108SN/A case R12: return myregs.r12; 1048108SN/A case R13: return myregs.r13; 1058108SN/A case R14: return myregs.r14; 1068108SN/A case R15: return myregs.r15; 1078108SN/A //Segmentation registers 1088108SN/A case CS: return myregs.cs; 1098108SN/A case DS: return myregs.ds; 1108108SN/A case ES: return myregs.es; 1118108SN/A case FS: return myregs.fs; 1128108SN/A case GS: return myregs.gs; 1138108SN/A case SS: return myregs.ss; 1148108SN/A case FS_BASE: return myregs.fs_base; 1158108SN/A case GS_BASE: return myregs.gs_base; 1168108SN/A //PC 1178108SN/A case RIP: return myregs.rip; 1188108SN/A //Flags 1198108SN/A case EFLAGS: return myregs.eflags; 1208108SN/A //MMX 1218108SN/A case MMX0_0: return myfpregs.st_space[0]; 1228108SN/A case MMX0_1: return myfpregs.st_space[1]; 1238108SN/A case MMX1_0: return myfpregs.st_space[2]; 1248108SN/A case MMX1_1: return myfpregs.st_space[3]; 1258108SN/A case MMX2_0: return myfpregs.st_space[4]; 1268108SN/A case MMX2_1: return myfpregs.st_space[5]; 1278108SN/A case MMX3_0: return myfpregs.st_space[6]; 1288108SN/A case MMX3_1: return myfpregs.st_space[7]; 1298108SN/A case MMX4_0: return myfpregs.st_space[8]; 1308108SN/A case MMX4_1: return myfpregs.st_space[9]; 1318108SN/A case MMX5_0: return myfpregs.st_space[10]; 1328108SN/A case MMX5_1: return myfpregs.st_space[11]; 1338108SN/A case MMX6_0: return myfpregs.st_space[12]; 1348108SN/A case MMX6_1: return myfpregs.st_space[13]; 1358108SN/A case MMX7_0: return myfpregs.st_space[14]; 1368108SN/A case MMX7_1: return myfpregs.st_space[15]; 1378108SN/A //XMM 1388108SN/A case XMM0_0: return myfpregs.xmm_space[0]; 1398108SN/A case XMM0_1: return myfpregs.xmm_space[1]; 1408108SN/A case XMM0_2: return myfpregs.xmm_space[2]; 1418108SN/A case XMM0_3: return myfpregs.xmm_space[3]; 1428108SN/A case XMM1_0: return myfpregs.xmm_space[4]; 1438108SN/A case XMM1_1: return myfpregs.xmm_space[5]; 1448108SN/A case XMM1_2: return myfpregs.xmm_space[6]; 1458108SN/A case XMM1_3: return myfpregs.xmm_space[7]; 1468108SN/A case XMM2_0: return myfpregs.xmm_space[8]; 1478108SN/A case XMM2_1: return myfpregs.xmm_space[9]; 1488108SN/A case XMM2_2: return myfpregs.xmm_space[10]; 1498108SN/A case XMM2_3: return myfpregs.xmm_space[11]; 1508108SN/A case XMM3_0: return myfpregs.xmm_space[12]; 1518108SN/A case XMM3_1: return myfpregs.xmm_space[13]; 1528108SN/A case XMM3_2: return myfpregs.xmm_space[14]; 1538108SN/A case XMM3_3: return myfpregs.xmm_space[15]; 1548108SN/A case XMM4_0: return myfpregs.xmm_space[16]; 1558108SN/A case XMM4_1: return myfpregs.xmm_space[17]; 1568108SN/A case XMM4_2: return myfpregs.xmm_space[18]; 1578108SN/A case XMM4_3: return myfpregs.xmm_space[19]; 1588108SN/A case XMM5_0: return myfpregs.xmm_space[20]; 1598108SN/A case XMM5_1: return myfpregs.xmm_space[21]; 1608108SN/A case XMM5_2: return myfpregs.xmm_space[22]; 1618108SN/A case XMM5_3: return myfpregs.xmm_space[23]; 1628108SN/A case XMM6_0: return myfpregs.xmm_space[24]; 1638108SN/A case XMM6_1: return myfpregs.xmm_space[25]; 1648108SN/A case XMM6_2: return myfpregs.xmm_space[26]; 1658108SN/A case XMM6_3: return myfpregs.xmm_space[27]; 1668108SN/A case XMM7_0: return myfpregs.xmm_space[28]; 1678108SN/A case XMM7_1: return myfpregs.xmm_space[29]; 1688108SN/A case XMM7_2: return myfpregs.xmm_space[30]; 1698108SN/A case XMM7_3: return myfpregs.xmm_space[31]; 1708108SN/A case XMM8_0: return myfpregs.xmm_space[32]; 1718108SN/A case XMM8_1: return myfpregs.xmm_space[33]; 1728108SN/A case XMM8_2: return myfpregs.xmm_space[34]; 1738108SN/A case XMM8_3: return myfpregs.xmm_space[35]; 1748108SN/A case XMM9_0: return myfpregs.xmm_space[36]; 1758108SN/A case XMM9_1: return myfpregs.xmm_space[37]; 1768108SN/A case XMM9_2: return myfpregs.xmm_space[38]; 1778108SN/A case XMM9_3: return myfpregs.xmm_space[39]; 1788108SN/A case XMM10_0: return myfpregs.xmm_space[40]; 1798108SN/A case XMM10_1: return myfpregs.xmm_space[41]; 1808108SN/A case XMM10_2: return myfpregs.xmm_space[42]; 1818108SN/A case XMM10_3: return myfpregs.xmm_space[43]; 1828108SN/A case XMM11_0: return myfpregs.xmm_space[44]; 1838108SN/A case XMM11_1: return myfpregs.xmm_space[45]; 1848108SN/A case XMM11_2: return myfpregs.xmm_space[46]; 1858108SN/A case XMM11_3: return myfpregs.xmm_space[47]; 1868108SN/A case XMM12_0: return myfpregs.xmm_space[48]; 1878108SN/A case XMM12_1: return myfpregs.xmm_space[49]; 1888108SN/A case XMM12_2: return myfpregs.xmm_space[50]; 1898108SN/A case XMM12_3: return myfpregs.xmm_space[51]; 1908108SN/A case XMM13_0: return myfpregs.xmm_space[52]; 1918108SN/A case XMM13_1: return myfpregs.xmm_space[53]; 1928108SN/A case XMM13_2: return myfpregs.xmm_space[54]; 1938108SN/A case XMM13_3: return myfpregs.xmm_space[55]; 1948108SN/A case XMM14_0: return myfpregs.xmm_space[56]; 1958108SN/A case XMM14_1: return myfpregs.xmm_space[57]; 1968108SN/A case XMM14_2: return myfpregs.xmm_space[58]; 1978108SN/A case XMM14_3: return myfpregs.xmm_space[59]; 1988108SN/A case XMM15_0: return myfpregs.xmm_space[60]; 1998108SN/A case XMM15_1: return myfpregs.xmm_space[61]; 2008108SN/A case XMM15_2: return myfpregs.xmm_space[62]; 2018108SN/A case XMM15_3: return myfpregs.xmm_space[63]; 2028108SN/A default: 2038108SN/A assert(0); 2048108SN/A return 0; 2055049SN/A } 2064780SN/A} 2074780SN/A 2088108SN/Abool 2098108SN/AAMD64TraceChild::update(int pid) 2104780SN/A{ 2114780SN/A oldregs = regs; 2125049SN/A oldfpregs = fpregs; 2138108SN/A if (ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) { 2144780SN/A cerr << "update: " << strerror(errno) << endl; 2154780SN/A return false; 2164780SN/A } 2178108SN/A if (ptrace(PTRACE_GETFPREGS, pid, 0, &fpregs) != 0) { 2185049SN/A cerr << "update: " << strerror(errno) << endl; 2195049SN/A return false; 2205049SN/A } 2218108SN/A for (unsigned int x = 0; x < numregs; x++) 2224780SN/A regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 2234780SN/A return true; 2244780SN/A} 2254780SN/A 2264780SN/AAMD64TraceChild::AMD64TraceChild() 2274780SN/A{ 2288108SN/A for (unsigned int x = 0; x < numregs; x++) 2294780SN/A regDiffSinceUpdate[x] = false; 2304780SN/A} 2314780SN/A 2328108SN/Aint64_t 2338108SN/AAMD64TraceChild::getRegVal(int num) 2344780SN/A{ 2358108SN/A return getRegs(regs, fpregs, num); 2364780SN/A} 2374780SN/A 2388108SN/Aint64_t 2398108SN/AAMD64TraceChild::getOldRegVal(int num) 2404780SN/A{ 2418108SN/A return getRegs(oldregs, oldfpregs, num); 2424780SN/A} 2434780SN/A 2448108SN/Aostream & 2458108SN/AAMD64TraceChild::outputStartState(ostream & os) 2464780SN/A{ 2474780SN/A uint64_t sp = getSP(); 2484780SN/A uint64_t pc = getPC(); 2494843SN/A uint64_t highestInfo = 0; 2504780SN/A char obuf[1024]; 2517071SN/A sprintf(obuf, "Initial stack pointer = 0x%016lx\n", sp); 2524780SN/A os << obuf; 2537071SN/A sprintf(obuf, "Initial program counter = 0x%016lx\n", pc); 2544780SN/A os << obuf; 2554780SN/A 2564780SN/A //Output the argument count 2574780SN/A uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2587071SN/A sprintf(obuf, "0x%016lx: Argc = 0x%016lx\n", sp, cargc); 2594780SN/A os << obuf; 2604780SN/A sp += 8; 2614780SN/A 2624780SN/A //Output argv pointers 2634780SN/A int argCount = 0; 2644780SN/A uint64_t cargv; 2658108SN/A do { 2664780SN/A cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2677071SN/A sprintf(obuf, "0x%016lx: argv[%d] = 0x%016lx\n", 2684780SN/A sp, argCount++, cargv); 2698108SN/A if (cargv) 2708108SN/A if (highestInfo < cargv) 2714843SN/A highestInfo = cargv; 2724780SN/A os << obuf; 2734780SN/A sp += 8; 27411321Ssteve.reinhardt@amd.com } while (cargv); 2754780SN/A 2764780SN/A //Output the envp pointers 2774780SN/A int envCount = 0; 2784780SN/A uint64_t cenvp; 2798108SN/A do { 2804780SN/A cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2817071SN/A sprintf(obuf, "0x%016lx: envp[%d] = 0x%016lx\n", 2824780SN/A sp, envCount++, cenvp); 2834780SN/A os << obuf; 2844780SN/A sp += 8; 28511321Ssteve.reinhardt@amd.com } while (cenvp); 2864780SN/A uint64_t auxType, auxVal; 2878108SN/A do { 2884780SN/A auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2894780SN/A sp += 8; 2904780SN/A auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 2914780SN/A sp += 8; 2927071SN/A sprintf(obuf, "0x%016lx: Auxiliary vector = {0x%016lx, 0x%016lx}\n", 2934791SN/A sp - 16, auxType, auxVal); 2944780SN/A os << obuf; 29511321Ssteve.reinhardt@amd.com } while (auxType != 0 || auxVal != 0); 2964780SN/A //Print out the argument strings, environment strings, and file name. 2974780SN/A string current; 2984780SN/A uint64_t buf; 2994780SN/A uint64_t currentStart = sp; 3004780SN/A bool clearedInitialPadding = false; 3018108SN/A do { 3024780SN/A buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 3034780SN/A char * cbuf = (char *)&buf; 3048108SN/A for (int x = 0; x < sizeof(uint64_t); x++) { 3058108SN/A if (cbuf[x]) 3064780SN/A current += cbuf[x]; 3078108SN/A else { 3087071SN/A sprintf(obuf, "0x%016lx: \"%s\"\n", 3094780SN/A currentStart, current.c_str()); 3104780SN/A os << obuf; 3114780SN/A current = ""; 3124780SN/A currentStart = sp + x + 1; 3134780SN/A } 3144780SN/A } 3154780SN/A sp += 8; 3164780SN/A clearedInitialPadding = clearedInitialPadding || buf != 0; 3178108SN/A } while (!clearedInitialPadding || buf != 0 || sp <= highestInfo); 3184780SN/A return os; 3194780SN/A} 3204780SN/A 3218108SN/Auint64_t 3228108SN/AAMD64TraceChild::findSyscall() 3234795SN/A{ 3244795SN/A uint64_t rip = getPC(); 3254795SN/A bool foundOpcode = false; 3264795SN/A bool twoByteOpcode = false; 3278108SN/A for (;;) { 3284795SN/A uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0); 3298108SN/A for (int i = 0; i < sizeof(uint64_t); i++) { 3304795SN/A unsigned char byte = buf & 0xFF; 3318108SN/A if (!foundOpcode) { 33211321Ssteve.reinhardt@amd.com if (!(byte == 0x66 || //operand override 3334795SN/A byte == 0x67 || //address override 3344795SN/A byte == 0x2E || //cs 3354795SN/A byte == 0x3E || //ds 3364795SN/A byte == 0x26 || //es 3374795SN/A byte == 0x64 || //fs 3384795SN/A byte == 0x65 || //gs 3394795SN/A byte == 0x36 || //ss 3404795SN/A byte == 0xF0 || //lock 3414795SN/A byte == 0xF2 || //repe 3424795SN/A byte == 0xF3 || //repne 3434795SN/A (byte >= 0x40 && byte <= 0x4F) // REX 3448108SN/A )) { 3454795SN/A foundOpcode = true; 3464795SN/A } 3474795SN/A } 3488108SN/A if (foundOpcode) { 3498108SN/A if (twoByteOpcode) { 3504795SN/A //SYSCALL or SYSENTER 3518108SN/A if (byte == 0x05 || byte == 0x34) 3524795SN/A return rip + 1; 3534795SN/A else 3544795SN/A return 0; 3554795SN/A } 3568108SN/A if (!twoByteOpcode) { 3578108SN/A if (byte == 0xCC) // INT3 3584795SN/A return rip + 1; 3598108SN/A else if (byte == 0xCD) // INT with byte immediate 3604795SN/A return rip + 2; 3618108SN/A else if (byte == 0x0F) // two byte opcode prefix 3624795SN/A twoByteOpcode = true; 3634795SN/A else 3644795SN/A return 0; 3654795SN/A } 3664795SN/A } 3674795SN/A buf >>= 8; 3684795SN/A rip++; 3694795SN/A } 3704795SN/A } 3714795SN/A} 3724795SN/A 3738108SN/Abool 3748108SN/AAMD64TraceChild::step() 3754795SN/A{ 3764795SN/A uint64_t ripAfterSyscall = findSyscall(); 3778108SN/A if (ripAfterSyscall) { 3784795SN/A //Get the original contents of memory 3794795SN/A uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0); 3804795SN/A //Patch the first two bytes of the memory immediately after this with 3814795SN/A //jmp -2. Either single stepping will take over before this 3824795SN/A //instruction, leaving the rip where it should be, or it will take 3834795SN/A //over after this instruction, -still- leaving the rip where it should 3844795SN/A //be. 3854795SN/A uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB; 3864795SN/A //Write the patched memory to the processes address space 3874795SN/A ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf); 3884795SN/A //Step and hit it 3894795SN/A ptraceSingleStep(); 3904795SN/A //Put things back to the way they started 3914795SN/A ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf); 3928108SN/A } else { 3934955SN/A //Get all the way past repe and repne string instructions in one shot. 3944955SN/A uint64_t newPC, origPC = getPC(); 3958108SN/A do { 3964955SN/A ptraceSingleStep(); 3974955SN/A newPC = getPC(); 39811321Ssteve.reinhardt@amd.com } while (newPC == origPC); 3994955SN/A } 4004795SN/A} 4014795SN/A 4024780SN/ATraceChild * genTraceChild() 4034780SN/A{ 4048108SN/A return new AMD64TraceChild; 4054780SN/A} 406