]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/linux/linux_ptrace.c
one-true-awk: import 20210221 (1e4bc42c53a1) which fixes a number of bugs
[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 /*
177  * Translate amd64 ptrace registers between Linux and FreeBSD formats.
178  * The translation is pretty straighforward, for all registers but
179  * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
180  */
181 static void
182 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
183 {
184
185         l_reg->r15 = b_reg->r_r15;
186         l_reg->r14 = b_reg->r_r14;
187         l_reg->r13 = b_reg->r_r13;
188         l_reg->r12 = b_reg->r_r12;
189         l_reg->rbp = b_reg->r_rbp;
190         l_reg->rbx = b_reg->r_rbx;
191         l_reg->r11 = b_reg->r_r11;
192         l_reg->r10 = b_reg->r_r10;
193         l_reg->r9 = b_reg->r_r9;
194         l_reg->r8 = b_reg->r_r8;
195         l_reg->rax = b_reg->r_rax;
196         l_reg->rcx = b_reg->r_rcx;
197         l_reg->rdx = b_reg->r_rdx;
198         l_reg->rsi = b_reg->r_rsi;
199         l_reg->rdi = b_reg->r_rdi;
200         l_reg->orig_rax = b_reg->r_rax;
201         l_reg->rip = b_reg->r_rip;
202         l_reg->cs = b_reg->r_cs;
203         l_reg->eflags = b_reg->r_rflags;
204         l_reg->rsp = b_reg->r_rsp;
205         l_reg->ss = b_reg->r_ss;
206 }
207
208 static void
209 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
210 {
211         b_reg->r_r15 = l_reg->r15;
212         b_reg->r_r14 = l_reg->r14;
213         b_reg->r_r13 = l_reg->r13;
214         b_reg->r_r12 = l_reg->r12;
215         b_reg->r_r11 = l_reg->r11;
216         b_reg->r_r10 = l_reg->r10;
217         b_reg->r_r9 = l_reg->r9;
218         b_reg->r_r8 = l_reg->r8;
219         b_reg->r_rdi = l_reg->rdi;
220         b_reg->r_rsi = l_reg->rsi;
221         b_reg->r_rbp = l_reg->rbp;
222         b_reg->r_rbx = l_reg->rbx;
223         b_reg->r_rdx = l_reg->rdx;
224         b_reg->r_rcx = l_reg->rcx;
225         b_reg->r_rax = l_reg->rax;
226
227         /*
228          * XXX: Are zeroes the right thing to put here?
229          */
230         b_reg->r_trapno = 0;
231         b_reg->r_fs = 0;
232         b_reg->r_gs = 0;
233         b_reg->r_err = 0;
234         b_reg->r_es = 0;
235         b_reg->r_ds = 0;
236
237         b_reg->r_rip = l_reg->rip;
238         b_reg->r_cs = l_reg->cs;
239         b_reg->r_rflags = l_reg->eflags;
240         b_reg->r_rsp = l_reg->rsp;
241         b_reg->r_ss = l_reg->ss;
242 }
243
244 static int
245 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
246 {
247         int error;
248
249         error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
250         if (error == 0)
251                 error = copyout(td->td_retval, data, sizeof(l_int));
252         else if (error == ENOMEM)
253                 error = EIO;
254         td->td_retval[0] = error;
255
256         return (error);
257 }
258
259 static int
260 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
261 {
262
263         linux_msg(td, "PTRACE_PEEKUSER not implemented; returning EINVAL");
264         return (EINVAL);
265 }
266
267 static int
268 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
269 {
270
271         linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
272         return (EINVAL);
273 }
274
275 static int
276 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
277 {
278         struct linux_pemuldata *pem;
279         int mask;
280
281         mask = 0;
282
283         if (data & ~LINUX_PTRACE_O_MASK) {
284                 linux_msg(td, "unknown ptrace option %lx set; "
285                     "returning EINVAL",
286                     data & ~LINUX_PTRACE_O_MASK);
287                 return (EINVAL);
288         }
289
290         pem = pem_find(td->td_proc);
291         KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
292
293         /*
294          * PTRACE_O_EXITKILL is ignored, we do that by default.
295          */
296
297         LINUX_PEM_XLOCK(pem);
298         if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
299                 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
300         } else {
301                 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
302         }
303         LINUX_PEM_XUNLOCK(pem);
304
305         if (data & LINUX_PTRACE_O_TRACEFORK)
306                 mask |= PTRACE_FORK;
307
308         if (data & LINUX_PTRACE_O_TRACEVFORK)
309                 mask |= PTRACE_VFORK;
310
311         if (data & LINUX_PTRACE_O_TRACECLONE)
312                 mask |= PTRACE_VFORK;
313
314         if (data & LINUX_PTRACE_O_TRACEEXEC)
315                 mask |= PTRACE_EXEC;
316
317         if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
318                 mask |= PTRACE_VFORK; /* XXX: Close enough? */
319
320         if (data & LINUX_PTRACE_O_TRACEEXIT) {
321                 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
322         } else {
323                 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
324         }
325
326         return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
327 }
328
329 static int
330 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
331 {
332         struct ptrace_lwpinfo lwpinfo;
333         l_siginfo_t l_siginfo;
334         int error, sig;
335
336         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
337         if (error != 0) {
338                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
339                 return (error);
340         }
341
342         if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
343                 error = EINVAL;
344                 linux_msg(td, "no PL_FLAG_SI, returning %d", error);
345                 return (error);
346         }
347
348         sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
349         memset(&l_siginfo, 0, sizeof(l_siginfo));
350         siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
351         error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
352         return (error);
353 }
354
355 static int
356 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
357 {
358         struct ptrace_lwpinfo lwpinfo;
359         struct reg b_reg;
360         struct linux_pt_reg l_reg;
361         int error;
362
363         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
364         if (error != 0)
365                 return (error);
366
367         map_regs_to_linux(&b_reg, &l_reg);
368
369         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
370         if (error != 0) {
371                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
372                 return (error);
373         }
374         if (lwpinfo.pl_flags & PL_FLAG_SCE) {
375                 /*
376                  * The strace(1) utility depends on RAX being set to -ENOSYS
377                  * on syscall entry; otherwise it loops printing those:
378                  *
379                  * [ Process PID=928 runs in 64 bit mode. ]
380                  * [ Process PID=928 runs in x32 mode. ]
381                  */
382                 l_reg.rax = -38; /* -ENOSYS */
383
384                 /*
385                  * Undo the mangling done in exception.S:fast_syscall_common().
386                  */
387                 l_reg.r10 = l_reg.rcx;
388         }
389
390         error = copyout(&l_reg, (void *)data, sizeof(l_reg));
391         return (error);
392 }
393
394 static int
395 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
396 {
397         struct reg b_reg;
398         struct linux_pt_reg l_reg;
399         int error;
400
401         error = copyin(data, &l_reg, sizeof(l_reg));
402         if (error != 0)
403                 return (error);
404         map_regs_from_linux(&b_reg, &l_reg);
405         error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
406         return (error);
407 }
408
409 static int
410 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
411 {
412         struct ptrace_lwpinfo lwpinfo;
413         struct reg b_reg;
414         struct linux_pt_regset l_regset;
415         struct iovec iov;
416         struct pcb *pcb;
417         size_t len;
418         int error;
419
420         error = copyin((const void *)data, &iov, sizeof(iov));
421         if (error != 0) {
422                 linux_msg(td, "copyin error %d", error);
423                 return (error);
424         }
425
426         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
427         if (error != 0)
428                 return (error);
429
430         pcb = td->td_pcb;
431         if (td == curthread)
432                 update_pcb_bases(pcb);
433
434         bsd_to_linux_regset(&b_reg, &l_regset);
435         l_regset.fs_base = pcb->pcb_fsbase;
436         l_regset.gs_base = pcb->pcb_gsbase;
437
438         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
439         if (error != 0) {
440                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
441                 return (error);
442         }
443         if (lwpinfo.pl_flags & PL_FLAG_SCE) {
444                 /*
445                  * Undo the mangling done in exception.S:fast_syscall_common().
446                  */
447                 l_regset.r10 = l_regset.rcx;
448         }
449
450         if (lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) {
451                 /*
452                  * In Linux, the syscall number - passed to the syscall
453                  * as rax - is preserved in orig_rax; rax gets overwritten
454                  * with syscall return value.
455                  */
456                 l_regset.orig_rax = lwpinfo.pl_syscall_code;
457         }
458
459         len = MIN(iov.iov_len, sizeof(l_regset));
460         error = copyout(&l_regset, (void *)iov.iov_base, len);
461         if (error != 0) {
462                 linux_msg(td, "copyout error %d", error);
463                 return (error);
464         }
465
466         iov.iov_len -= len;
467         error = copyout(&iov, (void *)data, sizeof(iov));
468         if (error != 0) {
469                 linux_msg(td, "iov copyout error %d", error);
470                 return (error);
471         }
472
473         return (error);
474 }
475
476 static int
477 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
478 {
479
480         switch (addr) {
481         case LINUX_NT_PRSTATUS:
482                 return (linux_ptrace_getregset_prstatus(td, pid, data));
483         default:
484                 linux_msg(td, "PTRACE_GETREGSET request %ld not implemented; "
485                     "returning EINVAL", addr);
486                 return (EINVAL);
487         }
488 }
489
490 static int
491 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
492 {
493
494         linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
495         return (EINVAL);
496 }
497
498 static int
499 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
500 {
501
502         linux_msg(td, "PTRACE_GET_SYSCALL_INFO not implemented; returning EINVAL");
503         return (EINVAL);
504 }
505
506 int
507 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
508 {
509         void *addr;
510         pid_t pid;
511         int error, sig;
512
513         pid  = (pid_t)uap->pid;
514         addr = (void *)uap->addr;
515
516         switch (uap->req) {
517         case LINUX_PTRACE_TRACEME:
518                 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
519                 break;
520         case LINUX_PTRACE_PEEKTEXT:
521         case LINUX_PTRACE_PEEKDATA:
522                 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
523                 if (error != 0)
524                         goto out;
525                 /*
526                  * Linux expects this syscall to read 64 bits, not 32.
527                  */
528                 error = linux_ptrace_peek(td, pid,
529                     (void *)(uap->addr + 4), (void *)(uap->data + 4));
530                 break;
531         case LINUX_PTRACE_PEEKUSER:
532                 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
533                 break;
534         case LINUX_PTRACE_POKETEXT:
535         case LINUX_PTRACE_POKEDATA:
536                 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
537                 if (error != 0)
538                         goto out;
539                 /*
540                  * Linux expects this syscall to write 64 bits, not 32.
541                  */
542                 error = kern_ptrace(td, PT_WRITE_D, pid,
543                     (void *)(uap->addr + 4), uap->data >> 32);
544                 break;
545         case LINUX_PTRACE_POKEUSER:
546                 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
547                 break;
548         case LINUX_PTRACE_CONT:
549                 error = map_signum(uap->data, &sig);
550                 if (error != 0)
551                         break;
552                 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
553                 break;
554         case LINUX_PTRACE_KILL:
555                 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
556                 break;
557         case LINUX_PTRACE_SINGLESTEP:
558                 error = map_signum(uap->data, &sig);
559                 if (error != 0)
560                         break;
561                 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
562                 break;
563         case LINUX_PTRACE_GETREGS:
564                 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
565                 break;
566         case LINUX_PTRACE_SETREGS:
567                 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
568                 break;
569         case LINUX_PTRACE_ATTACH:
570                 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
571                 break;
572         case LINUX_PTRACE_DETACH:
573                 error = map_signum(uap->data, &sig);
574                 if (error != 0)
575                         break;
576                 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
577                 break;
578         case LINUX_PTRACE_SYSCALL:
579                 error = map_signum(uap->data, &sig);
580                 if (error != 0)
581                         break;
582                 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
583                 break;
584         case LINUX_PTRACE_SETOPTIONS:
585                 error = linux_ptrace_setoptions(td, pid, uap->data);
586                 break;
587         case LINUX_PTRACE_GETSIGINFO:
588                 error = linux_ptrace_getsiginfo(td, pid, uap->data);
589                 break;
590         case LINUX_PTRACE_GETREGSET:
591                 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
592                 break;
593         case LINUX_PTRACE_SEIZE:
594                 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
595                 break;
596         case LINUX_PTRACE_GET_SYSCALL_INFO:
597                 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
598                 break;
599         default:
600                 linux_msg(td, "ptrace(%ld, ...) not implemented; "
601                     "returning EINVAL", uap->req);
602                 error = EINVAL;
603                 break;
604         }
605
606 out:
607         if (error == EBUSY)
608                 error = ESRCH;
609
610         return (error);
611 }