tracechild.cc revision 3382
1/* 2 * Copyright (c) 2006 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 57int64_t getRegs(regs & myregs, fpu & myfpu, 58 int64_t * locals, int64_t * inputs, int num) 59{ 60 assert(num < SparcTraceChild::numregs && num >= 0); 61 switch(num) 62 { 63 //Global registers 64 case SparcTraceChild::G0: return 0; 65 case SparcTraceChild::G1: return myregs.r_g1; 66 case SparcTraceChild::G2: return myregs.r_g2; 67 case SparcTraceChild::G3: return myregs.r_g3; 68 case SparcTraceChild::G4: return myregs.r_g4; 69 case SparcTraceChild::G5: return myregs.r_g5; 70 case SparcTraceChild::G6: return myregs.r_g6; 71 case SparcTraceChild::G7: return myregs.r_g7; 72 //Output registers 73 case SparcTraceChild::O0: return myregs.r_o0; 74 case SparcTraceChild::O1: return myregs.r_o1; 75 case SparcTraceChild::O2: return myregs.r_o2; 76 case SparcTraceChild::O3: return myregs.r_o3; 77 case SparcTraceChild::O4: return myregs.r_o4; 78 case SparcTraceChild::O5: return myregs.r_o5; 79 case SparcTraceChild::O6: return myregs.r_o6; 80 case SparcTraceChild::O7: return myregs.r_o7; 81 //Local registers 82 case SparcTraceChild::L0: return locals[0]; 83 case SparcTraceChild::L1: return locals[1]; 84 case SparcTraceChild::L2: return locals[2]; 85 case SparcTraceChild::L3: return locals[3]; 86 case SparcTraceChild::L4: return locals[4]; 87 case SparcTraceChild::L5: return locals[5]; 88 case SparcTraceChild::L6: return locals[6]; 89 case SparcTraceChild::L7: return locals[7]; 90 //Input registers 91 case SparcTraceChild::I0: return inputs[0]; 92 case SparcTraceChild::I1: return inputs[1]; 93 case SparcTraceChild::I2: return inputs[2]; 94 case SparcTraceChild::I3: return inputs[3]; 95 case SparcTraceChild::I4: return inputs[4]; 96 case SparcTraceChild::I5: return inputs[5]; 97 case SparcTraceChild::I6: return inputs[6]; 98 case SparcTraceChild::I7: return inputs[7]; 99 //Floating point 100 case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0]; 101 case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1]; 102 case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2]; 103 case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3]; 104 case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4]; 105 case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5]; 106 case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6]; 107 case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7]; 108 case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8]; 109 case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9]; 110 case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10]; 111 case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11]; 112 case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12]; 113 case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13]; 114 case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14]; 115 case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15]; 116 case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16]; 117 case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17]; 118 case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18]; 119 case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19]; 120 case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20]; 121 case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21]; 122 case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22]; 123 case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23]; 124 case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24]; 125 case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25]; 126 case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26]; 127 case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27]; 128 case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28]; 129 case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29]; 130 case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30]; 131 case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31]; 132 //Miscelaneous 133 case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr; 134 case SparcTraceChild::FPRS: return myregs.r_fprs; 135 case SparcTraceChild::PC: return myregs.r_tpc; 136 case SparcTraceChild::NPC: return myregs.r_tnpc; 137 case SparcTraceChild::Y: return myregs.r_y; 138 case SparcTraceChild::CWP: 139 return (myregs.r_tstate >> 0) & ((1 << 5) - 1); 140 case SparcTraceChild::PSTATE: 141 return (myregs.r_tstate >> 8) & ((1 << 13) - 1); 142 case SparcTraceChild::ASI: 143 return (myregs.r_tstate >> 24) & ((1 << 8) - 1); 144 case SparcTraceChild::CCR: 145 return (myregs.r_tstate >> 32) & ((1 << 8) - 1); 146 default: 147 assert(0); 148 return 0; 149 } 150} 151 152bool SparcTraceChild::update(int pid) 153{ 154 static const int stackBias = 2047; 155 memcpy(&oldregs, &theregs, sizeof(regs)); 156 memcpy(&oldfpregs, &thefpregs, sizeof(fpu)); 157 memcpy(oldLocals, locals, 8 * sizeof(uint64_t)); 158 memcpy(oldInputs, inputs, 8 * sizeof(uint64_t)); 159 if(ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0) 160 { 161 cerr << "Update failed" << endl; 162 return false; 163 } 164 uint64_t StackPointer = getRegVal(O6); 165 for(unsigned int x = 0; x < 8; x++) 166 { 167 locals[x] = ptrace(PTRACE_PEEKTEXT, pid, 168 StackPointer + stackBias + x * 8, 0); 169 inputs[x] = ptrace(PTRACE_PEEKTEXT, pid, 170 StackPointer + stackBias + x * 8 + (8 * 8), 0); 171 } 172 if(ptrace(PTRACE_GETFPREGS, pid, &thefpregs, 0) != 0) 173 return false; 174 for(unsigned int x = 0; x < numregs; x++) 175 regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); 176 return true; 177} 178 179SparcTraceChild::SparcTraceChild() 180{ 181 for(unsigned int x = 0; x < numregs; x++) 182 regDiffSinceUpdate[x] = false; 183} 184 185bool SparcTraceChild::step() 186{ 187 //Two important considerations are that the address of the instruction 188 //being breakpointed should be word (64bit) aligned, and that both the 189 //next instruction and the instruction after that need to be breakpointed 190 //so that annulled branches will still stop as well. 191 192 /* 193 * Useful constants 194 */ 195 const static uint64_t breakInst = 0x91d02001; 196 const static uint64_t breakWord = breakInst | (breakInst << 32); 197 const static uint64_t lowMask = 0xFFFFFFFFULL; 198 const static uint64_t highMask = lowMask << 32; 199 200 /* 201 * storage for the original contents of the child process's memory 202 */ 203 uint64_t originalInst, originalAnnulInst; 204 205 /* 206 * Get information about where the process is and is headed next. 207 */ 208 uint64_t currentPC = getRegVal(PC); 209 bool unalignedPC = currentPC & 7; 210 uint64_t alignedPC = currentPC & (~7); 211 uint64_t nextPC = getRegVal(NPC); 212 bool unalignedNPC = nextPC & 7; 213 uint64_t alignedNPC = nextPC & (~7); 214 215 /* 216 * Store the original contents of the child process's memory 217 */ 218 originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC, 0); 219 //Save a ptrace call if we can 220 if(unalignedNPC) 221 { 222 originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC+8, 0); 223 } 224 225 /* 226 * Prepare breakpointed copies of child processes memory 227 */ 228 uint64_t newInst, newAnnulInst; 229 //If the current instruction is in the same word as the npc 230 if(alignedPC == alignedNPC) 231 { 232 //Make sure we only replace the other part 233 if(unalignedPC) 234 newInst = (originalInst & lowMask) | (breakWord & highMask); 235 else 236 newInst = (originalInst & highMask) | (breakWord & lowMask); 237 } 238 else 239 { 240 //otherwise replace the whole thing 241 newInst = breakWord; 242 } 243 //If the current instruction is in the same word as the word after 244 //the npc 245 if(alignedPC == alignedNPC+8) 246 { 247 //Make sure we only replace the other part 248 if(unalignedPC) 249 newAnnulInst = (originalAnnulInst & lowMask) | (breakWord & highMask); 250 else 251 newAnnulInst = (originalAnnulInst & highMask) | (breakWord & lowMask); 252 } 253 else 254 { 255 //otherwise replace the whole thing 256 newAnnulInst = breakWord; 257 } 258 259 /* 260 * Stuff the breakpoint instructions into the child's address space. 261 */ 262 //Replace the word at npc 263 if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, newInst) != 0) 264 cerr << "Poke failed" << endl; 265 //Replace the next word, if necessary 266 if(unalignedNPC) 267 { 268 if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, newAnnulInst) != 0) 269 cerr << "Poke failed" << endl; 270 } 271 272 /* 273 * Restart the child process 274 */ 275 //Note that the "addr" parameter is supposed to be ignored, but in at 276 //least one version of the kernel, it must be 1 or it will set what 277 //pc to continue from 278 if(ptrace(PTRACE_CONT, pid, 1, 0) != 0) 279 cerr << "Cont failed" << endl; 280 doWait(); 281 282 /* 283 * Update our record of the child's state 284 */ 285 update(pid); 286 287 /* 288 * Put back the original contents of the childs address space 289 */ 290 if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, originalInst) != 0) 291 cerr << "Repoke failed" << endl; 292 if(unalignedNPC) 293 { 294 if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, originalAnnulInst) != 0) 295 cerr << "Repoke failed" << endl; 296 } 297 return true; 298} 299 300int64_t SparcTraceChild::getRegVal(int num) 301{ 302 return getRegs(theregs, thefpregs, locals, inputs, num); 303} 304 305int64_t SparcTraceChild::getOldRegVal(int num) 306{ 307 return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num); 308} 309 310char * SparcTraceChild::printReg(int num) 311{ 312 sprintf(printBuffer, "0x%016llx", getRegVal(num)); 313 return printBuffer; 314} 315 316ostream & SparcTraceChild::outputStartState(ostream & os) 317{ 318 uint64_t sp = getSP(); 319 uint64_t pc = getPC(); 320 char obuf[1024]; 321 sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp); 322 os << obuf; 323 sprintf(obuf, "Initial program counter = 0x%016llx\n", pc); 324 os << obuf; 325 //Take out the stack bias 326 sp += 2047; 327 //Output the window save area 328 for(unsigned int x = 0; x < 16; x++) 329 { 330 uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 331 sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n", 332 sp, x+1, regspot); 333 os << obuf; 334 sp += 8; 335 } 336 //Output the argument count 337 uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 338 sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc); 339 os << obuf; 340 sp += 8; 341 //Output argv pointers 342 int argCount = 0; 343 uint64_t cargv; 344 do 345 { 346 cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 347 sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n", 348 sp, argCount++, cargv); 349 os << obuf; 350 sp += 8; 351 } while(cargv); 352 //Output the envp pointers 353 int envCount = 0; 354 uint64_t cenvp; 355 do 356 { 357 cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 358 sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n", 359 sp, envCount++, cenvp); 360 os << obuf; 361 sp += 8; 362 } while(cenvp); 363 uint64_t auxType, auxVal; 364 do 365 { 366 auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 367 sp += 8; 368 auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 369 sp += 8; 370 sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n", 371 sp - 16, auxType, auxVal); 372 os << obuf; 373 } while(auxType != 0 || auxVal != 0); 374 //Print out the argument strings, environment strings, and file name. 375 string current; 376 uint64_t buf; 377 uint64_t currentStart = sp; 378 bool clearedInitialPadding = false; 379 do 380 { 381 buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); 382 char * cbuf = (char *)&buf; 383 for(int x = 0; x < sizeof(uint64_t); x++) 384 { 385 if(cbuf[x]) 386 current += cbuf[x]; 387 else 388 { 389 sprintf(obuf, "0x%016llx: \"%s\"\n", 390 currentStart, current.c_str()); 391 os << obuf; 392 current = ""; 393 currentStart = sp + x + 1; 394 } 395 } 396 sp += 8; 397 clearedInitialPadding = clearedInitialPadding || buf != 0; 398 } while(!clearedInitialPadding || buf != 0); 399 return os; 400} 401 402TraceChild * genTraceChild() 403{ 404 return new SparcTraceChild; 405} 406 407