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