1 /*- 2 * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.proprietary.c% 15 * 16 * @(#)sys_process.c 7.4 (Berkeley) 04/20/93 17 */ 18 19 #include <sys/param.h> 20 #include <sys/proc.h> 21 #include <sys/vnode.h> 22 #include <sys/buf.h> 23 #include <sys/malloc.h> 24 #include <sys/ptrace.h> 25 #include <sys/user.h> 26 27 #include <vm/vm.h> 28 #include <vm/vm_page.h> 29 30 #include <machine/psl.h> 31 #include <machine/reg.h> 32 33 /* 34 * Priority for tracing 35 */ 36 #define IPCPRI PZERO 37 38 /* 39 * Tracing variables. 40 * Used to pass trace command from 41 * parent to child being traced. 42 * This data base cannot be 43 * shared and is locked 44 * per user. 45 */ 46 struct { 47 int ip_lock; 48 int ip_req; 49 int ip_error; 50 union { 51 char un_any[4]; 52 struct { 53 int wd_data; 54 caddr_t wd_addr; 55 } un_wd; 56 struct trapframe un_tf; 57 struct fpstate un_f; 58 } ip_un; 59 } ipc; 60 #define ip_any ip_un.un_any 61 #define ip_data ip_un.un_wd.wd_data 62 #define ip_addr ip_un.un_wd.wd_addr 63 #define ip_tf ip_un.un_tf 64 #define ip_f ip_un.un_f 65 66 /* 67 * Process debugging system call. 68 */ 69 struct ptrace_args { 70 int req; 71 int pid; 72 caddr_t addr; 73 int data; 74 }; 75 ptrace(curp, uap, retval) 76 struct proc *curp; 77 register struct ptrace_args *uap; 78 int *retval; 79 { 80 register struct proc *p; 81 register enum { t_oneword, t_regin, t_regout } type; 82 register size_t size; 83 register int error; 84 85 if (uap->req == PT_TRACE_ME) { 86 curp->p_flag |= STRC; 87 return (0); 88 } 89 if ((p = pfind(uap->pid)) == NULL) 90 return (ESRCH); 91 switch (uap->req) { 92 93 case PT_READ_I: 94 case PT_READ_D: 95 case PT_WRITE_I: 96 case PT_WRITE_D: 97 case PT_CONTINUE: 98 case PT_KILL: 99 case PT_DETACH: 100 type = t_oneword; 101 size = 0; 102 break; 103 104 case PT_ATTACH: 105 /* 106 * Must be root if the process has used set user or group 107 * privileges or does not belong to the real user. Must 108 * not be already traced. Can't attach to ourselves. 109 */ 110 if ((p->p_flag & SUGID || 111 p->p_cred->p_ruid != curp->p_cred->p_ruid) && 112 (error = suser(p->p_ucred, &p->p_acflag)) != 0) 113 return (error); 114 if (p->p_flag & STRC) 115 return (EALREADY); /* ??? */ 116 if (p == curp) 117 return (EINVAL); 118 /* 119 * It would be nice if the tracing relationship was separate 120 * from the parent relationship but that would require 121 * another set of links in the proc struct or for "wait" 122 * to scan the entire proc table. To make life easier, 123 * we just re-parent the process we're trying to trace. 124 * The old parent is remembered so we can put things back 125 * on a "detach". 126 */ 127 p->p_flag |= STRC; 128 p->p_oppid = p->p_pptr->p_pid; 129 proc_reparent(p, curp); 130 if (p->p_stat == SSTOP) 131 setrun(p); /* long enough to stop */ 132 psignal(p, SIGSTOP); 133 return (0); 134 135 case PT_GETREGS: 136 type = t_regout; 137 size = sizeof(struct trapframe); 138 break; 139 140 case PT_SETREGS: 141 type = t_regin; 142 size = sizeof(struct trapframe); 143 break; 144 145 case PT_GETFPREGS: 146 type = t_regout; 147 size = sizeof(struct fpstate); 148 break; 149 150 case PT_SETFPREGS: 151 type = t_regin; 152 size = sizeof(struct fpstate); 153 break; 154 155 default: 156 return (EINVAL); 157 } 158 if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & STRC)) 159 return (ESRCH); 160 while (ipc.ip_lock) 161 sleep((caddr_t)&ipc, IPCPRI); 162 ipc.ip_lock = p->p_pid; 163 ipc.ip_req = uap->req; 164 ipc.ip_error = 0; 165 switch (type) { 166 167 case t_oneword: 168 ipc.ip_addr = uap->addr; 169 ipc.ip_data = uap->data; 170 break; 171 172 case t_regin: 173 if ((error = copyin(uap->addr, ipc.ip_any, size)) != 0) 174 return (error); 175 break; 176 177 case t_regout: 178 break; 179 180 default: 181 panic("ptrace"); 182 } 183 p->p_flag &= ~SWTED; 184 do { 185 if (p->p_stat == SSTOP) 186 setrun(p); 187 sleep((caddr_t)&ipc, IPCPRI); 188 } while (ipc.ip_req > 0); 189 if ((error = ipc.ip_error) == 0) { 190 if (type == t_oneword) 191 *retval = ipc.ip_data; 192 else if (type == t_regout) 193 error = copyout(ipc.ip_any, uap->addr, size); 194 } 195 ipc.ip_lock = 0; 196 wakeup((caddr_t)&ipc); 197 return (error); 198 } 199 200 /* 201 * Write text space by unprotecting, writing, and reprotecting. 202 */ 203 static int 204 writetext(p, addr, data, len) 205 struct proc *p; 206 caddr_t addr, data; 207 int len; 208 { 209 vm_offset_t sa, ea; 210 vm_map_t map; 211 int error; 212 213 map = &p->p_vmspace->vm_map; 214 sa = trunc_page((vm_offset_t)addr); 215 ea = round_page((vm_offset_t)addr + len); 216 if (vm_map_protect(map, sa, ea, VM_PROT_DEFAULT, 0) != KERN_SUCCESS) 217 return (-1); 218 error = copyout(data, addr, len); 219 (void) vm_map_protect(map, sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 0); 220 return (error); 221 } 222 223 /* 224 * Transmit a tracing request from the parent to the child process 225 * being debugged. This code runs in the context of the child process 226 * to fulfill the command requested by the parent. 227 */ 228 procxmt(p) 229 register struct proc *p; 230 { 231 register int req, error, sig, pc, psr; 232 register caddr_t addr; 233 register struct trapframe *tf, *utf; 234 register struct fpstate *fs, *oldfs; 235 extern struct fpstate initfpstate; 236 237 if (ipc.ip_lock != p->p_pid) 238 return (0); 239 p->p_slptime = 0; 240 req = ipc.ip_req; 241 ipc.ip_req = 0; 242 error = 0; 243 switch (req) { 244 245 case PT_READ_I: /* read the child's text space */ 246 case PT_READ_D: /* read the child's data space */ 247 write_user_windows(); 248 (void) rwindow_save(p); /* ignore unwritable windows */ 249 error = copyin(ipc.ip_addr, ipc.ip_any, sizeof(int)); 250 break; 251 252 case PT_WRITE_I: /* write the child's text space */ 253 case PT_WRITE_D: /* write the child's data space */ 254 addr = ipc.ip_addr; 255 write_user_windows(); 256 (void) rwindow_save(p); 257 error = copyout(ipc.ip_any, addr, sizeof(int)); 258 if (error && req == PT_WRITE_I) 259 error = writetext(p, addr, ipc.ip_any, sizeof(int)); 260 break; 261 262 case PT_CONTINUE: /* continue the child */ 263 sig = ipc.ip_data; 264 if ((unsigned)sig >= NSIG) { 265 error = EINVAL; 266 break; 267 } 268 pc = (int)ipc.ip_addr; 269 if (pc & 3) { 270 if (pc != 1) { 271 error = EINVAL; 272 break; 273 } 274 } else { 275 tf = p->p_md.md_tf; 276 tf->tf_pc = pc; 277 tf->tf_npc = pc + 4; 278 } 279 p->p_xstat = sig; /* see issig */ 280 wakeup((caddr_t)&ipc); 281 return (1); 282 283 case PT_KILL: /* kill the child process */ 284 wakeup((caddr_t)&ipc); 285 exit1(p, (int)p->p_xstat); 286 287 case PT_DETACH: /* stop tracing the child */ 288 sig = ipc.ip_data; 289 if ((unsigned)sig >= NSIG) { 290 error = EINVAL; 291 break; 292 } 293 pc = (int)ipc.ip_addr; 294 if (pc & 3) { 295 if (pc != 1) { 296 error = EINVAL; 297 break; 298 } 299 } else { 300 tf = p->p_md.md_tf; 301 tf->tf_pc = pc; 302 tf->tf_npc = pc + 4; 303 } 304 p->p_xstat = sig; /* see issig */ 305 p->p_flag &= ~STRC; 306 if (p->p_oppid != p->p_pptr->p_pid) { 307 register struct proc *pp = pfind(p->p_oppid); 308 309 if (pp) 310 proc_reparent(p, pp); 311 } 312 p->p_oppid = 0; 313 wakeup((caddr_t)&ipc); 314 return (1); 315 316 case PT_GETREGS: 317 copywords((caddr_t)p->p_md.md_tf, (caddr_t)&ipc.ip_tf, 318 sizeof(struct trapframe)); 319 ipc.ip_tf.tf_global[0] = 0; /* XXX */ 320 break; 321 322 case PT_SETREGS: 323 tf = p->p_md.md_tf; 324 utf = &ipc.ip_tf; 325 if ((utf->tf_pc | utf->tf_npc) & 3) { 326 error = EINVAL; 327 break; 328 } 329 psr = (tf->tf_psr & ~PSR_ICC) | (utf->tf_psr & PSR_ICC); 330 copywords((caddr_t)utf, (caddr_t)tf, sizeof(*tf)); 331 tf->tf_psr = psr; 332 break; 333 334 case PT_GETFPREGS: 335 if ((fs = p->p_md.md_fpstate) == NULL) 336 fs = &initfpstate; 337 else if (p == fpproc) 338 savefpstate(fs); 339 copywords((caddr_t)fs, (caddr_t)&ipc.ip_f, sizeof *fs); 340 break; 341 342 case PT_SETFPREGS: 343 fs = &ipc.ip_f; 344 if ((fs->fs_fsr & FSR_MBZ) != 0 || fs->fs_qsize) { 345 error = EINVAL; 346 break; 347 } 348 oldfs = p->p_md.md_fpstate; 349 if (oldfs == NULL) 350 p->p_md.md_fpstate = oldfs = malloc(sizeof *oldfs, 351 M_SUBPROC, M_WAITOK); 352 else if (p == fpproc) { 353 savefpstate(oldfs); 354 fpproc = NULL; 355 p->p_md.md_tf->tf_psr &= ~PSR_EF; 356 } 357 copywords((caddr_t)fs, (caddr_t)oldfs, sizeof *oldfs); 358 break; 359 360 default: 361 panic("procxmt"); 362 } 363 ipc.ip_error = error; 364 wakeup((caddr_t)&ipc); 365 return (0); 366 } 367