1 /* $NetBSD: linux_ptrace.c,v 1.3 1999/12/16 15:11:19 tron 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 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/mount.h> 42 #include <sys/proc.h> 43 #include <sys/ptrace.h> 44 #include <sys/systm.h> 45 #include <sys/syscallargs.h> 46 47 #include <machine/reg.h> 48 49 #include <compat/linux/common/linux_types.h> 50 #include <compat/linux/common/linux_ptrace.h> 51 #include <compat/linux/common/linux_signal.h> 52 53 #include <compat/linux/common/linux_util.h> 54 #include <compat/linux/common/linux_machdep.h> 55 56 #include <compat/linux/linux_syscallargs.h> 57 58 #define LINUX_PTRACE_GETREGS 12 59 #define LINUX_PTRACE_SETREGS 13 60 #define LINUX_PTRACE_GETFPREGS 14 61 #define LINUX_PTRACE_SETFPREGS 15 62 63 struct linux_reg { 64 long ebx; 65 long ecx; 66 long edx; 67 long esi; 68 long edi; 69 long ebp; 70 long eax; 71 int xds; 72 int xes; 73 long orig_eax; 74 long eip; 75 int xcs; 76 long eflags; 77 long esp; 78 int xss; 79 }; 80 81 #define ISSET(t, f) ((t) & (f)) 82 83 int 84 linux_sys_ptrace_arch(p, v, retval) 85 struct proc *p; 86 void *v; 87 register_t *retval; 88 { 89 struct linux_sys_ptrace_args /* { 90 syscallarg(int) request; 91 syscallarg(int) pid; 92 syscallarg(int) addr; 93 syscallarg(int) data; 94 } */ *uap = v; 95 int request, error; 96 struct proc *t; /* target process */ 97 struct reg regs; 98 struct linux_reg linux_regs; 99 100 request = SCARG(uap, request); 101 102 if ((request != LINUX_PTRACE_GETREGS) && 103 (request != LINUX_PTRACE_SETREGS) && 104 (request != LINUX_PTRACE_GETFPREGS) && 105 (request != LINUX_PTRACE_SETFPREGS)) 106 return EIO; 107 108 /* Find the process we're supposed to be operating on. */ 109 if ((t = pfind(SCARG(uap, pid))) == NULL) 110 return ESRCH; 111 112 /* 113 * You can't do what you want to the process if: 114 * (1) It's not being traced at all, 115 */ 116 if (!ISSET(t->p_flag, P_TRACED)) 117 return EPERM; 118 119 /* 120 * (2) it's being traced by procfs (which has 121 * different signal delivery semantics), 122 */ 123 if (ISSET(t->p_flag, P_FSTRACE)) 124 return EBUSY; 125 126 /* 127 * (3) it's not being traced by _you_, or 128 */ 129 if (t->p_pptr != p) 130 return EBUSY; 131 132 /* 133 * (4) it's not currently stopped. 134 */ 135 if (t->p_stat != SSTOP || !ISSET(t->p_flag, P_WAITED)) 136 return EBUSY; 137 138 *retval = 0; 139 140 switch (request) { 141 case LINUX_PTRACE_GETREGS: 142 error = process_read_regs(t, ®s); 143 if (error != 0) 144 return error; 145 146 linux_regs.ebx = regs.r_ebx; 147 linux_regs.ecx = regs.r_ecx; 148 linux_regs.edx = regs.r_edx; 149 linux_regs.esi = regs.r_esi; 150 linux_regs.edi = regs.r_edi; 151 linux_regs.ebp = regs.r_ebp; 152 linux_regs.eax = regs.r_eax; 153 linux_regs.xds = regs.r_ds; 154 linux_regs.xes = regs.r_es; 155 linux_regs.orig_eax = regs.r_eax; /* XXX is this correct? */ 156 linux_regs.eip = regs.r_eip; 157 linux_regs.xcs = regs.r_cs; 158 linux_regs.eflags = regs.r_eflags; 159 linux_regs.esp = regs.r_esp; 160 linux_regs.xss = regs.r_ss; 161 162 return copyout(&linux_regs, (caddr_t)SCARG(uap, data), 163 sizeof(struct linux_reg)); 164 case LINUX_PTRACE_SETREGS: 165 error = copyin((caddr_t)SCARG(uap, data), &linux_regs, 166 sizeof(struct linux_reg)); 167 if (error != 0) 168 return error; 169 170 regs.r_ebx = linux_regs.ebx; 171 regs.r_ecx = linux_regs.ecx; 172 regs.r_edx = linux_regs.edx; 173 regs.r_esi = linux_regs.esi; 174 regs.r_edi = linux_regs.edi; 175 regs.r_ebp = linux_regs.ebp; 176 regs.r_eax = linux_regs.eax; 177 regs.r_ds = linux_regs.xds; 178 regs.r_es = linux_regs.xes; 179 regs.r_eip = linux_regs.eip; 180 regs.r_cs = linux_regs.xcs; 181 regs.r_eflags = linux_regs.eflags; 182 regs.r_esp = linux_regs.esp; 183 regs.r_ss = linux_regs.xss; 184 185 return process_write_regs(t, ®s); 186 } 187 188 return EIO; 189 } 190