Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 288 lines (242 sloc) 8.287 kb
43b260e @nelhage Import stub ptrace infrastructure.
authored
1 #include <sys/ptrace.h>
6e4d75a @nelhage Initial ARM support.
authored
2 #include <asm/ptrace.h>
84114a0 @ingramj Fix a compiler error in ptrace.c
ingramj authored
3 #include <sys/types.h>
43b260e @nelhage Import stub ptrace infrastructure.
authored
4 #include <sys/user.h>
5 #include <sys/wait.h>
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <sys/syscall.h>
12 #include <sys/mman.h>
13 #include <assert.h>
988d4d1 @nelhage Get offsetof from stddef.h.
authored
14 #include <stddef.h>
43b260e @nelhage Import stub ptrace infrastructure.
authored
15
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
16 #include "ptrace.h"
17
da5c7fa @nelhage Define some ptrace constants on platforms where ptrace.h is missing them...
authored
18 /*
19 * RHEL 5's kernel supports these flags, but their libc doesn't ship a ptrace.h
20 * that defines them. Define them here, and if our kernel doesn't support them,
21 * we'll find out when PTRACE_SETOPTIONS fails.
22 */
23 #ifndef PTRACE_O_TRACESYSGOOD
24 #define PTRACE_O_TRACESYSGOOD 0x00000001
25 #endif
26
27 #ifndef PTRACE_O_TRACEFORK
28 #define PTRACE_O_TRACEFORK 0x00000002
29 #endif
30
31 #ifndef PTRACE_EVENT_FORK
32 #define PTRACE_EVENT_FORK 1
33 #endif
34
35d826e @nelhage Implement memcpy to/from child.
authored
35 #define min(x, y) ({ \
36 typeof(x) _min1 = (x); \
37 typeof(y) _min2 = (y); \
38 _min1 < _min2 ? _min1 : _min2; })
43b260e @nelhage Import stub ptrace infrastructure.
authored
39
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
40 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
41 void *, void*);
42
43 #define ptrace_command(cld, req, ...) _ptrace_command(cld, req, ## __VA_ARGS__, NULL, NULL)
44 #define _ptrace_command(cld, req, addr, data, ...) __ptrace_command((cld), (req), (void*)(addr), (void*)(data))
45
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
46 #if defined(__amd64__)
47 #include "arch/amd64.h"
48 #elif defined(__i386__)
49 #include "arch/i386.h"
6e4d75a @nelhage Initial ARM support.
authored
50 #elif defined(__arm__)
51 #include "arch/arm.h"
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
52 #else
53 #error Unsupported architecture.
54 #endif
43b260e @nelhage Import stub ptrace infrastructure.
authored
55
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
56 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
57 memset(child, 0, sizeof child);
58 child->pid = pid;
59 if (ptrace_command(child, PTRACE_ATTACH) < 0)
60 return -1;
9e91662 @nelhage Checkpoint working version.
authored
61
62 return ptrace_finish_attach(child, pid);
63 }
64
65 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
66 memset(child, 0, sizeof child);
67 child->pid = pid;
68
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
69 if (ptrace_wait(child) < 0)
70 goto detach;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
71
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
72 if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
73 PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEFORK) < 0)
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
74 goto detach;
75
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
76 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
77
78 detach:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
79 /* Don't clobber child->error */
80 ptrace(PTRACE_DETACH, child->pid, 0, 0);
81 return -1;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
82 }
83
84 int ptrace_detach_child(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
85 if (ptrace_command(child, PTRACE_DETACH, 0, 0) < 0)
86 return -1;
87 child->state = ptrace_detached;
88 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
89 }
90
91 int ptrace_wait(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
92 if (waitpid(child->pid, &child->status, 0) < 0) {
93 child->error = errno;
94 return -1;
95 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
96 if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
97 child->state = ptrace_exited;
98 } else if(WIFSTOPPED(child->status)) {
9e91662 @nelhage Checkpoint working version.
authored
99 int sig = WSTOPSIG(child->status);
100 if (sig & 0x80) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
101 child->state = (child->state == ptrace_at_syscall) ?
102 ptrace_after_syscall : ptrace_at_syscall;
103 } else {
9e91662 @nelhage Checkpoint working version.
authored
104 if (sig == SIGTRAP && (((child->status >> 8) & PTRACE_EVENT_FORK) == PTRACE_EVENT_FORK))
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
105 ptrace_command(child, PTRACE_GETEVENTMSG, 0, &child->forked_pid);
9e91662 @nelhage Checkpoint working version.
authored
106 if (child->state != ptrace_at_syscall)
107 child->state = ptrace_stopped;
065cb54 @nelhage Handle attaching to processes that are already session leaders.
authored
108 if (sig != SIGSTOP && sig != SIGTRAP && sig != SIGCHLD && sig != SIGHUP && sig != SIGCONT) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
109 child->error = EAGAIN;
95e1d51 @nelhage ptrace.c: Don't spin forever if the child gets a weird signal.
authored
110 return -1;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
111 }
43b260e @nelhage Import stub ptrace infrastructure.
authored
112 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
113 } else {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
114 child->error = EINVAL;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
115 return -1;
116 }
117 return 0;
118 }
119
120 int ptrace_advance_to_state(struct ptrace_child *child,
121 enum child_state desired) {
122 int err;
123 while(child->state != desired) {
124 switch(desired) {
125 case ptrace_at_syscall:
126 case ptrace_after_syscall:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
127 err = ptrace_command(child, PTRACE_SYSCALL, 0, 0);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
128 break;
129 case ptrace_running:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
130 return ptrace_command(child, PTRACE_CONT, 0, 0);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
131 case ptrace_stopped:
132 err = kill(child->pid, SIGSTOP);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
133 if (err < 0)
134 child->error = errno;
43b260e @nelhage Import stub ptrace infrastructure.
authored
135 break;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
136 default:
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
137 child->error = EINVAL;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
138 return -1;
139 }
140 if (err < 0)
141 return err;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
142 if(ptrace_wait(child) < 0)
143 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
144 }
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
145 return 0;
43b260e @nelhage Import stub ptrace infrastructure.
authored
146 }
147
35d826e @nelhage Implement memcpy to/from child.
authored
148
149 static void reset_user_struct(struct user *user) {
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
150 arch_fixup_regs(user);
35d826e @nelhage Implement memcpy to/from child.
authored
151 }
152
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
153 int ptrace_save_regs(struct ptrace_child *child) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
154 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
155 return -1;
156 if (ptrace_command(child, PTRACE_GETREGS, 0, &child->user) < 0)
157 return -1;
158 reset_user_struct(&child->user);
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
159 if (arch_save_syscall(child) < 0)
160 return -1;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
161 return 0;
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
162 }
163
164 int ptrace_restore_regs(struct ptrace_child *child) {
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
165 int err;
166 err = ptrace_command(child, PTRACE_SETREGS, 0, &child->user);
167 if (err < 0)
168 return err;
169 return arch_restore_syscall(child);
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
170 }
171
172 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
173 unsigned long sysno,
174 unsigned long p0, unsigned long p1,
175 unsigned long p2, unsigned long p3,
176 unsigned long p4, unsigned long p5) {
35d826e @nelhage Implement memcpy to/from child.
authored
177 unsigned long rv;
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
178 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
179 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
180
181 #define setreg(r, v) do { \
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
182 if (ptrace_command(child, PTRACE_POKEUSER, \
183 offsetof(struct user, regs.r), \
184 (v)) < 0) \
185 return -1; \
43b260e @nelhage Import stub ptrace infrastructure.
authored
186 } while(0)
187
1dfdfbc @nelhage Add architecture hooks for saving and restoring the syscall number.
authored
188 if (arch_set_syscall(child, sysno) < 0)
189 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
190 setreg(syscall_arg0, p0);
191 setreg(syscall_arg1, p1);
192 setreg(syscall_arg2, p2);
193 setreg(syscall_arg3, p3);
194 setreg(syscall_arg4, p4);
195 setreg(syscall_arg5, p5);
196
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
197 if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
198 return -1;
43b260e @nelhage Import stub ptrace infrastructure.
authored
199
c84bdba @nelhage Refactor architecture-dependent headers slightly.
authored
200 rv = ptrace_command(child, PTRACE_PEEKUSER,
201 offsetof(struct user, regs.syscall_rv));
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
202 if (child->error)
203 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
204
205 setreg(reg_ip, child->user.regs.reg_ip);
206
207 #undef setreg
208
209 return rv;
43b260e @nelhage Import stub ptrace infrastructure.
authored
210 }
211
fff1db5 @nelhage const fix for memcpy_to_child
authored
212 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
213 unsigned long scratch;
214
215 while (n >= sizeof(unsigned long)) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
216 if (ptrace_command(child, PTRACE_POKEDATA, dst, *((unsigned long*)src)) < 0)
217 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
218 dst += sizeof(unsigned long);
219 src += sizeof(unsigned long);
220 n -= sizeof(unsigned long);
221 }
222
223 if (n) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
224 scratch = ptrace_command(child, PTRACE_PEEKDATA, dst);
225 if (child->error)
35d826e @nelhage Implement memcpy to/from child.
authored
226 return -1;
227 memcpy(&scratch, src, n);
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
228 if (ptrace_command(child, PTRACE_POKEDATA, dst, scratch) < 0)
229 return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
230 }
231
232 return 0;
43b260e @nelhage Import stub ptrace infrastructure.
authored
233 }
234
35d826e @nelhage Implement memcpy to/from child.
authored
235 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
236 unsigned long scratch;
237
238 while (n) {
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
239 scratch = ptrace_command(child, PTRACE_PEEKDATA, src);
240 if (child->error) return -1;
35d826e @nelhage Implement memcpy to/from child.
authored
241 memcpy(dst, &scratch, min(n, sizeof(unsigned long)));
242
243 dst += sizeof(unsigned long);
244 src += sizeof(unsigned long);
245 if (n >= sizeof(unsigned long))
246 n -= sizeof(unsigned long);
247 else
248 n = 0;
249 }
250 return 0;
251 }
252
c2c4701 @nelhage ptrace: Make error handling consistent.
authored
253 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
254 void *addr, void *data) {
255 long rv;
256 errno = 0;
257 rv = ptrace(req, child->pid, addr, data);
258 child->error = errno;
259 return rv;
260 }
261
35d826e @nelhage Implement memcpy to/from child.
authored
262
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
263 #ifdef BUILD_PTRACE_MAIN
43b260e @nelhage Import stub ptrace infrastructure.
authored
264 int main(int argc, char **argv) {
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
265 struct ptrace_child child;
43b260e @nelhage Import stub ptrace infrastructure.
authored
266 pid_t pid;
267
268 if (argc < 2) {
269 printf("Usage: %s pid\n", argv[0]);
270 return 1;
271 }
272 pid = atoi(argv[1]);
273
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
274 assert(!ptrace_attach_child(&child, pid));
275 assert(!ptrace_save_regs(&child));
43b260e @nelhage Import stub ptrace infrastructure.
authored
276
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
277 printf("mmap = %lx\n", ptrace_remote_syscall(&child, mmap_syscall, 0,
278 4096, PROT_READ|PROT_WRITE,
279 MAP_ANONYMOUS|MAP_PRIVATE, 0, 0));
43b260e @nelhage Import stub ptrace infrastructure.
authored
280
1fb6ce8 @nelhage Clean up ptrace infrastructure slightly.
authored
281 reset_user_struct(&child.user);
282 assert(!ptrace_restore_regs(&child));
283 assert(!ptrace_detach_child(&child));
43b260e @nelhage Import stub ptrace infrastructure.
authored
284
285 return 0;
286 }
648ff26 @nelhage Start to separate ptrace.c into a library.
authored
287 #endif
Something went wrong with that request. Please try again.