Home | History | Annotate | Line # | Download | only in arm
linux_ptrace.c revision 1.7.2.1
      1  1.7.2.1     yamt /*	$NetBSD: linux_ptrace.c,v 1.7.2.1 2007/02/27 16:53:35 yamt Exp $	*/
      2      1.2    bjh21 
      3      1.2    bjh21 /*-
      4      1.2    bjh21  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5      1.2    bjh21  * All rights reserved.
      6      1.2    bjh21  *
      7      1.2    bjh21  * This code is derived from software contributed to The NetBSD Foundation
      8      1.2    bjh21  * by Matthias Scheler.
      9      1.2    bjh21  *
     10      1.2    bjh21  * Redistribution and use in source and binary forms, with or without
     11      1.2    bjh21  * modification, are permitted provided that the following conditions
     12      1.2    bjh21  * are met:
     13      1.2    bjh21  * 1. Redistributions of source code must retain the above copyright
     14      1.2    bjh21  *    notice, this list of conditions and the following disclaimer.
     15      1.2    bjh21  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.2    bjh21  *    notice, this list of conditions and the following disclaimer in the
     17      1.2    bjh21  *    documentation and/or other materials provided with the distribution.
     18      1.2    bjh21  * 3. All advertising materials mentioning features or use of this software
     19      1.2    bjh21  *    must display the following acknowledgement:
     20      1.2    bjh21  *	This product includes software developed by the NetBSD
     21      1.2    bjh21  *	Foundation, Inc. and its contributors.
     22      1.2    bjh21  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23      1.2    bjh21  *    contributors may be used to endorse or promote products derived
     24      1.2    bjh21  *    from this software without specific prior written permission.
     25      1.2    bjh21  *
     26      1.2    bjh21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27      1.2    bjh21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28      1.2    bjh21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29      1.2    bjh21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30      1.2    bjh21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31      1.2    bjh21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32      1.2    bjh21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33      1.2    bjh21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34      1.2    bjh21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35      1.2    bjh21  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36      1.2    bjh21  * POSSIBILITY OF SUCH DAMAGE.
     37      1.2    bjh21  */
     38      1.2    bjh21 
     39      1.2    bjh21 
     40      1.2    bjh21 #include <sys/cdefs.h>
     41  1.7.2.1     yamt __KERNEL_RCSID(0, "$NetBSD: linux_ptrace.c,v 1.7.2.1 2007/02/27 16:53:35 yamt Exp $");
     42      1.1    bjh21 
     43      1.1    bjh21 #include <sys/param.h>
     44      1.2    bjh21 #include <sys/malloc.h>
     45      1.2    bjh21 #include <sys/mount.h>
     46      1.2    bjh21 #include <sys/proc.h>
     47      1.2    bjh21 #include <sys/ptrace.h>
     48      1.2    bjh21 #include <sys/systm.h>
     49      1.2    bjh21 #include <sys/syscallargs.h>
     50      1.2    bjh21 #include <uvm/uvm_extern.h>
     51      1.2    bjh21 
     52      1.2    bjh21 #include <machine/reg.h>
     53      1.2    bjh21 
     54      1.2    bjh21 #include <compat/linux/common/linux_types.h>
     55      1.2    bjh21 #include <compat/linux/common/linux_ptrace.h>
     56      1.2    bjh21 #include <compat/linux/common/linux_signal.h>
     57      1.2    bjh21 
     58      1.2    bjh21 #include <compat/linux/common/linux_util.h>
     59      1.2    bjh21 #include <compat/linux/common/linux_machdep.h>
     60      1.2    bjh21 #include <compat/linux/common/linux_emuldata.h>
     61      1.2    bjh21 #include <compat/linux/common/linux_exec.h>	/* for emul_linux */
     62      1.2    bjh21 
     63      1.2    bjh21 #include <compat/linux/linux_syscallargs.h>
     64      1.1    bjh21 
     65      1.2    bjh21 #include <lib/libkern/libkern.h>	/* for offsetof() */
     66      1.1    bjh21 
     67      1.2    bjh21 /*
     68      1.2    bjh21  * On ARMv2, uregs contains R0--R15, orig_R0.
     69      1.2    bjh21  * On ARMv3 and later, it's R0--R15, CPSR, orig_R0.
     70      1.2    bjh21  * As far as I can see, Linux doesn't initialise orig_R0 on ARMv2, so we
     71      1.2    bjh21  * just produce the ARMv3 version.
     72      1.2    bjh21  */
     73      1.2    bjh21 
     74      1.2    bjh21 struct linux_reg {
     75      1.2    bjh21 	long uregs[18];
     76      1.2    bjh21 };
     77      1.2    bjh21 
     78      1.2    bjh21 #define LINUX_REG_R0	0
     79      1.2    bjh21 #define LINUX_REG_R1	1
     80      1.2    bjh21 #define LINUX_REG_R2	2
     81      1.2    bjh21 #define LINUX_REG_R3	3
     82      1.2    bjh21 #define LINUX_REG_R4	4
     83      1.2    bjh21 #define LINUX_REG_R5	5
     84      1.2    bjh21 #define LINUX_REG_R6	6
     85      1.2    bjh21 #define LINUX_REG_R7	7
     86      1.2    bjh21 #define LINUX_REG_R8	8
     87      1.2    bjh21 #define LINUX_REG_R9	9
     88      1.2    bjh21 #define LINUX_REG_R10	10
     89      1.2    bjh21 #define LINUX_REG_FP	11
     90      1.2    bjh21 #define LINUX_REG_IP	12
     91      1.2    bjh21 #define LINUX_REG_SP	13
     92      1.2    bjh21 #define LINUX_REG_LR	14
     93      1.2    bjh21 #define LINUX_REG_PC	15
     94      1.2    bjh21 #define LINUX_REG_CPSR	16
     95      1.2    bjh21 #define LINUX_REG_ORIG_R0 17
     96      1.2    bjh21 
     97      1.1    bjh21 int
     98      1.3  thorpej linux_sys_ptrace_arch(l, v, retval)
     99      1.3  thorpej 	struct lwp *l;
    100      1.1    bjh21 	void *v;
    101      1.1    bjh21 	register_t *retval;
    102      1.1    bjh21 {
    103      1.2    bjh21 	struct linux_sys_ptrace_args /* {
    104      1.2    bjh21 		syscallarg(int) request;
    105      1.2    bjh21 		syscallarg(int) pid;
    106      1.2    bjh21 		syscallarg(int) addr;
    107      1.2    bjh21 		syscallarg(int) data;
    108      1.2    bjh21 	} */ *uap = v;
    109      1.3  thorpej 	struct proc *p = l->l_proc;
    110      1.2    bjh21 	int request, error;
    111      1.2    bjh21 	struct proc *t;				/* target process */
    112      1.3  thorpej 	struct lwp *lt;
    113      1.2    bjh21 	struct reg *regs = NULL;
    114      1.2    bjh21 	struct fpreg *fpregs = NULL;
    115      1.2    bjh21 	struct linux_reg *linux_regs = NULL;
    116      1.2    bjh21 	struct linux_fpreg *linux_fpregs = NULL;
    117      1.2    bjh21 
    118      1.2    bjh21 	request = SCARG(uap, request);
    119      1.2    bjh21 
    120      1.2    bjh21 	if ((request != LINUX_PTRACE_GETREGS) &&
    121      1.2    bjh21 	    (request != LINUX_PTRACE_SETREGS))
    122      1.2    bjh21 		return EIO;
    123      1.2    bjh21 
    124      1.2    bjh21 	/* Find the process we're supposed to be operating on. */
    125      1.2    bjh21 	if ((t = pfind(SCARG(uap, pid))) == NULL)
    126      1.2    bjh21 		return ESRCH;
    127      1.2    bjh21 
    128      1.2    bjh21 	/*
    129      1.2    bjh21 	 * You can't do what you want to the process if:
    130      1.2    bjh21 	 *	(1) It's not being traced at all,
    131      1.2    bjh21 	 */
    132  1.7.2.1     yamt 	if (!ISSET(t->p_slflag, PSL_TRACED))
    133      1.2    bjh21 		return EPERM;
    134      1.2    bjh21 
    135      1.2    bjh21 	/*
    136      1.2    bjh21 	 *	(2) it's being traced by procfs (which has
    137      1.2    bjh21 	 *	    different signal delivery semantics),
    138      1.2    bjh21 	 */
    139  1.7.2.1     yamt 	if (ISSET(t->p_slflag, PSL_FSTRACE))
    140      1.2    bjh21 		return EBUSY;
    141      1.2    bjh21 
    142      1.2    bjh21 	/*
    143      1.2    bjh21 	 *	(3) it's not being traced by _you_, or
    144      1.2    bjh21 	 */
    145      1.2    bjh21 	if (t->p_pptr != p)
    146      1.2    bjh21 		return EBUSY;
    147      1.2    bjh21 
    148      1.2    bjh21 	/*
    149      1.2    bjh21 	 *	(4) it's not currently stopped.
    150      1.2    bjh21 	 */
    151  1.7.2.1     yamt 	if (t->p_stat != SSTOP || !t->p_waited)
    152      1.2    bjh21 		return EBUSY;
    153      1.2    bjh21 
    154      1.3  thorpej 	/* XXX NJWLWP
    155      1.3  thorpej 	 * The entire ptrace interface needs work to be useful to
    156      1.3  thorpej 	 * a process with multiple LWPs. For the moment, we'll
    157      1.3  thorpej 	 * just kluge this and fail on others.
    158      1.3  thorpej 	 */
    159      1.3  thorpej 
    160      1.3  thorpej 	if (p->p_nlwps > 1)
    161      1.3  thorpej 		return (ENOSYS);
    162      1.3  thorpej 
    163      1.3  thorpej 	lt = LIST_FIRST(&t->p_lwps);
    164      1.3  thorpej 
    165      1.2    bjh21 	*retval = 0;
    166      1.2    bjh21 
    167      1.2    bjh21 	switch (request) {
    168      1.2    bjh21 	case  LINUX_PTRACE_GETREGS:
    169      1.2    bjh21 		MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
    170      1.2    bjh21 		MALLOC(linux_regs, struct linux_reg*, sizeof(struct linux_reg),
    171      1.2    bjh21 			M_TEMP, M_WAITOK);
    172      1.2    bjh21 
    173      1.3  thorpej 		error = process_read_regs(lt, regs);
    174      1.2    bjh21 		if (error != 0)
    175      1.2    bjh21 			goto out;
    176      1.2    bjh21 
    177      1.2    bjh21 		memcpy(linux_regs->uregs, regs->r, 13 * sizeof(register_t));
    178      1.2    bjh21 		linux_regs->uregs[LINUX_REG_SP] = regs->r_sp;
    179      1.2    bjh21 		linux_regs->uregs[LINUX_REG_LR] = regs->r_lr;
    180      1.2    bjh21 		linux_regs->uregs[LINUX_REG_PC] = regs->r_pc;
    181      1.2    bjh21 		linux_regs->uregs[LINUX_REG_CPSR] = regs->r_cpsr;
    182      1.2    bjh21 		linux_regs->uregs[LINUX_REG_ORIG_R0] = regs->r[0];
    183      1.2    bjh21 
    184      1.2    bjh21 		error = copyout(linux_regs, (caddr_t)SCARG(uap, data),
    185      1.2    bjh21 		    sizeof(struct linux_reg));
    186      1.2    bjh21 		goto out;
    187      1.2    bjh21 
    188      1.2    bjh21 	case  LINUX_PTRACE_SETREGS:
    189      1.2    bjh21 		MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK);
    190      1.2    bjh21 		MALLOC(linux_regs, struct linux_reg *, sizeof(struct linux_reg),
    191      1.2    bjh21 			M_TEMP, M_WAITOK);
    192      1.2    bjh21 
    193      1.2    bjh21 		error = copyin((caddr_t)SCARG(uap, data), linux_regs,
    194      1.2    bjh21 		    sizeof(struct linux_reg));
    195      1.2    bjh21 		if (error != 0)
    196      1.2    bjh21 			goto out;
    197      1.2    bjh21 
    198      1.2    bjh21 		memcpy(regs->r, linux_regs->uregs, 13 * sizeof(register_t));
    199      1.2    bjh21 		regs->r_sp = linux_regs->uregs[LINUX_REG_SP];
    200      1.2    bjh21 		regs->r_lr = linux_regs->uregs[LINUX_REG_LR];
    201      1.2    bjh21 		regs->r_pc = linux_regs->uregs[LINUX_REG_PC];
    202      1.2    bjh21 		regs->r_cpsr = linux_regs->uregs[LINUX_REG_CPSR];
    203      1.2    bjh21 
    204      1.3  thorpej 		error = process_write_regs(lt, regs);
    205      1.2    bjh21 		goto out;
    206      1.2    bjh21 
    207      1.2    bjh21 	default:
    208      1.2    bjh21 		/* never reached */
    209      1.2    bjh21 		break;
    210      1.2    bjh21 	}
    211      1.2    bjh21 
    212      1.2    bjh21 	return EIO;
    213      1.2    bjh21 
    214      1.2    bjh21     out:
    215      1.2    bjh21 	if (regs)
    216      1.2    bjh21 		FREE(regs, M_TEMP);
    217      1.2    bjh21 	if (fpregs)
    218      1.2    bjh21 		FREE(fpregs, M_TEMP);
    219      1.2    bjh21 	if (linux_regs)
    220      1.2    bjh21 		FREE(linux_regs, M_TEMP);
    221      1.2    bjh21 	if (linux_fpregs)
    222      1.2    bjh21 		FREE(linux_fpregs, M_TEMP);
    223      1.2    bjh21 	return (error);
    224      1.1    bjh21 
    225      1.1    bjh21 }
    226