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