]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linux/linux_ptrace.c
bsddialog: import version 0.1
[FreeBSD/FreeBSD.git] / sys / compat / 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/../linux/linux.h>
43 #include <machine/../linux/linux_proto.h>
44 #include <compat/linux/linux_emul.h>
45 #include <compat/linux/linux_errno.h>
46 #include <compat/linux/linux_misc.h>
47 #include <compat/linux/linux_signal.h>
48 #include <compat/linux/linux_util.h>
49
50 #define LINUX_PTRACE_TRACEME            0
51 #define LINUX_PTRACE_PEEKTEXT           1
52 #define LINUX_PTRACE_PEEKDATA           2
53 #define LINUX_PTRACE_PEEKUSER           3
54 #define LINUX_PTRACE_POKETEXT           4
55 #define LINUX_PTRACE_POKEDATA           5
56 #define LINUX_PTRACE_POKEUSER           6
57 #define LINUX_PTRACE_CONT               7
58 #define LINUX_PTRACE_KILL               8
59 #define LINUX_PTRACE_SINGLESTEP         9
60 #define LINUX_PTRACE_GETREGS            12
61 #define LINUX_PTRACE_SETREGS            13
62 #define LINUX_PTRACE_GETFPREGS          14
63 #define LINUX_PTRACE_SETFPREGS          15
64 #define LINUX_PTRACE_ATTACH             16
65 #define LINUX_PTRACE_DETACH             17
66 #define LINUX_PTRACE_SYSCALL            24
67 #define LINUX_PTRACE_SETOPTIONS         0x4200
68 #define LINUX_PTRACE_GETEVENTMSG        0x4201
69 #define LINUX_PTRACE_GETSIGINFO         0x4202
70 #define LINUX_PTRACE_GETREGSET          0x4204
71 #define LINUX_PTRACE_SEIZE              0x4206
72 #define LINUX_PTRACE_GET_SYSCALL_INFO   0x420e
73
74 #define LINUX_PTRACE_EVENT_EXEC         4
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               0x1
89 #define LINUX_NT_PRFPREG                0x2
90 #define LINUX_NT_X86_XSTATE             0x202
91
92 #define LINUX_PTRACE_O_MASK     (LINUX_PTRACE_O_TRACESYSGOOD |  \
93     LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK |      \
94     LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC |      \
95     LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT |  \
96     LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL |     \
97     LINUX_PTRACE_O_SUSPEND_SECCOMP)
98
99 #define LINUX_PTRACE_SYSCALL_INFO_NONE  0
100 #define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1
101 #define LINUX_PTRACE_SYSCALL_INFO_EXIT  2
102
103 #define LINUX_PTRACE_PEEKUSER_ORIG_RAX  120
104 #define LINUX_PTRACE_PEEKUSER_RIP       128
105 #define LINUX_PTRACE_PEEKUSER_CS        136
106 #define LINUX_PTRACE_PEEKUSER_DS        184
107
108 static int
109 map_signum(int lsig, int *bsigp)
110 {
111         int bsig;
112
113         if (lsig == 0) {
114                 *bsigp = 0;
115                 return (0);
116         }
117
118         if (lsig < 0 || lsig > LINUX_SIGRTMAX)
119                 return (EINVAL);
120
121         bsig = linux_to_bsd_signal(lsig);
122         if (bsig == SIGSTOP)
123                 bsig = 0;
124
125         *bsigp = bsig;
126         return (0);
127 }
128
129 int
130 linux_ptrace_status(struct thread *td, pid_t pid, int status)
131 {
132         struct ptrace_lwpinfo lwpinfo;
133         struct linux_pemuldata *pem;
134         register_t saved_retval;
135         int error;
136
137         saved_retval = td->td_retval[0];
138         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
139         td->td_retval[0] = saved_retval;
140         if (error != 0) {
141                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
142                 return (status);
143         }
144
145         pem = pem_find(td->td_proc);
146         KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
147
148         LINUX_PEM_SLOCK(pem);
149         if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
150             lwpinfo.pl_flags & PL_FLAG_SCE)
151                 status |= (LINUX_SIGTRAP | 0x80) << 8;
152         if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
153             lwpinfo.pl_flags & PL_FLAG_SCX) {
154                 if (lwpinfo.pl_flags & PL_FLAG_EXEC)
155                         status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
156                 else
157                         status |= (LINUX_SIGTRAP | 0x80) << 8;
158         }
159         if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
160             lwpinfo.pl_flags & PL_FLAG_EXITED)
161                 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
162         LINUX_PEM_SUNLOCK(pem);
163
164         return (status);
165 }
166
167 static int
168 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
169 {
170         int error;
171
172         error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
173         if (error == 0)
174                 error = copyout(td->td_retval, data, sizeof(l_int));
175         else if (error == ENOMEM)
176                 error = EIO;
177         td->td_retval[0] = error;
178
179         return (error);
180 }
181
182 static int
183 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
184 {
185         struct reg b_reg;
186         uint64_t val;
187         int error;
188
189         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
190         if (error != 0)
191                 return (error);
192
193         switch ((uintptr_t)addr) {
194 #ifdef __amd64__
195         case LINUX_PTRACE_PEEKUSER_ORIG_RAX:
196                 val = b_reg.r_rax;
197                 break;
198         case LINUX_PTRACE_PEEKUSER_RIP:
199                 val = b_reg.r_rip;
200                 break;
201         case LINUX_PTRACE_PEEKUSER_CS:
202                 val = b_reg.r_cs;
203                 break;
204         case LINUX_PTRACE_PEEKUSER_DS:
205                 val = b_reg.r_ds;
206                 break;
207 #endif /* __amd64__ */
208         default:
209                 linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; "
210                     "returning EINVAL", (uintptr_t)addr);
211                 return (EINVAL);
212         }
213
214         error = copyout(&val, data, sizeof(val));
215         td->td_retval[0] = error;
216
217         return (error);
218 }
219
220 static int
221 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
222 {
223
224         linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
225         return (EINVAL);
226 }
227
228 static int
229 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
230 {
231         struct linux_pemuldata *pem;
232         int mask;
233
234         mask = 0;
235
236         if (data & ~LINUX_PTRACE_O_MASK) {
237                 linux_msg(td, "unknown ptrace option %lx set; "
238                     "returning EINVAL",
239                     data & ~LINUX_PTRACE_O_MASK);
240                 return (EINVAL);
241         }
242
243         pem = pem_find(td->td_proc);
244         KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
245
246         /*
247          * PTRACE_O_EXITKILL is ignored, we do that by default.
248          */
249
250         LINUX_PEM_XLOCK(pem);
251         if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
252                 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
253         } else {
254                 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
255         }
256         LINUX_PEM_XUNLOCK(pem);
257
258         if (data & LINUX_PTRACE_O_TRACEFORK)
259                 mask |= PTRACE_FORK;
260
261         if (data & LINUX_PTRACE_O_TRACEVFORK)
262                 mask |= PTRACE_VFORK;
263
264         if (data & LINUX_PTRACE_O_TRACECLONE)
265                 mask |= PTRACE_VFORK;
266
267         if (data & LINUX_PTRACE_O_TRACEEXEC)
268                 mask |= PTRACE_EXEC;
269
270         if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
271                 mask |= PTRACE_VFORK; /* XXX: Close enough? */
272
273         if (data & LINUX_PTRACE_O_TRACEEXIT) {
274                 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
275         } else {
276                 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
277         }
278
279         return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
280 }
281
282 static int
283 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
284 {
285
286         linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
287         return (EINVAL);
288 }
289
290 static int
291 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
292 {
293         struct ptrace_lwpinfo lwpinfo;
294         l_siginfo_t l_siginfo;
295         int error, sig;
296
297         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
298         if (error != 0) {
299                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
300                 return (error);
301         }
302
303         if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
304                 error = EINVAL;
305                 linux_msg(td, "no PL_FLAG_SI, returning %d", error);
306                 return (error);
307         }
308
309         sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
310         memset(&l_siginfo, 0, sizeof(l_siginfo));
311         siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
312         error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
313         return (error);
314 }
315
316 static int
317 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
318 {
319         struct reg b_reg;
320         struct linux_pt_regset l_regset;
321         int error;
322
323         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
324         if (error != 0)
325                 return (error);
326
327         bsd_to_linux_regset(&b_reg, &l_regset);
328         error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
329         if (error != 0)
330                 return (error);
331
332         error = copyout(&l_regset, (void *)data, sizeof(l_regset));
333         return (error);
334 }
335
336 static int
337 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
338 {
339         struct reg b_reg;
340         struct linux_pt_regset l_regset;
341         int error;
342
343         error = copyin(data, &l_regset, sizeof(l_regset));
344         if (error != 0)
345                 return (error);
346         linux_to_bsd_regset(&b_reg, &l_regset);
347         error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
348         return (error);
349 }
350
351 static int
352 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
353 {
354         struct reg b_reg;
355         struct linux_pt_regset l_regset;
356         struct iovec iov;
357         size_t len;
358         int error;
359
360         error = copyin((const void *)data, &iov, sizeof(iov));
361         if (error != 0) {
362                 linux_msg(td, "copyin error %d", error);
363                 return (error);
364         }
365
366         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
367         if (error != 0)
368                 return (error);
369
370         bsd_to_linux_regset(&b_reg, &l_regset);
371         error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
372         if (error != 0)
373                 return (error);
374
375         len = MIN(iov.iov_len, sizeof(l_regset));
376         error = copyout(&l_regset, (void *)iov.iov_base, len);
377         if (error != 0) {
378                 linux_msg(td, "copyout error %d", error);
379                 return (error);
380         }
381
382         iov.iov_len = len;
383         error = copyout(&iov, (void *)data, sizeof(iov));
384         if (error != 0) {
385                 linux_msg(td, "iov copyout error %d", error);
386                 return (error);
387         }
388
389         return (error);
390 }
391
392 static int
393 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
394 {
395
396         switch (addr) {
397         case LINUX_NT_PRSTATUS:
398                 return (linux_ptrace_getregset_prstatus(td, pid, data));
399         case LINUX_NT_PRFPREG:
400                 linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
401                     "returning EINVAL");
402                 return (EINVAL);
403         case LINUX_NT_X86_XSTATE:
404                 linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
405                     "returning EINVAL");
406                 return (EINVAL);
407         default:
408                 linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
409                     "returning EINVAL", addr);
410                 return (EINVAL);
411         }
412 }
413
414 static int
415 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
416 {
417
418         linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
419         return (EINVAL);
420 }
421
422 static int
423 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
424     l_ulong len, l_ulong data)
425 {
426         struct ptrace_lwpinfo lwpinfo;
427         struct ptrace_sc_ret sr;
428         struct reg b_reg;
429         struct syscall_info si;
430         int error;
431
432         error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
433         if (error != 0) {
434                 linux_msg(td, "PT_LWPINFO failed with error %d", error);
435                 return (error);
436         }
437
438         memset(&si, 0, sizeof(si));
439
440         if (lwpinfo.pl_flags & PL_FLAG_SCE) {
441                 si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
442                 si.entry.nr = lwpinfo.pl_syscall_code;
443                 /*
444                  * The use of PT_GET_SC_ARGS there is special,
445                  * implementation of PT_GET_SC_ARGS for Linux-ABI
446                  * callers emulates Linux bug which strace(1) depends
447                  * on: at initialization it tests whether ptrace works
448                  * by calling close(2), or some other single-argument
449                  * syscall, _with six arguments_, and then verifies
450                  * whether it can fetch them all using this API;
451                  * otherwise it bails out.
452                  */
453                 error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
454                     &si.entry.args, sizeof(si.entry.args));
455                 if (error != 0) {
456                         linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
457                             error);
458                         return (error);
459                 }
460         } else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
461                 si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
462                 error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
463
464                 if (error != 0) {
465                         linux_msg(td, "PT_GET_SC_RET failed with error %d",
466                             error);
467                         return (error);
468                 }
469
470                 if (sr.sr_error == 0) {
471                         si.exit.rval = sr.sr_retval[0];
472                         si.exit.is_error = 0;
473                 } else if (sr.sr_error == EJUSTRETURN) {
474                         /*
475                          * EJUSTRETURN means the actual value to return
476                          * has already been put into td_frame; instead
477                          * of extracting it and trying to determine whether
478                          * it's an error or not just bail out and let
479                          * the ptracing process fall back to another method.
480                          */
481                         si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
482                 } else if (sr.sr_error == ERESTART) {
483                         si.exit.rval = -LINUX_ERESTARTSYS;
484                         si.exit.is_error = 1;
485                 } else {
486                         si.exit.rval = bsd_to_linux_errno(sr.sr_error);
487                         si.exit.is_error = 1;
488                 }
489         } else {
490                 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
491         }
492
493         error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
494         if (error != 0)
495                 return (error);
496
497         linux_ptrace_get_syscall_info_machdep(&b_reg, &si);
498
499         len = MIN(len, sizeof(si));
500         error = copyout(&si, (void *)data, len);
501         if (error == 0)
502                 td->td_retval[0] = sizeof(si);
503
504         return (error);
505 }
506
507 int
508 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
509 {
510         void *addr;
511         pid_t pid;
512         int error, sig;
513
514         if (!allow_ptrace)
515                 return (ENOSYS);
516
517         pid  = (pid_t)uap->pid;
518         addr = (void *)uap->addr;
519
520         switch (uap->req) {
521         case LINUX_PTRACE_TRACEME:
522                 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
523                 break;
524         case LINUX_PTRACE_PEEKTEXT:
525         case LINUX_PTRACE_PEEKDATA:
526                 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
527                 if (error != 0)
528                         goto out;
529                 /*
530                  * Linux expects this syscall to read 64 bits, not 32.
531                  */
532                 error = linux_ptrace_peek(td, pid,
533                     (void *)(uap->addr + 4), (void *)(uap->data + 4));
534                 break;
535         case LINUX_PTRACE_PEEKUSER:
536                 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
537                 break;
538         case LINUX_PTRACE_POKETEXT:
539         case LINUX_PTRACE_POKEDATA:
540                 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
541                 if (error != 0)
542                         goto out;
543                 /*
544                  * Linux expects this syscall to write 64 bits, not 32.
545                  */
546                 error = kern_ptrace(td, PT_WRITE_D, pid,
547                     (void *)(uap->addr + 4), uap->data >> 32);
548                 break;
549         case LINUX_PTRACE_POKEUSER:
550                 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
551                 break;
552         case LINUX_PTRACE_CONT:
553                 error = map_signum(uap->data, &sig);
554                 if (error != 0)
555                         break;
556                 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
557                 break;
558         case LINUX_PTRACE_KILL:
559                 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
560                 break;
561         case LINUX_PTRACE_SINGLESTEP:
562                 error = map_signum(uap->data, &sig);
563                 if (error != 0)
564                         break;
565                 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
566                 break;
567         case LINUX_PTRACE_GETREGS:
568                 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
569                 break;
570         case LINUX_PTRACE_SETREGS:
571                 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
572                 break;
573         case LINUX_PTRACE_ATTACH:
574                 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
575                 break;
576         case LINUX_PTRACE_DETACH:
577                 error = map_signum(uap->data, &sig);
578                 if (error != 0)
579                         break;
580                 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
581                 break;
582         case LINUX_PTRACE_SYSCALL:
583                 error = map_signum(uap->data, &sig);
584                 if (error != 0)
585                         break;
586                 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
587                 break;
588         case LINUX_PTRACE_SETOPTIONS:
589                 error = linux_ptrace_setoptions(td, pid, uap->data);
590                 break;
591         case LINUX_PTRACE_GETEVENTMSG:
592                 error = linux_ptrace_geteventmsg(td, pid, uap->data);
593                 break;
594         case LINUX_PTRACE_GETSIGINFO:
595                 error = linux_ptrace_getsiginfo(td, pid, uap->data);
596                 break;
597         case LINUX_PTRACE_GETREGSET:
598                 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
599                 break;
600         case LINUX_PTRACE_SEIZE:
601                 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
602                 break;
603         case LINUX_PTRACE_GET_SYSCALL_INFO:
604                 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
605                 break;
606         default:
607                 linux_msg(td, "ptrace(%ld, ...) not implemented; "
608                     "returning EINVAL", uap->req);
609                 error = EINVAL;
610                 break;
611         }
612
613 out:
614         if (error == EBUSY)
615                 error = ESRCH;
616
617         return (error);
618 }