2 * Copyright (c) 2006-2007 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.
29 #include <sys/ptrace.h>
35 #include "arch/sparc/tracechild.hh"
40 SparcTraceChild::sendState(int socket
)
43 for (int x
= 0; x
<= I7
; x
++) {
44 regVal
= getRegVal(x
);
45 if (write(socket
, ®Val
, sizeof(regVal
)) == -1) {
46 cerr
<< "Write failed! " << strerror(errno
) << endl
;
51 regVal
= getRegVal(PC
);
52 if (write(socket
, ®Val
, sizeof(regVal
)) == -1) {
53 cerr
<< "Write failed! " << strerror(errno
) << endl
;
57 regVal
= getRegVal(NPC
);
58 if (write(socket
, ®Val
, sizeof(regVal
)) == -1) {
59 cerr
<< "Write failed! " << strerror(errno
) << endl
;
63 regVal
= getRegVal(CCR
);
64 if (write(socket
, ®Val
, sizeof(regVal
)) == -1) {
65 cerr
<< "Write failed! " << strerror(errno
) << endl
;
73 getRegs(regs
& myregs
, fpu
& myfpu
, uint64_t * locals
,
74 uint64_t * inputs
, int num
)
76 assert(num
< SparcTraceChild::numregs
&& num
>= 0);
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
;
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
;
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];
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];
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];
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);
168 SparcTraceChild::update(int pid
)
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
;
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;
191 if (ptrace(PTRACE_GETFPREGS
, pid
, &thefpregs
, 0) != 0)
193 for (unsigned int x
= 0; x
< numregs
; x
++)
194 regDiffSinceUpdate
[x
] = (getRegVal(x
) != getOldRegVal(x
));
198 SparcTraceChild::SparcTraceChild()
200 for (unsigned int x
= 0; x
< numregs
; x
++)
201 regDiffSinceUpdate
[x
] = false;
205 SparcTraceChild::getTargets(uint32_t inst
, uint64_t pc
, uint64_t npc
,
206 uint64_t &target1
, uint64_t &target2
)
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));
216 //Check if it's a ba...
217 bool ba
= (cond
== 0x8) &&
218 (sig
== 0x1 || sig
== 0x2 || sig
== 0x5 || sig
== 0x6);
220 bool bn
= (cond
== 0x0) &&
221 (sig
== 0x1 || sig
== 0x2 || sig
== 0x5 || sig
== 0x6);
223 bool bcc
= (cond
& 0x7) &&
224 (sig
== 0x1 || sig
== 0x2 || sig
== 0x3 || sig
== 0x5 || sig
== 0x6);
232 //This branches immediately to the effective address of the branch
233 //which we'll have to calculate.
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);
241 disp
= inst
& ((1 << 22) - 1);
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.
262 SparcTraceChild::step()
264 //Increment the count of the number of instructions executed
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.
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;
282 * storage for the original contents of the child process's memory
284 uint64_t originalInst
, originalAnnulInst
;
287 * Get information about where the process is and is headed next.
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);
296 //Get the current instruction
297 uint64_t curInst
= ptrace(PTRACE_PEEKTEXT
, pid
, alignedPC
);
298 curInst
= unalignedPC
? (curInst
& 0xffffffffULL
) : (curInst
>> 32);
301 int numTargets
= getTargets(curInst
, currentPC
, nextPC
, bp1
, bp2
);
302 assert(numTargets
== 1 || numTargets
== 2);
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
;
311 * Set the first breakpoint
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
;
320 * Set the second breakpoint if necessary
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
;
332 * Restart the child process
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
;
342 * Update our record of the child's state
347 * Put back the original contents of the childs address space in the
350 if (numTargets
== 2) {
351 if (ptrace(PTRACE_POKETEXT
, pid
, alignedBp2
, origBp2
) != 0)
352 cerr
<< "Poke failed" << endl
;
354 if (ptrace(PTRACE_POKETEXT
, pid
, alignedBp1
, origBp1
) != 0)
355 cerr
<< "Poke failed" << endl
;
359 SparcTraceChild::getRegVal(int num
)
361 return getRegs(theregs
, thefpregs
, locals
, inputs
, num
);
365 SparcTraceChild::getOldRegVal(int num
)
367 return getRegs(oldregs
, oldfpregs
, oldLocals
, oldInputs
, num
);
371 SparcTraceChild::outputStartState(ostream
& os
)
374 uint64_t sp
= getSP();
376 os
<< "Detected a 64 bit executable.\n";
379 os
<< "Detected a 32 bit executable.\n";
382 uint64_t pc
= getPC();
384 sprintf(obuf
, "Initial stack pointer = 0x%016llx\n", sp
);
386 sprintf(obuf
, "Initial program counter = 0x%016llx\n", pc
);
389 //Take out the stack bias
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",
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
);
407 //Output argv pointers
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
);
418 //Output the envp pointers
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
);
429 uint64_t auxType
, auxVal
;
431 auxType
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
432 if (v8
) auxType
= auxType
>> 32;
434 auxVal
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
435 if (v8
) auxVal
= auxVal
>> 32;
437 sprintf(obuf
, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
438 sp
- 8, auxType
, auxVal
);
440 } while (auxType
!= 0 || auxVal
!= 0);
441 //Print out the argument strings, environment strings, and file name.
444 uint64_t currentStart
= sp
;
445 bool clearedInitialPadding
= false;
447 buf
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
448 char * cbuf
= (char *)&buf
;
449 for (int x
= 0; x
< sizeof(uint32_t); x
++) {
453 sprintf(obuf
, "0x%016llx: \"%s\"\n",
454 currentStart
, current
.c_str());
457 currentStart
= sp
+ x
+ 1;
461 clearedInitialPadding
= clearedInitialPadding
|| buf
!= 0;
462 } while (!clearedInitialPadding
|| buf
!= 0);
469 return new SparcTraceChild
;