405c36cd7340fcb06bef1fea3670258737b080a7
[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
58 SparcTraceChild::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, &regVal, 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, &regVal, 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, &regVal, 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, &regVal, sizeof(regVal)) == -1) {
83 cerr << "Write failed! " << strerror(errno) << endl;
84 tracing = false;
85 return false;
86 }
87 return true;
88 }
89
90 int64_t
91 getRegs(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
185 bool
186 SparcTraceChild::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
216 SparcTraceChild::SparcTraceChild()
217 {
218 for (unsigned int x = 0; x < numregs; x++)
219 regDiffSinceUpdate[x] = false;
220 }
221
222 int
223 SparcTraceChild::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
279 bool
280 SparcTraceChild::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
376 int64_t
377 SparcTraceChild::getRegVal(int num)
378 {
379 return getRegs(theregs, thefpregs, locals, inputs, num);
380 }
381
382 int64_t
383 SparcTraceChild::getOldRegVal(int num)
384 {
385 return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
386 }
387
388 char *
389 SparcTraceChild::printReg(int num)
390 {
391 sprintf(printBuffer, "0x%016llx", getRegVal(num));
392 return printBuffer;
393 }
394
395 ostream &
396 SparcTraceChild::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
491 TraceChild *
492 genTraceChild()
493 {
494 return new SparcTraceChild;
495 }
496