1*41aa5859Sriastradh /* $NetBSD: linux_ptrace.c,v 1.23 2021/09/07 11:43:04 riastradh Exp $ */
24929dc57Sbjh21
34929dc57Sbjh21 /*-
44929dc57Sbjh21 * Copyright (c) 1999 The NetBSD Foundation, Inc.
54929dc57Sbjh21 * All rights reserved.
64929dc57Sbjh21 *
74929dc57Sbjh21 * This code is derived from software contributed to The NetBSD Foundation
84929dc57Sbjh21 * by Matthias Scheler.
94929dc57Sbjh21 *
104929dc57Sbjh21 * Redistribution and use in source and binary forms, with or without
114929dc57Sbjh21 * modification, are permitted provided that the following conditions
124929dc57Sbjh21 * are met:
134929dc57Sbjh21 * 1. Redistributions of source code must retain the above copyright
144929dc57Sbjh21 * notice, this list of conditions and the following disclaimer.
154929dc57Sbjh21 * 2. Redistributions in binary form must reproduce the above copyright
164929dc57Sbjh21 * notice, this list of conditions and the following disclaimer in the
174929dc57Sbjh21 * documentation and/or other materials provided with the distribution.
184929dc57Sbjh21 *
194929dc57Sbjh21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
204929dc57Sbjh21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214929dc57Sbjh21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
224929dc57Sbjh21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
234929dc57Sbjh21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244929dc57Sbjh21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254929dc57Sbjh21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264929dc57Sbjh21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274929dc57Sbjh21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284929dc57Sbjh21 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294929dc57Sbjh21 * POSSIBILITY OF SUCH DAMAGE.
304929dc57Sbjh21 */
314929dc57Sbjh21
324929dc57Sbjh21
334929dc57Sbjh21 #include <sys/cdefs.h>
34*41aa5859Sriastradh __KERNEL_RCSID(0, "$NetBSD: linux_ptrace.c,v 1.23 2021/09/07 11:43:04 riastradh Exp $");
3564625064Sbjh21
3664625064Sbjh21 #include <sys/param.h>
374929dc57Sbjh21 #include <sys/mount.h>
384929dc57Sbjh21 #include <sys/proc.h>
394929dc57Sbjh21 #include <sys/ptrace.h>
4064625064Sbjh21 #include <sys/systm.h>
414929dc57Sbjh21 #include <sys/syscallargs.h>
424929dc57Sbjh21 #include <uvm/uvm_extern.h>
434929dc57Sbjh21
444929dc57Sbjh21 #include <machine/reg.h>
45d31df958Smatt #include <machine/pcb.h>
464929dc57Sbjh21
474929dc57Sbjh21 #include <compat/linux/common/linux_types.h>
484929dc57Sbjh21 #include <compat/linux/common/linux_ptrace.h>
494929dc57Sbjh21 #include <compat/linux/common/linux_signal.h>
504929dc57Sbjh21
514929dc57Sbjh21 #include <compat/linux/common/linux_util.h>
524929dc57Sbjh21 #include <compat/linux/common/linux_machdep.h>
534929dc57Sbjh21 #include <compat/linux/common/linux_emuldata.h>
544929dc57Sbjh21 #include <compat/linux/common/linux_exec.h> /* for emul_linux */
554929dc57Sbjh21
564929dc57Sbjh21 #include <compat/linux/linux_syscallargs.h>
574929dc57Sbjh21
584929dc57Sbjh21 #include <lib/libkern/libkern.h> /* for offsetof() */
594929dc57Sbjh21
604929dc57Sbjh21 /*
614929dc57Sbjh21 * On ARMv2, uregs contains R0--R15, orig_R0.
624929dc57Sbjh21 * On ARMv3 and later, it's R0--R15, CPSR, orig_R0.
634929dc57Sbjh21 * As far as I can see, Linux doesn't initialise orig_R0 on ARMv2, so we
644929dc57Sbjh21 * just produce the ARMv3 version.
654929dc57Sbjh21 */
664929dc57Sbjh21
674929dc57Sbjh21 struct linux_reg {
684929dc57Sbjh21 long uregs[18];
694929dc57Sbjh21 };
704929dc57Sbjh21
714929dc57Sbjh21 #define LINUX_REG_R0 0
724929dc57Sbjh21 #define LINUX_REG_R1 1
734929dc57Sbjh21 #define LINUX_REG_R2 2
744929dc57Sbjh21 #define LINUX_REG_R3 3
754929dc57Sbjh21 #define LINUX_REG_R4 4
764929dc57Sbjh21 #define LINUX_REG_R5 5
774929dc57Sbjh21 #define LINUX_REG_R6 6
784929dc57Sbjh21 #define LINUX_REG_R7 7
794929dc57Sbjh21 #define LINUX_REG_R8 8
804929dc57Sbjh21 #define LINUX_REG_R9 9
814929dc57Sbjh21 #define LINUX_REG_R10 10
824929dc57Sbjh21 #define LINUX_REG_FP 11
834929dc57Sbjh21 #define LINUX_REG_IP 12
844929dc57Sbjh21 #define LINUX_REG_SP 13
854929dc57Sbjh21 #define LINUX_REG_LR 14
864929dc57Sbjh21 #define LINUX_REG_PC 15
874929dc57Sbjh21 #define LINUX_REG_CPSR 16
884929dc57Sbjh21 #define LINUX_REG_ORIG_R0 17
894929dc57Sbjh21
90bfb6f314Sad int linux_ptrace_disabled = 1; /* bitrotted */
91bfb6f314Sad
9264625064Sbjh21 int
linux_sys_ptrace_arch(struct lwp * l,const struct linux_sys_ptrace_args * uap,register_t * retval)933c507045Srmind linux_sys_ptrace_arch(struct lwp *l, const struct linux_sys_ptrace_args *uap,
943c507045Srmind register_t *retval)
9564625064Sbjh21 {
967e2790cfSdsl /* {
974929dc57Sbjh21 syscallarg(int) request;
984929dc57Sbjh21 syscallarg(int) pid;
994929dc57Sbjh21 syscallarg(int) addr;
1004929dc57Sbjh21 syscallarg(int) data;
1017e2790cfSdsl } */
1023c507045Srmind struct proc *p = l->l_proc, *t;
10346141a31Sthorpej struct lwp *lt;
10433fa5ccbSchs #ifdef _ARM_ARCH_6
10533fa5ccbSchs struct pcb *pcb;
10633fa5ccbSchs void *val;
10733fa5ccbSchs #endif
1084929dc57Sbjh21 struct reg *regs = NULL;
1094929dc57Sbjh21 struct linux_reg *linux_regs = NULL;
1103c507045Srmind int request, error;
11164625064Sbjh21
112bfb6f314Sad if (linux_ptrace_disabled)
113bfb6f314Sad return ENOSYS;
114bfb6f314Sad
1153c507045Srmind error = 0;
1164929dc57Sbjh21 request = SCARG(uap, request);
1173c507045Srmind regs = kmem_alloc(sizeof(struct reg), KM_SLEEP);
1183c507045Srmind linux_regs = kmem_alloc(sizeof(struct linux_reg), KM_SLEEP);
1194929dc57Sbjh21
1203c507045Srmind switch (request) {
1213c507045Srmind case LINUX_PTRACE_GETREGS:
1223c507045Srmind break;
1233c507045Srmind case LINUX_PTRACE_SETREGS:
1243c507045Srmind error = copyin((void *)SCARG(uap, data), linux_regs,
1253c507045Srmind sizeof(struct linux_reg));
1263c507045Srmind if (error) {
1273c507045Srmind goto out;
1283c507045Srmind }
1293c507045Srmind break;
1303c507045Srmind default:
1313c507045Srmind error = EIO;
1323c507045Srmind goto out;
1333c507045Srmind }
1344929dc57Sbjh21
1353c507045Srmind /* Find the process we are supposed to be operating on. */
1360eaaa024Sad mutex_enter(&proc_lock);
1373c507045Srmind if ((t = proc_find(SCARG(uap, pid))) == NULL) {
1380eaaa024Sad mutex_exit(&proc_lock);
1393c507045Srmind error = ESRCH;
1403c507045Srmind goto out;
1413c507045Srmind }
1423c507045Srmind mutex_enter(t->p_lock);
1434929dc57Sbjh21
1444929dc57Sbjh21 /*
1453c507045Srmind * You cannot do what you want to the process if:
1463c507045Srmind * 1. It is not being traced at all,
1474929dc57Sbjh21 */
1483c507045Srmind if (!ISSET(t->p_slflag, PSL_TRACED)) {
1493c507045Srmind mutex_exit(t->p_lock);
1500eaaa024Sad mutex_exit(&proc_lock);
1513c507045Srmind error = EPERM;
1523c507045Srmind goto out;
1533c507045Srmind }
1544929dc57Sbjh21 /*
1553c507045Srmind * 2. It is being traced by procfs (which has different signal
1563c507045Srmind * delivery semantics),
1573c507045Srmind * 3. It is not being traced by _you_, or
1583c507045Srmind * 4. It is not currently stopped.
1594929dc57Sbjh21 */
160a69b333eSkamil if (t->p_pptr != p || t->p_stat != SSTOP || !t->p_waited) {
1613c507045Srmind mutex_exit(t->p_lock);
1620eaaa024Sad mutex_exit(&proc_lock);
1633c507045Srmind error = EBUSY;
1643c507045Srmind goto out;
1653c507045Srmind }
1660eaaa024Sad mutex_exit(&proc_lock);
1673c507045Srmind /* XXX: ptrace needs revamp for multi-threading support. */
1683c507045Srmind if (t->p_nlwps > 1) {
1693c507045Srmind mutex_exit(t->p_lock);
1703c507045Srmind error = ENOSYS;
1713c507045Srmind goto out;
1723c507045Srmind }
17346141a31Sthorpej lt = LIST_FIRST(&t->p_lwps);
1744929dc57Sbjh21 *retval = 0;
1754929dc57Sbjh21
1764929dc57Sbjh21 switch (request) {
1774929dc57Sbjh21 case LINUX_PTRACE_GETREGS:
17846141a31Sthorpej error = process_read_regs(lt, regs);
1793c507045Srmind mutex_exit(t->p_lock);
1803c507045Srmind if (error) {
1813c507045Srmind break;
1823c507045Srmind }
183*41aa5859Sriastradh memset(linux_regs, 0, sizeof(*linux_regs));
1844929dc57Sbjh21 memcpy(linux_regs->uregs, regs->r, 13 * sizeof(register_t));
1854929dc57Sbjh21 linux_regs->uregs[LINUX_REG_SP] = regs->r_sp;
1864929dc57Sbjh21 linux_regs->uregs[LINUX_REG_LR] = regs->r_lr;
1874929dc57Sbjh21 linux_regs->uregs[LINUX_REG_PC] = regs->r_pc;
1884929dc57Sbjh21 linux_regs->uregs[LINUX_REG_CPSR] = regs->r_cpsr;
1894929dc57Sbjh21 linux_regs->uregs[LINUX_REG_ORIG_R0] = regs->r[0];
1904929dc57Sbjh21
19153524e44Schristos error = copyout(linux_regs, (void *)SCARG(uap, data),
1924929dc57Sbjh21 sizeof(struct linux_reg));
1933c507045Srmind break;
1944929dc57Sbjh21
1954929dc57Sbjh21 case LINUX_PTRACE_SETREGS:
1964929dc57Sbjh21 memcpy(regs->r, linux_regs->uregs, 13 * sizeof(register_t));
1974929dc57Sbjh21 regs->r_sp = linux_regs->uregs[LINUX_REG_SP];
1984929dc57Sbjh21 regs->r_lr = linux_regs->uregs[LINUX_REG_LR];
1994929dc57Sbjh21 regs->r_pc = linux_regs->uregs[LINUX_REG_PC];
2004929dc57Sbjh21 regs->r_cpsr = linux_regs->uregs[LINUX_REG_CPSR];
20146141a31Sthorpej error = process_write_regs(lt, regs);
20233fa5ccbSchs mutex_exit(t->p_lock);
20333fa5ccbSchs break;
20433fa5ccbSchs
20533fa5ccbSchs #ifdef _ARM_ARCH_6
20633fa5ccbSchs #define LINUX_PTRACE_GET_THREAD_AREA 22
20733fa5ccbSchs case LINUX_PTRACE_GET_THREAD_AREA:
20833fa5ccbSchs mutex_exit(t->p_lock);
20933fa5ccbSchs pcb = lwp_getpcb(l);
21051618153Schristos val = (void *)pcb->pcb_user_pid_ro;
21133fa5ccbSchs error = copyout(&val, (void *)SCARG(uap, data), sizeof(val));
21233fa5ccbSchs break;
21333fa5ccbSchs #endif
21433fa5ccbSchs
2154929dc57Sbjh21 default:
2163c507045Srmind mutex_exit(t->p_lock);
2174929dc57Sbjh21 }
2184929dc57Sbjh21 out:
2194929dc57Sbjh21 if (regs)
2203c507045Srmind kmem_free(regs, sizeof(*regs));
2214929dc57Sbjh21 if (linux_regs)
2223c507045Srmind kmem_free(linux_regs, sizeof(*linux_regs));
2233c507045Srmind return error;
2244929dc57Sbjh21
22564625064Sbjh21 }
226