]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/linux/linux_ptrace.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / sys / amd64 / linux / linux_ptrace.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/lock.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/sx.h>
40 #include <sys/syscallsubr.h>
41
42 #include <machine/pcb.h>
43 #include <machine/reg.h>
44
45 #include <amd64/linux/linux.h>
46 #include <amd64/linux/linux_proto.h>
47 #include <compat/linux/linux_emul.h>
48 #include <compat/linux/linux_misc.h>
49 #include <compat/linux/linux_signal.h>
50 #include <compat/linux/linux_util.h>
51
52 #define LINUX_PTRACE_TRACEME            0
53 #define LINUX_PTRACE_PEEKTEXT           1
54 #define LINUX_PTRACE_PEEKDATA           2
55 #define LINUX_PTRACE_PEEKUSER           3
56 #define LINUX_PTRACE_POKETEXT           4
57 #define LINUX_PTRACE_POKEDATA           5
58 #define LINUX_PTRACE_POKEUSER           6
59 #define LINUX_PTRACE_CONT               7
60 #define LINUX_PTRACE_KILL               8
61 #define LINUX_PTRACE_SINGLESTEP         9
62 #define LINUX_PTRACE_GETREGS            12
63 #define LINUX_PTRACE_SETREGS            13
64 #define LINUX_PTRACE_GETFPREGS          14
65 #define LINUX_PTRACE_SETFPREGS          15
66 #define LINUX_PTRACE_ATTACH             16
67 #define LINUX_PTRACE_DETACH             17
68 #define LINUX_PTRACE_SYSCALL            24
69 #define LINUX_PTRACE_SETOPTIONS         0x4200
70 #define LINUX_PTRACE_GETSIGINFO         0x4202
71 #define LINUX_PTRACE_GETREGSET          0x4204
72 #define LINUX_PTRACE_SEIZE              0x4206
73 #define LINUX_PTRACE_GET_SYSCALL_INFO   0x420e
74
75 #define LINUX_PTRACE_EVENT_EXIT         6
76
77 #define LINUX_PTRACE_O_TRACESYSGOOD     1
78 #define LINUX_PTRACE_O_TRACEFORK        2
79 #define LINUX_PTRACE_O_TRACEVFORK       4
80 #define LINUX_PTRACE_O_TRACECLONE       8
81 #define LINUX_PTRACE_O_TRACEEXEC        16
82 #define LINUX_PTRACE_O_TRACEVFORKDONE   32
83 #define LINUX_PTRACE_O_TRACEEXIT        64
84 #define LINUX_PTRACE_O_TRACESECCOMP     128
85 #define LINUX_PTRACE_O_EXITKILL         1048576
86 #define LINUX_PTRACE_O_SUSPEND_SECCOMP  2097152
87
88 #define LINUX_NT_PRSTATUS               1
89
90 #define LINUX_PTRACE_O_MASK     (LINUX_PTRACE_O_TRACESYSGOOD |  \
91     LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK |      \
92     LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC |      \
93     LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT |  \
94     LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL |     \
95     LINUX_PTRACE_O_SUSPEND_SECCOMP)
96
97 static int
98 map_signum(int lsig, int *bsigp)
99 {
100         int bsig;
101
102         if (lsig == 0) {
103                 *bsigp = 0;
104                 return (0);
105         }
106
107         if (lsig < 0 || lsig > LINUX_SIGRTMAX)
108                 return (EINVAL);
109
110         bsig = linux_to_bsd_signal(lsig);
111         if (bsig == SIGSTOP)
112                 bsig = 0;
113
114         *bsigp = bsig;
115         return (0);
116 }
117
118 int
119 linux_ptrace_status(struct thread *td, pid_t pid, int status)
120 {
121         struct ptrace_lwpinfo lwpinfo;
122         struct linux_pemuldata *pem;
123         register_t saved_retval;
124         int error;
125
126         saved_retval = td->td_retval[0];
127         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
128         td->td_retval[0] = saved_retval;
129         if (error != 0) {
130                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
131                 return (status);
132         }
133
134         pem = pem_find(td->td_proc);
135         KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
136
137         LINUX_PEM_SLOCK(pem);
138         if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
139             lwpinfo.pl_flags & PL_FLAG_SCE)
140                 status |= (LINUX_SIGTRAP | 0x80) << 8;
141         if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
142             lwpinfo.pl_flags & PL_FLAG_SCX)
143                 status |= (LINUX_SIGTRAP | 0x80) << 8;
144         if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
145             lwpinfo.pl_flags & PL_FLAG_EXITED)
146                 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
147         LINUX_PEM_SUNLOCK(pem);
148
149         return (status);
150 }
151
152 struct linux_pt_reg {
153         l_ulong r15;
154         l_ulong r14;
155         l_ulong r13;
156         l_ulong r12;
157         l_ulong rbp;
158         l_ulong rbx;
159         l_ulong r11;
160         l_ulong r10;
161         l_ulong r9;
162         l_ulong r8;
163         l_ulong rax;
164         l_ulong rcx;
165         l_ulong rdx;
166         l_ulong rsi;
167         l_ulong rdi;
168         l_ulong orig_rax;
169         l_ulong rip;
170         l_ulong cs;
171         l_ulong eflags;
172         l_ulong rsp;
173         l_ulong ss;
174 };
175
176 struct linux_pt_regset {
177         l_ulong r15;
178         l_ulong r14;
179         l_ulong r13;
180         l_ulong r12;
181         l_ulong rbp;
182         l_ulong rbx;
183         l_ulong r11;
184         l_ulong r10;
185         l_ulong r9;
186         l_ulong r8;
187         l_ulong rax;
188         l_ulong rcx;
189         l_ulong rdx;
190         l_ulong rsi;
191         l_ulong rdi;
192         l_ulong orig_rax;
193         l_ulong rip;
194         l_ulong cs;
195         l_ulong eflags;
196         l_ulong rsp;
197         l_ulong ss;
198         l_ulong fs_base;
199         l_ulong gs_base;
200         l_ulong ds;
201         l_ulong es;
202         l_ulong fs;
203         l_ulong gs;
204 };
205
206 /*
207  * Translate amd64 ptrace registers between Linux and FreeBSD formats.
208  * The translation is pretty straighforward, for all registers but
209  * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
210  */
211 static void
212 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
213 {
214
215         l_reg->r15 = b_reg->r_r15;
216         l_reg->r14 = b_reg->r_r14;
217         l_reg->r13 = b_reg->r_r13;
218         l_reg->r12 = b_reg->r_r12;
219         l_reg->rbp = b_reg->r_rbp;
220         l_reg->rbx = b_reg->r_rbx;
221         l_reg->r11 = b_reg->r_r11;
222         l_reg->r10 = b_reg->r_r10;
223         l_reg->r9 = b_reg->r_r9;
224         l_reg->r8 = b_reg->r_r8;
225         l_reg->rax = b_reg->r_rax;
226         l_reg->rcx = b_reg->r_rcx;
227         l_reg->rdx = b_reg->r_rdx;
228         l_reg->rsi = b_reg->r_rsi;
229         l_reg->rdi = b_reg->r_rdi;
230         l_reg->orig_rax = b_reg->r_rax;
231         l_reg->rip = b_reg->r_rip;
232         l_reg->cs = b_reg->r_cs;
233         l_reg->eflags = b_reg->r_rflags;
234         l_reg->rsp = b_reg->r_rsp;
235         l_reg->ss = b_reg->r_ss;
236 }
237
238 static void
239 map_regs_to_linux_regset(struct reg *b_reg, unsigned long fs_base,
240     unsigned long gs_base, struct linux_pt_regset *l_regset)
241 {
242
243         l_regset->r15 = b_reg->r_r15;
244         l_regset->r14 = b_reg->r_r14;
245         l_regset->r13 = b_reg->r_r13;
246         l_regset->r12 = b_reg->r_r12;
247         l_regset->rbp = b_reg->r_rbp;
248         l_regset->rbx = b_reg->r_rbx;
249         l_regset->r11 = b_reg->r_r11;
250         l_regset->r10 = b_reg->r_r10;
251         l_regset->r9 = b_reg->r_r9;
252         l_regset->r8 = b_reg->r_r8;
253         l_regset->rax = b_reg->r_rax;
254         l_regset->rcx = b_reg->r_rcx;
255         l_regset->rdx = b_reg->r_rdx;
256         l_regset->rsi = b_reg->r_rsi;
257         l_regset->rdi = b_reg->r_rdi;
258         l_regset->orig_rax = b_reg->r_rax;
259         l_regset->rip = b_reg->r_rip;
260         l_regset->cs = b_reg->r_cs;
261         l_regset->eflags = b_reg->r_rflags;
262         l_regset->rsp = b_reg->r_rsp;
263         l_regset->ss = b_reg->r_ss;
264         l_regset->fs_base = fs_base;
265         l_regset->gs_base = gs_base;
266         l_regset->ds = b_reg->r_ds;
267         l_regset->es = b_reg->r_es;
268         l_regset->fs = b_reg->r_fs;
269         l_regset->gs = b_reg->r_gs;
270 }
271
272 static void
273 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
274 {
275         b_reg->r_r15 = l_reg->r15;
276         b_reg->r_r14 = l_reg->r14;
277         b_reg->r_r13 = l_reg->r13;
278         b_reg->r_r12 = l_reg->r12;
279         b_reg->r_r11 = l_reg->r11;
280         b_reg->r_r10 = l_reg->r10;
281         b_reg->r_r9 = l_reg->r9;
282         b_reg->r_r8 = l_reg->r8;
283         b_reg->r_rdi = l_reg->rdi;
284         b_reg->r_rsi = l_reg->rsi;
285         b_reg->r_rbp = l_reg->rbp;
286         b_reg->r_rbx = l_reg->rbx;
287         b_reg->r_rdx = l_reg->rdx;
288         b_reg->r_rcx = l_reg->rcx;
289         b_reg->r_rax = l_reg->rax;
290
291         /*
292          * XXX: Are zeroes the right thing to put here?
293          */
294         b_reg->r_trapno = 0;
295         b_reg->r_fs = 0;
296         b_reg->r_gs = 0;
297         b_reg->r_err = 0;
298         b_reg->r_es = 0;
299         b_reg->r_ds = 0;
300
301         b_reg->r_rip = l_reg->rip;
302         b_reg->r_cs = l_reg->cs;
303         b_reg->r_rflags = l_reg->eflags;
304         b_reg->r_rsp = l_reg->rsp;
305         b_reg->r_ss = l_reg->ss;
306 }
307
308 static int
309 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
310 {
311         int error;
312
313         error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
314         if (error == 0)
315                 error = copyout(td->td_retval, data, sizeof(l_int));
316         td->td_retval[0] = error;
317
318         return (error);
319 }
320
321 static int
322 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
323 {
324
325         linux_msg(td, "PTRACE_PEEKUSER not implemented; returning EINVAL");
326         return (EINVAL);
327 }
328
329 static int
330 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
331 {
332
333         linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
334         return (EINVAL);
335 }
336
337 static int
338 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
339 {
340         struct linux_pemuldata *pem;
341         int mask;
342
343         mask = 0;
344
345         if (data & ~LINUX_PTRACE_O_MASK) {
346                 linux_msg(td, "unknown ptrace option %lx set; "
347                     "returning EINVAL",
348                     data & ~LINUX_PTRACE_O_MASK);
349                 return (EINVAL);
350         }
351
352         pem = pem_find(td->td_proc);
353         KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
354
355         /*
356          * PTRACE_O_EXITKILL is ignored, we do that by default.
357          */
358
359         LINUX_PEM_XLOCK(pem);
360         if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
361                 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
362         } else {
363                 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
364         }
365         LINUX_PEM_XUNLOCK(pem);
366
367         if (data & LINUX_PTRACE_O_TRACEFORK)
368                 mask |= PTRACE_FORK;
369
370         if (data & LINUX_PTRACE_O_TRACEVFORK)
371                 mask |= PTRACE_VFORK;
372
373         if (data & LINUX_PTRACE_O_TRACECLONE)
374                 mask |= PTRACE_VFORK;
375
376         if (data & LINUX_PTRACE_O_TRACEEXEC)
377                 mask |= PTRACE_EXEC;
378
379         if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
380                 mask |= PTRACE_VFORK; /* XXX: Close enough? */
381
382         if (data & LINUX_PTRACE_O_TRACEEXIT) {
383                 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
384         } else {
385                 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
386         }
387
388         return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
389 }
390
391 static int
392 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
393 {
394         struct ptrace_lwpinfo lwpinfo;
395         l_siginfo_t l_siginfo;
396         int error, sig;
397
398         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
399         if (error != 0) {
400                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
401                 return (error);
402         }
403
404         if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
405                 error = EINVAL;
406                 linux_msg(td, "no PL_FLAG_SI, returning %d", error);
407                 return (error);
408         }
409
410         sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
411         siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
412         error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
413         return (error);
414 }
415
416 static int
417 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
418 {
419         struct ptrace_lwpinfo lwpinfo;
420         struct reg b_reg;
421         struct linux_pt_reg l_reg;
422         int error;
423
424         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
425         if (error != 0)
426                 return (error);
427
428         map_regs_to_linux(&b_reg, &l_reg);
429
430         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
431         if (error != 0) {
432                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
433                 return (error);
434         }
435         if (lwpinfo.pl_flags & PL_FLAG_SCE) {
436                 /*
437                  * The strace(1) utility depends on RAX being set to -ENOSYS
438                  * on syscall entry; otherwise it loops printing those:
439                  *
440                  * [ Process PID=928 runs in 64 bit mode. ]
441                  * [ Process PID=928 runs in x32 mode. ]
442                  */
443                 l_reg.rax = -38; /* -ENOSYS */
444
445                 /*
446                  * Undo the mangling done in exception.S:fast_syscall_common().
447                  */
448                 l_reg.r10 = l_reg.rcx;
449         }
450
451         error = copyout(&l_reg, (void *)data, sizeof(l_reg));
452         return (error);
453 }
454
455 static int
456 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
457 {
458         struct reg b_reg;
459         struct linux_pt_reg l_reg;
460         int error;
461
462         error = copyin(data, &l_reg, sizeof(l_reg));
463         if (error != 0)
464                 return (error);
465         map_regs_from_linux(&b_reg, &l_reg);
466         error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
467         return (error);
468 }
469
470 static int
471 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
472 {
473         struct ptrace_lwpinfo lwpinfo;
474         struct reg b_reg;
475         struct linux_pt_regset l_regset;
476         struct iovec iov;
477         struct pcb *pcb;
478         unsigned long fsbase, gsbase;
479         size_t len;
480         int error;
481
482         error = copyin((const void *)data, &iov, sizeof(iov));
483         if (error != 0) {
484                 linux_msg(td, "copyin error %d", error);
485                 return (error);
486         }
487
488         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
489         if (error != 0)
490                 return (error);
491
492         pcb = td->td_pcb;
493         if (td == curthread)
494                 update_pcb_bases(pcb);
495         fsbase = pcb->pcb_fsbase;
496         gsbase = pcb->pcb_gsbase;
497
498         map_regs_to_linux_regset(&b_reg, fsbase, gsbase, &l_regset);
499
500         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
501         if (error != 0) {
502                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
503                 return (error);
504         }
505         if (lwpinfo.pl_flags & PL_FLAG_SCE) {
506                 /*
507                  * The strace(1) utility depends on RAX being set to -ENOSYS
508                  * on syscall entry; otherwise it loops printing those:
509                  *
510                  * [ Process PID=928 runs in 64 bit mode. ]
511                  * [ Process PID=928 runs in x32 mode. ]
512                  */
513                 l_regset.rax = -38; /* -ENOSYS */
514
515                 /*
516                  * Undo the mangling done in exception.S:fast_syscall_common().
517                  */
518                 l_regset.r10 = l_regset.rcx;
519         }
520
521         len = MIN(iov.iov_len, sizeof(l_regset));
522         error = copyout(&l_regset, (void *)iov.iov_base, len);
523         if (error != 0) {
524                 linux_msg(td, "copyout error %d", error);
525                 return (error);
526         }
527
528         iov.iov_len -= len;
529         error = copyout(&iov, (void *)data, sizeof(iov));
530         if (error != 0) {
531                 linux_msg(td, "iov copyout error %d", error);
532                 return (error);
533         }
534
535         return (error);
536 }
537
538 static int
539 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
540 {
541
542         switch (addr) {
543         case LINUX_NT_PRSTATUS:
544                 return (linux_ptrace_getregset_prstatus(td, pid, data));
545         default:
546                 linux_msg(td, "PTRACE_GETREGSET request %ld not implemented; "
547                     "returning EINVAL", addr);
548                 return (EINVAL);
549         }
550 }
551
552 static int
553 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
554 {
555
556         linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
557         return (EINVAL);
558 }
559
560 static int
561 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
562 {
563
564         linux_msg(td, "PTRACE_GET_SYSCALL_INFO not implemented; returning EINVAL");
565         return (EINVAL);
566 }
567
568 int
569 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
570 {
571         void *addr;
572         pid_t pid;
573         int error, sig;
574
575         pid  = (pid_t)uap->pid;
576         addr = (void *)uap->addr;
577
578         switch (uap->req) {
579         case LINUX_PTRACE_TRACEME:
580                 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
581                 break;
582         case LINUX_PTRACE_PEEKTEXT:
583         case LINUX_PTRACE_PEEKDATA:
584                 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
585                 if (error != 0)
586                         return (error);
587                 /*
588                  * Linux expects this syscall to read 64 bits, not 32.
589                  */
590                 error = linux_ptrace_peek(td, pid,
591                     (void *)(uap->addr + 4), (void *)(uap->data + 4));
592                 break;
593         case LINUX_PTRACE_PEEKUSER:
594                 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
595                 break;
596         case LINUX_PTRACE_POKETEXT:
597                 error = kern_ptrace(td, PT_WRITE_I, pid, addr, uap->data);
598                 break;
599         case LINUX_PTRACE_POKEDATA:
600                 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
601                 break;
602         case LINUX_PTRACE_POKEUSER:
603                 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
604                 break;
605         case LINUX_PTRACE_CONT:
606                 error = map_signum(uap->data, &sig);
607                 if (error != 0)
608                         break;
609                 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
610                 break;
611         case LINUX_PTRACE_KILL:
612                 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
613                 break;
614         case LINUX_PTRACE_SINGLESTEP:
615                 error = map_signum(uap->data, &sig);
616                 if (error != 0)
617                         break;
618                 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
619                 break;
620         case LINUX_PTRACE_GETREGS:
621                 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
622                 break;
623         case LINUX_PTRACE_SETREGS:
624                 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
625                 break;
626         case LINUX_PTRACE_ATTACH:
627                 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
628                 break;
629         case LINUX_PTRACE_DETACH:
630                 error = map_signum(uap->data, &sig);
631                 if (error != 0)
632                         break;
633                 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
634                 break;
635         case LINUX_PTRACE_SYSCALL:
636                 error = map_signum(uap->data, &sig);
637                 if (error != 0)
638                         break;
639                 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
640                 break;
641         case LINUX_PTRACE_SETOPTIONS:
642                 error = linux_ptrace_setoptions(td, pid, uap->data);
643                 break;
644         case LINUX_PTRACE_GETSIGINFO:
645                 error = linux_ptrace_getsiginfo(td, pid, uap->data);
646                 break;
647         case LINUX_PTRACE_GETREGSET:
648                 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
649                 break;
650         case LINUX_PTRACE_SEIZE:
651                 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
652                 break;
653         case LINUX_PTRACE_GET_SYSCALL_INFO:
654                 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
655                 break;
656         default:
657                 linux_msg(td, "ptrace(%ld, ...) not implemented; "
658                     "returning EINVAL", uap->req);
659                 error = EINVAL;
660                 break;
661         }
662
663         return (error);
664 }