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