Fixing statetrace to work with 32 bit SPARC processes, as well as rewritting it's...
[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 int64_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
152 bool SparcTraceChild::update(int pid)
153 {
154 memcpy(&oldregs, &theregs, sizeof(regs));
155 memcpy(&oldfpregs, &thefpregs, sizeof(fpu));
156 memcpy(oldLocals, locals, 8 * sizeof(uint64_t));
157 memcpy(oldInputs, inputs, 8 * sizeof(uint64_t));
158 if(ptrace(PTRACE_GETREGS, pid, &theregs, 0) != 0)
159 {
160 cerr << "Update failed" << endl;
161 return false;
162 }
163 uint64_t StackPointer = getSP();
164 const int stackBias = (StackPointer % 1) ? 2047 : 0;
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
179 SparcTraceChild::SparcTraceChild()
180 {
181 for(unsigned int x = 0; x < numregs; x++)
182 regDiffSinceUpdate[x] = false;
183 }
184
185 int SparcTraceChild::getTargets(uint32_t inst, uint64_t pc, uint64_t npc,
186 uint64_t &target1, uint64_t &target2)
187 {
188 //We can identify the instruction categories we care about using the top
189 //10 bits of the instruction, excluding the annul bit in the 3rd most
190 //significant bit position and the condition field. We'll call these
191 //bits the "sig" for signature.
192 uint32_t sig = (inst >> 22) & 0x307;
193 uint32_t cond = (inst >> 25) & 0xf;
194 bool annul = (inst & (1 << 29));
195
196 //Check if it's a ba...
197 bool ba = (cond == 0x8) &&
198 (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
199 //or a bn...
200 bool bn = (cond == 0x0) &&
201 (sig == 0x1 || sig == 0x2 || sig == 0x5 || sig == 0x6);
202 //or a bcc
203 bool bcc = (cond & 0x7) &&
204 (sig == 0x1 || sig == 0x2 || sig == 0x3 || sig == 0x5 || sig == 0x6);
205
206 if(annul)
207 {
208 if(bcc)
209 {
210 target1 = npc;
211 target2 = npc + 4;
212 return 2;
213 }
214 else if(ba)
215 {
216 //This branches immediately to the effective address of the branch
217 //which we'll have to calculate.
218 uint64_t disp = 0;
219 int64_t extender = 0;
220 //Figure out how big the displacement field is, and grab the bits
221 if(sig == 0x1 || sig == 0x5)
222 {
223 disp = inst & ((1 << 19) - 1);
224 extender = 1 << 18;
225 }
226 else
227 {
228 disp = inst & ((1 << 22) - 1);
229 extender = 1 << 21;
230 }
231 //This does sign extension, believe it or not.
232 disp = (disp ^ extender) - extender;
233 //Multiply the displacement by 4. I'm assuming the compiler is
234 //smart enough to turn this into a shift.
235 disp *= 4;
236 target1 = pc + disp;
237 }
238 else if(bn)
239 target1 = npc + 4;
240 else
241 target1 = npc;
242 return 1;
243 }
244 else
245 {
246 target1 = npc;
247 return 1;
248 }
249 }
250
251 bool SparcTraceChild::step()
252 {
253 //Increment the count of the number of instructions executed
254 instructions++;
255 //Two important considerations are that the address of the instruction
256 //being breakpointed should be word (64bit) aligned, and that both the
257 //next instruction and the instruction after that need to be breakpointed
258 //so that annulled branches will still stop as well.
259
260 /*
261 * Useful constants
262 */
263 const static uint64_t breakInst = 0x91d02001;
264 const static uint64_t lowBreakInst = breakInst;
265 const static uint64_t highBreakInst = breakInst << 32;
266 const static uint64_t breakWord = breakInst | (breakInst << 32);
267 const static uint64_t lowMask = 0xFFFFFFFFULL;
268 const static uint64_t highMask = lowMask << 32;
269
270 /*
271 * storage for the original contents of the child process's memory
272 */
273 uint64_t originalInst, originalAnnulInst;
274
275 /*
276 * Get information about where the process is and is headed next.
277 */
278 uint64_t currentPC = getRegVal(PC);
279 bool unalignedPC = currentPC & 7;
280 uint64_t alignedPC = currentPC & (~7);
281 uint64_t nextPC = getRegVal(NPC);
282 bool unalignedNPC = nextPC & 7;
283 uint64_t alignedNPC = nextPC & (~7);
284
285 //Get the current instruction
286 uint64_t curInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC);
287 curInst = unalignedPC ? (curInst & 0xffffffffULL) : (curInst >> 32);
288
289 uint64_t bp1, bp2;
290 int numTargets = getTargets(curInst, currentPC, nextPC, bp1, bp2);
291 assert(numTargets == 1 || numTargets == 2);
292
293 bool unalignedBp1 = bp1 & 7;
294 uint64_t alignedBp1 = bp1 & (~7);
295 bool unalignedBp2 = bp2 & 7;
296 uint64_t alignedBp2 = bp2 & (~7);
297 uint64_t origBp1, origBp2;
298
299 /*
300 * Set the first breakpoint
301 */
302 origBp1 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp1, 0);
303 uint64_t newBp1 = origBp1;
304 newBp1 &= unalignedBp1 ? highMask : lowMask;
305 newBp1 |= unalignedBp1 ? lowBreakInst : highBreakInst;
306 if(ptrace(PTRACE_POKETEXT, pid, alignedBp1, newBp1) != 0)
307 cerr << "Poke failed" << endl;
308 /*
309 * Set the second breakpoint if necessary
310 */
311 if(numTargets == 2)
312 {
313 origBp2 = ptrace(PTRACE_PEEKTEXT, pid, alignedBp2, 0);
314 uint64_t newBp2 = origBp2;
315 newBp2 &= unalignedBp2 ? highMask : lowMask;
316 newBp2 |= unalignedBp2 ? lowBreakInst : highBreakInst;
317 if(ptrace(PTRACE_POKETEXT, pid, alignedBp2, newBp2) != 0)
318 cerr << "Poke failed" << endl;
319 }
320
321 /*
322 * Restart the child process
323 */
324 //Note that the "addr" parameter is supposed to be ignored, but in at
325 //least one version of the kernel, it must be 1 or it will set what
326 //pc to continue from
327 if(ptrace(PTRACE_CONT, pid, 1, 0) != 0)
328 cerr << "Cont failed" << endl;
329 doWait();
330
331 /*
332 * Update our record of the child's state
333 */
334 update(pid);
335
336 /*
337 * Put back the original contents of the childs address space in the
338 * reverse order.
339 */
340 if(numTargets == 2)
341 {
342 if(ptrace(PTRACE_POKETEXT, pid, alignedBp2, origBp2) != 0)
343 cerr << "Poke failed" << endl;
344 }
345 if(ptrace(PTRACE_POKETEXT, pid, alignedBp1, origBp1) != 0)
346 cerr << "Poke failed" << endl;
347 }
348
349 int64_t SparcTraceChild::getRegVal(int num)
350 {
351 return getRegs(theregs, thefpregs, locals, inputs, num);
352 }
353
354 int64_t SparcTraceChild::getOldRegVal(int num)
355 {
356 return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
357 }
358
359 char * SparcTraceChild::printReg(int num)
360 {
361 sprintf(printBuffer, "0x%016llx", getRegVal(num));
362 return printBuffer;
363 }
364
365 ostream & SparcTraceChild::outputStartState(ostream & os)
366 {
367 bool v8 = false;
368 uint64_t sp = getSP();
369 if(sp % 1)
370 {
371 os << "Detected a 64 bit executable.\n";
372 v8 = false;
373 }
374 else
375 {
376 os << "Detected a 32 bit executable.\n";
377 v8 = true;
378 }
379 uint64_t pc = getPC();
380 char obuf[1024];
381 sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
382 os << obuf;
383 sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
384 os << obuf;
385 if(!v8)
386 {
387 //Take out the stack bias
388 sp += 2047;
389 }
390 //Output the window save area
391 for(unsigned int x = 0; x < 16; x++)
392 {
393 uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
394 if(v8) regspot = regspot >> 32;
395 sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
396 sp, x+1, regspot);
397 os << obuf;
398 sp += v8 ? 4 : 8;
399 }
400 //Output the argument count
401 uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
402 if(v8) cargc = cargc >> 32;
403 sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
404 os << obuf;
405 sp += v8 ? 4 : 8;
406 //Output argv pointers
407 int argCount = 0;
408 uint64_t cargv;
409 do
410 {
411 cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
412 if(v8) cargv = cargv >> 32;
413 sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
414 sp, argCount++, cargv);
415 os << obuf;
416 sp += v8 ? 4 : 8;
417 } while(cargv);
418 //Output the envp pointers
419 int envCount = 0;
420 uint64_t cenvp;
421 do
422 {
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 {
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 {
450 buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
451 char * cbuf = (char *)&buf;
452 for(int x = 0; x < sizeof(uint32_t); x++)
453 {
454 if(cbuf[x])
455 current += cbuf[x];
456 else
457 {
458 sprintf(obuf, "0x%016llx: \"%s\"\n",
459 currentStart, current.c_str());
460 os << obuf;
461 current = "";
462 currentStart = sp + x + 1;
463 }
464 }
465 sp += (v8 ? 4 : 8);
466 clearedInitialPadding = clearedInitialPadding || buf != 0;
467 } while(!clearedInitialPadding || buf != 0);
468 return os;
469 }
470
471 TraceChild * genTraceChild()
472 {
473 return new SparcTraceChild;
474 }
475