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.28 (Berkeley) 06/24/92 8 */ 9 10 #define IPCREG 11 #include "param.h" 12 #include "proc.h" 13 #include "vnode.h" 14 #include "buf.h" 15 #include "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 "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 int *ip_addr; 41 int ip_data; 42 } ipc; 43 44 /* 45 * Process debugging system call. 46 */ 47 ptrace(curp, uap, retval) 48 struct proc *curp; 49 register struct args { 50 int req; 51 int pid; 52 int *addr; 53 int data; 54 } *uap; 55 int *retval; 56 { 57 register struct proc *p; 58 int error; 59 60 p = pfind(uap->pid); 61 if (uap->req == PT_ATTACH) { 62 /* 63 * Must be root if the process has used set user or 64 * group privileges or does not belong to the real 65 * user. Must not be already traced. 66 */ 67 if ((p->p_flag & SUGID || 68 p->p_cred->p_ruid != curp->p_cred->p_ruid) && 69 (error = suser(p->p_ucred, &p->p_acflag)) != 0) 70 return (error); 71 if (p->p_flag & STRC) 72 return (EALREADY); /* ??? */ 73 /* 74 * It would be nice if the tracing relationship was separate 75 * from the parent relationship but that would require 76 * another set of links in the proc struct or for "wait" 77 * to scan the entire proc table. To make life easier, 78 * we just re-parent the process we're trying to trace. 79 * The old parent is remembered so we can put things back 80 * on a "detach". 81 */ 82 p->p_flag |= STRC; 83 p->p_oppid = p->p_pptr->p_pid; 84 proc_reparent(p, curp); 85 psignal(p, SIGSTOP); 86 return (0); 87 } 88 if (uap->req <= 0) { 89 curp->p_flag |= STRC; 90 return (0); 91 } 92 if (p == 0 || p->p_stat != SSTOP || p->p_pptr != curp || 93 !(p->p_flag & STRC)) 94 return (ESRCH); 95 while (ipc.ip_lock) 96 sleep((caddr_t)&ipc, IPCPRI); 97 ipc.ip_lock = p->p_pid; 98 ipc.ip_data = uap->data; 99 ipc.ip_addr = uap->addr; 100 ipc.ip_req = uap->req; 101 p->p_flag &= ~SWTED; 102 while (ipc.ip_req > 0) { 103 if (p->p_stat==SSTOP) 104 setrun(p); 105 sleep((caddr_t)&ipc, IPCPRI); 106 } 107 *retval = ipc.ip_data; 108 ipc.ip_lock = 0; 109 wakeup((caddr_t)&ipc); 110 if (ipc.ip_req < 0) 111 return (EIO); 112 return (0); 113 } 114 115 #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) 116 117 #if defined(i386) 118 #undef PC 119 #undef SP 120 #undef PS 121 #undef R0 122 #undef R1 123 124 #define PC tEIP 125 #define SP tESP 126 #define PS tEFLAGS 127 #define R0 tEDX 128 #define R1 tECX 129 #endif 130 131 /* 132 * Transmit a tracing request from the parent to the child process 133 * being debugged. This code runs in the context of the child process 134 * to fulfill the command requested by the parent. 135 */ 136 procxmt(p) 137 register struct proc *p; 138 { 139 register int i, *poff; 140 extern char kstack[]; 141 142 if (ipc.ip_lock != p->p_pid) 143 return (0); 144 p->p_slptime = 0; 145 p->p_addr->u_kproc.kp_proc.p_md.md_regs = p->p_md.md_regs; /* u.u_ar0 */ 146 i = ipc.ip_req; 147 ipc.ip_req = 0; 148 switch (i) { 149 150 case PT_READ_I: /* read the child's text space */ 151 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 152 goto error; 153 ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 154 break; 155 156 case PT_READ_D: /* read the child's data space */ 157 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 158 goto error; 159 ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 160 break; 161 162 case PT_READ_U: /* read the child's u. */ 163 #ifdef HPUXCOMPAT 164 if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) 165 i = hpuxtobsduoff(ipc.ip_addr); 166 else 167 #endif 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)-1); 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 #ifdef HPUXCOMPAT 202 if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) 203 i = hpuxtobsduoff(ipc.ip_addr); 204 else 205 #endif 206 i = (int)ipc.ip_addr; 207 #ifdef mips 208 poff = (int *)PHYSOFF(curproc->p_addr, i); 209 #else 210 poff = (int *)PHYSOFF(kstack, i); 211 #endif 212 for (i=0; i<NIPCREG; i++) 213 if (poff == &p->p_md.md_regs[ipcreg[i]]) 214 goto ok; 215 if (poff == &p->p_md.md_regs[PS]) { 216 ipc.ip_data |= PSL_USERSET; 217 ipc.ip_data &= ~PSL_USERCLR; 218 #ifdef PSL_CM_CLR 219 if (ipc.ip_data & PSL_CM) 220 ipc.ip_data &= ~PSL_CM_CLR; 221 #endif 222 goto ok; 223 } 224 #if defined(hp300) || defined(luna68k) 225 #ifdef FPCOPROC 226 if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 227 poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 228 goto ok; 229 #endif 230 #endif 231 goto error; 232 233 ok: 234 *poff = ipc.ip_data; 235 break; 236 237 case PT_STEP: /* single step the child */ 238 case PT_CONTINUE: /* continue the child */ 239 if ((unsigned)ipc.ip_data >= NSIG) 240 goto error; 241 if ((int)ipc.ip_addr != 1) 242 p->p_md.md_regs[PC] = (int)ipc.ip_addr; 243 p->p_xstat = ipc.ip_data; /* see issig */ 244 #ifdef PSL_T 245 /* need something more machine independent here... */ 246 if (i == PT_STEP) 247 p->p_md.md_regs[PS] |= PSL_T; 248 #endif 249 wakeup((caddr_t)&ipc); 250 return (1); 251 252 case PT_KILL: /* kill the child process */ 253 wakeup((caddr_t)&ipc); 254 exit(p, (int)p->p_xstat); 255 256 case PT_DETACH: /* stop tracing the child */ 257 if ((unsigned)ipc.ip_data >= NSIG) 258 goto error; 259 if ((int)ipc.ip_addr != 1) 260 p->p_md.md_regs[PC] = (int)ipc.ip_addr; 261 p->p_xstat = ipc.ip_data; /* see issig */ 262 p->p_flag &= ~STRC; 263 if (p->p_oppid != p->p_pptr->p_pid) { 264 register struct proc *pp = pfind(p->p_oppid); 265 266 if (pp) 267 proc_reparent(p, pp); 268 } 269 p->p_oppid = 0; 270 wakeup((caddr_t)&ipc); 271 return (1); 272 273 default: 274 error: 275 ipc.ip_req = -1; 276 } 277 wakeup((caddr_t)&ipc); 278 return (0); 279 } 280 281 /* 282 * Process debugging system call. 283 */ 284 /* ARGSUSED */ 285 profil(p, uap, retval) 286 struct proc *p; 287 register struct args { 288 short *bufbase; 289 unsigned bufsize; 290 unsigned pcoffset; 291 unsigned pcscale; 292 } *uap; 293 int *retval; 294 { 295 register struct uprof *upp; 296 int s; 297 298 upp = &p->p_stats->p_prof; 299 s = splhigh(); /* block profile interrupts while changing state */ 300 upp->pr_base = uap->bufbase; 301 upp->pr_size = uap->bufsize; 302 upp->pr_off = uap->pcoffset; 303 upp->pr_scale = uap->pcscale; 304 if (uap->pcscale) { 305 if ((p->p_flag & SPROFIL) == 0) 306 startprofclock(p); 307 } else { 308 if (p->p_flag & SPROFIL) 309 stopprofclock(p); 310 } 311 splx(s); 312 return (0); 313 } 314