tracechild.cc revision 5049
1/* 2 * Copyright (c) 2007 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Gabe Black 29 */ 30 31#include <iostream> 32#include <iomanip> 33#include <errno.h> 34#include <sys/ptrace.h> 35#include <stdint.h> 36 37#include "tracechild_amd64.hh" 38 39using namespace std; 40 41char * AMD64TraceChild::regNames[numregs] = { 42 //GPRs 43 "rax", "rbx", "rcx", "rdx", 44 //Index registers 45 "rsi", "rdi", 46 //Base pointer and stack pointer 47 "rbp", "rsp", 48 //New 64 bit mode registers 49 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 50 //Segmentation registers 51 "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base", 52 //PC 53 "rip", 54 //Flags 55 "eflags", 56 //MMX 57 "mmx0_0", "mmx0_1", 58 "mmx1_0", "mmx1_1", 59 "mmx2_0", "mmx2_1", 60 "mmx3_0", "mmx3_1", 61 "mmx4_0", "mmx4_1", 62 "mmx5_0", "mmx5_1", 63 "mmx6_0", "mmx6_1", 64 "mmx7_0", "mmx7_1", 65 //XMM 66 "xmm0_0", "xmm0_1", "xmm0_2", "xmm0_3", 67 "xmm1_0", "xmm1_1", "xmm1_2", "xmm1_3", 68 "xmm2_0", "xmm2_1", "xmm2_2", "xmm2_3", 69 "xmm3_0", "xmm3_1", "xmm3_2", "xmm3_3", 70 "xmm4_0", "xmm4_1", "xmm4_2", "xmm4_3", 71 "xmm5_0", "xmm5_1", "xmm5_2", "xmm5_3", 72 "xmm6_0", "xmm6_1", "xmm6_2", "xmm6_3", 73 "xmm7_0", "xmm7_1", "xmm7_2", "xmm7_3", 74 "xmm8_0", "xmm8_1", "xmm8_2", "xmm8_3", 75 "xmm9_0", "xmm9_1", "xmm9_2", "xmm9_3", 76 "xmm10_0", "xmm10_1", "xmm10_2", "xmm10_3", 77 "xmm11_0", "xmm11_1", "xmm11_2", "xmm11_3", 78 "xmm12_0", "xmm12_1", "xmm12_2", "xmm12_3", 79 "xmm13_0", "xmm13_1", "xmm13_2", "xmm13_3", 80 "xmm14_0", "xmm14_1", "xmm14_2", "xmm14_3", 81 "xmm15_0", "xmm15_1", "xmm15_2", "xmm15_3"}; 82 83bool AMD64TraceChild::sendState(int socket) 84{ 85 uint64_t regVal64 = 0; 86 uint32_t regVal32 = 0; 87 for(int x = 0; x <= R15; x++) 88 { 89 regVal64 = getRegVal(x); 90 if(write(socket, ®Val64, sizeof(regVal64)) == -1) 91 { 92 cerr << "Write failed! " << strerror(errno) << endl; 93 tracing = false; 94 return false; 95 } 96 } 97 regVal64 = getRegVal(RIP); 98 if(write(socket, ®Val64, sizeof(regVal64)) == -1) 99 { 100 cerr << "Write failed! " << strerror(errno) << endl; 101 tracing = false; 102 return false; 103 } 104 for(int x = MMX0_0; x <= MMX7_1; x++) 105 { 106 regVal32 = getRegVal(x); 107 if(write(socket, ®Val32, sizeof(regVal32)) == -1) 108 { 109 cerr << "Write failed! " << strerror(errno) << endl; 110 tracing = false; 111 return false; 112 } 113 } 114 for(int x = XMM0_0; x <= XMM15_3; x++) 115 { 116 regVal32 = getRegVal(x); 117 if(write(socket, ®Val32, sizeof(regVal32)) == -1) 118 { 119 cerr << "Write failed! " << strerror(errno) << endl; 120 tracing = false; 121 return false; 122 } 123 } 124 return true; 125} 126 127int64_t AMD64TraceChild::getRegs(user_regs_struct & myregs, 128 user_fpregs_struct & myfpregs, int num) 129{ 130 assert(num < numregs && num >= 0); 131 switch(num) 132 { 133 //GPRs 134 case RAX: return myregs.rax; 135 case RBX: return myregs.rbx; 136 case RCX: return myregs.rcx; 137 case RDX: return myregs.rdx; 138 //Index registers 139 case RSI: return myregs.rsi; 140 case RDI: return myregs.rdi; 141 //Base pointer and stack pointer 142 case RBP: return myregs.rbp; 143 case RSP: return myregs.rsp; 144 //New 64 bit mode registers 145 case R8: return myregs.r8; 146 case R9: return myregs.r9; 147 case R10: return myregs.r10; 148 case R11: return myregs.r11; 149 case R12: return myregs.r12; 150 case R13: return myregs.r13; 151 case R14: return myregs.r14; 152 case R15: return myregs.r15; 153 //Segmentation registers 154 case CS: return myregs.cs; 155 case DS: return myregs.ds; 156 case ES: return myregs.es; 157 case FS: return myregs.fs; 158 case GS: return myregs.gs; 159 case SS: return myregs.ss; 160 case FS_BASE: return myregs.fs_base; 161 case GS_BASE: return myregs.gs_base; 162 //PC 163 case RIP: return myregs.rip; 164 //Flags 165 case EFLAGS: return myregs.eflags; 166 //MMX 167 case MMX0_0: return myfpregs.st_space[0]; 168 case MMX0_1: return myfpregs.st_space[1]; 169 case MMX1_0: return myfpregs.st_space[2]; 170 case MMX1_1: return myfpregs.st_space[3]; 171 case MMX2_0: return myfpregs.st_space[4]; 172 case MMX2_1: return myfpregs.st_space[5]; 173 case MMX3_0: return myfpregs.st_space[6]; 174 case MMX3_1: return myfpregs.st_space[7]; 175 case MMX4_0: return myfpregs.st_space[8]; 176 case MMX4_1: return myfpregs.st_space[9]; 177 case MMX5_0: return myfpregs.st_space[10]; 178 case MMX5_1: return myfpregs.st_space[11]; 179 case MMX6_0: return myfpregs.st_space[12]; 180 case MMX6_1: return myfpregs.st_space[13]; 181 case MMX7_0: return myfpregs.st_space[14]; 182 case MMX7_1: return myfpregs.st_space[15]; 183 //XMM 184 case XMM0_0: return myfpregs.xmm_space[0]; 185 case XMM0_1: return myfpregs.xmm_space[1]; 186 case XMM0_2: return myfpregs.xmm_space[2]; 187 case XMM0_3: return myfpregs.xmm_space[3]; 188 case XMM1_0: return myfpregs.xmm_space[4]; 189 case XMM1_1: return myfpregs.xmm_space[5]; 190 case XMM1_2: return myfpregs.xmm_space[6]; 191 case XMM1_3: return myfpregs.xmm_space[7]; 192 case XMM2_0: return myfpregs.xmm_space[8]; 193 case XMM2_1: return myfpregs.xmm_space[9]; 194 case XMM2_2: return myfpregs.xmm_space[10]; 195 case XMM2_3: return myfpregs.xmm_space[11]; 196 case XMM3_0: return myfpregs.xmm_space[12]; 197 case XMM3_1: return myfpregs.xmm_space[13]; 198 case XMM3_2: return myfpregs.xmm_space[14]; 199 case XMM3_3: return myfpregs.xmm_space[15]; 200 case XMM4_0: return myfpregs.xmm_space[16]; 201 case XMM4_1: return myfpregs.xmm_space[17]; 202 case XMM4_2: return myfpregs.xmm_space[18]; 203 case XMM4_3: return myfpregs.xmm_space[19]; 204 case XMM5_0: return myfpregs.xmm_space[20]; 205 case XMM5_1: return myfpregs.xmm_space[21]; 206 case XMM5_2: return myfpregs.xmm_space[22]; 207 case XMM5_3: return myfpregs.xmm_space[23]; 208 case XMM6_0: return myfpregs.xmm_space[24]; 209 case XMM6_1: return myfpregs.xmm_space[25]; 210 case XMM6_2: return myfpregs.xmm_space[26]; 211 case XMM6_3: return myfpregs.xmm_space[27]; 212 case XMM7_0: return myfpregs.xmm_space[28]; 213 case XMM7_1: return myfpregs.xmm_space[29]; 214 case XMM7_2: return myfpregs.xmm_space[30]; 215 case XMM7_3: return myfpregs.xmm_space[31]; 216 case XMM8_0: return myfpregs.xmm_space[32]; 217 case XMM8_1: return myfpregs.xmm_space[33]; 218 case XMM8_2: return myfpregs.xmm_space[34]; 219 case XMM8_3: return myfpregs.xmm_space[35]; 220 case XMM9_0: return myfpregs.xmm_space[36]; 221 case XMM9_1: return myfpregs.xmm_space[37]; 222 case XMM9_2: return myfpregs.xmm_space[38]; 223 case XMM9_3: return myfpregs.xmm_space[39]; 224 case XMM10_0: return myfpregs.xmm_space[40]; 225 case XMM10_1: return myfpregs.xmm_space[41]; 226 case XMM10_2: return myfpregs.xmm_space[42]; 227 case XMM10_3: return myfpregs.xmm_space[43]; 228 case XMM11_0: return myfpregs.xmm_space[44]; 229 case XMM11_1: return myfpregs.xmm_space[45]; 230 case XMM11_2: return myfpregs.xmm_space[46]; 231 case XMM11_3: return myfpregs.xmm_space[47]; 232 case XMM12_0: return myfpregs.xmm_space[48]; 233 case XMM12_1: return myfpregs.xmm_space[49]; 234 case XMM12_2: return myfpregs.xmm_space[50]; 235 case XMM12_3: return myfpregs.xmm_space[51]; 236 case XMM13_0: return myfpregs.xmm_space[52]; 237 case XMM13_1: return myfpregs.xmm_space[53]; 238 case XMM13_2: return myfpregs.xmm_space[54]; 239 case XMM13_3: return myfpregs.xmm_space[55]; 240 case XMM14_0: return myfpregs.xmm_space[56]; 241 case XMM14_1: return myfpregs.xmm_space[57]; 242 case XMM14_2: return myfpregs.xmm_space[58]; 243 case XMM14_3: return myfpregs.xmm_space[59]; 244 case XMM15_0: return myfpregs.xmm_space[60]; 245 case XMM15_1: return myfpregs.xmm_space[61]; 246 case XMM15_2: return myfpregs.xmm_space[62]; 247 case XMM15_3: return myfpregs.xmm_space[63]; 248 default: 249 assert(0); 250 return 0; 251 } 252} 253 254bool AMD64TraceChild::update(int pid) 255{ 256 oldregs = regs; 257 oldfpregs = fpregs; 258 if(ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) 259 { 260 cerr << "update: " << strerror(errno) << endl; 261 return false; 262 } 263 if(ptrace(PTRACE_GETFPREGS, pid, 0, &fpregs) != 0) 264 { 265 cerr << "update: " << strerror(errno) << endl; 266 return false; 267 } 268 for(unsigned int x = 0; x < numregs; x++) 269 regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 270 return true; 271} 272 273AMD64TraceChild::AMD64TraceChild() 274{ 275 for(unsigned int x = 0; x < numregs; x++) 276 regDiffSinceUpdate[x] = false; 277} 278 279int64_t AMD64TraceChild::getRegVal(int num) 280{ 281 return getRegs(regs, fpregs, num); 282} 283 284int64_t AMD64TraceChild::getOldRegVal(int num) 285{ 286 return getRegs(oldregs, oldfpregs, num); 287} 288 289char * AMD64TraceChild::printReg(int num) 290{ 291 sprintf(printBuffer, "0x%08X", getRegVal(num)); 292 return printBuffer; 293} 294 295ostream & AMD64TraceChild::outputStartState(ostream & os) 296{ 297 uint64_t sp = getSP(); 298 uint64_t pc = getPC(); 299 uint64_t highestInfo = 0; 300 char obuf[1024]; 301 sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp); 302 os << obuf; 303 sprintf(obuf, "Initial program counter = 0x%016llx\n", pc); 304 os << obuf; 305 306 //Output the argument count 307 uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 308 sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc); 309 os << obuf; 310 sp += 8; 311 312 //Output argv pointers 313 int argCount = 0; 314 uint64_t cargv; 315 do 316 { 317 cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 318 sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n", 319 sp, argCount++, cargv); 320 if(cargv) 321 if(highestInfo < cargv) 322 highestInfo = cargv; 323 os << obuf; 324 sp += 8; 325 } while(cargv); 326 327 //Output the envp pointers 328 int envCount = 0; 329 uint64_t cenvp; 330 do 331 { 332 cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 333 sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n", 334 sp, envCount++, cenvp); 335 os << obuf; 336 sp += 8; 337 } while(cenvp); 338 uint64_t auxType, auxVal; 339 do 340 { 341 auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 342 sp += 8; 343 auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 344 sp += 8; 345 sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", 346 sp - 16, auxType, auxVal); 347 os << obuf; 348 } while(auxType != 0 || auxVal != 0); 349 //Print out the argument strings, environment strings, and file name. 350 string current; 351 uint64_t buf; 352 uint64_t currentStart = sp; 353 bool clearedInitialPadding = false; 354 do 355 { 356 buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 357 char * cbuf = (char *)&buf; 358 for(int x = 0; x < sizeof(uint64_t); x++) 359 { 360 if(cbuf[x]) 361 current += cbuf[x]; 362 else 363 { 364 sprintf(obuf, "0x%016llx: \"%s\"\n", 365 currentStart, current.c_str()); 366 os << obuf; 367 current = ""; 368 currentStart = sp + x + 1; 369 } 370 } 371 sp += 8; 372 clearedInitialPadding = clearedInitialPadding || buf != 0; 373 } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo); 374 return os; 375} 376 377uint64_t AMD64TraceChild::findSyscall() 378{ 379 uint64_t rip = getPC(); 380 bool foundOpcode = false; 381 bool twoByteOpcode = false; 382 for(;;) 383 { 384 uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0); 385 for(int i = 0; i < sizeof(uint64_t); i++) 386 { 387 unsigned char byte = buf & 0xFF; 388 if(!foundOpcode) 389 { 390 if(!(byte == 0x66 || //operand override 391 byte == 0x67 || //address override 392 byte == 0x2E || //cs 393 byte == 0x3E || //ds 394 byte == 0x26 || //es 395 byte == 0x64 || //fs 396 byte == 0x65 || //gs 397 byte == 0x36 || //ss 398 byte == 0xF0 || //lock 399 byte == 0xF2 || //repe 400 byte == 0xF3 || //repne 401 (byte >= 0x40 && byte <= 0x4F) // REX 402 )) 403 { 404 foundOpcode = true; 405 } 406 } 407 if(foundOpcode) 408 { 409 if(twoByteOpcode) 410 { 411 //SYSCALL or SYSENTER 412 if(byte == 0x05 || byte == 0x34) 413 return rip + 1; 414 else 415 return 0; 416 } 417 if(!twoByteOpcode) 418 { 419 if(byte == 0xCC) // INT3 420 return rip + 1; 421 else if(byte == 0xCD) // INT with byte immediate 422 return rip + 2; 423 else if(byte == 0x0F) // two byte opcode prefix 424 twoByteOpcode = true; 425 else 426 return 0; 427 } 428 } 429 buf >>= 8; 430 rip++; 431 } 432 } 433} 434 435bool AMD64TraceChild::step() 436{ 437 uint64_t ripAfterSyscall = findSyscall(); 438 if(ripAfterSyscall) 439 { 440 //Get the original contents of memory 441 uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0); 442 //Patch the first two bytes of the memory immediately after this with 443 //jmp -2. Either single stepping will take over before this 444 //instruction, leaving the rip where it should be, or it will take 445 //over after this instruction, -still- leaving the rip where it should 446 //be. 447 uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB; 448 //Write the patched memory to the processes address space 449 ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf); 450 //Step and hit it 451 ptraceSingleStep(); 452 //Put things back to the way they started 453 ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf); 454 } 455 else 456 { 457 //Get all the way past repe and repne string instructions in one shot. 458 uint64_t newPC, origPC = getPC(); 459 do 460 { 461 ptraceSingleStep(); 462 newPC = getPC(); 463 } while(newPC == origPC); 464 } 465} 466 467TraceChild * genTraceChild() 468{ 469 return new AMD64TraceChild; 470} 471