1 /*- 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * %sccs.include.proprietary.c% 11 * 12 * @(#)sys_process.c 8.6 (Berkeley) 02/14/95 13 */ 14 15 #define IPCREG 16 #include <sys/param.h> 17 #include <sys/systm.h> 18 #include <sys/proc.h> 19 #include <sys/vnode.h> 20 #include <sys/buf.h> 21 #include <sys/ptrace.h> 22 23 #include <sys/mount.h> 24 #include <sys/syscallargs.h> 25 26 #include <machine/reg.h> 27 #include <machine/psl.h> 28 #include <vm/vm.h> 29 #include <vm/vm_page.h> 30 31 #include <sys/user.h> 32 33 /* 34 * Priority for tracing 35 */ 36 #define IPCPRI PZERO 37 38 /* 39 * Tracing variables. 40 * Used to pass trace command from 41 * parent to child being traced. 42 * This data base cannot be 43 * shared and is locked 44 * per user. 45 */ 46 struct { 47 int ip_lock; 48 int ip_req; 49 caddr_t ip_addr; 50 int ip_data; 51 } ipc; 52 53 /* 54 * Process debugging system call. 55 */ 56 ptrace(curp, uap, retval) 57 struct proc *curp; 58 struct ptrace_args /* { 59 syscallarg(int) req; 60 syscallarg(pid_t) pid; 61 syscallarg(caddr_t) addr; 62 syscallarg(int) data; 63 } */ *uap; 64 register_t *retval; 65 { 66 register struct proc *p; 67 int error; 68 69 if (SCARG(uap, req) <= 0) { 70 curp->p_flag |= P_TRACED; 71 return (0); 72 } 73 p = pfind(SCARG(uap, pid)); 74 if (p == 0) 75 return (ESRCH); 76 if (SCARG(uap, req) == PT_ATTACH) { 77 /* 78 * Must be root if the process has used set user or group 79 * privileges or does not belong to the real user. Must 80 * not be already traced. Can't attach to ourselves. 81 */ 82 if ((p->p_flag & P_SUGID || 83 p->p_cred->p_ruid != curp->p_cred->p_ruid) && 84 (error = suser(p->p_ucred, &p->p_acflag)) != 0) 85 return (error); 86 if (p->p_flag & P_TRACED) 87 return (EALREADY); /* ??? */ 88 if (p->p_pid == curp->p_pid) 89 return (EINVAL); 90 /* 91 * It would be nice if the tracing relationship was separate 92 * from the parent relationship but that would require 93 * another set of links in the proc struct or for "wait" 94 * to scan the entire proc table. To make life easier, 95 * we just re-parent the process we're trying to trace. 96 * The old parent is remembered so we can put things back 97 * on a "detach". 98 */ 99 p->p_flag |= P_TRACED; 100 p->p_oppid = p->p_pptr->p_pid; 101 proc_reparent(p, curp); 102 psignal(p, SIGSTOP); 103 return (0); 104 } 105 if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & P_TRACED)) 106 return (ESRCH); 107 while (ipc.ip_lock) 108 sleep((caddr_t)&ipc, IPCPRI); 109 ipc.ip_lock = p->p_pid; 110 ipc.ip_data = SCARG(uap, data); 111 ipc.ip_addr = SCARG(uap, addr); 112 ipc.ip_req = SCARG(uap, req); 113 p->p_flag &= ~P_WAITED; 114 while (ipc.ip_req > 0) { 115 if (p->p_stat==SSTOP) 116 setrunnable(p); 117 sleep((caddr_t)&ipc, IPCPRI); 118 } 119 *retval = ipc.ip_data; 120 ipc.ip_lock = 0; 121 wakeup((caddr_t)&ipc); 122 if (ipc.ip_req < 0) 123 return (EIO); 124 return (0); 125 } 126 127 #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) 128 #if defined(hp300) || defined(luna68k) 129 #define PHYSALIGNED(a) (((int)(a) & (sizeof(short) - 1)) == 0) 130 #else 131 #define PHYSALIGNED(a) (((int)(a) & (sizeof(int) - 1)) == 0) 132 #endif 133 134 #if defined(i386) 135 #undef PC 136 #undef SP 137 #undef PS 138 #undef R0 139 #undef R1 140 141 #define PC tEIP 142 #define SP tESP 143 #define PS tEFLAGS 144 #define R0 tEDX 145 #define R1 tECX 146 #endif 147 148 /* 149 * Transmit a tracing request from the parent to the child process 150 * being debugged. This code runs in the context of the child process 151 * to fulfill the command requested by the parent. 152 */ 153 trace_req(p) 154 register struct proc *p; 155 { 156 register int i, *poff, *regs; 157 extern char kstack[]; 158 159 if (ipc.ip_lock != p->p_pid) 160 return (0); 161 p->p_slptime = 0; 162 regs = p->p_md.md_regs; 163 p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */ 164 i = ipc.ip_req; 165 ipc.ip_req = 0; 166 switch (i) { 167 168 case PT_READ_I: /* read the child's text space */ 169 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 170 goto error; 171 ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 172 break; 173 174 case PT_READ_D: /* read the child's data space */ 175 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 176 goto error; 177 ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 178 break; 179 180 case PT_READ_U: /* read the child's u. */ 181 i = (int)ipc.ip_addr; 182 if ((u_int) i > ctob(UPAGES)-sizeof(int) || !PHYSALIGNED(i)) 183 goto error; 184 ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); 185 break; 186 187 case PT_WRITE_I: /* write the child's text space */ 188 if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { 189 vm_offset_t sa, ea; 190 int rv; 191 192 sa = trunc_page((vm_offset_t)ipc.ip_addr); 193 ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)); 194 rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 195 VM_PROT_DEFAULT, FALSE); 196 if (rv == KERN_SUCCESS) { 197 i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); 198 (void) vm_map_protect(&p->p_vmspace->vm_map, 199 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 200 FALSE); 201 } 202 } 203 if (i < 0) 204 goto error; 205 break; 206 207 case PT_WRITE_D: /* write the child's data space */ 208 if (suword((caddr_t)ipc.ip_addr, 0) < 0) 209 goto error; 210 (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); 211 break; 212 213 case PT_WRITE_U: /* write the child's u. */ 214 i = (int)ipc.ip_addr; 215 #ifdef mips 216 poff = (int *)PHYSOFF(p->p_addr, i); 217 #else 218 poff = (int *)PHYSOFF(kstack, i); 219 #endif 220 for (i=0; i<NIPCREG; i++) 221 if (poff == ®s[ipcreg[i]]) 222 goto ok; 223 #if defined(hp300) || defined(luna68k) 224 /* 225 * In the new frame layout, PS/PC are skewed by 2 bytes. 226 */ 227 regs = (int *)((short *)regs + 1); 228 if (poff == ®s[PC]) 229 goto ok; 230 #endif 231 if (poff == ®s[PS]) { 232 ipc.ip_data |= PSL_USERSET; 233 ipc.ip_data &= ~PSL_USERCLR; 234 #ifdef PSL_CM_CLR 235 if (ipc.ip_data & PSL_CM) 236 ipc.ip_data &= ~PSL_CM_CLR; 237 #endif 238 goto ok; 239 } 240 #if defined(hp300) || defined(luna68k) 241 #ifdef FPCOPROC 242 if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 243 poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 244 goto ok; 245 #endif 246 #endif 247 goto error; 248 249 ok: 250 *poff = ipc.ip_data; 251 break; 252 253 case PT_STEP: /* single step the child */ 254 case PT_CONTINUE: /* continue the child */ 255 #ifndef mips 256 regs = (int *)((short *)regs + 1); 257 #endif 258 if ((unsigned)ipc.ip_data >= NSIG) 259 goto error; 260 if ((int)ipc.ip_addr != 1) 261 regs[PC] = (int)ipc.ip_addr; 262 p->p_xstat = ipc.ip_data; /* see issignal */ 263 #ifdef mips 264 if (i == PT_STEP && cpu_singlestep(p)) 265 goto error; 266 #else 267 #ifdef PSL_T 268 /* need something more machine independent here... */ 269 if (i == PT_STEP) 270 regs[PS] |= PSL_T; 271 #endif 272 #endif 273 wakeup((caddr_t)&ipc); 274 return (1); 275 276 case PT_KILL: /* kill the child process */ 277 wakeup((caddr_t)&ipc); 278 exit1(p, (int)p->p_xstat); 279 280 case PT_DETACH: /* stop tracing the child */ 281 regs = (int *)((short *)regs + 1); 282 if ((unsigned)ipc.ip_data >= NSIG) 283 goto error; 284 if ((int)ipc.ip_addr != 1) 285 regs[PC] = (int)ipc.ip_addr; 286 p->p_xstat = ipc.ip_data; /* see issignal */ 287 p->p_flag &= ~P_TRACED; 288 if (p->p_oppid != p->p_pptr->p_pid) { 289 register struct proc *pp = pfind(p->p_oppid); 290 291 if (pp) 292 proc_reparent(p, pp); 293 } 294 p->p_oppid = 0; 295 wakeup((caddr_t)&ipc); 296 return (1); 297 298 default: 299 error: 300 ipc.ip_req = -1; 301 } 302 wakeup((caddr_t)&ipc); 303 return (0); 304 } 305