1 /* $NetBSD: linux_ptrace.c,v 1.3 2001/02/04 22:59:26 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2001 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 and Emmanuel Dreyfus. 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 * Function linux_sys_ptrace_arch() is taken from NetBSD/i386 41 * with some stuff deleted to get it compiling. It is not expected to 42 * work, and it should be checked with care or re-writen. 43 */ 44 45 #include <sys/types.h> 46 #include <sys/param.h> 47 #include <sys/malloc.h> 48 #include <sys/mount.h> 49 #include <sys/proc.h> 50 #include <sys/ptrace.h> 51 #include <sys/systm.h> 52 #include <sys/syscallargs.h> 53 #include <uvm/uvm_extern.h> 54 55 #include <machine/reg.h> 56 57 #include <compat/linux/common/linux_types.h> 58 #include <compat/linux/common/linux_ptrace.h> 59 #include <compat/linux/common/linux_signal.h> 60 61 #include <compat/linux/common/linux_util.h> 62 #include <compat/linux/common/linux_machdep.h> 63 #include <compat/linux/common/linux_emuldata.h> 64 #include <compat/linux/common/linux_exec.h> /* for emul_linux */ 65 66 #include <compat/linux/linux_syscallargs.h> 67 68 #include <lib/libkern/libkern.h> /* for offsetof() */ 69 70 /* 71 * From Linux's include/asm-ppc/ptrace.h. 72 * structure used for storing reg context: defined in linux_machdep.h 73 * structure used for storing floating point context: 74 * Linux just uses a double fpr[32], no struct 75 */ 76 77 /* 78 * user struct for linux process - this is used for Linux ptrace emulation 79 * most of it is junk only used by gdb 80 * 81 * From Linux's include/asm-ppc/user.h 82 * 83 * XXX u_ar0 was a struct reg in Linux/powerpc 84 * Can't find out what a struct regs is for Linux/powerpc, 85 * so we use a struct pt_regs instead. don't know if this is right. 86 */ 87 88 struct linux_user { 89 struct linux_pt_regs regs; 90 size_t u_tsize; 91 size_t u_dsize; 92 size_t u_ssize; 93 unsigned long start_code; 94 unsigned long start_data; 95 unsigned long start_stack; 96 long int signal; 97 struct linux_pt_regs *u_ar0; /* help gdb find registers */ 98 unsigned long magic; 99 char u_comm[32]; 100 }; 101 102 #define lusr_startgdb regs 103 #define LUSR_OFF(member) offsetof(struct linux_user, member) 104 #define ISSET(t, f) ((t) & (f)) 105 106 int 107 linux_sys_ptrace_arch(p, v, retval) /* XXX Check me! (From NetBSD/i386) */ 108 struct proc *p; 109 void *v; 110 register_t *retval; 111 { 112 struct linux_sys_ptrace_args /* { 113 syscallarg(int) request; 114 syscallarg(int) pid; 115 syscallarg(int) addr; 116 syscallarg(int) data; 117 } */ *uap = v; 118 int request, error; 119 struct proc *t; /* target process */ 120 struct reg *regs = NULL; 121 struct fpreg *fpregs = NULL; 122 struct linux_pt_regs *linux_regs = NULL; 123 double *linux_fpreg = NULL; /* it's an array, not a struct */ 124 int addr; 125 int i; 126 127 128 switch (request = SCARG(uap, request)) { 129 case LINUX_PTRACE_PEEKUSR: 130 case LINUX_PTRACE_POKEUSR: 131 case LINUX_PTRACE_GETREGS: 132 case LINUX_PTRACE_SETREGS: 133 case LINUX_PTRACE_GETFPREGS: 134 case LINUX_PTRACE_SETFPREGS: 135 break; 136 default: 137 return EIO; 138 } 139 140 /* Find the process we're supposed to be operating on. */ 141 if ((t = pfind(SCARG(uap, pid))) == NULL) 142 return ESRCH; 143 144 /* 145 * You can't do what you want to the process if: 146 * (1) It's not being traced at all, 147 */ 148 if (!ISSET(t->p_flag, P_TRACED)) 149 return EPERM; 150 151 /* 152 * (2) it's being traced by procfs (which has 153 * different signal delivery semantics), 154 */ 155 if (ISSET(t->p_flag, P_FSTRACE)) 156 return EBUSY; 157 158 /* 159 * (3) it's not being traced by _you_, or 160 */ 161 if (t->p_pptr != p) 162 return EBUSY; 163 164 /* 165 * (4) it's not currently stopped. 166 */ 167 if (t->p_stat != SSTOP || !ISSET(t->p_flag, P_WAITED)) 168 return EBUSY; 169 170 *retval = 0; 171 172 switch (request) { 173 case LINUX_PTRACE_GETREGS: 174 MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK); 175 MALLOC(linux_regs, struct linux_pt_regs*, sizeof(*linux_regs), 176 M_TEMP, M_WAITOK); 177 178 error = process_read_regs(t, regs); 179 if (error != 0) 180 goto out; 181 182 for (i=0; i<=31; i++) 183 linux_regs->lgpr[i] = regs->fixreg[i]; 184 linux_regs->lnip = regs->pc; 185 linux_regs->lmsr = 0; 186 /* XXX Is that right? */ 187 linux_regs->lorig_gpr3 = regs->fixreg[3]; 188 linux_regs->lctr = regs->ctr; 189 linux_regs->llink = regs->lr; 190 linux_regs->lxer = regs->xer; 191 linux_regs->lccr = regs->cr; 192 linux_regs->lmq = 0; 193 linux_regs->ltrap = 0; 194 linux_regs->ldar = 0; 195 linux_regs->ldsisr = 0; 196 linux_regs->lresult = 0; 197 198 error = copyout(linux_regs, (caddr_t)SCARG(uap, data), 199 sizeof(struct linux_pt_regs)); 200 goto out; 201 202 case LINUX_PTRACE_SETREGS: 203 MALLOC(regs, struct reg*, sizeof(struct reg), M_TEMP, M_WAITOK); 204 MALLOC(linux_regs, struct linux_pt_regs*, sizeof(*linux_regs), 205 M_TEMP, M_WAITOK); 206 207 error = copyin((caddr_t)SCARG(uap, data), linux_regs, 208 sizeof(struct linux_pt_regs)); 209 if (error != 0) 210 goto out; 211 212 for (i=0; i<=31; i++) 213 regs->fixreg[i] = linux_regs->lgpr[i]; 214 regs->lr = linux_regs->llink; 215 regs->cr = linux_regs->lccr; 216 regs->xer = linux_regs->lxer; 217 regs->ctr = linux_regs->lctr; 218 regs->pc = linux_regs->lnip; /* XXX */ 219 220 error = process_write_regs(t, regs); 221 goto out; 222 223 case LINUX_PTRACE_GETFPREGS: 224 MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg), 225 M_TEMP, M_WAITOK); 226 MALLOC(linux_fpreg, double *, 227 32*sizeof(double), M_TEMP, M_WAITOK); 228 229 error = process_read_fpregs(t, fpregs); 230 if (error != 0) 231 goto out; 232 233 /* zero the contents if NetBSD fpreg structure is smaller */ 234 if (sizeof(struct fpreg) < (32*sizeof(double))) 235 memset(linux_fpreg, '\0', (32*sizeof(double))); 236 237 memcpy(linux_fpreg, fpregs, 238 min(32*sizeof(double), sizeof(struct fpreg))); 239 error = copyout(linux_fpreg, (caddr_t)SCARG(uap, data), 240 32*sizeof(double)); 241 goto out; 242 243 case LINUX_PTRACE_SETFPREGS: 244 MALLOC(fpregs, struct fpreg *, sizeof(struct fpreg), 245 M_TEMP, M_WAITOK); 246 MALLOC(linux_fpreg, double *, 247 32*sizeof(double), M_TEMP, M_WAITOK); 248 error = copyin((caddr_t)SCARG(uap, data), linux_fpreg, 249 32*sizeof(double)); 250 if (error != 0) 251 goto out; 252 253 memset(fpregs, '\0', sizeof(struct fpreg)); 254 memcpy(fpregs, linux_fpreg, 255 min(32*sizeof(double), sizeof(struct fpreg))); 256 257 error = process_write_regs(t, regs); 258 goto out; 259 260 case LINUX_PTRACE_PEEKUSR: 261 addr = SCARG(uap, addr); 262 263 PHOLD(t); /* need full process info */ 264 error = 0; 265 if (addr < LUSR_OFF(lusr_startgdb)) { 266 error = 1; 267 } else if (addr == LUSR_OFF(u_tsize)) 268 *retval = p->p_vmspace->vm_tsize; 269 else if (addr == LUSR_OFF(u_dsize)) 270 *retval = p->p_vmspace->vm_dsize; 271 else if (addr == LUSR_OFF(u_ssize)) 272 *retval = p->p_vmspace->vm_ssize; 273 else if (addr == LUSR_OFF(start_code)) 274 *retval = (register_t) p->p_vmspace->vm_taddr; 275 else if (addr == LUSR_OFF(start_stack)) 276 *retval = (register_t) p->p_vmspace->vm_minsaddr; 277 else if (addr == LUSR_OFF(u_ar0)) 278 *retval = LUSR_OFF(regs); 279 else if (addr == LUSR_OFF(signal)) { 280 error = 1; 281 } else if (addr == LUSR_OFF(signal)) { 282 error = 1; 283 } else if (addr == LUSR_OFF(magic)) { 284 error = 1; 285 } else if (addr == LUSR_OFF(u_comm)) { 286 error = 1; 287 } else { 288 #ifdef DEBUG_LINUX 289 printf("linux_ptrace: unsupported address: %d\n", addr); 290 #endif 291 error = 1; 292 } 293 294 PRELE(t); 295 296 if (!error) 297 return 0; 298 299 case LINUX_PTRACE_POKEUSR: 300 /* 301 * XXX NetBSD/i386 only handle debugregs here. It seems these 302 * debugregs are not availlable on powerpc. Hence we do nothing. 303 */ 304 break; 305 default: 306 /* never reached */ 307 break; 308 } 309 310 return EIO; 311 312 out: 313 if (regs) 314 FREE(regs, M_TEMP); 315 if (fpregs) 316 FREE(fpregs, M_TEMP); 317 if (linux_regs) 318 FREE(linux_regs, M_TEMP); 319 if (linux_fpreg) 320 FREE(linux_fpreg, M_TEMP); 321 return (error); 322 } 323