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