2 * Copyright (c) 2006 The Regents of The University of Michigan
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.
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.
33 #include <sys/ptrace.h>
36 #include "tracechild_sparc.hh"
40 string
SparcTraceChild::regNames
[numregs
] = {
42 "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
44 "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
46 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
48 "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
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",
55 "fsr", "fprs", "pc", "npc", "y", "cwp", "pstate", "asi", "ccr"};
57 int64_t getRegs(regs
& myregs
, fpu
& myfpu
,
58 int64_t * locals
, int64_t * inputs
, int num
)
60 assert(num
< SparcTraceChild::numregs
&& num
>= 0);
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
;
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
;
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];
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];
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];
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);
152 bool SparcTraceChild::update(int pid
)
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)
161 cerr
<< "Update failed" << endl
;
164 uint64_t StackPointer
= getRegVal(O6
);
165 for(unsigned int x
= 0; x
< 8; x
++)
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);
172 if(ptrace(PTRACE_GETFPREGS
, pid
, &thefpregs
, 0) != 0)
174 for(unsigned int x
= 0; x
< numregs
; x
++)
175 regDiffSinceUpdate
[x
] = (getRegVal(x
) != getOldRegVal(x
));
179 SparcTraceChild::SparcTraceChild()
181 for(unsigned int x
= 0; x
< numregs
; x
++)
182 regDiffSinceUpdate
[x
] = false;
185 bool SparcTraceChild::step()
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.
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;
201 * storage for the original contents of the child process's memory
203 uint64_t originalInst
, originalAnnulInst
;
206 * Get information about where the process is and is headed next.
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);
216 * Store the original contents of the child process's memory
218 originalInst
= ptrace(PTRACE_PEEKTEXT
, pid
, alignedNPC
, 0);
219 //Save a ptrace call if we can
222 originalAnnulInst
= ptrace(PTRACE_PEEKTEXT
, pid
, alignedNPC
+8, 0);
226 * Prepare breakpointed copies of child processes memory
228 uint64_t newInst
, newAnnulInst
;
229 //If the current instruction is in the same word as the npc
230 if(alignedPC
== alignedNPC
)
232 //Make sure we only replace the other part
234 newInst
= (originalInst
& lowMask
) | (breakWord
& highMask
);
236 newInst
= (originalInst
& highMask
) | (breakWord
& lowMask
);
240 //otherwise replace the whole thing
243 //If the current instruction is in the same word as the word after
245 if(alignedPC
== alignedNPC
+8)
247 //Make sure we only replace the other part
249 newAnnulInst
= (originalAnnulInst
& lowMask
) | (breakWord
& highMask
);
251 newAnnulInst
= (originalAnnulInst
& highMask
) | (breakWord
& lowMask
);
255 //otherwise replace the whole thing
256 newAnnulInst
= breakWord
;
260 * Stuff the breakpoint instructions into the child's address space.
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
268 if(ptrace(PTRACE_POKETEXT
, pid
, alignedNPC
+8, newAnnulInst
) != 0)
269 cerr
<< "Poke failed" << endl
;
273 * Restart the child process
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
;
283 * Update our record of the child's state
288 * Put back the original contents of the childs address space
290 if(ptrace(PTRACE_POKETEXT
, pid
, alignedNPC
, originalInst
) != 0)
291 cerr
<< "Repoke failed" << endl
;
294 if(ptrace(PTRACE_POKETEXT
, pid
, alignedNPC
+8, originalAnnulInst
) != 0)
295 cerr
<< "Repoke failed" << endl
;
300 int64_t SparcTraceChild::getRegVal(int num
)
302 return getRegs(theregs
, thefpregs
, locals
, inputs
, num
);
305 int64_t SparcTraceChild::getOldRegVal(int num
)
307 return getRegs(oldregs
, oldfpregs
, oldLocals
, oldInputs
, num
);
310 char * SparcTraceChild::printReg(int num
)
312 sprintf(printBuffer
, "0x%016llx", getRegVal(num
));
316 ostream
& SparcTraceChild::outputStartState(ostream
& os
)
318 uint64_t sp
= getSP();
319 uint64_t pc
= getPC();
321 sprintf(obuf
, "Initial stack pointer = 0x%016llx\n", sp
);
323 sprintf(obuf
, "Initial program counter = 0x%016llx\n", pc
);
325 //Take out the stack bias
327 //Output the window save area
328 for(unsigned int x
= 0; x
< 16; x
++)
330 uint64_t regspot
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
331 sprintf(obuf
, "0x%016llx: Window save %d = 0x%016llx\n",
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
);
341 //Output argv pointers
346 cargv
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
347 sprintf(obuf
, "0x%016llx: argv[%d] = 0x%016llx\n",
348 sp
, argCount
++, cargv
);
352 //Output the envp pointers
357 cenvp
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
358 sprintf(obuf
, "0x%016llx: envp[%d] = 0x%016llx\n",
359 sp
, envCount
++, cenvp
);
363 uint64_t auxType
, auxVal
;
366 auxType
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
368 auxVal
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
370 sprintf(obuf
, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
371 sp
- 16, auxType
, auxVal
);
373 } while(auxType
!= 0 || auxVal
!= 0);
374 //Print out the argument strings, environment strings, and file name.
377 uint64_t currentStart
= sp
;
378 bool clearedInitialPadding
= false;
381 buf
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
382 char * cbuf
= (char *)&buf
;
383 for(int x
= 0; x
< sizeof(uint64_t); x
++)
389 sprintf(obuf
, "0x%016llx: \"%s\"\n",
390 currentStart
, current
.c_str());
393 currentStart
= sp
+ x
+ 1;
397 clearedInitialPadding
= clearedInitialPadding
|| buf
!= 0;
398 } while(!clearedInitialPadding
|| buf
!= 0);
402 TraceChild
* genTraceChild()
404 return new SparcTraceChild
;