Fixed up exetrace.cc to deal with microcode, and to made floating point register...
[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 const static uint64_t breakInst = 0x91d02001;
192 const static uint64_t breakWord = breakInst | (breakInst << 32);
193 const static uint64_t lowMask = (uint64_t)(0xFFFFFFFF);
194 const static uint64_t highMask = lowMask << 32;
195 uint64_t originalInst, originalAnnulInst;
196 uint64_t nextPC = getRegVal(NPC);
197 bool unaligned = nextPC & 7;
198 uint64_t alignedPC = nextPC & (~7);
199 originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC, 0);
200 if(unaligned)
201 {
202 originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC+8, 0);
203 }
204 uint64_t newInst;
205 if(unaligned)
206 {
207 newInst = (originalInst & highMask) | (breakInst << 0);
208 if(ptrace(PTRACE_POKETEXT, pid, alignedPC, newInst) != 0)
209 cerr << "Poke failed" << endl;
210 newInst = (originalAnnulInst & lowMask) | (breakInst << 32);
211 if(ptrace(PTRACE_POKETEXT, pid, alignedPC+8, newInst) != 0)
212 cerr << "Poke failed" << endl;
213 }
214 else
215 {
216 if(ptrace(PTRACE_POKETEXT, pid, alignedPC, breakWord) != 0)
217 cerr << "Poke failed" << endl;
218 }
219 //Note that the "addr" parameter is supposed to be ignored, but in at
220 //least one version of the kernel, it must be 1 or it will set what
221 //pc to continue from
222 if(ptrace(PTRACE_CONT, pid, /*nextPC - 4*/ 1, 0) != 0)
223 cerr << "Cont failed" << endl;
224 doWait();
225 update(pid);
226 if(ptrace(PTRACE_POKETEXT, pid, alignedPC, originalInst) != 0)
227 cerr << "Repoke failed" << endl;
228 if(unaligned)
229 {
230 if(ptrace(PTRACE_POKETEXT, pid, alignedPC+8, originalAnnulInst) != 0)
231 cerr << "Repoke failed" << endl;
232 }
233 return true;
234 }
235
236 int64_t SparcTraceChild::getRegVal(int num)
237 {
238 return getRegs(theregs, thefpregs, locals, inputs, num);
239 }
240
241 int64_t SparcTraceChild::getOldRegVal(int num)
242 {
243 return getRegs(oldregs, oldfpregs, oldLocals, oldInputs, num);
244 }
245
246 char * SparcTraceChild::printReg(int num)
247 {
248 sprintf(printBuffer, "0x%016llx", getRegVal(num));
249 return printBuffer;
250 }
251
252 ostream & SparcTraceChild::outputStartState(ostream & os)
253 {
254 uint64_t sp = getSP();
255 uint64_t pc = getPC();
256 char obuf[1024];
257 sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
258 os << obuf;
259 sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
260 os << obuf;
261 //Take out the stack bias
262 sp += 2047;
263 //Output the window save area
264 for(unsigned int x = 0; x < 16; x++)
265 {
266 uint64_t regspot = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
267 sprintf(obuf, "0x%016llx: Window save %d = 0x%016llx\n",
268 sp, x+1, regspot);
269 os << obuf;
270 sp += 8;
271 }
272 //Output the argument count
273 uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
274 sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
275 os << obuf;
276 sp += 8;
277 //Output argv pointers
278 int argCount = 0;
279 uint64_t cargv;
280 do
281 {
282 cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
283 sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
284 sp, argCount++, cargv);
285 os << obuf;
286 sp += 8;
287 } while(cargv);
288 //Output the envp pointers
289 int envCount = 0;
290 uint64_t cenvp;
291 do
292 {
293 cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
294 sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
295 sp, envCount++, cenvp);
296 os << obuf;
297 sp += 8;
298 } while(cenvp);
299 uint64_t auxType, auxVal;
300 do
301 {
302 auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
303 sp += 8;
304 auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
305 sp += 8;
306 sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
307 sp - 16, auxType, auxVal);
308 os << obuf;
309 } while(auxType != 0 || auxVal != 0);
310 //Print out the argument strings, environment strings, and file name.
311 string current;
312 uint64_t buf;
313 uint64_t currentStart = sp;
314 bool clearedInitialPadding = false;
315 do
316 {
317 buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
318 char * cbuf = (char *)&buf;
319 for(int x = 0; x < sizeof(uint64_t); x++)
320 {
321 if(cbuf[x])
322 current += cbuf[x];
323 else
324 {
325 sprintf(obuf, "0x%016llx: \"%s\"\n",
326 currentStart, current.c_str());
327 os << obuf;
328 current = "";
329 currentStart = sp + x + 1;
330 }
331 }
332 sp += 8;
333 clearedInitialPadding = clearedInitialPadding || buf != 0;
334 } while(!clearedInitialPadding || buf != 0);
335 return os;
336 }
337
338 TraceChild * genTraceChild()
339 {
340 return new SparcTraceChild;
341 }
342