47bd6aa17070acee7b63507c0d747561bc0cc843
2 * Copyright (c) 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.
34 #include <sys/ptrace.h>
38 #include "tracechild_amd64.hh"
42 const char * AMD64TraceChild::regNames
[numregs
] = {
44 "rax", "rbx", "rcx", "rdx",
47 //Base pointer and stack pointer
49 //New 64 bit mode registers
50 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
51 //Segmentation registers
52 "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base",
58 "mmx0_0", "mmx0_1", "mmx1_0", "mmx1_1",
59 "mmx2_0", "mmx2_1", "mmx3_0", "mmx3_1",
60 "mmx4_0", "mmx4_1", "mmx5_0", "mmx5_1",
61 "mmx6_0", "mmx6_1", "mmx7_0", "mmx7_1",
63 "xmm0_0", "xmm0_1", "xmm0_2", "xmm0_3",
64 "xmm1_0", "xmm1_1", "xmm1_2", "xmm1_3",
65 "xmm2_0", "xmm2_1", "xmm2_2", "xmm2_3",
66 "xmm3_0", "xmm3_1", "xmm3_2", "xmm3_3",
67 "xmm4_0", "xmm4_1", "xmm4_2", "xmm4_3",
68 "xmm5_0", "xmm5_1", "xmm5_2", "xmm5_3",
69 "xmm6_0", "xmm6_1", "xmm6_2", "xmm6_3",
70 "xmm7_0", "xmm7_1", "xmm7_2", "xmm7_3",
71 "xmm8_0", "xmm8_1", "xmm8_2", "xmm8_3",
72 "xmm9_0", "xmm9_1", "xmm9_2", "xmm9_3",
73 "xmm10_0", "xmm10_1", "xmm10_2", "xmm10_3",
74 "xmm11_0", "xmm11_1", "xmm11_2", "xmm11_3",
75 "xmm12_0", "xmm12_1", "xmm12_2", "xmm12_3",
76 "xmm13_0", "xmm13_1", "xmm13_2", "xmm13_3",
77 "xmm14_0", "xmm14_1", "xmm14_2", "xmm14_3",
78 "xmm15_0", "xmm15_1", "xmm15_2", "xmm15_3"};
81 AMD64TraceChild::sendState(int socket
)
83 uint64_t regVal64
= 0;
84 uint32_t regVal32
= 0;
85 for (int x
= 0; x
<= R15
; x
++) {
86 regVal64
= getRegVal(x
);
87 if (write(socket
, ®Val64
, sizeof(regVal64
)) == -1) {
88 cerr
<< "Write failed! " << strerror(errno
) << endl
;
93 regVal64
= getRegVal(RIP
);
94 if (write(socket
, ®Val64
, sizeof(regVal64
)) == -1) {
95 cerr
<< "Write failed! " << strerror(errno
) << endl
;
99 for (int x
= MMX0_0
; x
<= MMX7_1
; x
++) {
100 regVal32
= getRegVal(x
);
101 if (write(socket
, ®Val32
, sizeof(regVal32
)) == -1) {
102 cerr
<< "Write failed! " << strerror(errno
) << endl
;
107 for (int x
= XMM0_0
; x
<= XMM15_3
; x
++) {
108 regVal32
= getRegVal(x
);
109 if (write(socket
, ®Val32
, sizeof(regVal32
)) == -1) {
110 cerr
<< "Write failed! " << strerror(errno
) << endl
;
119 AMD64TraceChild::getRegs(user_regs_struct
& myregs
,
120 user_fpregs_struct
& myfpregs
, int num
)
122 assert(num
< numregs
&& num
>= 0);
125 case RAX
: return myregs
.rax
;
126 case RBX
: return myregs
.rbx
;
127 case RCX
: return myregs
.rcx
;
128 case RDX
: return myregs
.rdx
;
130 case RSI
: return myregs
.rsi
;
131 case RDI
: return myregs
.rdi
;
132 //Base pointer and stack pointer
133 case RBP
: return myregs
.rbp
;
134 case RSP
: return myregs
.rsp
;
135 //New 64 bit mode registers
136 case R8
: return myregs
.r8
;
137 case R9
: return myregs
.r9
;
138 case R10
: return myregs
.r10
;
139 case R11
: return myregs
.r11
;
140 case R12
: return myregs
.r12
;
141 case R13
: return myregs
.r13
;
142 case R14
: return myregs
.r14
;
143 case R15
: return myregs
.r15
;
144 //Segmentation registers
145 case CS
: return myregs
.cs
;
146 case DS
: return myregs
.ds
;
147 case ES
: return myregs
.es
;
148 case FS
: return myregs
.fs
;
149 case GS
: return myregs
.gs
;
150 case SS
: return myregs
.ss
;
151 case FS_BASE
: return myregs
.fs_base
;
152 case GS_BASE
: return myregs
.gs_base
;
154 case RIP
: return myregs
.rip
;
156 case EFLAGS
: return myregs
.eflags
;
158 case MMX0_0
: return myfpregs
.st_space
[0];
159 case MMX0_1
: return myfpregs
.st_space
[1];
160 case MMX1_0
: return myfpregs
.st_space
[2];
161 case MMX1_1
: return myfpregs
.st_space
[3];
162 case MMX2_0
: return myfpregs
.st_space
[4];
163 case MMX2_1
: return myfpregs
.st_space
[5];
164 case MMX3_0
: return myfpregs
.st_space
[6];
165 case MMX3_1
: return myfpregs
.st_space
[7];
166 case MMX4_0
: return myfpregs
.st_space
[8];
167 case MMX4_1
: return myfpregs
.st_space
[9];
168 case MMX5_0
: return myfpregs
.st_space
[10];
169 case MMX5_1
: return myfpregs
.st_space
[11];
170 case MMX6_0
: return myfpregs
.st_space
[12];
171 case MMX6_1
: return myfpregs
.st_space
[13];
172 case MMX7_0
: return myfpregs
.st_space
[14];
173 case MMX7_1
: return myfpregs
.st_space
[15];
175 case XMM0_0
: return myfpregs
.xmm_space
[0];
176 case XMM0_1
: return myfpregs
.xmm_space
[1];
177 case XMM0_2
: return myfpregs
.xmm_space
[2];
178 case XMM0_3
: return myfpregs
.xmm_space
[3];
179 case XMM1_0
: return myfpregs
.xmm_space
[4];
180 case XMM1_1
: return myfpregs
.xmm_space
[5];
181 case XMM1_2
: return myfpregs
.xmm_space
[6];
182 case XMM1_3
: return myfpregs
.xmm_space
[7];
183 case XMM2_0
: return myfpregs
.xmm_space
[8];
184 case XMM2_1
: return myfpregs
.xmm_space
[9];
185 case XMM2_2
: return myfpregs
.xmm_space
[10];
186 case XMM2_3
: return myfpregs
.xmm_space
[11];
187 case XMM3_0
: return myfpregs
.xmm_space
[12];
188 case XMM3_1
: return myfpregs
.xmm_space
[13];
189 case XMM3_2
: return myfpregs
.xmm_space
[14];
190 case XMM3_3
: return myfpregs
.xmm_space
[15];
191 case XMM4_0
: return myfpregs
.xmm_space
[16];
192 case XMM4_1
: return myfpregs
.xmm_space
[17];
193 case XMM4_2
: return myfpregs
.xmm_space
[18];
194 case XMM4_3
: return myfpregs
.xmm_space
[19];
195 case XMM5_0
: return myfpregs
.xmm_space
[20];
196 case XMM5_1
: return myfpregs
.xmm_space
[21];
197 case XMM5_2
: return myfpregs
.xmm_space
[22];
198 case XMM5_3
: return myfpregs
.xmm_space
[23];
199 case XMM6_0
: return myfpregs
.xmm_space
[24];
200 case XMM6_1
: return myfpregs
.xmm_space
[25];
201 case XMM6_2
: return myfpregs
.xmm_space
[26];
202 case XMM6_3
: return myfpregs
.xmm_space
[27];
203 case XMM7_0
: return myfpregs
.xmm_space
[28];
204 case XMM7_1
: return myfpregs
.xmm_space
[29];
205 case XMM7_2
: return myfpregs
.xmm_space
[30];
206 case XMM7_3
: return myfpregs
.xmm_space
[31];
207 case XMM8_0
: return myfpregs
.xmm_space
[32];
208 case XMM8_1
: return myfpregs
.xmm_space
[33];
209 case XMM8_2
: return myfpregs
.xmm_space
[34];
210 case XMM8_3
: return myfpregs
.xmm_space
[35];
211 case XMM9_0
: return myfpregs
.xmm_space
[36];
212 case XMM9_1
: return myfpregs
.xmm_space
[37];
213 case XMM9_2
: return myfpregs
.xmm_space
[38];
214 case XMM9_3
: return myfpregs
.xmm_space
[39];
215 case XMM10_0
: return myfpregs
.xmm_space
[40];
216 case XMM10_1
: return myfpregs
.xmm_space
[41];
217 case XMM10_2
: return myfpregs
.xmm_space
[42];
218 case XMM10_3
: return myfpregs
.xmm_space
[43];
219 case XMM11_0
: return myfpregs
.xmm_space
[44];
220 case XMM11_1
: return myfpregs
.xmm_space
[45];
221 case XMM11_2
: return myfpregs
.xmm_space
[46];
222 case XMM11_3
: return myfpregs
.xmm_space
[47];
223 case XMM12_0
: return myfpregs
.xmm_space
[48];
224 case XMM12_1
: return myfpregs
.xmm_space
[49];
225 case XMM12_2
: return myfpregs
.xmm_space
[50];
226 case XMM12_3
: return myfpregs
.xmm_space
[51];
227 case XMM13_0
: return myfpregs
.xmm_space
[52];
228 case XMM13_1
: return myfpregs
.xmm_space
[53];
229 case XMM13_2
: return myfpregs
.xmm_space
[54];
230 case XMM13_3
: return myfpregs
.xmm_space
[55];
231 case XMM14_0
: return myfpregs
.xmm_space
[56];
232 case XMM14_1
: return myfpregs
.xmm_space
[57];
233 case XMM14_2
: return myfpregs
.xmm_space
[58];
234 case XMM14_3
: return myfpregs
.xmm_space
[59];
235 case XMM15_0
: return myfpregs
.xmm_space
[60];
236 case XMM15_1
: return myfpregs
.xmm_space
[61];
237 case XMM15_2
: return myfpregs
.xmm_space
[62];
238 case XMM15_3
: return myfpregs
.xmm_space
[63];
246 AMD64TraceChild::update(int pid
)
250 if (ptrace(PTRACE_GETREGS
, pid
, 0, ®s
) != 0) {
251 cerr
<< "update: " << strerror(errno
) << endl
;
254 if (ptrace(PTRACE_GETFPREGS
, pid
, 0, &fpregs
) != 0) {
255 cerr
<< "update: " << strerror(errno
) << endl
;
258 for (unsigned int x
= 0; x
< numregs
; x
++)
259 regDiffSinceUpdate
[x
] = (getRegVal(x
) != getOldRegVal(x
));
263 AMD64TraceChild::AMD64TraceChild()
265 for (unsigned int x
= 0; x
< numregs
; x
++)
266 regDiffSinceUpdate
[x
] = false;
270 AMD64TraceChild::getRegVal(int num
)
272 return getRegs(regs
, fpregs
, num
);
276 AMD64TraceChild::getOldRegVal(int num
)
278 return getRegs(oldregs
, oldfpregs
, num
);
282 AMD64TraceChild::printReg(int num
)
284 sprintf(printBuffer
, "0x%016lX", getRegVal(num
));
289 AMD64TraceChild::outputStartState(ostream
& os
)
291 uint64_t sp
= getSP();
292 uint64_t pc
= getPC();
293 uint64_t highestInfo
= 0;
295 sprintf(obuf
, "Initial stack pointer = 0x%016lx\n", sp
);
297 sprintf(obuf
, "Initial program counter = 0x%016lx\n", pc
);
300 //Output the argument count
301 uint64_t cargc
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
302 sprintf(obuf
, "0x%016lx: Argc = 0x%016lx\n", sp
, cargc
);
306 //Output argv pointers
310 cargv
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
311 sprintf(obuf
, "0x%016lx: argv[%d] = 0x%016lx\n",
312 sp
, argCount
++, cargv
);
314 if (highestInfo
< cargv
)
320 //Output the envp pointers
324 cenvp
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
325 sprintf(obuf
, "0x%016lx: envp[%d] = 0x%016lx\n",
326 sp
, envCount
++, cenvp
);
330 uint64_t auxType
, auxVal
;
332 auxType
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
334 auxVal
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
336 sprintf(obuf
, "0x%016lx: Auxiliary vector = {0x%016lx, 0x%016lx}\n",
337 sp
- 16, auxType
, auxVal
);
339 } while(auxType
!= 0 || auxVal
!= 0);
340 //Print out the argument strings, environment strings, and file name.
343 uint64_t currentStart
= sp
;
344 bool clearedInitialPadding
= false;
346 buf
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
347 char * cbuf
= (char *)&buf
;
348 for (int x
= 0; x
< sizeof(uint64_t); x
++) {
352 sprintf(obuf
, "0x%016lx: \"%s\"\n",
353 currentStart
, current
.c_str());
356 currentStart
= sp
+ x
+ 1;
360 clearedInitialPadding
= clearedInitialPadding
|| buf
!= 0;
361 } while (!clearedInitialPadding
|| buf
!= 0 || sp
<= highestInfo
);
366 AMD64TraceChild::findSyscall()
368 uint64_t rip
= getPC();
369 bool foundOpcode
= false;
370 bool twoByteOpcode
= false;
372 uint64_t buf
= ptrace(PTRACE_PEEKDATA
, pid
, rip
, 0);
373 for (int i
= 0; i
< sizeof(uint64_t); i
++) {
374 unsigned char byte
= buf
& 0xFF;
376 if(!(byte
== 0x66 || //operand override
377 byte
== 0x67 || //address override
384 byte
== 0xF0 || //lock
385 byte
== 0xF2 || //repe
386 byte
== 0xF3 || //repne
387 (byte
>= 0x40 && byte
<= 0x4F) // REX
394 //SYSCALL or SYSENTER
395 if (byte
== 0x05 || byte
== 0x34)
400 if (!twoByteOpcode
) {
401 if (byte
== 0xCC) // INT3
403 else if (byte
== 0xCD) // INT with byte immediate
405 else if (byte
== 0x0F) // two byte opcode prefix
406 twoByteOpcode
= true;
418 AMD64TraceChild::step()
420 uint64_t ripAfterSyscall
= findSyscall();
421 if (ripAfterSyscall
) {
422 //Get the original contents of memory
423 uint64_t buf
= ptrace(PTRACE_PEEKDATA
, pid
, ripAfterSyscall
, 0);
424 //Patch the first two bytes of the memory immediately after this with
425 //jmp -2. Either single stepping will take over before this
426 //instruction, leaving the rip where it should be, or it will take
427 //over after this instruction, -still- leaving the rip where it should
429 uint64_t newBuf
= (buf
& ~0xFFFF) | 0xFEEB;
430 //Write the patched memory to the processes address space
431 ptrace(PTRACE_POKEDATA
, pid
, ripAfterSyscall
, newBuf
);
434 //Put things back to the way they started
435 ptrace(PTRACE_POKEDATA
, pid
, ripAfterSyscall
, buf
);
437 //Get all the way past repe and repne string instructions in one shot.
438 uint64_t newPC
, origPC
= getPC();
442 } while(newPC
== origPC
);
446 TraceChild
* genTraceChild()
448 return new AMD64TraceChild
;