Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 325 lines (276 sloc) 9.815 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 them...
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
14f8754 @nelhage Change how arch/ works in preparation for 32-on-64 support.
authored
67
68 struct ptrace_personality {
69 size_t syscall_rv;
70 size_t syscall_arg0;
71 size_t syscall_arg1;
72 size_t syscall_arg2;
73 size_t syscall_arg3;
74 size_t syscall_arg4;
75 size_t syscall_arg5;
76 size_t reg_ip;
77 };
78
79 struct ptrace_personality *personality(struct ptrace_child *child);
80
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
81 #if defined(__amd64__)
82 #include "arch/amd64.h"
83 #elif defined(__i386__)
84 #include "arch/i386.h"
6e4d75a @nelhage Initial ARM support.
authored
85 #elif defined(__arm__)
86 #include "arch/arm.h"
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
87 #else
88 #error Unsupported architecture.
89 #endif
43b260e @nelhage Import stub ptrace infrastructure.
authored
90
14f8754 @nelhage Change how arch/ works in preparation for 32-on-64 support.
authored
91 struct ptrace_personality *personality(struct ptrace_child *child) {
92 return &arch_personality[child->personality];
93 }
94
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
95 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
4b15af8 @nelhage ptrace.c: Fix the size on some memsets.
authored
96 memset(child, 0, sizeof *child);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
97 child->pid = pid;
98 if (ptrace_command(child, PTRACE_ATTACH) < 0)
99 return -1;
9e91662 @nelhage Checkpoint working version.
authored
100
101 return ptrace_finish_attach(child, pid);
102 }
103
104 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
4b15af8 @nelhage ptrace.c: Fix the size on some memsets.
authored
105 memset(child, 0, sizeof *child);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
106 child->pid = pid;
107
0672cf4 @nelhage Explicitly CONT the child on attach, and then STOP/CONT after attach.
authored
108 kill(pid, SIGCONT);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
109 if (ptrace_wait(child) < 0)
110 goto detach;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
111
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
112 if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
113 PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEFORK) < 0)
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
114 goto detach;
115
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
116 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
117
118 detach:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
119 /* Don't clobber child->error */
120 ptrace(PTRACE_DETACH, child->pid, 0, 0);
121 return -1;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
122 }
123
124 int ptrace_detach_child(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
125 if (ptrace_command(child, PTRACE_DETACH, 0, 0) < 0)
126 return -1;
127 child->state = ptrace_detached;
128 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
129 }
130
131 int ptrace_wait(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
132 if (waitpid(child->pid, &child->status, 0) < 0) {
133 child->error = errno;
134 return -1;
135 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
136 if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
137 child->state = ptrace_exited;
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
138 } else if (WIFSTOPPED(child->status)) {
9e91662 @nelhage Checkpoint working version.
authored
139 int sig = WSTOPSIG(child->status);
140 if (sig & 0x80) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
141 child->state = (child->state == ptrace_at_syscall) ?
142 ptrace_after_syscall : ptrace_at_syscall;
143 } else {
9e91662 @nelhage Checkpoint working version.
authored
144 if (sig == SIGTRAP && (((child->status >> 8) & PTRACE_EVENT_FORK) == PTRACE_EVENT_FORK))
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
145 ptrace_command(child, PTRACE_GETEVENTMSG, 0, &child->forked_pid);
9e91662 @nelhage Checkpoint working version.
authored
146 if (child->state != ptrace_at_syscall)
147 child->state = ptrace_stopped;
43b260e @nelhage Import stub ptrace infrastructure.
authored
148 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
149 } else {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
150 child->error = EINVAL;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
151 return -1;
152 }
153 return 0;
154 }
155
156 int ptrace_advance_to_state(struct ptrace_child *child,
157 enum child_state desired) {
158 int err;
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
159 while (child->state != desired) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
160 switch(desired) {
161 case ptrace_after_syscall:
0046dc7 @nelhage ptrace.c: Improve the wait / advance_to_state logic somewhat.
authored
162 case ptrace_at_syscall:
163 if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
164 child->error = EAGAIN;
165 return -1;
166 }
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
167 err = ptrace_command(child, PTRACE_SYSCALL, 0, 0);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
168 break;
169 case ptrace_running:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
170 return ptrace_command(child, PTRACE_CONT, 0, 0);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
171 case ptrace_stopped:
172 err = kill(child->pid, SIGSTOP);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
173 if (err < 0)
174 child->error = errno;
43b260e @nelhage Import stub ptrace infrastructure.
authored
175 break;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
176 default:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
177 child->error = EINVAL;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
178 return -1;
179 }
180 if (err < 0)
181 return err;
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
182 if (ptrace_wait(child) < 0)
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
183 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
184 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
185 return 0;
43b260e @nelhage Import stub ptrace infrastructure.
authored
186 }
187
35d826e @nelhage Implement memcpy to/from child.
authored
188
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
189 int ptrace_save_regs(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
190 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
191 return -1;
192 if (ptrace_command(child, PTRACE_GETREGS, 0, &child->user) < 0)
193 return -1;
14f8754 @nelhage Change how arch/ works in preparation for 32-on-64 support.
authored
194 arch_fixup_regs(child);
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
195 if (arch_save_syscall(child) < 0)
196 return -1;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
197 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
198 }
199
200 int ptrace_restore_regs(struct ptrace_child *child) {
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
201 int err;
202 err = ptrace_command(child, PTRACE_SETREGS, 0, &child->user);
203 if (err < 0)
204 return err;
205 return arch_restore_syscall(child);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
206 }
207
208 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
209 unsigned long sysno,
210 unsigned long p0, unsigned long p1,
211 unsigned long p2, unsigned long p3,
212 unsigned long p4, unsigned long p5) {
35d826e @nelhage Implement memcpy to/from child.
authored
213 unsigned long rv;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
214 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
215 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
216
217 #define setreg(r, v) do { \
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
218 if (ptrace_command(child, PTRACE_POKEUSER, \
14f8754 @nelhage Change how arch/ works in preparation for 32-on-64 support.
authored
219 personality(child)->r, \
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
220 (v)) < 0) \
221 return -1; \
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
222 } while (0)
43b260e @nelhage Import stub ptrace infrastructure.
authored
223
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
224 if (arch_set_syscall(child, sysno) < 0)
225 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
226 setreg(syscall_arg0, p0);
227 setreg(syscall_arg1, p1);
228 setreg(syscall_arg2, p2);
229 setreg(syscall_arg3, p3);
230 setreg(syscall_arg4, p4);
231 setreg(syscall_arg5, p5);
232
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
233 if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
234 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
235
c84bdba @nelhage Refactor architecture-dependent headers slightly.
authored
236 rv = ptrace_command(child, PTRACE_PEEKUSER,
14f8754 @nelhage Change how arch/ works in preparation for 32-on-64 support.
authored
237 personality(child)->syscall_rv);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
238 if (child->error)
239 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
240
14f8754 @nelhage Change how arch/ works in preparation for 32-on-64 support.
authored
241 setreg(reg_ip, *(unsigned long*)((void*)&child->user +
242 personality(child)->reg_ip));
35d826e @nelhage Implement memcpy to/from child.
authored
243
244 #undef setreg
245
246 return rv;
43b260e @nelhage Import stub ptrace infrastructure.
authored
247 }
248
fff1db5 @nelhage const fix for memcpy_to_child
authored
249 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
250 unsigned long scratch;
251
252 while (n >= sizeof(unsigned long)) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
253 if (ptrace_command(child, PTRACE_POKEDATA, dst, *((unsigned long*)src)) < 0)
254 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
255 dst += sizeof(unsigned long);
256 src += sizeof(unsigned long);
257 n -= sizeof(unsigned long);
258 }
259
260 if (n) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
261 scratch = ptrace_command(child, PTRACE_PEEKDATA, dst);
262 if (child->error)
35d826e @nelhage Implement memcpy to/from child.
authored
263 return -1;
264 memcpy(&scratch, src, n);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
265 if (ptrace_command(child, PTRACE_POKEDATA, dst, scratch) < 0)
266 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
267 }
268
269 return 0;
43b260e @nelhage Import stub ptrace infrastructure.
authored
270 }
271
35d826e @nelhage Implement memcpy to/from child.
authored
272 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
273 unsigned long scratch;
274
275 while (n) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
276 scratch = ptrace_command(child, PTRACE_PEEKDATA, src);
277 if (child->error) return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
278 memcpy(dst, &scratch, min(n, sizeof(unsigned long)));
279
280 dst += sizeof(unsigned long);
281 src += sizeof(unsigned long);
282 if (n >= sizeof(unsigned long))
283 n -= sizeof(unsigned long);
284 else
285 n = 0;
286 }
287 return 0;
288 }
289
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
290 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
291 void *addr, void *data) {
292 long rv;
293 errno = 0;
294 rv = ptrace(req, child->pid, addr, data);
295 child->error = errno;
296 return rv;
297 }
298
35d826e @nelhage Implement memcpy to/from child.
authored
299
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
300 #ifdef BUILD_PTRACE_MAIN
43b260e @nelhage Import stub ptrace infrastructure.
authored
301 int main(int argc, char **argv) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
302 struct ptrace_child child;
43b260e @nelhage Import stub ptrace infrastructure.
authored
303 pid_t pid;
304
305 if (argc < 2) {
306 printf("Usage: %s pid\n", argv[0]);
307 return 1;
308 }
309 pid = atoi(argv[1]);
310
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
311 assert(!ptrace_attach_child(&child, pid));
312 assert(!ptrace_save_regs(&child));
43b260e @nelhage Import stub ptrace infrastructure.
authored
313
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
314 printf("mmap = %lx\n", ptrace_remote_syscall(&child, mmap_syscall, 0,
315 4096, PROT_READ|PROT_WRITE,
316 MAP_ANONYMOUS|MAP_PRIVATE, 0, 0));
43b260e @nelhage Import stub ptrace infrastructure.
authored
317
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
318 reset_user_struct(&child.user);
319 assert(!ptrace_restore_regs(&child));
320 assert(!ptrace_detach_child(&child));
43b260e @nelhage Import stub ptrace infrastructure.
authored
321
322 return 0;
323 }
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
324 #endif
Something went wrong with that request. Please try again.