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