655c9dbfa0f663f480f46324ba64467c2a43f4cd
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",
67 "xmm0_0", "xmm0_1", "xmm0_2", "xmm0_3",
68 "xmm1_0", "xmm1_1", "xmm1_2", "xmm1_3",
69 "xmm2_0", "xmm2_1", "xmm2_2", "xmm2_3",
70 "xmm3_0", "xmm3_1", "xmm3_2", "xmm3_3",
71 "xmm4_0", "xmm4_1", "xmm4_2", "xmm4_3",
72 "xmm5_0", "xmm5_1", "xmm5_2", "xmm5_3",
73 "xmm6_0", "xmm6_1", "xmm6_2", "xmm6_3",
74 "xmm7_0", "xmm7_1", "xmm7_2", "xmm7_3",
75 "xmm8_0", "xmm8_1", "xmm8_2", "xmm8_3",
76 "xmm9_0", "xmm9_1", "xmm9_2", "xmm9_3",
77 "xmm10_0", "xmm10_1", "xmm10_2", "xmm10_3",
78 "xmm11_0", "xmm11_1", "xmm11_2", "xmm11_3",
79 "xmm12_0", "xmm12_1", "xmm12_2", "xmm12_3",
80 "xmm13_0", "xmm13_1", "xmm13_2", "xmm13_3",
81 "xmm14_0", "xmm14_1", "xmm14_2", "xmm14_3",
82 "xmm15_0", "xmm15_1", "xmm15_2", "xmm15_3"};
84 bool AMD64TraceChild::sendState(int socket
)
86 uint64_t regVal64
= 0;
87 uint32_t regVal32
= 0;
88 for(int x
= 0; x
<= R15
; x
++)
90 regVal64
= getRegVal(x
);
91 if(write(socket
, ®Val64
, sizeof(regVal64
)) == -1)
93 cerr
<< "Write failed! " << strerror(errno
) << endl
;
98 regVal64
= getRegVal(RIP
);
99 if(write(socket
, ®Val64
, sizeof(regVal64
)) == -1)
101 cerr
<< "Write failed! " << strerror(errno
) << endl
;
105 for(int x
= MMX0_0
; x
<= MMX7_1
; x
++)
107 regVal32
= getRegVal(x
);
108 if(write(socket
, ®Val32
, sizeof(regVal32
)) == -1)
110 cerr
<< "Write failed! " << strerror(errno
) << endl
;
115 for(int x
= XMM0_0
; x
<= XMM15_3
; x
++)
117 regVal32
= getRegVal(x
);
118 if(write(socket
, ®Val32
, sizeof(regVal32
)) == -1)
120 cerr
<< "Write failed! " << strerror(errno
) << endl
;
128 int64_t AMD64TraceChild::getRegs(user_regs_struct
& myregs
,
129 user_fpregs_struct
& myfpregs
, int num
)
131 assert(num
< numregs
&& num
>= 0);
135 case RAX
: return myregs
.rax
;
136 case RBX
: return myregs
.rbx
;
137 case RCX
: return myregs
.rcx
;
138 case RDX
: return myregs
.rdx
;
140 case RSI
: return myregs
.rsi
;
141 case RDI
: return myregs
.rdi
;
142 //Base pointer and stack pointer
143 case RBP
: return myregs
.rbp
;
144 case RSP
: return myregs
.rsp
;
145 //New 64 bit mode registers
146 case R8
: return myregs
.r8
;
147 case R9
: return myregs
.r9
;
148 case R10
: return myregs
.r10
;
149 case R11
: return myregs
.r11
;
150 case R12
: return myregs
.r12
;
151 case R13
: return myregs
.r13
;
152 case R14
: return myregs
.r14
;
153 case R15
: return myregs
.r15
;
154 //Segmentation registers
155 case CS
: return myregs
.cs
;
156 case DS
: return myregs
.ds
;
157 case ES
: return myregs
.es
;
158 case FS
: return myregs
.fs
;
159 case GS
: return myregs
.gs
;
160 case SS
: return myregs
.ss
;
161 case FS_BASE
: return myregs
.fs_base
;
162 case GS_BASE
: return myregs
.gs_base
;
164 case RIP
: return myregs
.rip
;
166 case EFLAGS
: return myregs
.eflags
;
168 case MMX0_0
: return myfpregs
.st_space
[0];
169 case MMX0_1
: return myfpregs
.st_space
[1];
170 case MMX1_0
: return myfpregs
.st_space
[2];
171 case MMX1_1
: return myfpregs
.st_space
[3];
172 case MMX2_0
: return myfpregs
.st_space
[4];
173 case MMX2_1
: return myfpregs
.st_space
[5];
174 case MMX3_0
: return myfpregs
.st_space
[6];
175 case MMX3_1
: return myfpregs
.st_space
[7];
176 case MMX4_0
: return myfpregs
.st_space
[8];
177 case MMX4_1
: return myfpregs
.st_space
[9];
178 case MMX5_0
: return myfpregs
.st_space
[10];
179 case MMX5_1
: return myfpregs
.st_space
[11];
180 case MMX6_0
: return myfpregs
.st_space
[12];
181 case MMX6_1
: return myfpregs
.st_space
[13];
182 case MMX7_0
: return myfpregs
.st_space
[14];
183 case MMX7_1
: return myfpregs
.st_space
[15];
185 case XMM0_0
: return myfpregs
.xmm_space
[0];
186 case XMM0_1
: return myfpregs
.xmm_space
[1];
187 case XMM0_2
: return myfpregs
.xmm_space
[2];
188 case XMM0_3
: return myfpregs
.xmm_space
[3];
189 case XMM1_0
: return myfpregs
.xmm_space
[4];
190 case XMM1_1
: return myfpregs
.xmm_space
[5];
191 case XMM1_2
: return myfpregs
.xmm_space
[6];
192 case XMM1_3
: return myfpregs
.xmm_space
[7];
193 case XMM2_0
: return myfpregs
.xmm_space
[8];
194 case XMM2_1
: return myfpregs
.xmm_space
[9];
195 case XMM2_2
: return myfpregs
.xmm_space
[10];
196 case XMM2_3
: return myfpregs
.xmm_space
[11];
197 case XMM3_0
: return myfpregs
.xmm_space
[12];
198 case XMM3_1
: return myfpregs
.xmm_space
[13];
199 case XMM3_2
: return myfpregs
.xmm_space
[14];
200 case XMM3_3
: return myfpregs
.xmm_space
[15];
201 case XMM4_0
: return myfpregs
.xmm_space
[16];
202 case XMM4_1
: return myfpregs
.xmm_space
[17];
203 case XMM4_2
: return myfpregs
.xmm_space
[18];
204 case XMM4_3
: return myfpregs
.xmm_space
[19];
205 case XMM5_0
: return myfpregs
.xmm_space
[20];
206 case XMM5_1
: return myfpregs
.xmm_space
[21];
207 case XMM5_2
: return myfpregs
.xmm_space
[22];
208 case XMM5_3
: return myfpregs
.xmm_space
[23];
209 case XMM6_0
: return myfpregs
.xmm_space
[24];
210 case XMM6_1
: return myfpregs
.xmm_space
[25];
211 case XMM6_2
: return myfpregs
.xmm_space
[26];
212 case XMM6_3
: return myfpregs
.xmm_space
[27];
213 case XMM7_0
: return myfpregs
.xmm_space
[28];
214 case XMM7_1
: return myfpregs
.xmm_space
[29];
215 case XMM7_2
: return myfpregs
.xmm_space
[30];
216 case XMM7_3
: return myfpregs
.xmm_space
[31];
217 case XMM8_0
: return myfpregs
.xmm_space
[32];
218 case XMM8_1
: return myfpregs
.xmm_space
[33];
219 case XMM8_2
: return myfpregs
.xmm_space
[34];
220 case XMM8_3
: return myfpregs
.xmm_space
[35];
221 case XMM9_0
: return myfpregs
.xmm_space
[36];
222 case XMM9_1
: return myfpregs
.xmm_space
[37];
223 case XMM9_2
: return myfpregs
.xmm_space
[38];
224 case XMM9_3
: return myfpregs
.xmm_space
[39];
225 case XMM10_0
: return myfpregs
.xmm_space
[40];
226 case XMM10_1
: return myfpregs
.xmm_space
[41];
227 case XMM10_2
: return myfpregs
.xmm_space
[42];
228 case XMM10_3
: return myfpregs
.xmm_space
[43];
229 case XMM11_0
: return myfpregs
.xmm_space
[44];
230 case XMM11_1
: return myfpregs
.xmm_space
[45];
231 case XMM11_2
: return myfpregs
.xmm_space
[46];
232 case XMM11_3
: return myfpregs
.xmm_space
[47];
233 case XMM12_0
: return myfpregs
.xmm_space
[48];
234 case XMM12_1
: return myfpregs
.xmm_space
[49];
235 case XMM12_2
: return myfpregs
.xmm_space
[50];
236 case XMM12_3
: return myfpregs
.xmm_space
[51];
237 case XMM13_0
: return myfpregs
.xmm_space
[52];
238 case XMM13_1
: return myfpregs
.xmm_space
[53];
239 case XMM13_2
: return myfpregs
.xmm_space
[54];
240 case XMM13_3
: return myfpregs
.xmm_space
[55];
241 case XMM14_0
: return myfpregs
.xmm_space
[56];
242 case XMM14_1
: return myfpregs
.xmm_space
[57];
243 case XMM14_2
: return myfpregs
.xmm_space
[58];
244 case XMM14_3
: return myfpregs
.xmm_space
[59];
245 case XMM15_0
: return myfpregs
.xmm_space
[60];
246 case XMM15_1
: return myfpregs
.xmm_space
[61];
247 case XMM15_2
: return myfpregs
.xmm_space
[62];
248 case XMM15_3
: return myfpregs
.xmm_space
[63];
255 bool AMD64TraceChild::update(int pid
)
259 if(ptrace(PTRACE_GETREGS
, pid
, 0, ®s
) != 0)
261 cerr
<< "update: " << strerror(errno
) << endl
;
264 if(ptrace(PTRACE_GETFPREGS
, pid
, 0, &fpregs
) != 0)
266 cerr
<< "update: " << strerror(errno
) << endl
;
269 for(unsigned int x
= 0; x
< numregs
; x
++)
270 regDiffSinceUpdate
[x
] = (getRegVal(x
) != getOldRegVal(x
));
274 AMD64TraceChild::AMD64TraceChild()
276 for(unsigned int x
= 0; x
< numregs
; x
++)
277 regDiffSinceUpdate
[x
] = false;
280 int64_t AMD64TraceChild::getRegVal(int num
)
282 return getRegs(regs
, fpregs
, num
);
285 int64_t AMD64TraceChild::getOldRegVal(int num
)
287 return getRegs(oldregs
, oldfpregs
, num
);
290 char * AMD64TraceChild::printReg(int num
)
292 sprintf(printBuffer
, "0x%016lX", getRegVal(num
));
296 ostream
& AMD64TraceChild::outputStartState(ostream
& os
)
298 uint64_t sp
= getSP();
299 uint64_t pc
= getPC();
300 uint64_t highestInfo
= 0;
302 sprintf(obuf
, "Initial stack pointer = 0x%016lx\n", sp
);
304 sprintf(obuf
, "Initial program counter = 0x%016lx\n", pc
);
307 //Output the argument count
308 uint64_t cargc
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
309 sprintf(obuf
, "0x%016lx: Argc = 0x%016lx\n", sp
, cargc
);
313 //Output argv pointers
318 cargv
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
319 sprintf(obuf
, "0x%016lx: argv[%d] = 0x%016lx\n",
320 sp
, argCount
++, cargv
);
322 if(highestInfo
< cargv
)
328 //Output the envp pointers
333 cenvp
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
334 sprintf(obuf
, "0x%016lx: envp[%d] = 0x%016lx\n",
335 sp
, envCount
++, cenvp
);
339 uint64_t auxType
, auxVal
;
342 auxType
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
344 auxVal
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
346 sprintf(obuf
, "0x%016lx: Auxiliary vector = {0x%016lx, 0x%016lx}\n",
347 sp
- 16, auxType
, auxVal
);
349 } while(auxType
!= 0 || auxVal
!= 0);
350 //Print out the argument strings, environment strings, and file name.
353 uint64_t currentStart
= sp
;
354 bool clearedInitialPadding
= false;
357 buf
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
358 char * cbuf
= (char *)&buf
;
359 for(int x
= 0; x
< sizeof(uint64_t); x
++)
365 sprintf(obuf
, "0x%016lx: \"%s\"\n",
366 currentStart
, current
.c_str());
369 currentStart
= sp
+ x
+ 1;
373 clearedInitialPadding
= clearedInitialPadding
|| buf
!= 0;
374 } while(!clearedInitialPadding
|| buf
!= 0 || sp
<= highestInfo
);
378 uint64_t AMD64TraceChild::findSyscall()
380 uint64_t rip
= getPC();
381 bool foundOpcode
= false;
382 bool twoByteOpcode
= false;
385 uint64_t buf
= ptrace(PTRACE_PEEKDATA
, pid
, rip
, 0);
386 for(int i
= 0; i
< sizeof(uint64_t); i
++)
388 unsigned char byte
= buf
& 0xFF;
391 if(!(byte
== 0x66 || //operand override
392 byte
== 0x67 || //address override
399 byte
== 0xF0 || //lock
400 byte
== 0xF2 || //repe
401 byte
== 0xF3 || //repne
402 (byte
>= 0x40 && byte
<= 0x4F) // REX
412 //SYSCALL or SYSENTER
413 if(byte
== 0x05 || byte
== 0x34)
420 if(byte
== 0xCC) // INT3
422 else if(byte
== 0xCD) // INT with byte immediate
424 else if(byte
== 0x0F) // two byte opcode prefix
425 twoByteOpcode
= true;
436 bool AMD64TraceChild::step()
438 uint64_t ripAfterSyscall
= findSyscall();
441 //Get the original contents of memory
442 uint64_t buf
= ptrace(PTRACE_PEEKDATA
, pid
, ripAfterSyscall
, 0);
443 //Patch the first two bytes of the memory immediately after this with
444 //jmp -2. Either single stepping will take over before this
445 //instruction, leaving the rip where it should be, or it will take
446 //over after this instruction, -still- leaving the rip where it should
448 uint64_t newBuf
= (buf
& ~0xFFFF) | 0xFEEB;
449 //Write the patched memory to the processes address space
450 ptrace(PTRACE_POKEDATA
, pid
, ripAfterSyscall
, newBuf
);
453 //Put things back to the way they started
454 ptrace(PTRACE_POKEDATA
, pid
, ripAfterSyscall
, buf
);
458 //Get all the way past repe and repne string instructions in one shot.
459 uint64_t newPC
, origPC
= getPC();
464 } while(newPC
== origPC
);
468 TraceChild
* genTraceChild()
470 return new AMD64TraceChild
;