Cleaned up the function a bit to help route out bugs.
[gem5.git] / util / statetrace / arch / tracechild_sparc.cc
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
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 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
179 SparcTraceChild::SparcTraceChild()
180 {
181 for(unsigned int x = 0; x < numregs; x++)
182 regDiffSinceUpdate[x] = false;
183 }
184
185 bool 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
300 int64_t SparcTraceChild::getRegVal(int num)
301 {
302 return getRegs(theregs, thefpregs, locals, inputs, num);
303 }
304
305 int64_t SparcTraceChild::getOldRegVal(int num)
306 {
307 return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
308 }
309
310 char * SparcTraceChild::printReg(int num)
311 {
312 sprintf(printBuffer, "0x%016llx", getRegVal(num));
313 return printBuffer;
314 }
315
316 ostream & 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
402 TraceChild * genTraceChild()
403 {
404 return new SparcTraceChild;
405 }
406