xref: /netbsd-src/sys/compat/linux/arch/arm/linux_ptrace.c (revision 41aa5859b647891f23013f613e0858c4b789a7bf)
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