xref: /freebsd/sys/compat/linux/linux_ptrace.c (revision 1323ec57)
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 }
619