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.33 (Berkeley) 10/11/92 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 int *ip_addr; 41 int ip_data; 42 } ipc; 43 44 /* 45 * Process debugging system call. 46 */ 47 struct ptrace_args { 48 int req; 49 int pid; 50 int *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 71 * group privileges or does not belong to the real 72 * user. Must not be already traced. 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 /* 81 * It would be nice if the tracing relationship was separate 82 * from the parent relationship but that would require 83 * another set of links in the proc struct or for "wait" 84 * to scan the entire proc table. To make life easier, 85 * we just re-parent the process we're trying to trace. 86 * The old parent is remembered so we can put things back 87 * on a "detach". 88 */ 89 p->p_flag |= STRC; 90 p->p_oppid = p->p_pptr->p_pid; 91 proc_reparent(p, curp); 92 psignal(p, SIGSTOP); 93 return (0); 94 } 95 if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & STRC)) 96 return (ESRCH); 97 while (ipc.ip_lock) 98 sleep((caddr_t)&ipc, IPCPRI); 99 ipc.ip_lock = p->p_pid; 100 ipc.ip_data = uap->data; 101 ipc.ip_addr = uap->addr; 102 ipc.ip_req = uap->req; 103 p->p_flag &= ~SWTED; 104 while (ipc.ip_req > 0) { 105 if (p->p_stat==SSTOP) 106 setrun(p); 107 sleep((caddr_t)&ipc, IPCPRI); 108 } 109 *retval = ipc.ip_data; 110 ipc.ip_lock = 0; 111 wakeup((caddr_t)&ipc); 112 if (ipc.ip_req < 0) 113 return (EIO); 114 return (0); 115 } 116 117 #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) 118 119 #if defined(i386) 120 #undef PC 121 #undef SP 122 #undef PS 123 #undef R0 124 #undef R1 125 126 #define PC tEIP 127 #define SP tESP 128 #define PS tEFLAGS 129 #define R0 tEDX 130 #define R1 tECX 131 #endif 132 133 /* 134 * Transmit a tracing request from the parent to the child process 135 * being debugged. This code runs in the context of the child process 136 * to fulfill the command requested by the parent. 137 */ 138 procxmt(p) 139 register struct proc *p; 140 { 141 register int i, *poff; 142 extern char kstack[]; 143 144 if (ipc.ip_lock != p->p_pid) 145 return (0); 146 p->p_slptime = 0; 147 p->p_addr->u_kproc.kp_proc.p_md.md_regs = p->p_md.md_regs; /* u.u_ar0 */ 148 i = ipc.ip_req; 149 ipc.ip_req = 0; 150 switch (i) { 151 152 case PT_READ_I: /* read the child's text space */ 153 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 154 goto error; 155 ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 156 break; 157 158 case PT_READ_D: /* read the child's data space */ 159 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 160 goto error; 161 ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 162 break; 163 164 case PT_READ_U: /* read the child's u. */ 165 #ifdef HPUXCOMPAT 166 if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) 167 i = hpuxtobsduoff(ipc.ip_addr); 168 else 169 #endif 170 i = (int)ipc.ip_addr; 171 if ((u_int) i > ctob(UPAGES)-sizeof(int) || (i & 1) != 0) 172 goto error; 173 ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); 174 break; 175 176 case PT_WRITE_I: /* write the child's text space */ 177 if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { 178 vm_offset_t sa, ea; 179 int rv; 180 181 sa = trunc_page((vm_offset_t)ipc.ip_addr); 182 ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)); 183 rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 184 VM_PROT_DEFAULT, FALSE); 185 if (rv == KERN_SUCCESS) { 186 i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); 187 (void) vm_map_protect(&p->p_vmspace->vm_map, 188 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 189 FALSE); 190 } 191 } 192 if (i < 0) 193 goto error; 194 break; 195 196 case PT_WRITE_D: /* write the child's data space */ 197 if (suword((caddr_t)ipc.ip_addr, 0) < 0) 198 goto error; 199 (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); 200 break; 201 202 case PT_WRITE_U: /* write the child's u. */ 203 #ifdef HPUXCOMPAT 204 if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) 205 i = hpuxtobsduoff(ipc.ip_addr); 206 else 207 #endif 208 i = (int)ipc.ip_addr; 209 #ifdef mips 210 poff = (int *)PHYSOFF(curproc->p_addr, i); 211 #else 212 poff = (int *)PHYSOFF(kstack, i); 213 #endif 214 for (i=0; i<NIPCREG; i++) 215 if (poff == &p->p_md.md_regs[ipcreg[i]]) 216 goto ok; 217 if (poff == &p->p_md.md_regs[PS]) { 218 ipc.ip_data |= PSL_USERSET; 219 ipc.ip_data &= ~PSL_USERCLR; 220 #ifdef PSL_CM_CLR 221 if (ipc.ip_data & PSL_CM) 222 ipc.ip_data &= ~PSL_CM_CLR; 223 #endif 224 goto ok; 225 } 226 #if defined(hp300) || defined(luna68k) 227 #ifdef FPCOPROC 228 if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 229 poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 230 goto ok; 231 #endif 232 #endif 233 goto error; 234 235 ok: 236 *poff = ipc.ip_data; 237 break; 238 239 case PT_STEP: /* single step the child */ 240 case PT_CONTINUE: /* continue the child */ 241 if ((unsigned)ipc.ip_data >= NSIG) 242 goto error; 243 if ((int)ipc.ip_addr != 1) 244 p->p_md.md_regs[PC] = (int)ipc.ip_addr; 245 p->p_xstat = ipc.ip_data; /* see issig */ 246 #ifdef PSL_T 247 /* need something more machine independent here... */ 248 if (i == PT_STEP) 249 p->p_md.md_regs[PS] |= PSL_T; 250 #endif 251 wakeup((caddr_t)&ipc); 252 return (1); 253 254 case PT_KILL: /* kill the child process */ 255 wakeup((caddr_t)&ipc); 256 exit(p, (int)p->p_xstat); 257 258 case PT_DETACH: /* stop tracing the child */ 259 if ((unsigned)ipc.ip_data >= NSIG) 260 goto error; 261 if ((int)ipc.ip_addr != 1) 262 p->p_md.md_regs[PC] = (int)ipc.ip_addr; 263 p->p_xstat = ipc.ip_data; /* see issig */ 264 p->p_flag &= ~STRC; 265 if (p->p_oppid != p->p_pptr->p_pid) { 266 register struct proc *pp = pfind(p->p_oppid); 267 268 if (pp) 269 proc_reparent(p, pp); 270 } 271 p->p_oppid = 0; 272 wakeup((caddr_t)&ipc); 273 return (1); 274 275 default: 276 error: 277 ipc.ip_req = -1; 278 } 279 wakeup((caddr_t)&ipc); 280 return (0); 281 } 282