tracechild.cc revision 8108
1/* 2 * Copyright (c) 2006-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 <errno.h> 33#include <sys/ptrace.h> 34#include <stdint.h> 35 36#include "tracechild_sparc.hh" 37 38using namespace std; 39 40string SparcTraceChild::regNames[numregs] = { 41 //Global registers 42 "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", 43 //Output registers 44 "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", 45 //Local registers 46 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", 47 //Input registers 48 "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", 49 //Floating point 50 "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14", 51 "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30", 52 "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", 53 "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", 54 //Miscelaneous 55 "fsr", "fprs", "pc", "npc", "y", "cwp", "pstate", "asi", "ccr"}; 56 57bool 58SparcTraceChild::sendState(int socket) 59{ 60 uint64_t regVal = 0; 61 for (int x = 0; x <= I7; x++) { 62 regVal = getRegVal(x); 63 if (write(socket, ®Val, sizeof(regVal)) == -1) { 64 cerr << "Write failed! " << strerror(errno) << endl; 65 tracing = false; 66 return false; 67 } 68 } 69 regVal = getRegVal(PC); 70 if (write(socket, ®Val, sizeof(regVal)) == -1) { 71 cerr << "Write failed! " << strerror(errno) << endl; 72 tracing = false; 73 return false; 74 } 75 regVal = getRegVal(NPC); 76 if (write(socket, ®Val, sizeof(regVal)) == -1) { 77 cerr << "Write failed! " << strerror(errno) << endl; 78 tracing = false; 79 return false; 80 } 81 regVal = getRegVal(CCR); 82 if (write(socket, ®Val, sizeof(regVal)) == -1) { 83 cerr << "Write failed! " << strerror(errno) << endl; 84 tracing = false; 85 return false; 86 } 87 return true; 88} 89 90int64_t 91getRegs(regs & myregs, fpu & myfpu, uint64_t * locals, 92 uint64_t * inputs, int num) 93{ 94 assert(num < SparcTraceChild::numregs && num >= 0); 95 switch (num) { 96 //Global registers 97 case SparcTraceChild::G0: return 0; 98 case SparcTraceChild::G1: return myregs.r_g1; 99 case SparcTraceChild::G2: return myregs.r_g2; 100 case SparcTraceChild::G3: return myregs.r_g3; 101 case SparcTraceChild::G4: return myregs.r_g4; 102 case SparcTraceChild::G5: return myregs.r_g5; 103 case SparcTraceChild::G6: return myregs.r_g6; 104 case SparcTraceChild::G7: return myregs.r_g7; 105 //Output registers 106 case SparcTraceChild::O0: return myregs.r_o0; 107 case SparcTraceChild::O1: return myregs.r_o1; 108 case SparcTraceChild::O2: return myregs.r_o2; 109 case SparcTraceChild::O3: return myregs.r_o3; 110 case SparcTraceChild::O4: return myregs.r_o4; 111 case SparcTraceChild::O5: return myregs.r_o5; 112 case SparcTraceChild::O6: return myregs.r_o6; 113 case SparcTraceChild::O7: return myregs.r_o7; 114 //Local registers 115 case SparcTraceChild::L0: return locals[0]; 116 case SparcTraceChild::L1: return locals[1]; 117 case SparcTraceChild::L2: return locals[2]; 118 case SparcTraceChild::L3: return locals[3]; 119 case SparcTraceChild::L4: return locals[4]; 120 case SparcTraceChild::L5: return locals[5]; 121 case SparcTraceChild::L6: return locals[6]; 122 case SparcTraceChild::L7: return locals[7]; 123 //Input registers 124 case SparcTraceChild::I0: return inputs[0]; 125 case SparcTraceChild::I1: return inputs[1]; 126 case SparcTraceChild::I2: return inputs[2]; 127 case SparcTraceChild::I3: return inputs[3]; 128 case SparcTraceChild::I4: return inputs[4]; 129 case SparcTraceChild::I5: return inputs[5]; 130 case SparcTraceChild::I6: return inputs[6]; 131 case SparcTraceChild::I7: return inputs[7]; 132 //Floating point 133 case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0]; 134 case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1]; 135 case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2]; 136 case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3]; 137 case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4]; 138 case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5]; 139 case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6]; 140 case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7]; 141 case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8]; 142 case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9]; 143 case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10]; 144 case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11]; 145 case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12]; 146 case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13]; 147 case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14]; 148 case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15]; 149 case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16]; 150 case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17]; 151 case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18]; 152 case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19]; 153 case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20]; 154 case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21]; 155 case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22]; 156 case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23]; 157 case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24]; 158 case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25]; 159 case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26]; 160 case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27]; 161 case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28]; 162 case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29]; 163 case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30]; 164 case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31]; 165 //Miscelaneous 166 case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr; 167 case SparcTraceChild::FPRS: return myregs.r_fprs; 168 case SparcTraceChild::PC: return myregs.r_tpc; 169 case SparcTraceChild::NPC: return myregs.r_tnpc; 170 case SparcTraceChild::Y: return myregs.r_y; 171 case SparcTraceChild::CWP: 172 return (myregs.r_tstate >> 0) & ((1 << 5) - 1); 173 case SparcTraceChild::PSTATE: 174 return (myregs.r_tstate >> 8) & ((1 << 13) - 1); 175 case SparcTraceChild::ASI: 176 return (myregs.r_tstate >> 24) & ((1 << 8) - 1); 177 case SparcTraceChild::CCR: 178 return (myregs.r_tstate >> 32) & ((1 << 8) - 1); 179 default: 180 assert(0); 181 return 0; 182 } 183} 184 185bool 186SparcTraceChild::update(int pid) 187{ 188 memcpy(&oldregs, &theregs, sizeof(regs)); 189 memcpy(&oldfpregs, &thefpregs, sizeof(fpu)); 190 memcpy(oldLocals, locals, 8 * sizeof(uint64_t)); 191 memcpy(oldInputs, inputs, 8 * sizeof(uint64_t)); 192 if (ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) { 193 cerr << "Update failed" << endl; 194 return false; 195 } 196 uint64_t stackPointer = getSP(); 197 uint64_t stackBias = 2047; 198 bool v9 = stackPointer % 2; 199 for (unsigned int x = 0; x < 8; x++) { 200 uint64_t localAddr = stackPointer + 201 (v9 ? (stackBias + x * 8) : (x * 4)); 202 locals[x] = ptrace(PTRACE_PEEKTEXT, pid, localAddr, 0); 203 if (!v9) locals[x] >>= 32; 204 uint64_t inputAddr = stackPointer + 205 (v9 ? (stackBias + x * 8 + (8 * 8)) : (x * 4 + 8 * 4)); 206 inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, inputAddr, 0); 207 if (!v9) inputs[x] >>= 32; 208 } 209 if (ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0) 210 return false; 211 for (unsigned int x = 0; x < numregs; x++) 212 regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 213 return true; 214} 215 216SparcTraceChild::SparcTraceChild() 217{ 218 for (unsigned int x = 0; x < numregs; x++) 219 regDiffSinceUpdate[x] = false; 220} 221 222int 223SparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc, 224 uint64_t &target1, uint64_t &target2) 225{ 226 //We can identify the instruction categories we care about using the top 227 //10 bits of the instruction, excluding the annul bit in the 3rd most 228 //significant bit position and the condition field. We'll call these 229 //bits the "sig" for signature. 230 uint32_t sig = (inst >> 22) & 0x307; 231 uint32_t cond = (inst >> 25) & 0xf; 232 bool annul = (inst & (1 << 29)); 233 234 //Check if it's a ba... 235 bool ba = (cond == 0x8) && 236 (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6); 237 //or a bn... 238 bool bn = (cond == 0x0) && 239 (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6); 240 //or a bcc 241 bool bcc = (cond & 0x7) && 242 (sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6); 243 244 if (annul) { 245 if (bcc) { 246 target1 = npc; 247 target2 = npc + 4; 248 return 2; 249 } else if(ba) { 250 //This branches immediately to the effective address of the branch 251 //which we'll have to calculate. 252 uint64_t disp = 0; 253 int64_t extender = 0; 254 //Figure out how big the displacement field is, and grab the bits 255 if (sig == 0x1 || sig == 0x5) { 256 disp = inst & ((1 << 19) - 1); 257 extender = 1 << 18; 258 } else { 259 disp = inst & ((1 << 22) - 1); 260 extender = 1 << 21; 261 } 262 //This does sign extension, believe it or not. 263 disp = (disp ^ extender) - extender; 264 //Multiply the displacement by 4. I'm assuming the compiler is 265 //smart enough to turn this into a shift. 266 disp *= 4; 267 target1 = pc + disp; 268 } else if(bn) 269 target1 = npc + 4; 270 else 271 target1 = npc; 272 return 1; 273 } else { 274 target1 = npc; 275 return 1; 276 } 277} 278 279bool 280SparcTraceChild::step() 281{ 282 //Increment the count of the number of instructions executed 283 instructions++; 284 //Two important considerations are that the address of the instruction 285 //being breakpointed should be word (64bit) aligned, and that both the 286 //next instruction and the instruction after that need to be breakpointed 287 //so that annulled branches will still stop as well. 288 289 /* 290 * Useful constants 291 */ 292 const static uint64_t breakInst = 0x91d02001; 293 const static uint64_t lowBreakInst = breakInst; 294 const static uint64_t highBreakInst = breakInst << 32; 295 const static uint64_t breakWord = breakInst | (breakInst << 32); 296 const static uint64_t lowMask = 0xFFFFFFFFULL; 297 const static uint64_t highMask = lowMask << 32; 298 299 /* 300 * storage for the original contents of the child process's memory 301 */ 302 uint64_t originalInst, originalAnnulInst; 303 304 /* 305 * Get information about where the process is and is headed next. 306 */ 307 uint64_t currentPC = getRegVal(PC); 308 bool unalignedPC = currentPC & 7; 309 uint64_t alignedPC = currentPC & (~7); 310 uint64_t nextPC = getRegVal(NPC); 311 bool unalignedNPC = nextPC & 7; 312 uint64_t alignedNPC = nextPC & (~7); 313 314 //Get the current instruction 315 uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC); 316 curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32); 317 318 uint64_t bp1, bp2; 319 int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2); 320 assert(numTargets == 1 || numTargets == 2); 321 322 bool unalignedBp1 = bp1 & 7; 323 uint64_t alignedBp1 = bp1 & (~7); 324 bool unalignedBp2 = bp2 & 7; 325 uint64_t alignedBp2 = bp2 & (~7); 326 uint64_t origBp1, origBp2; 327 328 /* 329 * Set the first breakpoint 330 */ 331 origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0); 332 uint64_t newBp1 = origBp1; 333 newBp1 &= unalignedBp1 ? highMask : lowMask; 334 newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst; 335 if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0) 336 cerr << "Poke failed" << endl; 337 /* 338 * Set the second breakpoint if necessary 339 */ 340 if (numTargets == 2) { 341 origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0); 342 uint64_t newBp2 = origBp2; 343 newBp2 &= unalignedBp2 ? highMask : lowMask; 344 newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst; 345 if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0) 346 cerr << "Poke failed" << endl; 347 } 348 349 /* 350 * Restart the child process 351 */ 352 //Note that the "addr" parameter is supposed to be ignored, but in at 353 //least one version of the kernel, it must be 1 or it will set what 354 //pc to continue from 355 if (ptrace(PTRACE_CONT, pid, 1, 0) != 0) 356 cerr << "Cont failed" << endl; 357 doWait(); 358 359 /* 360 * Update our record of the child's state 361 */ 362 update(pid); 363 364 /* 365 * Put back the original contents of the childs address space in the 366 * reverse order. 367 */ 368 if (numTargets == 2) { 369 if (ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0) 370 cerr << "Poke failed" << endl; 371 } 372 if (ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0) 373 cerr << "Poke failed" << endl; 374} 375 376int64_t 377SparcTraceChild::getRegVal(int num) 378{ 379 return getRegs(theregs, thefpregs, locals, inputs, num); 380} 381 382int64_t 383SparcTraceChild::getOldRegVal(int num) 384{ 385 return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num); 386} 387 388char * 389SparcTraceChild::printReg(int num) 390{ 391 sprintf(printBuffer, "0x%016llx", getRegVal(num)); 392 return printBuffer; 393} 394 395ostream & 396SparcTraceChild::outputStartState(ostream & os) 397{ 398 bool v8 = false; 399 uint64_t sp = getSP(); 400 if (sp % 2) { 401 os << "Detected a 64 bit executable.\n"; 402 v8 = false; 403 } else { 404 os << "Detected a 32 bit executable.\n"; 405 v8 = true; 406 } 407 uint64_t pc = getPC(); 408 char obuf[1024]; 409 sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp); 410 os << obuf; 411 sprintf(obuf, "Initial program counter = 0x%016llx\n", pc); 412 os << obuf; 413 if (!v8) { 414 //Take out the stack bias 415 sp += 2047; 416 } 417 //Output the window save area 418 for (unsigned int x = 0; x < 16; x++) { 419 uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 420 if (v8) regspot = regspot >> 32; 421 sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n", 422 sp, x+1, regspot); 423 os << obuf; 424 sp += v8 ? 4 : 8; 425 } 426 //Output the argument count 427 uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 428 if (v8) cargc = cargc >> 32; 429 sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc); 430 os << obuf; 431 sp += v8 ? 4 : 8; 432 //Output argv pointers 433 int argCount = 0; 434 uint64_t cargv; 435 do { 436 cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 437 if (v8) cargv = cargv >> 32; 438 sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n", 439 sp, argCount++, cargv); 440 os << obuf; 441 sp += v8 ? 4 : 8; 442 } while(cargv); 443 //Output the envp pointers 444 int envCount = 0; 445 uint64_t cenvp; 446 do { 447 cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 448 if (v8) cenvp = cenvp >> 32; 449 sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n", 450 sp, envCount++, cenvp); 451 os << obuf; 452 sp += v8 ? 4 : 8; 453 } while (cenvp); 454 uint64_t auxType, auxVal; 455 do { 456 auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 457 if (v8) auxType = auxType >> 32; 458 sp += (v8 ? 4 : 8); 459 auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 460 if (v8) auxVal = auxVal >> 32; 461 sp += (v8 ? 4 : 8); 462 sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", 463 sp - 8, auxType, auxVal); 464 os << obuf; 465 } while (auxType != 0 || auxVal != 0); 466 //Print out the argument strings, environment strings, and file name. 467 string current; 468 uint64_t buf; 469 uint64_t currentStart = sp; 470 bool clearedInitialPadding = false; 471 do { 472 buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 473 char * cbuf = (char *)&buf; 474 for (int x = 0; x < sizeof(uint32_t); x++) { 475 if (cbuf[x]) 476 current += cbuf[x]; 477 else { 478 sprintf(obuf, "0x%016llx: \"%s\"\n", 479 currentStart, current.c_str()); 480 os << obuf; 481 current = ""; 482 currentStart = sp + x + 1; 483 } 484 } 485 sp += (v8 ? 4 : 8); 486 clearedInitialPadding = clearedInitialPadding || buf != 0; 487 } while (!clearedInitialPadding || buf != 0); 488 return os; 489} 490 491TraceChild * 492genTraceChild() 493{ 494 return new SparcTraceChild; 495} 496 497