xref: /netbsd-src/sys/compat/netbsd32/netbsd32_ptrace.c (revision 41aa5859b647891f23013f613e0858c4b789a7bf)
1*41aa5859Sriastradh /*	$NetBSD: netbsd32_ptrace.c,v 1.9 2021/09/07 11:43:05 riastradh Exp $	*/
2f2ef31cbSskrll 
3f2ef31cbSskrll /*
4f2ef31cbSskrll  * Copyright (c) 2016 The NetBSD Foundation, Inc.
5f2ef31cbSskrll  * All rights reserved.
6f2ef31cbSskrll  *
7f2ef31cbSskrll  * This code is derived from software contributed to The NetBSD Foundation
8f2ef31cbSskrll  * by Nick Hudson
9f2ef31cbSskrll  *
10f2ef31cbSskrll  * Redistribution and use in source and binary forms, with or without
11f2ef31cbSskrll  * modification, are permitted provided that the following conditions
12f2ef31cbSskrll  * are met:
13f2ef31cbSskrll  * 1. Redistributions of source code must retain the above copyright
14f2ef31cbSskrll  *    notice, this list of conditions and the following disclaimer.
15f2ef31cbSskrll  * 2. Redistributions in binary form must reproduce the above copyright
16f2ef31cbSskrll  *    notice, this list of conditions and the following disclaimer in the
17f2ef31cbSskrll  *    documentation and/or other materials provided with the distribution.
18f2ef31cbSskrll  *
19f2ef31cbSskrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f2ef31cbSskrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f2ef31cbSskrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f2ef31cbSskrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f2ef31cbSskrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f2ef31cbSskrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f2ef31cbSskrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f2ef31cbSskrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f2ef31cbSskrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f2ef31cbSskrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f2ef31cbSskrll  * POSSIBILITY OF SUCH DAMAGE.
30f2ef31cbSskrll  */
31f2ef31cbSskrll 
32f2ef31cbSskrll #include <sys/cdefs.h>
33*41aa5859Sriastradh __KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.9 2021/09/07 11:43:05 riastradh Exp $");
34f2ef31cbSskrll 
35f2ef31cbSskrll #if defined(_KERNEL_OPT)
36f2ef31cbSskrll #include "opt_ptrace.h"
37f2ef31cbSskrll #include "opt_compat_netbsd.h"
38f2ef31cbSskrll #endif
39f2ef31cbSskrll 
40f2ef31cbSskrll #include <sys/param.h>
41f2ef31cbSskrll #include <sys/module.h>
42f2ef31cbSskrll #include <sys/ptrace.h>
43f2ef31cbSskrll #include <sys/syscallvar.h>
44f2ef31cbSskrll 
45f2ef31cbSskrll #include <compat/netbsd32/netbsd32.h>
46f2ef31cbSskrll #include <compat/netbsd32/netbsd32_syscall.h>
47f2ef31cbSskrll #include <compat/netbsd32/netbsd32_syscallargs.h>
48f2ef31cbSskrll #include <compat/netbsd32/netbsd32_conv.h>
49f2ef31cbSskrll 
5001cfb8b6Smgorny #ifndef PTRACE_TRANSLATE_REQUEST32
5101cfb8b6Smgorny #define PTRACE_TRANSLATE_REQUEST32(x) x
5201cfb8b6Smgorny #endif
5301cfb8b6Smgorny 
544f79a484Skamil static void
netbsd32_lwpstatus_to_lwpstatus32(struct netbsd32_ptrace_lwpstatus * pls32,const struct ptrace_lwpstatus * pls)554f79a484Skamil netbsd32_lwpstatus_to_lwpstatus32(struct netbsd32_ptrace_lwpstatus *pls32,
564f79a484Skamil     const struct ptrace_lwpstatus *pls)
574f79a484Skamil {
58*41aa5859Sriastradh 	memset(pls32, 0, sizeof(*pls32));
594f79a484Skamil 	pls32->pl_lwpid = pls->pl_lwpid;
604f79a484Skamil 	pls32->pl_sigpend = pls->pl_sigpend;
614f79a484Skamil 	pls32->pl_sigmask = pls->pl_sigmask;
624f79a484Skamil 	memcpy(&pls32->pl_name, &pls->pl_name, PL_LNAMELEN);
634f79a484Skamil 	NETBSD32PTR32(pls32->pl_private, pls->pl_private);
644f79a484Skamil }
654f79a484Skamil 
664f79a484Skamil void
netbsd32_read_lwpstatus(struct lwp * l,struct netbsd32_ptrace_lwpstatus * pls32)674f79a484Skamil netbsd32_read_lwpstatus(struct lwp *l, struct netbsd32_ptrace_lwpstatus *pls32)
684f79a484Skamil {
694f79a484Skamil 	struct ptrace_lwpstatus pls;
704f79a484Skamil 
714f79a484Skamil 	process_read_lwpstatus(l, &pls);
724f79a484Skamil 
734f79a484Skamil 	netbsd32_lwpstatus_to_lwpstatus32(pls32, &pls);
744f79a484Skamil }
754f79a484Skamil 
76f2ef31cbSskrll /*
77f2ef31cbSskrll  * PTRACE methods
78f2ef31cbSskrll  */
79f2ef31cbSskrll 
80f2ef31cbSskrll static int
netbsd32_copyin_piod(struct ptrace_io_desc * piod,const void * addr,size_t len)81f818d5c4Schristos netbsd32_copyin_piod(struct ptrace_io_desc *piod, const void *addr, size_t len)
82f2ef31cbSskrll {
83f2ef31cbSskrll 	struct netbsd32_ptrace_io_desc piod32;
84f2ef31cbSskrll 
85f818d5c4Schristos 	if (len != 0 && sizeof(piod32) != len)
86f818d5c4Schristos 		return EINVAL;
87f818d5c4Schristos 
88f2ef31cbSskrll 	int error = copyin(addr, &piod32, sizeof(piod32));
89f2ef31cbSskrll 	if (error)
90f2ef31cbSskrll 		return error;
91f2ef31cbSskrll 	piod->piod_op = piod32.piod_op;
92f2ef31cbSskrll 	piod->piod_offs = NETBSD32PTR64(piod32.piod_offs);
93f2ef31cbSskrll 	piod->piod_addr = NETBSD32PTR64(piod32.piod_addr);
94f2ef31cbSskrll 	piod->piod_len = (size_t)piod32.piod_len;
95f2ef31cbSskrll 
96f2ef31cbSskrll 	return 0;
97f2ef31cbSskrll }
98f2ef31cbSskrll 
99f818d5c4Schristos static int
netbsd32_copyout_piod(const struct ptrace_io_desc * piod,void * addr,size_t len)100f818d5c4Schristos netbsd32_copyout_piod(const struct ptrace_io_desc *piod, void *addr, size_t len)
101f2ef31cbSskrll {
102f2ef31cbSskrll 	struct netbsd32_ptrace_io_desc piod32;
103f2ef31cbSskrll 
104f818d5c4Schristos 	if (len != 0 && sizeof(piod32) != len)
105f818d5c4Schristos 		return EINVAL;
106f818d5c4Schristos 
107*41aa5859Sriastradh 	memset(&piod32, 0, sizeof(piod32));
108f2ef31cbSskrll 	piod32.piod_op = piod->piod_op;
109f2ef31cbSskrll 	NETBSD32PTR32(piod32.piod_offs, piod->piod_offs);
110f2ef31cbSskrll 	NETBSD32PTR32(piod32.piod_addr, piod->piod_addr);
111f2ef31cbSskrll 	piod32.piod_len = (netbsd32_size_t)piod->piod_len;
112f818d5c4Schristos 	return copyout(&piod32, addr, sizeof(piod32));
113f2ef31cbSskrll }
114f2ef31cbSskrll 
115f818d5c4Schristos static int
netbsd32_copyin_siginfo(struct ptrace_siginfo * psi,const void * addr,size_t len)116f818d5c4Schristos netbsd32_copyin_siginfo(struct ptrace_siginfo *psi, const void *addr, size_t len)
117f818d5c4Schristos {
118f818d5c4Schristos 	struct netbsd32_ptrace_siginfo psi32;
119f818d5c4Schristos 
120f818d5c4Schristos 	if (sizeof(psi32) != len)
121f818d5c4Schristos 		return EINVAL;
122f818d5c4Schristos 
123f818d5c4Schristos 	int error = copyin(addr, &psi32, sizeof(psi32));
124f818d5c4Schristos 	if (error)
125f818d5c4Schristos 		return error;
126f818d5c4Schristos 	psi->psi_lwpid = psi32.psi_lwpid;
127f818d5c4Schristos 	netbsd32_si32_to_si(&psi->psi_siginfo, &psi32.psi_siginfo);
128f818d5c4Schristos 	return 0;
129f818d5c4Schristos }
130f818d5c4Schristos 
131f818d5c4Schristos static int
netbsd32_copyout_siginfo(const struct ptrace_siginfo * psi,void * addr,size_t len)132f818d5c4Schristos netbsd32_copyout_siginfo(const struct ptrace_siginfo *psi, void *addr, size_t len)
133f818d5c4Schristos {
134f818d5c4Schristos 	struct netbsd32_ptrace_siginfo psi32;
135f818d5c4Schristos 
136f818d5c4Schristos 	if (sizeof(psi32) != len)
137f818d5c4Schristos 		return EINVAL;
138f818d5c4Schristos 
139*41aa5859Sriastradh 	memset(&psi32, 0, sizeof(psi32));
140f818d5c4Schristos 	psi32.psi_lwpid = psi->psi_lwpid;
141f818d5c4Schristos 	netbsd32_si_to_si32(&psi32.psi_siginfo, &psi->psi_siginfo);
142f818d5c4Schristos 	return copyout(&psi32, addr, sizeof(psi32));
143f818d5c4Schristos }
144f2ef31cbSskrll 
145f2ef31cbSskrll static int
netbsd32_copyout_lwpstatus(const struct ptrace_lwpstatus * pls,void * addr,size_t len)1464f79a484Skamil netbsd32_copyout_lwpstatus(const struct ptrace_lwpstatus *pls, void *addr, size_t len)
1474f79a484Skamil {
1484f79a484Skamil 	struct netbsd32_ptrace_lwpstatus pls32;
1494f79a484Skamil 
1504f79a484Skamil 	if (len > sizeof(pls32))
1514f79a484Skamil 		return EINVAL;
1524f79a484Skamil 
1534f79a484Skamil 	netbsd32_lwpstatus_to_lwpstatus32(&pls32, pls);
1544f79a484Skamil 
1554f79a484Skamil 	return copyout(&pls32, addr, MIN(len, sizeof(pls32)));
1564f79a484Skamil }
1574f79a484Skamil 
1584f79a484Skamil static int
netbsd32_doregs(struct lwp * curl,struct lwp * l,struct uio * uio)159f2ef31cbSskrll netbsd32_doregs(struct lwp *curl /*tracer*/,
160f2ef31cbSskrll     struct lwp *l /*traced*/,
161f2ef31cbSskrll     struct uio *uio)
162f2ef31cbSskrll {
163f2ef31cbSskrll #if defined(PT_GETREGS) || defined(PT_SETREGS)
164f2ef31cbSskrll 	process_reg32 r32;
165f2ef31cbSskrll 	int error;
166f2ef31cbSskrll 	char *kv;
167f2ef31cbSskrll 	int kl;
168f2ef31cbSskrll 
169f2ef31cbSskrll 	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
170f2ef31cbSskrll 		return EINVAL;
171f2ef31cbSskrll 
172f2ef31cbSskrll 	kl = sizeof(r32);
173f2ef31cbSskrll 	kv = (char *)&r32;
174f2ef31cbSskrll 
175f2ef31cbSskrll 	kv += uio->uio_offset;
176f2ef31cbSskrll 	kl -= uio->uio_offset;
177f2ef31cbSskrll 	if ((size_t)kl > uio->uio_resid)
178f2ef31cbSskrll 		kl = uio->uio_resid;
179f2ef31cbSskrll 	error = process_read_regs32(l, &r32);
180f2ef31cbSskrll 	if (error == 0)
181f2ef31cbSskrll 		error = uiomove(kv, kl, uio);
182f2ef31cbSskrll 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
183f2ef31cbSskrll 		if (l->l_stat != LSSTOP)
184f2ef31cbSskrll 			error = EBUSY;
185f2ef31cbSskrll 		else
186f2ef31cbSskrll 			error = process_write_regs32(l, &r32);
187f2ef31cbSskrll 	}
188f2ef31cbSskrll 
189f2ef31cbSskrll 	uio->uio_offset = 0;
190f2ef31cbSskrll 	return error;
191f2ef31cbSskrll #else
192f2ef31cbSskrll 	return EINVAL;
193f2ef31cbSskrll #endif
194f2ef31cbSskrll }
195f2ef31cbSskrll 
196f2ef31cbSskrll static int
netbsd32_dofpregs(struct lwp * curl,struct lwp * l,struct uio * uio)197f2ef31cbSskrll netbsd32_dofpregs(struct lwp *curl /*tracer*/,
198f2ef31cbSskrll     struct lwp *l /*traced*/,
199f2ef31cbSskrll     struct uio *uio)
200f2ef31cbSskrll {
201f2ef31cbSskrll #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
202f2ef31cbSskrll 	process_fpreg32 r32;
203f2ef31cbSskrll 	int error;
204f2ef31cbSskrll 	char *kv;
205f2ef31cbSskrll 	size_t kl;
206f2ef31cbSskrll 
207f2ef31cbSskrll 	KASSERT(l->l_proc->p_flag & PK_32);
208f2ef31cbSskrll 	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
209f2ef31cbSskrll 		return EINVAL;
210f2ef31cbSskrll 	kl = sizeof(r32);
211f2ef31cbSskrll 	kv = (char *)&r32;
212f2ef31cbSskrll 
213f2ef31cbSskrll 	kv += uio->uio_offset;
214f2ef31cbSskrll 	kl -= uio->uio_offset;
215f2ef31cbSskrll 	if (kl > uio->uio_resid)
216f2ef31cbSskrll 		kl = uio->uio_resid;
217f2ef31cbSskrll 
218f2ef31cbSskrll 	error = process_read_fpregs32(l, &r32, &kl);
219f2ef31cbSskrll 	if (error == 0)
220f2ef31cbSskrll 		error = uiomove(kv, kl, uio);
221f2ef31cbSskrll 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
222f2ef31cbSskrll 		if (l->l_stat != LSSTOP)
223f2ef31cbSskrll 			error = EBUSY;
224f2ef31cbSskrll 		else
225f2ef31cbSskrll 			error = process_write_fpregs32(l, &r32, kl);
226f2ef31cbSskrll 	}
227f2ef31cbSskrll 	uio->uio_offset = 0;
228f2ef31cbSskrll 	return error;
229f2ef31cbSskrll #else
230f2ef31cbSskrll 	return EINVAL;
231f2ef31cbSskrll #endif
232f2ef31cbSskrll }
233f2ef31cbSskrll 
234241cf91dSkamil static int
netbsd32_dodbregs(struct lwp * curl,struct lwp * l,struct uio * uio)235988eb7edSkamil netbsd32_dodbregs(struct lwp *curl /*tracer*/,
236988eb7edSkamil     struct lwp *l /*traced*/,
237988eb7edSkamil     struct uio *uio)
238241cf91dSkamil {
239988eb7edSkamil #if defined(PT_GETDBREGS) || defined(PT_SETDBREGS)
240988eb7edSkamil 	process_dbreg32 r32;
241988eb7edSkamil 	int error;
242988eb7edSkamil 	char *kv;
243988eb7edSkamil 	size_t kl;
244241cf91dSkamil 
245988eb7edSkamil 	KASSERT(l->l_proc->p_flag & PK_32);
246988eb7edSkamil 	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
247241cf91dSkamil 		return EINVAL;
248988eb7edSkamil 	kl = sizeof(r32);
249988eb7edSkamil 	kv = (char *)&r32;
250988eb7edSkamil 
251988eb7edSkamil 	kv += uio->uio_offset;
252988eb7edSkamil 	kl -= uio->uio_offset;
253988eb7edSkamil 	if (kl > uio->uio_resid)
254988eb7edSkamil 		kl = uio->uio_resid;
255988eb7edSkamil 
256988eb7edSkamil 	error = process_read_dbregs32(l, &r32, &kl);
257988eb7edSkamil 	if (error == 0)
258988eb7edSkamil 		error = uiomove(kv, kl, uio);
259988eb7edSkamil 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
260988eb7edSkamil 		if (l->l_stat != LSSTOP)
261988eb7edSkamil 			error = EBUSY;
262988eb7edSkamil 		else
263988eb7edSkamil 			error = process_write_dbregs32(l, &r32, kl);
264988eb7edSkamil 	}
265988eb7edSkamil 	uio->uio_offset = 0;
266988eb7edSkamil 	return error;
267988eb7edSkamil #else
268988eb7edSkamil 	return EINVAL;
269988eb7edSkamil #endif
270241cf91dSkamil }
271241cf91dSkamil 
272f2ef31cbSskrll static struct ptrace_methods netbsd32_ptm = {
273f818d5c4Schristos 	.ptm_copyin_piod = netbsd32_copyin_piod,
274f818d5c4Schristos 	.ptm_copyout_piod = netbsd32_copyout_piod,
275f818d5c4Schristos 	.ptm_copyin_siginfo = netbsd32_copyin_siginfo,
276f818d5c4Schristos 	.ptm_copyout_siginfo = netbsd32_copyout_siginfo,
2774f79a484Skamil 	.ptm_copyout_lwpstatus = netbsd32_copyout_lwpstatus,
278f2ef31cbSskrll 	.ptm_doregs = netbsd32_doregs,
279241cf91dSkamil 	.ptm_dofpregs = netbsd32_dofpregs,
280988eb7edSkamil 	.ptm_dodbregs = netbsd32_dodbregs
281f2ef31cbSskrll };
282f2ef31cbSskrll 
283f2ef31cbSskrll 
284f2ef31cbSskrll int
netbsd32_ptrace(struct lwp * l,const struct netbsd32_ptrace_args * uap,register_t * retval)285f2ef31cbSskrll netbsd32_ptrace(struct lwp *l, const struct netbsd32_ptrace_args *uap,
286f2ef31cbSskrll     register_t *retval)
287f2ef31cbSskrll {
28801cfb8b6Smgorny 	int req;
28901cfb8b6Smgorny 
290f2ef31cbSskrll 	/* {
291f2ef31cbSskrll 		syscallarg(int) req;
292f2ef31cbSskrll 		syscallarg(pid_t) pid;
293f2ef31cbSskrll 		syscallarg(netbsd32_voidp *) addr;
294f2ef31cbSskrll 		syscallarg(int) data;
295f2ef31cbSskrll 	} */
296f2ef31cbSskrll 
29701cfb8b6Smgorny 	req = PTRACE_TRANSLATE_REQUEST32(SCARG(uap, req));
29801cfb8b6Smgorny 	if (req == -1)
29901cfb8b6Smgorny 		return EOPNOTSUPP;
30001cfb8b6Smgorny 
30101cfb8b6Smgorny 	return do_ptrace(&netbsd32_ptm, l, req, SCARG(uap, pid),
302f2ef31cbSskrll 	    SCARG_P32(uap, addr), SCARG(uap, data), retval);
303f2ef31cbSskrll }
304f2ef31cbSskrll 
305f2ef31cbSskrll static const struct syscall_package compat_ptrace_syscalls[] = {
306f2ef31cbSskrll 	{ NETBSD32_SYS_netbsd32_ptrace, 0, (sy_call_t *)netbsd32_ptrace },
307f2ef31cbSskrll 	{ 0, 0, NULL },
308f2ef31cbSskrll };
309f2ef31cbSskrll 
310a60b9909Spgoyette #define	DEPS	"compat_netbsd32,ptrace_common"
311a60b9909Spgoyette 
312a60b9909Spgoyette MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, DEPS);
313f2ef31cbSskrll 
314f2ef31cbSskrll static int
compat_netbsd32_ptrace_modcmd(modcmd_t cmd,void * arg)315f2ef31cbSskrll compat_netbsd32_ptrace_modcmd(modcmd_t cmd, void *arg)
316f2ef31cbSskrll {
317f2ef31cbSskrll 	int error;
318f2ef31cbSskrll 
319f2ef31cbSskrll 	switch (cmd) {
320f2ef31cbSskrll 	case MODULE_CMD_INIT:
321f2ef31cbSskrll 		error = syscall_establish(&emul_netbsd32,
322f2ef31cbSskrll 		    compat_ptrace_syscalls);
323f2ef31cbSskrll 		break;
324f2ef31cbSskrll 	case MODULE_CMD_FINI:
325f2ef31cbSskrll 		error = syscall_disestablish(&emul_netbsd32,
326f2ef31cbSskrll 		    compat_ptrace_syscalls);
327f2ef31cbSskrll 		break;
328f2ef31cbSskrll 	default:
329f2ef31cbSskrll 		error = ENOTTY;
330f2ef31cbSskrll 		break;
331f2ef31cbSskrll 	}
332f2ef31cbSskrll 	return error;
333f2ef31cbSskrll }
334