Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 310 lines (264 sloc) 9.416 kB
20b3b40 @nelhage Add the license to all of the source files.
authored
1 /*
2 * Copyright (C) 2011 by Nelson Elhage
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
43b260e @nelhage Import stub ptrace infrastructure.
authored
22 #include <sys/ptrace.h>
6e4d75a @nelhage Initial ARM support.
authored
23 #include <asm/ptrace.h>
84114a0 @ingramj Fix a compiler error in ptrace.c
ingramj authored
24 #include <sys/types.h>
43b260e @nelhage Import stub ptrace infrastructure.
authored
25 #include <sys/user.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <sys/syscall.h>
33 #include <sys/mman.h>
34 #include <assert.h>
988d4d1 @nelhage Get offsetof from stddef.h.
authored
35 #include <stddef.h>
43b260e @nelhage Import stub ptrace infrastructure.
authored
36
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
37 #include "ptrace.h"
38
da5c7fa @nelhage Define some ptrace constants on platforms where ptrace.h is missing t…
authored
39 /*
40 * RHEL 5's kernel supports these flags, but their libc doesn't ship a ptrace.h
41 * that defines them. Define them here, and if our kernel doesn't support them,
42 * we'll find out when PTRACE_SETOPTIONS fails.
43 */
44 #ifndef PTRACE_O_TRACESYSGOOD
45 #define PTRACE_O_TRACESYSGOOD 0x00000001
46 #endif
47
48 #ifndef PTRACE_O_TRACEFORK
49 #define PTRACE_O_TRACEFORK 0x00000002
50 #endif
51
52 #ifndef PTRACE_EVENT_FORK
53 #define PTRACE_EVENT_FORK 1
54 #endif
55
35d826e @nelhage Implement memcpy to/from child.
authored
56 #define min(x, y) ({ \
57 typeof(x) _min1 = (x); \
58 typeof(y) _min2 = (y); \
59 _min1 < _min2 ? _min1 : _min2; })
43b260e @nelhage Import stub ptrace infrastructure.
authored
60
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
61 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
62 void *, void*);
63
64 #define ptrace_command(cld, req, ...) _ptrace_command(cld, req, ## __VA_ARGS__, NULL, NULL)
65 #define _ptrace_command(cld, req, addr, data, ...) __ptrace_command((cld), (req), (void*)(addr), (void*)(data))
66
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
67 #if defined(__amd64__)
68 #include "arch/amd64.h"
69 #elif defined(__i386__)
70 #include "arch/i386.h"
6e4d75a @nelhage Initial ARM support.
authored
71 #elif defined(__arm__)
72 #include "arch/arm.h"
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
73 #else
74 #error Unsupported architecture.
75 #endif
43b260e @nelhage Import stub ptrace infrastructure.
authored
76
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
77 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
4b15af8 @nelhage ptrace.c: Fix the size on some memsets.
authored
78 memset(child, 0, sizeof *child);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
79 child->pid = pid;
80 if (ptrace_command(child, PTRACE_ATTACH) < 0)
81 return -1;
9e91662 @nelhage Checkpoint working version.
authored
82
83 return ptrace_finish_attach(child, pid);
84 }
85
86 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
4b15af8 @nelhage ptrace.c: Fix the size on some memsets.
authored
87 memset(child, 0, sizeof *child);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
88 child->pid = pid;
89
0672cf4 @nelhage Explicitly CONT the child on attach, and then STOP/CONT after attach.
authored
90 kill(pid, SIGCONT);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
91 if (ptrace_wait(child) < 0)
92 goto detach;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
93
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
94 if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
95 PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEFORK) < 0)
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
96 goto detach;
97
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
98 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
99
100 detach:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
101 /* Don't clobber child->error */
102 ptrace(PTRACE_DETACH, child->pid, 0, 0);
103 return -1;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
104 }
105
106 int ptrace_detach_child(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
107 if (ptrace_command(child, PTRACE_DETACH, 0, 0) < 0)
108 return -1;
109 child->state = ptrace_detached;
110 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
111 }
112
113 int ptrace_wait(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
114 if (waitpid(child->pid, &child->status, 0) < 0) {
115 child->error = errno;
116 return -1;
117 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
118 if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
119 child->state = ptrace_exited;
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
120 } else if (WIFSTOPPED(child->status)) {
9e91662 @nelhage Checkpoint working version.
authored
121 int sig = WSTOPSIG(child->status);
122 if (sig & 0x80) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
123 child->state = (child->state == ptrace_at_syscall) ?
124 ptrace_after_syscall : ptrace_at_syscall;
125 } else {
9e91662 @nelhage Checkpoint working version.
authored
126 if (sig == SIGTRAP && (((child->status >> 8) & PTRACE_EVENT_FORK) == PTRACE_EVENT_FORK))
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
127 ptrace_command(child, PTRACE_GETEVENTMSG, 0, &child->forked_pid);
9e91662 @nelhage Checkpoint working version.
authored
128 if (child->state != ptrace_at_syscall)
129 child->state = ptrace_stopped;
43b260e @nelhage Import stub ptrace infrastructure.
authored
130 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
131 } else {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
132 child->error = EINVAL;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
133 return -1;
134 }
135 return 0;
136 }
137
138 int ptrace_advance_to_state(struct ptrace_child *child,
139 enum child_state desired) {
140 int err;
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
141 while (child->state != desired) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
142 switch(desired) {
143 case ptrace_after_syscall:
0046dc7 @nelhage ptrace.c: Improve the wait / advance_to_state logic somewhat.
authored
144 case ptrace_at_syscall:
145 if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
146 child->error = EAGAIN;
147 return -1;
148 }
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
149 err = ptrace_command(child, PTRACE_SYSCALL, 0, 0);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
150 break;
151 case ptrace_running:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
152 return ptrace_command(child, PTRACE_CONT, 0, 0);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
153 case ptrace_stopped:
154 err = kill(child->pid, SIGSTOP);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
155 if (err < 0)
156 child->error = errno;
43b260e @nelhage Import stub ptrace infrastructure.
authored
157 break;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
158 default:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
159 child->error = EINVAL;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
160 return -1;
161 }
162 if (err < 0)
163 return err;
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
164 if (ptrace_wait(child) < 0)
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
165 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
166 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
167 return 0;
43b260e @nelhage Import stub ptrace infrastructure.
authored
168 }
169
35d826e @nelhage Implement memcpy to/from child.
authored
170
171 static void reset_user_struct(struct user *user) {
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
172 arch_fixup_regs(user);
35d826e @nelhage Implement memcpy to/from child.
authored
173 }
174
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
175 int ptrace_save_regs(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
176 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
177 return -1;
178 if (ptrace_command(child, PTRACE_GETREGS, 0, &child->user) < 0)
179 return -1;
180 reset_user_struct(&child->user);
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
181 if (arch_save_syscall(child) < 0)
182 return -1;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
183 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
184 }
185
186 int ptrace_restore_regs(struct ptrace_child *child) {
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
187 int err;
188 err = ptrace_command(child, PTRACE_SETREGS, 0, &child->user);
189 if (err < 0)
190 return err;
191 return arch_restore_syscall(child);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
192 }
193
194 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
195 unsigned long sysno,
196 unsigned long p0, unsigned long p1,
197 unsigned long p2, unsigned long p3,
198 unsigned long p4, unsigned long p5) {
35d826e @nelhage Implement memcpy to/from child.
authored
199 unsigned long rv;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
200 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
201 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
202
203 #define setreg(r, v) do { \
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
204 if (ptrace_command(child, PTRACE_POKEUSER, \
205 offsetof(struct user, regs.r), \
206 (v)) < 0) \
207 return -1; \
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
208 } while (0)
43b260e @nelhage Import stub ptrace infrastructure.
authored
209
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
210 if (arch_set_syscall(child, sysno) < 0)
211 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
212 setreg(syscall_arg0, p0);
213 setreg(syscall_arg1, p1);
214 setreg(syscall_arg2, p2);
215 setreg(syscall_arg3, p3);
216 setreg(syscall_arg4, p4);
217 setreg(syscall_arg5, p5);
218
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
219 if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
220 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
221
c84bdba @nelhage Refactor architecture-dependent headers slightly.
authored
222 rv = ptrace_command(child, PTRACE_PEEKUSER,
223 offsetof(struct user, regs.syscall_rv));
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
224 if (child->error)
225 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
226
227 setreg(reg_ip, child->user.regs.reg_ip);
228
229 #undef setreg
230
231 return rv;
43b260e @nelhage Import stub ptrace infrastructure.
authored
232 }
233
fff1db5 @nelhage const fix for memcpy_to_child
authored
234 int ptrace_memcpy_to_child(struct ptrace_child *child, child_addr_t dst, const void *src, size_t n) {
35d826e @nelhage Implement memcpy to/from child.
authored
235 unsigned long scratch;
236
237 while (n >= sizeof(unsigned long)) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
238 if (ptrace_command(child, PTRACE_POKEDATA, dst, *((unsigned long*)src)) < 0)
239 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
240 dst += sizeof(unsigned long);
241 src += sizeof(unsigned long);
242 n -= sizeof(unsigned long);
243 }
244
245 if (n) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
246 scratch = ptrace_command(child, PTRACE_PEEKDATA, dst);
247 if (child->error)
35d826e @nelhage Implement memcpy to/from child.
authored
248 return -1;
249 memcpy(&scratch, src, n);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
250 if (ptrace_command(child, PTRACE_POKEDATA, dst, scratch) < 0)
251 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
252 }
253
254 return 0;
43b260e @nelhage Import stub ptrace infrastructure.
authored
255 }
256
35d826e @nelhage Implement memcpy to/from child.
authored
257 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
258 unsigned long scratch;
259
260 while (n) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
261 scratch = ptrace_command(child, PTRACE_PEEKDATA, src);
262 if (child->error) return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
263 memcpy(dst, &scratch, min(n, sizeof(unsigned long)));
264
265 dst += sizeof(unsigned long);
266 src += sizeof(unsigned long);
267 if (n >= sizeof(unsigned long))
268 n -= sizeof(unsigned long);
269 else
270 n = 0;
271 }
272 return 0;
273 }
274
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
275 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
276 void *addr, void *data) {
277 long rv;
278 errno = 0;
279 rv = ptrace(req, child->pid, addr, data);
280 child->error = errno;
281 return rv;
282 }
283
35d826e @nelhage Implement memcpy to/from child.
authored
284
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
285 #ifdef BUILD_PTRACE_MAIN
43b260e @nelhage Import stub ptrace infrastructure.
authored
286 int main(int argc, char **argv) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
287 struct ptrace_child child;
43b260e @nelhage Import stub ptrace infrastructure.
authored
288 pid_t pid;
289
290 if (argc < 2) {
291 printf("Usage: %s pid\n", argv[0]);
292 return 1;
293 }
294 pid = atoi(argv[1]);
295
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
296 assert(!ptrace_attach_child(&child, pid));
297 assert(!ptrace_save_regs(&child));
43b260e @nelhage Import stub ptrace infrastructure.
authored
298
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
299 printf("mmap = %lx\n", ptrace_remote_syscall(&child, mmap_syscall, 0,
300 4096, PROT_READ|PROT_WRITE,
301 MAP_ANONYMOUS|MAP_PRIVATE, 0, 0));
43b260e @nelhage Import stub ptrace infrastructure.
authored
302
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
303 reset_user_struct(&child.user);
304 assert(!ptrace_restore_regs(&child));
305 assert(!ptrace_detach_child(&child));
43b260e @nelhage Import stub ptrace infrastructure.
authored
306
307 return 0;
308 }
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
309 #endif
Something went wrong with that request. Please try again.