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