"Fossies" - the Fresh Open Source Software Archive 
Member "reptyr-reptyr-0.9.0/platform/linux/linux_ptrace.c" (12 Jun 2022, 10192 Bytes) of package /linux/privat/reptyr-reptyr-0.9.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "linux_ptrace.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
0.8.0_vs_0.9.0.
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 */
22
23 #ifdef __linux__
24
25 #include <elf.h>
26 #include "../../ptrace.h"
27 #include "../platform.h"
28
29 /*
30 * RHEL 5's kernel supports these flags, but their libc doesn't ship a ptrace.h
31 * that defines them. Define them here, and if our kernel doesn't support them,
32 * we'll find out when PTRACE_SETOPTIONS fails.
33 */
34 #ifndef PTRACE_O_TRACESYSGOOD
35 #define PTRACE_O_TRACESYSGOOD 0x00000001
36 #endif
37
38 #ifndef PTRACE_O_TRACEFORK
39 #define PTRACE_O_TRACEFORK 0x00000002
40 #endif
41
42 #ifndef PTRACE_EVENT_FORK
43 #define PTRACE_EVENT_FORK 1
44 #endif
45
46 #define min(x, y) ({ \
47 typeof(x) _min1 = (x); \
48 typeof(y) _min2 = (y); \
49 _min1 < _min2 ? _min1 : _min2; })
50
51 #ifdef PTRACE_TRACEME
52 static long __ptrace_command(struct ptrace_child *child, int req,
53 void *, void*);
54 #else
55 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
56 void *, void*);
57 #endif
58
59 #define ptrace_command(cld, req, ...) _ptrace_command(cld, req, ## __VA_ARGS__, NULL, NULL)
60 #define _ptrace_command(cld, req, addr, data, ...) __ptrace_command((cld), (req), (void*)(addr), (void*)(data))
61
62 #define ptr(regs, off) ((unsigned long*)((void*)(regs)+(off)))
63
64 struct ptrace_personality {
65 size_t syscall_rv;
66 size_t syscall_arg0;
67 size_t syscall_arg1;
68 size_t syscall_arg2;
69 size_t syscall_arg3;
70 size_t syscall_arg4;
71 size_t syscall_arg5;
72 size_t reg_ip;
73 };
74
75 static struct ptrace_personality *personality(struct ptrace_child *child);
76
77 #if defined(__amd64__)
78 #include "arch/amd64.h"
79 #elif defined(__i386__)
80 #include "arch/i386.h"
81 #elif defined(__arm__)
82 #include "arch/arm.h"
83 #elif defined(__aarch64__)
84 #include "arch/aarch64.h"
85 #elif defined(__powerpc__)
86 #include "arch/powerpc.h"
87 #elif defined(__riscv) && __riscv_xlen == 64
88 #include "arch/riscv64.h"
89 #else
90 #error Unsupported architecture.
91 #endif
92
93 #ifndef ARCH_HAVE_MULTIPLE_PERSONALITIES
94 int arch_get_personality(struct ptrace_child *child) {
95 return 0;
96 }
97
98 struct syscall_numbers arch_syscall_numbers[] = {
99 #include "arch/default-syscalls.h"
100 };
101 #endif
102
103 static struct ptrace_personality *personality(struct ptrace_child *child) {
104 return &arch_personality[child->personality];
105 }
106
107 struct syscall_numbers *ptrace_syscall_numbers(struct ptrace_child *child) {
108 return &arch_syscall_numbers[child->personality];
109 }
110
111 int ptrace_attach_child(struct ptrace_child *child, pid_t pid) {
112 memset(child, 0, sizeof * child);
113 child->pid = pid;
114 if (ptrace_command(child, PTRACE_ATTACH) < 0)
115 return -1;
116
117 return ptrace_finish_attach(child, pid);
118 }
119
120 int ptrace_finish_attach(struct ptrace_child *child, pid_t pid) {
121 memset(child, 0, sizeof * child);
122 child->pid = pid;
123
124 kill(pid, SIGCONT);
125 if (ptrace_wait(child) < 0)
126 goto detach;
127
128 if (arch_get_personality(child))
129 goto detach;
130
131 if (ptrace_command(child, PTRACE_SETOPTIONS, 0,
132 PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK) < 0)
133 goto detach;
134
135 return 0;
136
137 detach:
138 /* Don't clobber child->error */
139 ptrace(PTRACE_DETACH, child->pid, 0, 0);
140 return -1;
141 }
142
143 int ptrace_detach_child(struct ptrace_child *child) {
144 if (ptrace_command(child, PTRACE_DETACH, 0, 0) < 0)
145 return -1;
146 child->state = ptrace_detached;
147 return 0;
148 }
149
150 int ptrace_wait(struct ptrace_child *child) {
151 if (waitpid(child->pid, &child->status, 0) < 0) {
152 child->error = errno;
153 return -1;
154 }
155 if (WIFEXITED(child->status) || WIFSIGNALED(child->status)) {
156 child->state = ptrace_exited;
157 } else if (WIFSTOPPED(child->status)) {
158 int sig = WSTOPSIG(child->status);
159 if (sig & 0x80) {
160 child->state = (child->state == ptrace_at_syscall) ?
161 ptrace_after_syscall : ptrace_at_syscall;
162 } else {
163 int event = child->status >> 16;
164 if (sig == SIGTRAP && event == PTRACE_EVENT_FORK)
165 ptrace_command(child, PTRACE_GETEVENTMSG, 0, &child->forked_pid);
166 if (child->state != ptrace_at_syscall)
167 child->state = ptrace_stopped;
168 }
169 } else {
170 child->error = EINVAL;
171 return -1;
172 }
173 return 0;
174 }
175
176 int ptrace_advance_to_state(struct ptrace_child *child,
177 enum child_state desired) {
178 int err;
179 while (child->state != desired) {
180 switch (desired) {
181 case ptrace_after_syscall:
182 case ptrace_at_syscall:
183 if (WIFSTOPPED(child->status) && WSTOPSIG(child->status) == SIGSEGV) {
184 child->error = EAGAIN;
185 return -1;
186 }
187 err = ptrace_command(child, PTRACE_SYSCALL, 0, 0);
188 break;
189 case ptrace_running:
190 return ptrace_command(child, PTRACE_CONT, 0, 0);
191 case ptrace_stopped:
192 err = kill(child->pid, SIGSTOP);
193 if (err < 0)
194 child->error = errno;
195 break;
196 default:
197 child->error = EINVAL;
198 return -1;
199 }
200 if (err < 0)
201 return err;
202 if (ptrace_wait(child) < 0)
203 return -1;
204 }
205 return 0;
206 }
207
208
209 int ptrace_save_regs(struct ptrace_child *child) {
210 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
211 return -1;
212
213 struct iovec reg_iovec = {
214 .iov_base = &child->regs,
215 .iov_len = sizeof(child->regs)
216 };
217 if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, ®_iovec) < 0)
218 return -1;
219 arch_fixup_regs(child);
220 if (arch_save_syscall(child) < 0)
221 return -1;
222 return 0;
223 }
224
225 int ptrace_restore_regs(struct ptrace_child *child) {
226 int err;
227 struct iovec reg_iovec = {
228 .iov_base = &child->regs,
229 .iov_len = sizeof(child->regs)
230 };
231 err = ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, ®_iovec);
232 if (err < 0)
233 return err;
234 return arch_restore_syscall(child);
235 }
236
237 unsigned long ptrace_remote_syscall(struct ptrace_child *child,
238 unsigned long sysno,
239 unsigned long p0, unsigned long p1,
240 unsigned long p2, unsigned long p3,
241 unsigned long p4, unsigned long p5) {
242 unsigned long rv;
243 if (ptrace_advance_to_state(child, ptrace_at_syscall) < 0)
244 return -1;
245
246 if (arch_set_syscall(child, sysno) < 0)
247 return -1;
248
249 typeof(child->regs) regs;
250
251 struct iovec reg_iovec = {
252 .iov_base = ®s,
253 .iov_len = sizeof(regs)
254 };
255
256 #define setreg(r, v) (*ptr(®s, (personality(child)->r))) = (v)
257
258 if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, ®_iovec) < 0)
259 return -1;
260
261 setreg(syscall_arg0, p0);
262 setreg(syscall_arg1, p1);
263 setreg(syscall_arg2, p2);
264 setreg(syscall_arg3, p3);
265 setreg(syscall_arg4, p4);
266 setreg(syscall_arg5, p5);
267
268 if (ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, ®_iovec) < 0)
269 return -1;
270
271 if (ptrace_advance_to_state(child, ptrace_after_syscall) < 0)
272 return -1;
273
274 if (ptrace_command(child, PTRACE_GETREGSET, NT_PRSTATUS, ®_iovec) < 0)
275 return -1;
276
277 rv = *ptr(®s, (personality(child)->syscall_rv));
278
279 setreg(reg_ip, *(unsigned long*)((void*)&child->regs + personality(child)->reg_ip));
280
281 if (ptrace_command(child, PTRACE_SETREGSET, NT_PRSTATUS, ®_iovec) < 0)
282 return -1;
283
284 #undef setreg
285
286 return rv;
287 }
288
289 int ptrace_memcpy_to_child(struct ptrace_child *child, child_addr_t dst, const void *src, size_t n) {
290 unsigned long scratch;
291
292 while (n >= sizeof(unsigned long)) {
293 if (ptrace_command(child, PTRACE_POKEDATA, dst, *((unsigned long*)src)) < 0)
294 return -1;
295 dst += sizeof(unsigned long);
296 src += sizeof(unsigned long);
297 n -= sizeof(unsigned long);
298 }
299
300 if (n) {
301 scratch = ptrace_command(child, PTRACE_PEEKDATA, dst);
302 if (child->error)
303 return -1;
304 memcpy(&scratch, src, n);
305 if (ptrace_command(child, PTRACE_POKEDATA, dst, scratch) < 0)
306 return -1;
307 }
308
309 return 0;
310 }
311
312 int ptrace_memcpy_from_child(struct ptrace_child *child, void *dst, child_addr_t src, size_t n) {
313 unsigned long scratch;
314
315 while (n) {
316 scratch = ptrace_command(child, PTRACE_PEEKDATA, src);
317 if (child->error) return -1;
318 memcpy(dst, &scratch, min(n, sizeof(unsigned long)));
319
320 dst += sizeof(unsigned long);
321 src += sizeof(unsigned long);
322 if (n >= sizeof(unsigned long))
323 n -= sizeof(unsigned long);
324 else
325 n = 0;
326 }
327 return 0;
328 }
329
330 #ifdef PTRACE_TRACEME
331 static long __ptrace_command(struct ptrace_child *child, int req,
332 void *addr, void *data) {
333 #else
334 static long __ptrace_command(struct ptrace_child *child, enum __ptrace_request req,
335 void *addr, void *data) {
336 #endif
337 long rv;
338 errno = 0;
339 rv = ptrace(req, child->pid, addr, data);
340 child->error = errno;
341 return rv;
342 }
343
344 #endif