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