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