xref: /freebsd/sys/compat/linux/linux_ptrace.c (revision 3460fab5fced39c7ea597cc7de0ebc3e4c88989a)
1a90ff3c4SEdward Tomasz Napierala /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3a90ff3c4SEdward Tomasz Napierala  *
4a90ff3c4SEdward Tomasz Napierala  * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
5a90ff3c4SEdward Tomasz Napierala  *
6a90ff3c4SEdward Tomasz Napierala  * This software was developed by SRI International and the University of
7a90ff3c4SEdward Tomasz Napierala  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8a90ff3c4SEdward Tomasz Napierala  * ("CTSRD"), as part of the DARPA CRASH research programme.
9a90ff3c4SEdward Tomasz Napierala  *
10a90ff3c4SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
11a90ff3c4SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
12a90ff3c4SEdward Tomasz Napierala  * are met:
13a90ff3c4SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
14a90ff3c4SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
15a90ff3c4SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
16a90ff3c4SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
17a90ff3c4SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
18a90ff3c4SEdward Tomasz Napierala  *
19a90ff3c4SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20a90ff3c4SEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21a90ff3c4SEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22a90ff3c4SEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23a90ff3c4SEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24a90ff3c4SEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25a90ff3c4SEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26a90ff3c4SEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27a90ff3c4SEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28a90ff3c4SEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29a90ff3c4SEdward Tomasz Napierala  * SUCH DAMAGE.
30a90ff3c4SEdward Tomasz Napierala  */
31a90ff3c4SEdward Tomasz Napierala 
32a90ff3c4SEdward Tomasz Napierala #include <sys/param.h>
33a90ff3c4SEdward Tomasz Napierala #include <sys/lock.h>
34a90ff3c4SEdward Tomasz Napierala #include <sys/proc.h>
35a90ff3c4SEdward Tomasz Napierala #include <sys/ptrace.h>
36a90ff3c4SEdward Tomasz Napierala #include <sys/sx.h>
37a90ff3c4SEdward Tomasz Napierala #include <sys/syscallsubr.h>
38a90ff3c4SEdward Tomasz Napierala 
39a90ff3c4SEdward Tomasz Napierala #include <machine/../linux/linux.h>
40a90ff3c4SEdward Tomasz Napierala #include <machine/../linux/linux_proto.h>
41a90ff3c4SEdward Tomasz Napierala #include <compat/linux/linux_emul.h>
42a90ff3c4SEdward Tomasz Napierala #include <compat/linux/linux_errno.h>
43a90ff3c4SEdward Tomasz Napierala #include <compat/linux/linux_misc.h>
44a90ff3c4SEdward Tomasz Napierala #include <compat/linux/linux_signal.h>
45a90ff3c4SEdward Tomasz Napierala #include <compat/linux/linux_util.h>
46a90ff3c4SEdward Tomasz Napierala 
47a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_TRACEME		0
48a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_PEEKTEXT		1
49a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_PEEKDATA		2
50a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_PEEKUSER		3
51a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_POKETEXT		4
52a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_POKEDATA		5
53a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_POKEUSER		6
54a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_CONT		7
55a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_KILL		8
56a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SINGLESTEP		9
57a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_GETREGS		12
58a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SETREGS		13
59a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_GETFPREGS		14
60a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SETFPREGS		15
61a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_ATTACH		16
62a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_DETACH		17
63a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SYSCALL		24
64a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SETOPTIONS		0x4200
65a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_GETEVENTMSG	0x4201
66a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_GETSIGINFO		0x4202
67a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_GETREGSET		0x4204
68a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SEIZE		0x4206
69a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_GET_SYSCALL_INFO	0x420e
70a90ff3c4SEdward Tomasz Napierala 
71a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_EVENT_EXEC		4
72a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_EVENT_EXIT		6
73a90ff3c4SEdward Tomasz Napierala 
74a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACESYSGOOD	1
75a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACEFORK	2
76a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACEVFORK	4
77a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACECLONE	8
78a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACEEXEC	16
79a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACEVFORKDONE	32
80a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACEEXIT	64
81a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_TRACESECCOMP	128
82a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_EXITKILL		1048576
83a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_SUSPEND_SECCOMP	2097152
84a90ff3c4SEdward Tomasz Napierala 
85a90ff3c4SEdward Tomasz Napierala #define	LINUX_NT_PRSTATUS		0x1
86a90ff3c4SEdward Tomasz Napierala #define	LINUX_NT_PRFPREG		0x2
87a90ff3c4SEdward Tomasz Napierala #define	LINUX_NT_X86_XSTATE		0x202
88a90ff3c4SEdward Tomasz Napierala 
89a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_O_MASK	(LINUX_PTRACE_O_TRACESYSGOOD |	\
90a90ff3c4SEdward Tomasz Napierala     LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK |	\
91a90ff3c4SEdward Tomasz Napierala     LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC |	\
92a90ff3c4SEdward Tomasz Napierala     LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT |	\
93a90ff3c4SEdward Tomasz Napierala     LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL |	\
94a90ff3c4SEdward Tomasz Napierala     LINUX_PTRACE_O_SUSPEND_SECCOMP)
95a90ff3c4SEdward Tomasz Napierala 
96a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SYSCALL_INFO_NONE	0
97a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SYSCALL_INFO_ENTRY	1
98a90ff3c4SEdward Tomasz Napierala #define	LINUX_PTRACE_SYSCALL_INFO_EXIT	2
99a90ff3c4SEdward Tomasz Napierala 
100a90ff3c4SEdward Tomasz Napierala static int
map_signum(int lsig,int * bsigp)101a90ff3c4SEdward Tomasz Napierala map_signum(int lsig, int *bsigp)
102a90ff3c4SEdward Tomasz Napierala {
103a90ff3c4SEdward Tomasz Napierala 	int bsig;
104a90ff3c4SEdward Tomasz Napierala 
105a90ff3c4SEdward Tomasz Napierala 	if (lsig == 0) {
106a90ff3c4SEdward Tomasz Napierala 		*bsigp = 0;
107a90ff3c4SEdward Tomasz Napierala 		return (0);
108a90ff3c4SEdward Tomasz Napierala 	}
109a90ff3c4SEdward Tomasz Napierala 
110a90ff3c4SEdward Tomasz Napierala 	if (lsig < 0 || lsig > LINUX_SIGRTMAX)
111a90ff3c4SEdward Tomasz Napierala 		return (EINVAL);
112a90ff3c4SEdward Tomasz Napierala 
113a90ff3c4SEdward Tomasz Napierala 	bsig = linux_to_bsd_signal(lsig);
114a90ff3c4SEdward Tomasz Napierala 	if (bsig == SIGSTOP)
115a90ff3c4SEdward Tomasz Napierala 		bsig = 0;
116a90ff3c4SEdward Tomasz Napierala 
117a90ff3c4SEdward Tomasz Napierala 	*bsigp = bsig;
118a90ff3c4SEdward Tomasz Napierala 	return (0);
119a90ff3c4SEdward Tomasz Napierala }
120a90ff3c4SEdward Tomasz Napierala 
121a90ff3c4SEdward Tomasz Napierala int
linux_ptrace_status(struct thread * td,pid_t pid,int status)122a90ff3c4SEdward Tomasz Napierala linux_ptrace_status(struct thread *td, pid_t pid, int status)
123a90ff3c4SEdward Tomasz Napierala {
124a90ff3c4SEdward Tomasz Napierala 	struct ptrace_lwpinfo lwpinfo;
125a90ff3c4SEdward Tomasz Napierala 	struct linux_pemuldata *pem;
126a90ff3c4SEdward Tomasz Napierala 	register_t saved_retval;
127a90ff3c4SEdward Tomasz Napierala 	int error;
128a90ff3c4SEdward Tomasz Napierala 
129a90ff3c4SEdward Tomasz Napierala 	saved_retval = td->td_retval[0];
130a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
131a90ff3c4SEdward Tomasz Napierala 	td->td_retval[0] = saved_retval;
132a90ff3c4SEdward Tomasz Napierala 	if (error != 0) {
133a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
134a90ff3c4SEdward Tomasz Napierala 		return (status);
135a90ff3c4SEdward Tomasz Napierala 	}
136a90ff3c4SEdward Tomasz Napierala 
137a90ff3c4SEdward Tomasz Napierala 	pem = pem_find(td->td_proc);
138a90ff3c4SEdward Tomasz Napierala 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
139a90ff3c4SEdward Tomasz Napierala 
140a90ff3c4SEdward Tomasz Napierala 	LINUX_PEM_SLOCK(pem);
141a90ff3c4SEdward Tomasz Napierala 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
142a90ff3c4SEdward Tomasz Napierala 	    lwpinfo.pl_flags & PL_FLAG_SCE)
143a90ff3c4SEdward Tomasz Napierala 		status |= (LINUX_SIGTRAP | 0x80) << 8;
144a90ff3c4SEdward Tomasz Napierala 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
145a90ff3c4SEdward Tomasz Napierala 	    lwpinfo.pl_flags & PL_FLAG_SCX) {
146a90ff3c4SEdward Tomasz Napierala 		if (lwpinfo.pl_flags & PL_FLAG_EXEC)
147a90ff3c4SEdward Tomasz Napierala 			status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
148a90ff3c4SEdward Tomasz Napierala 		else
149a90ff3c4SEdward Tomasz Napierala 			status |= (LINUX_SIGTRAP | 0x80) << 8;
150a90ff3c4SEdward Tomasz Napierala 	}
151a90ff3c4SEdward Tomasz Napierala 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
152a90ff3c4SEdward Tomasz Napierala 	    lwpinfo.pl_flags & PL_FLAG_EXITED)
153a90ff3c4SEdward Tomasz Napierala 		status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
154a90ff3c4SEdward Tomasz Napierala 	LINUX_PEM_SUNLOCK(pem);
155a90ff3c4SEdward Tomasz Napierala 
156a90ff3c4SEdward Tomasz Napierala 	return (status);
157a90ff3c4SEdward Tomasz Napierala }
158a90ff3c4SEdward Tomasz Napierala 
159a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_peek(struct thread * td,pid_t pid,void * addr,void * data)160a90ff3c4SEdward Tomasz Napierala linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
161a90ff3c4SEdward Tomasz Napierala {
162a90ff3c4SEdward Tomasz Napierala 	int error;
163a90ff3c4SEdward Tomasz Napierala 
164a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
165a90ff3c4SEdward Tomasz Napierala 	if (error == 0)
166a90ff3c4SEdward Tomasz Napierala 		error = copyout(td->td_retval, data, sizeof(l_int));
167a90ff3c4SEdward Tomasz Napierala 	else if (error == ENOMEM)
168a90ff3c4SEdward Tomasz Napierala 		error = EIO;
169a90ff3c4SEdward Tomasz Napierala 	td->td_retval[0] = error;
170a90ff3c4SEdward Tomasz Napierala 
171a90ff3c4SEdward Tomasz Napierala 	return (error);
172a90ff3c4SEdward Tomasz Napierala }
173a90ff3c4SEdward Tomasz Napierala 
174a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_setoptions(struct thread * td,pid_t pid,l_ulong data)175a90ff3c4SEdward Tomasz Napierala linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
176a90ff3c4SEdward Tomasz Napierala {
177a90ff3c4SEdward Tomasz Napierala 	struct linux_pemuldata *pem;
178a90ff3c4SEdward Tomasz Napierala 	int mask;
179a90ff3c4SEdward Tomasz Napierala 
180a90ff3c4SEdward Tomasz Napierala 	mask = 0;
181a90ff3c4SEdward Tomasz Napierala 
182a90ff3c4SEdward Tomasz Napierala 	if (data & ~LINUX_PTRACE_O_MASK) {
183a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "unknown ptrace option %lx set; "
184a90ff3c4SEdward Tomasz Napierala 		    "returning EINVAL",
185a90ff3c4SEdward Tomasz Napierala 		    data & ~LINUX_PTRACE_O_MASK);
186a90ff3c4SEdward Tomasz Napierala 		return (EINVAL);
187a90ff3c4SEdward Tomasz Napierala 	}
188a90ff3c4SEdward Tomasz Napierala 
189a90ff3c4SEdward Tomasz Napierala 	pem = pem_find(td->td_proc);
190a90ff3c4SEdward Tomasz Napierala 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
191a90ff3c4SEdward Tomasz Napierala 
192a90ff3c4SEdward Tomasz Napierala 	/*
193a90ff3c4SEdward Tomasz Napierala 	 * PTRACE_O_EXITKILL is ignored, we do that by default.
194a90ff3c4SEdward Tomasz Napierala 	 */
195a90ff3c4SEdward Tomasz Napierala 
196a90ff3c4SEdward Tomasz Napierala 	LINUX_PEM_XLOCK(pem);
197a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
198a90ff3c4SEdward Tomasz Napierala 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
199a90ff3c4SEdward Tomasz Napierala 	} else {
200a90ff3c4SEdward Tomasz Napierala 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
201a90ff3c4SEdward Tomasz Napierala 	}
202a90ff3c4SEdward Tomasz Napierala 	LINUX_PEM_XUNLOCK(pem);
203a90ff3c4SEdward Tomasz Napierala 
204a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACEFORK)
205a90ff3c4SEdward Tomasz Napierala 		mask |= PTRACE_FORK;
206a90ff3c4SEdward Tomasz Napierala 
207a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACEVFORK)
208a90ff3c4SEdward Tomasz Napierala 		mask |= PTRACE_VFORK;
209a90ff3c4SEdward Tomasz Napierala 
210a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACECLONE)
211a90ff3c4SEdward Tomasz Napierala 		mask |= PTRACE_VFORK;
212a90ff3c4SEdward Tomasz Napierala 
213a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACEEXEC)
214a90ff3c4SEdward Tomasz Napierala 		mask |= PTRACE_EXEC;
215a90ff3c4SEdward Tomasz Napierala 
216a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
217a90ff3c4SEdward Tomasz Napierala 		mask |= PTRACE_VFORK; /* XXX: Close enough? */
218a90ff3c4SEdward Tomasz Napierala 
219a90ff3c4SEdward Tomasz Napierala 	if (data & LINUX_PTRACE_O_TRACEEXIT) {
220a90ff3c4SEdward Tomasz Napierala 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
221a90ff3c4SEdward Tomasz Napierala 	} else {
222a90ff3c4SEdward Tomasz Napierala 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
223a90ff3c4SEdward Tomasz Napierala 	}
224a90ff3c4SEdward Tomasz Napierala 
225a90ff3c4SEdward Tomasz Napierala 	return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
226a90ff3c4SEdward Tomasz Napierala }
227a90ff3c4SEdward Tomasz Napierala 
228a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_geteventmsg(struct thread * td,pid_t pid,l_ulong data)229a90ff3c4SEdward Tomasz Napierala linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
230a90ff3c4SEdward Tomasz Napierala {
231a90ff3c4SEdward Tomasz Napierala 
232a90ff3c4SEdward Tomasz Napierala 	linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
233a90ff3c4SEdward Tomasz Napierala 	return (EINVAL);
234a90ff3c4SEdward Tomasz Napierala }
235a90ff3c4SEdward Tomasz Napierala 
236a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_getsiginfo(struct thread * td,pid_t pid,l_ulong data)237a90ff3c4SEdward Tomasz Napierala linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
238a90ff3c4SEdward Tomasz Napierala {
239a90ff3c4SEdward Tomasz Napierala 	struct ptrace_lwpinfo lwpinfo;
240a90ff3c4SEdward Tomasz Napierala 	l_siginfo_t l_siginfo;
241a90ff3c4SEdward Tomasz Napierala 	int error, sig;
242a90ff3c4SEdward Tomasz Napierala 
243a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
244a90ff3c4SEdward Tomasz Napierala 	if (error != 0) {
245a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
246a90ff3c4SEdward Tomasz Napierala 		return (error);
247a90ff3c4SEdward Tomasz Napierala 	}
248a90ff3c4SEdward Tomasz Napierala 
249a90ff3c4SEdward Tomasz Napierala 	if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
250a90ff3c4SEdward Tomasz Napierala 		error = EINVAL;
251a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "no PL_FLAG_SI, returning %d", error);
252a90ff3c4SEdward Tomasz Napierala 		return (error);
253a90ff3c4SEdward Tomasz Napierala 	}
254a90ff3c4SEdward Tomasz Napierala 
255a90ff3c4SEdward Tomasz Napierala 	sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
256a90ff3c4SEdward Tomasz Napierala 	memset(&l_siginfo, 0, sizeof(l_siginfo));
257a90ff3c4SEdward Tomasz Napierala 	siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
258a90ff3c4SEdward Tomasz Napierala 	error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
259a90ff3c4SEdward Tomasz Napierala 	return (error);
260a90ff3c4SEdward Tomasz Napierala }
261a90ff3c4SEdward Tomasz Napierala 
262a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_getregs(struct thread * td,pid_t pid,void * data)263a90ff3c4SEdward Tomasz Napierala linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
264a90ff3c4SEdward Tomasz Napierala {
265a90ff3c4SEdward Tomasz Napierala 	struct reg b_reg;
266a90ff3c4SEdward Tomasz Napierala 	struct linux_pt_regset l_regset;
267a90ff3c4SEdward Tomasz Napierala 	int error;
268a90ff3c4SEdward Tomasz Napierala 
269a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
270a90ff3c4SEdward Tomasz Napierala 	if (error != 0)
271a90ff3c4SEdward Tomasz Napierala 		return (error);
272a90ff3c4SEdward Tomasz Napierala 
273a90ff3c4SEdward Tomasz Napierala 	bsd_to_linux_regset(&b_reg, &l_regset);
2740bf8d5d5SEdward Tomasz Napierala 	error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
2750bf8d5d5SEdward Tomasz Napierala 	if (error != 0)
276a90ff3c4SEdward Tomasz Napierala 		return (error);
277a90ff3c4SEdward Tomasz Napierala 
278a90ff3c4SEdward Tomasz Napierala 	error = copyout(&l_regset, (void *)data, sizeof(l_regset));
279a90ff3c4SEdward Tomasz Napierala 	return (error);
280a90ff3c4SEdward Tomasz Napierala }
281a90ff3c4SEdward Tomasz Napierala 
282a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_setregs(struct thread * td,pid_t pid,void * data)283a90ff3c4SEdward Tomasz Napierala linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
284a90ff3c4SEdward Tomasz Napierala {
285a90ff3c4SEdward Tomasz Napierala 	struct reg b_reg;
286a90ff3c4SEdward Tomasz Napierala 	struct linux_pt_regset l_regset;
287a90ff3c4SEdward Tomasz Napierala 	int error;
288a90ff3c4SEdward Tomasz Napierala 
289a90ff3c4SEdward Tomasz Napierala 	error = copyin(data, &l_regset, sizeof(l_regset));
290a90ff3c4SEdward Tomasz Napierala 	if (error != 0)
291a90ff3c4SEdward Tomasz Napierala 		return (error);
292a90ff3c4SEdward Tomasz Napierala 	linux_to_bsd_regset(&b_reg, &l_regset);
293a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
294a90ff3c4SEdward Tomasz Napierala 	return (error);
295a90ff3c4SEdward Tomasz Napierala }
296a90ff3c4SEdward Tomasz Napierala 
297a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_getregset_prstatus(struct thread * td,pid_t pid,l_ulong data)298a90ff3c4SEdward Tomasz Napierala linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
299a90ff3c4SEdward Tomasz Napierala {
300a90ff3c4SEdward Tomasz Napierala 	struct reg b_reg;
301a90ff3c4SEdward Tomasz Napierala 	struct linux_pt_regset l_regset;
302a90ff3c4SEdward Tomasz Napierala 	struct iovec iov;
303a90ff3c4SEdward Tomasz Napierala 	size_t len;
304a90ff3c4SEdward Tomasz Napierala 	int error;
305a90ff3c4SEdward Tomasz Napierala 
306a90ff3c4SEdward Tomasz Napierala 	error = copyin((const void *)data, &iov, sizeof(iov));
307a90ff3c4SEdward Tomasz Napierala 	if (error != 0) {
308a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "copyin error %d", error);
309a90ff3c4SEdward Tomasz Napierala 		return (error);
310a90ff3c4SEdward Tomasz Napierala 	}
311a90ff3c4SEdward Tomasz Napierala 
312a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
313a90ff3c4SEdward Tomasz Napierala 	if (error != 0)
314a90ff3c4SEdward Tomasz Napierala 		return (error);
315a90ff3c4SEdward Tomasz Napierala 
316a90ff3c4SEdward Tomasz Napierala 	bsd_to_linux_regset(&b_reg, &l_regset);
3170bf8d5d5SEdward Tomasz Napierala 	error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
3180bf8d5d5SEdward Tomasz Napierala 	if (error != 0)
319a90ff3c4SEdward Tomasz Napierala 		return (error);
320a90ff3c4SEdward Tomasz Napierala 
321a90ff3c4SEdward Tomasz Napierala 	len = MIN(iov.iov_len, sizeof(l_regset));
322a90ff3c4SEdward Tomasz Napierala 	error = copyout(&l_regset, (void *)iov.iov_base, len);
323a90ff3c4SEdward Tomasz Napierala 	if (error != 0) {
324a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "copyout error %d", error);
325a90ff3c4SEdward Tomasz Napierala 		return (error);
326a90ff3c4SEdward Tomasz Napierala 	}
327a90ff3c4SEdward Tomasz Napierala 
328a90ff3c4SEdward Tomasz Napierala 	iov.iov_len = len;
329a90ff3c4SEdward Tomasz Napierala 	error = copyout(&iov, (void *)data, sizeof(iov));
330a90ff3c4SEdward Tomasz Napierala 	if (error != 0) {
331a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "iov copyout error %d", error);
332a90ff3c4SEdward Tomasz Napierala 		return (error);
333a90ff3c4SEdward Tomasz Napierala 	}
334a90ff3c4SEdward Tomasz Napierala 
335a90ff3c4SEdward Tomasz Napierala 	return (error);
336a90ff3c4SEdward Tomasz Napierala }
337a90ff3c4SEdward Tomasz Napierala 
338a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_getregset(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)339a90ff3c4SEdward Tomasz Napierala linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
340a90ff3c4SEdward Tomasz Napierala {
341a90ff3c4SEdward Tomasz Napierala 
342a90ff3c4SEdward Tomasz Napierala 	switch (addr) {
343a90ff3c4SEdward Tomasz Napierala 	case LINUX_NT_PRSTATUS:
344a90ff3c4SEdward Tomasz Napierala 		return (linux_ptrace_getregset_prstatus(td, pid, data));
345a90ff3c4SEdward Tomasz Napierala 	case LINUX_NT_PRFPREG:
346a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
347a90ff3c4SEdward Tomasz Napierala 		    "returning EINVAL");
348a90ff3c4SEdward Tomasz Napierala 		return (EINVAL);
349a90ff3c4SEdward Tomasz Napierala 	case LINUX_NT_X86_XSTATE:
350a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
351a90ff3c4SEdward Tomasz Napierala 		    "returning EINVAL");
352a90ff3c4SEdward Tomasz Napierala 		return (EINVAL);
353a90ff3c4SEdward Tomasz Napierala 	default:
354a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
355a90ff3c4SEdward Tomasz Napierala 		    "returning EINVAL", addr);
356a90ff3c4SEdward Tomasz Napierala 		return (EINVAL);
357a90ff3c4SEdward Tomasz Napierala 	}
358a90ff3c4SEdward Tomasz Napierala }
359a90ff3c4SEdward Tomasz Napierala 
360a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_seize(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)361a90ff3c4SEdward Tomasz Napierala linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
362a90ff3c4SEdward Tomasz Napierala {
363a90ff3c4SEdward Tomasz Napierala 
364a90ff3c4SEdward Tomasz Napierala 	linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
365a90ff3c4SEdward Tomasz Napierala 	return (EINVAL);
366a90ff3c4SEdward Tomasz Napierala }
367a90ff3c4SEdward Tomasz Napierala 
368a90ff3c4SEdward Tomasz Napierala static int
linux_ptrace_get_syscall_info(struct thread * td,pid_t pid,l_ulong len,l_ulong data)369a90ff3c4SEdward Tomasz Napierala linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
370a90ff3c4SEdward Tomasz Napierala     l_ulong len, l_ulong data)
371a90ff3c4SEdward Tomasz Napierala {
372a90ff3c4SEdward Tomasz Napierala 	struct ptrace_lwpinfo lwpinfo;
373a90ff3c4SEdward Tomasz Napierala 	struct ptrace_sc_ret sr;
374a90ff3c4SEdward Tomasz Napierala 	struct reg b_reg;
375a90ff3c4SEdward Tomasz Napierala 	struct syscall_info si;
376a90ff3c4SEdward Tomasz Napierala 	int error;
377a90ff3c4SEdward Tomasz Napierala 
378a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
379a90ff3c4SEdward Tomasz Napierala 	if (error != 0) {
380a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
381a90ff3c4SEdward Tomasz Napierala 		return (error);
382a90ff3c4SEdward Tomasz Napierala 	}
383a90ff3c4SEdward Tomasz Napierala 
384a90ff3c4SEdward Tomasz Napierala 	memset(&si, 0, sizeof(si));
385a90ff3c4SEdward Tomasz Napierala 
386a90ff3c4SEdward Tomasz Napierala 	if (lwpinfo.pl_flags & PL_FLAG_SCE) {
387a90ff3c4SEdward Tomasz Napierala 		si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
388a90ff3c4SEdward Tomasz Napierala 		si.entry.nr = lwpinfo.pl_syscall_code;
389a90ff3c4SEdward Tomasz Napierala 		/*
390a90ff3c4SEdward Tomasz Napierala 		 * The use of PT_GET_SC_ARGS there is special,
391a90ff3c4SEdward Tomasz Napierala 		 * implementation of PT_GET_SC_ARGS for Linux-ABI
392a90ff3c4SEdward Tomasz Napierala 		 * callers emulates Linux bug which strace(1) depends
393a90ff3c4SEdward Tomasz Napierala 		 * on: at initialization it tests whether ptrace works
394a90ff3c4SEdward Tomasz Napierala 		 * by calling close(2), or some other single-argument
395a90ff3c4SEdward Tomasz Napierala 		 * syscall, _with six arguments_, and then verifies
396a90ff3c4SEdward Tomasz Napierala 		 * whether it can fetch them all using this API;
397a90ff3c4SEdward Tomasz Napierala 		 * otherwise it bails out.
398a90ff3c4SEdward Tomasz Napierala 		 */
399a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
400a90ff3c4SEdward Tomasz Napierala 		    &si.entry.args, sizeof(si.entry.args));
401a90ff3c4SEdward Tomasz Napierala 		if (error != 0) {
402a90ff3c4SEdward Tomasz Napierala 			linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
403a90ff3c4SEdward Tomasz Napierala 			    error);
404a90ff3c4SEdward Tomasz Napierala 			return (error);
405a90ff3c4SEdward Tomasz Napierala 		}
406a90ff3c4SEdward Tomasz Napierala 	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
407a90ff3c4SEdward Tomasz Napierala 		si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
408a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
409a90ff3c4SEdward Tomasz Napierala 
410a90ff3c4SEdward Tomasz Napierala 		if (error != 0) {
411a90ff3c4SEdward Tomasz Napierala 			linux_msg(td, "PT_GET_SC_RET failed with error %d",
412a90ff3c4SEdward Tomasz Napierala 			    error);
413a90ff3c4SEdward Tomasz Napierala 			return (error);
414a90ff3c4SEdward Tomasz Napierala 		}
415a90ff3c4SEdward Tomasz Napierala 
416a90ff3c4SEdward Tomasz Napierala 		if (sr.sr_error == 0) {
417a90ff3c4SEdward Tomasz Napierala 			si.exit.rval = sr.sr_retval[0];
418a90ff3c4SEdward Tomasz Napierala 			si.exit.is_error = 0;
419a90ff3c4SEdward Tomasz Napierala 		} else if (sr.sr_error == EJUSTRETURN) {
420a90ff3c4SEdward Tomasz Napierala 			/*
421a90ff3c4SEdward Tomasz Napierala 			 * EJUSTRETURN means the actual value to return
422a90ff3c4SEdward Tomasz Napierala 			 * has already been put into td_frame; instead
423a90ff3c4SEdward Tomasz Napierala 			 * of extracting it and trying to determine whether
424a90ff3c4SEdward Tomasz Napierala 			 * it's an error or not just bail out and let
425a90ff3c4SEdward Tomasz Napierala 			 * the ptracing process fall back to another method.
426a90ff3c4SEdward Tomasz Napierala 			 */
427a90ff3c4SEdward Tomasz Napierala 			si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
428a90ff3c4SEdward Tomasz Napierala 		} else if (sr.sr_error == ERESTART) {
429a90ff3c4SEdward Tomasz Napierala 			si.exit.rval = -LINUX_ERESTARTSYS;
430a90ff3c4SEdward Tomasz Napierala 			si.exit.is_error = 1;
431a90ff3c4SEdward Tomasz Napierala 		} else {
432a90ff3c4SEdward Tomasz Napierala 			si.exit.rval = bsd_to_linux_errno(sr.sr_error);
433a90ff3c4SEdward Tomasz Napierala 			si.exit.is_error = 1;
434a90ff3c4SEdward Tomasz Napierala 		}
435a90ff3c4SEdward Tomasz Napierala 	} else {
436a90ff3c4SEdward Tomasz Napierala 		si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
437a90ff3c4SEdward Tomasz Napierala 	}
438a90ff3c4SEdward Tomasz Napierala 
439a90ff3c4SEdward Tomasz Napierala 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
440a90ff3c4SEdward Tomasz Napierala 	if (error != 0)
441a90ff3c4SEdward Tomasz Napierala 		return (error);
442a90ff3c4SEdward Tomasz Napierala 
4430bf8d5d5SEdward Tomasz Napierala 	linux_ptrace_get_syscall_info_machdep(&b_reg, &si);
444a90ff3c4SEdward Tomasz Napierala 
445a90ff3c4SEdward Tomasz Napierala 	len = MIN(len, sizeof(si));
446a90ff3c4SEdward Tomasz Napierala 	error = copyout(&si, (void *)data, len);
447a90ff3c4SEdward Tomasz Napierala 	if (error == 0)
448a90ff3c4SEdward Tomasz Napierala 		td->td_retval[0] = sizeof(si);
449a90ff3c4SEdward Tomasz Napierala 
450a90ff3c4SEdward Tomasz Napierala 	return (error);
451a90ff3c4SEdward Tomasz Napierala }
452a90ff3c4SEdward Tomasz Napierala 
453a90ff3c4SEdward Tomasz Napierala int
linux_ptrace(struct thread * td,struct linux_ptrace_args * uap)454a90ff3c4SEdward Tomasz Napierala linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
455a90ff3c4SEdward Tomasz Napierala {
456a90ff3c4SEdward Tomasz Napierala 	void *addr;
457a90ff3c4SEdward Tomasz Napierala 	pid_t pid;
458a90ff3c4SEdward Tomasz Napierala 	int error, sig;
459a90ff3c4SEdward Tomasz Napierala 
460fe6db727SKonstantin Belousov 	if (!allow_ptrace)
461fe6db727SKonstantin Belousov 		return (ENOSYS);
462fe6db727SKonstantin Belousov 
463a90ff3c4SEdward Tomasz Napierala 	pid  = (pid_t)uap->pid;
464a90ff3c4SEdward Tomasz Napierala 	addr = (void *)uap->addr;
465a90ff3c4SEdward Tomasz Napierala 
466a90ff3c4SEdward Tomasz Napierala 	switch (uap->req) {
467a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_TRACEME:
468a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
469a90ff3c4SEdward Tomasz Napierala 		break;
470a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_PEEKTEXT:
471a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_PEEKDATA:
472a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
473a90ff3c4SEdward Tomasz Napierala 		if (error != 0)
474a90ff3c4SEdward Tomasz Napierala 			goto out;
475a90ff3c4SEdward Tomasz Napierala 		/*
476a90ff3c4SEdward Tomasz Napierala 		 * Linux expects this syscall to read 64 bits, not 32.
477a90ff3c4SEdward Tomasz Napierala 		 */
478a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_peek(td, pid,
479a90ff3c4SEdward Tomasz Napierala 		    (void *)(uap->addr + 4), (void *)(uap->data + 4));
480a90ff3c4SEdward Tomasz Napierala 		break;
481a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_PEEKUSER:
482a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
483a90ff3c4SEdward Tomasz Napierala 		break;
484a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_POKETEXT:
485a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_POKEDATA:
486a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
487a90ff3c4SEdward Tomasz Napierala 		if (error != 0)
488a90ff3c4SEdward Tomasz Napierala 			goto out;
489a90ff3c4SEdward Tomasz Napierala 		/*
490a90ff3c4SEdward Tomasz Napierala 		 * Linux expects this syscall to write 64 bits, not 32.
491a90ff3c4SEdward Tomasz Napierala 		 */
492a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_WRITE_D, pid,
493a90ff3c4SEdward Tomasz Napierala 		    (void *)(uap->addr + 4), uap->data >> 32);
494a90ff3c4SEdward Tomasz Napierala 		break;
495a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_POKEUSER:
496a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
497a90ff3c4SEdward Tomasz Napierala 		break;
498a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_CONT:
499a90ff3c4SEdward Tomasz Napierala 		error = map_signum(uap->data, &sig);
500a90ff3c4SEdward Tomasz Napierala 		if (error != 0)
501a90ff3c4SEdward Tomasz Napierala 			break;
502a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
503a90ff3c4SEdward Tomasz Napierala 		break;
504a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_KILL:
505a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
506a90ff3c4SEdward Tomasz Napierala 		break;
507a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_SINGLESTEP:
508a90ff3c4SEdward Tomasz Napierala 		error = map_signum(uap->data, &sig);
509a90ff3c4SEdward Tomasz Napierala 		if (error != 0)
510a90ff3c4SEdward Tomasz Napierala 			break;
511a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
512a90ff3c4SEdward Tomasz Napierala 		break;
513a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_GETREGS:
514a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_getregs(td, pid, (void *)uap->data);
515a90ff3c4SEdward Tomasz Napierala 		break;
516a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_SETREGS:
517a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_setregs(td, pid, (void *)uap->data);
518a90ff3c4SEdward Tomasz Napierala 		break;
519a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_ATTACH:
520a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
521a90ff3c4SEdward Tomasz Napierala 		break;
522a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_DETACH:
523a90ff3c4SEdward Tomasz Napierala 		error = map_signum(uap->data, &sig);
524a90ff3c4SEdward Tomasz Napierala 		if (error != 0)
525a90ff3c4SEdward Tomasz Napierala 			break;
526a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
527a90ff3c4SEdward Tomasz Napierala 		break;
528a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_SYSCALL:
529a90ff3c4SEdward Tomasz Napierala 		error = map_signum(uap->data, &sig);
530a90ff3c4SEdward Tomasz Napierala 		if (error != 0)
531a90ff3c4SEdward Tomasz Napierala 			break;
532a90ff3c4SEdward Tomasz Napierala 		error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
533a90ff3c4SEdward Tomasz Napierala 		break;
534a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_SETOPTIONS:
535a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_setoptions(td, pid, uap->data);
536a90ff3c4SEdward Tomasz Napierala 		break;
537a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_GETEVENTMSG:
538a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_geteventmsg(td, pid, uap->data);
539a90ff3c4SEdward Tomasz Napierala 		break;
540a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_GETSIGINFO:
541a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_getsiginfo(td, pid, uap->data);
542a90ff3c4SEdward Tomasz Napierala 		break;
543a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_GETREGSET:
544a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
545a90ff3c4SEdward Tomasz Napierala 		break;
546a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_SEIZE:
547a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
548a90ff3c4SEdward Tomasz Napierala 		break;
549a90ff3c4SEdward Tomasz Napierala 	case LINUX_PTRACE_GET_SYSCALL_INFO:
550a90ff3c4SEdward Tomasz Napierala 		error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
551a90ff3c4SEdward Tomasz Napierala 		break;
552a90ff3c4SEdward Tomasz Napierala 	default:
553a90ff3c4SEdward Tomasz Napierala 		linux_msg(td, "ptrace(%ld, ...) not implemented; "
554a90ff3c4SEdward Tomasz Napierala 		    "returning EINVAL", uap->req);
555a90ff3c4SEdward Tomasz Napierala 		error = EINVAL;
556a90ff3c4SEdward Tomasz Napierala 		break;
557a90ff3c4SEdward Tomasz Napierala 	}
558a90ff3c4SEdward Tomasz Napierala 
559a90ff3c4SEdward Tomasz Napierala out:
560a90ff3c4SEdward Tomasz Napierala 	if (error == EBUSY)
561a90ff3c4SEdward Tomasz Napierala 		error = ESRCH;
562a90ff3c4SEdward Tomasz Napierala 
563a90ff3c4SEdward Tomasz Napierala 	return (error);
564a90ff3c4SEdward Tomasz Napierala }
565