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"
43 AMD64TraceChild::sendState(int socket
)
45 uint64_t regVal64
= 0;
46 uint32_t regVal32
= 0;
47 for (int x
= 0; x
<= R15
; x
++) {
48 regVal64
= getRegVal(x
);
49 if (write(socket
, ®Val64
, sizeof(regVal64
)) == -1) {
50 cerr
<< "Write failed! " << strerror(errno
) << endl
;
55 regVal64
= getRegVal(RIP
);
56 if (write(socket
, ®Val64
, sizeof(regVal64
)) == -1) {
57 cerr
<< "Write failed! " << strerror(errno
) << endl
;
61 for (int x
= MMX0_0
; x
<= MMX7_1
; x
++) {
62 regVal32
= getRegVal(x
);
63 if (write(socket
, ®Val32
, sizeof(regVal32
)) == -1) {
64 cerr
<< "Write failed! " << strerror(errno
) << endl
;
69 for (int x
= XMM0_0
; x
<= XMM15_3
; x
++) {
70 regVal32
= getRegVal(x
);
71 if (write(socket
, ®Val32
, sizeof(regVal32
)) == -1) {
72 cerr
<< "Write failed! " << strerror(errno
) << endl
;
81 AMD64TraceChild::getRegs(user_regs_struct
& myregs
,
82 user_fpregs_struct
& myfpregs
, int num
)
84 assert(num
< numregs
&& num
>= 0);
87 case RAX
: return myregs
.rax
;
88 case RBX
: return myregs
.rbx
;
89 case RCX
: return myregs
.rcx
;
90 case RDX
: return myregs
.rdx
;
92 case RSI
: return myregs
.rsi
;
93 case RDI
: return myregs
.rdi
;
94 //Base pointer and stack pointer
95 case RBP
: return myregs
.rbp
;
96 case RSP
: return myregs
.rsp
;
97 //New 64 bit mode registers
98 case R8
: return myregs
.r8
;
99 case R9
: return myregs
.r9
;
100 case R10
: return myregs
.r10
;
101 case R11
: return myregs
.r11
;
102 case R12
: return myregs
.r12
;
103 case R13
: return myregs
.r13
;
104 case R14
: return myregs
.r14
;
105 case R15
: return myregs
.r15
;
106 //Segmentation registers
107 case CS
: return myregs
.cs
;
108 case DS
: return myregs
.ds
;
109 case ES
: return myregs
.es
;
110 case FS
: return myregs
.fs
;
111 case GS
: return myregs
.gs
;
112 case SS
: return myregs
.ss
;
113 case FS_BASE
: return myregs
.fs_base
;
114 case GS_BASE
: return myregs
.gs_base
;
116 case RIP
: return myregs
.rip
;
118 case EFLAGS
: return myregs
.eflags
;
120 case MMX0_0
: return myfpregs
.st_space
[0];
121 case MMX0_1
: return myfpregs
.st_space
[1];
122 case MMX1_0
: return myfpregs
.st_space
[2];
123 case MMX1_1
: return myfpregs
.st_space
[3];
124 case MMX2_0
: return myfpregs
.st_space
[4];
125 case MMX2_1
: return myfpregs
.st_space
[5];
126 case MMX3_0
: return myfpregs
.st_space
[6];
127 case MMX3_1
: return myfpregs
.st_space
[7];
128 case MMX4_0
: return myfpregs
.st_space
[8];
129 case MMX4_1
: return myfpregs
.st_space
[9];
130 case MMX5_0
: return myfpregs
.st_space
[10];
131 case MMX5_1
: return myfpregs
.st_space
[11];
132 case MMX6_0
: return myfpregs
.st_space
[12];
133 case MMX6_1
: return myfpregs
.st_space
[13];
134 case MMX7_0
: return myfpregs
.st_space
[14];
135 case MMX7_1
: return myfpregs
.st_space
[15];
137 case XMM0_0
: return myfpregs
.xmm_space
[0];
138 case XMM0_1
: return myfpregs
.xmm_space
[1];
139 case XMM0_2
: return myfpregs
.xmm_space
[2];
140 case XMM0_3
: return myfpregs
.xmm_space
[3];
141 case XMM1_0
: return myfpregs
.xmm_space
[4];
142 case XMM1_1
: return myfpregs
.xmm_space
[5];
143 case XMM1_2
: return myfpregs
.xmm_space
[6];
144 case XMM1_3
: return myfpregs
.xmm_space
[7];
145 case XMM2_0
: return myfpregs
.xmm_space
[8];
146 case XMM2_1
: return myfpregs
.xmm_space
[9];
147 case XMM2_2
: return myfpregs
.xmm_space
[10];
148 case XMM2_3
: return myfpregs
.xmm_space
[11];
149 case XMM3_0
: return myfpregs
.xmm_space
[12];
150 case XMM3_1
: return myfpregs
.xmm_space
[13];
151 case XMM3_2
: return myfpregs
.xmm_space
[14];
152 case XMM3_3
: return myfpregs
.xmm_space
[15];
153 case XMM4_0
: return myfpregs
.xmm_space
[16];
154 case XMM4_1
: return myfpregs
.xmm_space
[17];
155 case XMM4_2
: return myfpregs
.xmm_space
[18];
156 case XMM4_3
: return myfpregs
.xmm_space
[19];
157 case XMM5_0
: return myfpregs
.xmm_space
[20];
158 case XMM5_1
: return myfpregs
.xmm_space
[21];
159 case XMM5_2
: return myfpregs
.xmm_space
[22];
160 case XMM5_3
: return myfpregs
.xmm_space
[23];
161 case XMM6_0
: return myfpregs
.xmm_space
[24];
162 case XMM6_1
: return myfpregs
.xmm_space
[25];
163 case XMM6_2
: return myfpregs
.xmm_space
[26];
164 case XMM6_3
: return myfpregs
.xmm_space
[27];
165 case XMM7_0
: return myfpregs
.xmm_space
[28];
166 case XMM7_1
: return myfpregs
.xmm_space
[29];
167 case XMM7_2
: return myfpregs
.xmm_space
[30];
168 case XMM7_3
: return myfpregs
.xmm_space
[31];
169 case XMM8_0
: return myfpregs
.xmm_space
[32];
170 case XMM8_1
: return myfpregs
.xmm_space
[33];
171 case XMM8_2
: return myfpregs
.xmm_space
[34];
172 case XMM8_3
: return myfpregs
.xmm_space
[35];
173 case XMM9_0
: return myfpregs
.xmm_space
[36];
174 case XMM9_1
: return myfpregs
.xmm_space
[37];
175 case XMM9_2
: return myfpregs
.xmm_space
[38];
176 case XMM9_3
: return myfpregs
.xmm_space
[39];
177 case XMM10_0
: return myfpregs
.xmm_space
[40];
178 case XMM10_1
: return myfpregs
.xmm_space
[41];
179 case XMM10_2
: return myfpregs
.xmm_space
[42];
180 case XMM10_3
: return myfpregs
.xmm_space
[43];
181 case XMM11_0
: return myfpregs
.xmm_space
[44];
182 case XMM11_1
: return myfpregs
.xmm_space
[45];
183 case XMM11_2
: return myfpregs
.xmm_space
[46];
184 case XMM11_3
: return myfpregs
.xmm_space
[47];
185 case XMM12_0
: return myfpregs
.xmm_space
[48];
186 case XMM12_1
: return myfpregs
.xmm_space
[49];
187 case XMM12_2
: return myfpregs
.xmm_space
[50];
188 case XMM12_3
: return myfpregs
.xmm_space
[51];
189 case XMM13_0
: return myfpregs
.xmm_space
[52];
190 case XMM13_1
: return myfpregs
.xmm_space
[53];
191 case XMM13_2
: return myfpregs
.xmm_space
[54];
192 case XMM13_3
: return myfpregs
.xmm_space
[55];
193 case XMM14_0
: return myfpregs
.xmm_space
[56];
194 case XMM14_1
: return myfpregs
.xmm_space
[57];
195 case XMM14_2
: return myfpregs
.xmm_space
[58];
196 case XMM14_3
: return myfpregs
.xmm_space
[59];
197 case XMM15_0
: return myfpregs
.xmm_space
[60];
198 case XMM15_1
: return myfpregs
.xmm_space
[61];
199 case XMM15_2
: return myfpregs
.xmm_space
[62];
200 case XMM15_3
: return myfpregs
.xmm_space
[63];
208 AMD64TraceChild::update(int pid
)
212 if (ptrace(PTRACE_GETREGS
, pid
, 0, ®s
) != 0) {
213 cerr
<< "update: " << strerror(errno
) << endl
;
216 if (ptrace(PTRACE_GETFPREGS
, pid
, 0, &fpregs
) != 0) {
217 cerr
<< "update: " << strerror(errno
) << endl
;
220 for (unsigned int x
= 0; x
< numregs
; x
++)
221 regDiffSinceUpdate
[x
] = (getRegVal(x
) != getOldRegVal(x
));
225 AMD64TraceChild::AMD64TraceChild()
227 for (unsigned int x
= 0; x
< numregs
; x
++)
228 regDiffSinceUpdate
[x
] = false;
232 AMD64TraceChild::getRegVal(int num
)
234 return getRegs(regs
, fpregs
, num
);
238 AMD64TraceChild::getOldRegVal(int num
)
240 return getRegs(oldregs
, oldfpregs
, num
);
244 AMD64TraceChild::outputStartState(ostream
& os
)
246 uint64_t sp
= getSP();
247 uint64_t pc
= getPC();
248 uint64_t highestInfo
= 0;
250 sprintf(obuf
, "Initial stack pointer = 0x%016lx\n", sp
);
252 sprintf(obuf
, "Initial program counter = 0x%016lx\n", pc
);
255 //Output the argument count
256 uint64_t cargc
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
257 sprintf(obuf
, "0x%016lx: Argc = 0x%016lx\n", sp
, cargc
);
261 //Output argv pointers
265 cargv
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
266 sprintf(obuf
, "0x%016lx: argv[%d] = 0x%016lx\n",
267 sp
, argCount
++, cargv
);
269 if (highestInfo
< cargv
)
275 //Output the envp pointers
279 cenvp
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
280 sprintf(obuf
, "0x%016lx: envp[%d] = 0x%016lx\n",
281 sp
, envCount
++, cenvp
);
285 uint64_t auxType
, auxVal
;
287 auxType
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
289 auxVal
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
291 sprintf(obuf
, "0x%016lx: Auxiliary vector = {0x%016lx, 0x%016lx}\n",
292 sp
- 16, auxType
, auxVal
);
294 } while(auxType
!= 0 || auxVal
!= 0);
295 //Print out the argument strings, environment strings, and file name.
298 uint64_t currentStart
= sp
;
299 bool clearedInitialPadding
= false;
301 buf
= ptrace(PTRACE_PEEKDATA
, pid
, sp
, 0);
302 char * cbuf
= (char *)&buf
;
303 for (int x
= 0; x
< sizeof(uint64_t); x
++) {
307 sprintf(obuf
, "0x%016lx: \"%s\"\n",
308 currentStart
, current
.c_str());
311 currentStart
= sp
+ x
+ 1;
315 clearedInitialPadding
= clearedInitialPadding
|| buf
!= 0;
316 } while (!clearedInitialPadding
|| buf
!= 0 || sp
<= highestInfo
);
321 AMD64TraceChild::findSyscall()
323 uint64_t rip
= getPC();
324 bool foundOpcode
= false;
325 bool twoByteOpcode
= false;
327 uint64_t buf
= ptrace(PTRACE_PEEKDATA
, pid
, rip
, 0);
328 for (int i
= 0; i
< sizeof(uint64_t); i
++) {
329 unsigned char byte
= buf
& 0xFF;
331 if(!(byte
== 0x66 || //operand override
332 byte
== 0x67 || //address override
339 byte
== 0xF0 || //lock
340 byte
== 0xF2 || //repe
341 byte
== 0xF3 || //repne
342 (byte
>= 0x40 && byte
<= 0x4F) // REX
349 //SYSCALL or SYSENTER
350 if (byte
== 0x05 || byte
== 0x34)
355 if (!twoByteOpcode
) {
356 if (byte
== 0xCC) // INT3
358 else if (byte
== 0xCD) // INT with byte immediate
360 else if (byte
== 0x0F) // two byte opcode prefix
361 twoByteOpcode
= true;
373 AMD64TraceChild::step()
375 uint64_t ripAfterSyscall
= findSyscall();
376 if (ripAfterSyscall
) {
377 //Get the original contents of memory
378 uint64_t buf
= ptrace(PTRACE_PEEKDATA
, pid
, ripAfterSyscall
, 0);
379 //Patch the first two bytes of the memory immediately after this with
380 //jmp -2. Either single stepping will take over before this
381 //instruction, leaving the rip where it should be, or it will take
382 //over after this instruction, -still- leaving the rip where it should
384 uint64_t newBuf
= (buf
& ~0xFFFF) | 0xFEEB;
385 //Write the patched memory to the processes address space
386 ptrace(PTRACE_POKEDATA
, pid
, ripAfterSyscall
, newBuf
);
389 //Put things back to the way they started
390 ptrace(PTRACE_POKEDATA
, pid
, ripAfterSyscall
, buf
);
392 //Get all the way past repe and repne string instructions in one shot.
393 uint64_t newPC
, origPC
= getPC();
397 } while(newPC
== origPC
);
401 TraceChild
* genTraceChild()
403 return new AMD64TraceChild
;