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