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 Laboratories. 13 * 14 * %sccs.include.proprietary.c% 15 * 16 * @(#)sys_process.c 7.2 (Berkeley) 07/21/92 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 curp->p_oppid = 0; /* XXX put in the zeroed section */ 88 return (0); 89 } 90 if ((p = pfind(uap->pid)) == NULL) 91 return (ESRCH); 92 switch (uap->req) { 93 94 case PT_READ_I: 95 case PT_READ_D: 96 case PT_WRITE_I: 97 case PT_WRITE_D: 98 case PT_CONTINUE: 99 case PT_KILL: 100 case PT_DETACH: 101 type = t_oneword; 102 size = 0; 103 break; 104 105 case PT_ATTACH: 106 /* 107 * Must be root if the process has used set user or 108 * group privileges or does not belong to the real 109 * user. Must not be already traced. 110 */ 111 if ((p->p_flag & SUGID || 112 p->p_cred->p_ruid != curp->p_cred->p_ruid) && 113 (error = suser(p->p_ucred, &p->p_acflag)) != 0) 114 return (error); 115 if (p->p_flag & STRC) 116 return (EALREADY); /* ??? */ 117 /* 118 * It would be nice if the tracing relationship was separate 119 * from the parent relationship but that would require 120 * another set of links in the proc struct or for "wait" 121 * to scan the entire proc table. To make life easier, 122 * we just re-parent the process we're trying to trace. 123 * The old parent is remembered so we can put things back 124 * on a "detach". 125 */ 126 p->p_flag |= STRC; 127 p->p_oppid = p->p_pptr->p_pid; 128 proc_reparent(p, curp); 129 psignal(p, SIGSTOP); 130 return (0); 131 132 case PT_GETREGS: 133 type = t_regout; 134 size = sizeof(struct trapframe); 135 break; 136 137 case PT_SETREGS: 138 type = t_regin; 139 size = sizeof(struct trapframe); 140 break; 141 142 case PT_GETFPREGS: 143 type = t_regout; 144 size = sizeof(struct fpstate); 145 break; 146 147 case PT_SETFPREGS: 148 type = t_regin; 149 size = sizeof(struct fpstate); 150 break; 151 152 default: 153 return (EINVAL); 154 } 155 if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & STRC)) 156 return (ESRCH); 157 while (ipc.ip_lock) 158 sleep((caddr_t)&ipc, IPCPRI); 159 ipc.ip_lock = p->p_pid; 160 ipc.ip_req = uap->req; 161 ipc.ip_error = 0; 162 switch (type) { 163 164 case t_oneword: 165 ipc.ip_addr = uap->addr; 166 ipc.ip_data = uap->data; 167 break; 168 169 case t_regin: 170 if ((error = copyin(uap->addr, ipc.ip_any, size)) != 0) 171 return (error); 172 break; 173 174 case t_regout: 175 break; 176 177 default: 178 panic("ptrace"); 179 } 180 p->p_flag &= ~SWTED; 181 do { 182 if (p->p_stat == SSTOP) 183 setrun(p); 184 sleep((caddr_t)&ipc, IPCPRI); 185 } while (ipc.ip_req > 0); 186 if ((error = ipc.ip_error) == 0) { 187 if (type == t_oneword) 188 *retval = ipc.ip_data; 189 else if (type == t_regout) 190 error = copyout(ipc.ip_any, uap->addr, size); 191 } 192 ipc.ip_lock = 0; 193 wakeup((caddr_t)&ipc); 194 return (error); 195 } 196 197 /* 198 * Write text space by unprotecting, writing, and reprotecting. 199 */ 200 static int 201 writetext(p, addr, data, len) 202 struct proc *p; 203 caddr_t addr, data; 204 int len; 205 { 206 vm_offset_t sa, ea; 207 vm_map_t map; 208 int error; 209 210 map = &p->p_vmspace->vm_map; 211 sa = trunc_page((vm_offset_t)addr); 212 ea = round_page((vm_offset_t)addr + len - 1); 213 if (vm_map_protect(map, sa, ea, VM_PROT_DEFAULT, 0) != KERN_SUCCESS) 214 return (-1); 215 error = copyout(data, addr, len); 216 (void) vm_map_protect(map, sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 0); 217 return (error); 218 } 219 220 /* 221 * Transmit a tracing request from the parent to the child process 222 * being debugged. This code runs in the context of the child process 223 * to fulfill the command requested by the parent. 224 */ 225 procxmt(p) 226 register struct proc *p; 227 { 228 register int req, error, sig, pc, psr; 229 register caddr_t addr; 230 register struct trapframe *tf, *utf; 231 register struct fpstate *fs, *oldfs; 232 extern struct fpstate initfpstate; 233 234 if (ipc.ip_lock != p->p_pid) 235 return (0); 236 p->p_slptime = 0; 237 req = ipc.ip_req; 238 ipc.ip_req = 0; 239 error = 0; 240 switch (req) { 241 242 case PT_READ_I: /* read the child's text space */ 243 case PT_READ_D: /* read the child's data space */ 244 write_user_windows(); 245 (void) rwindow_save(p); /* ignore unwritable windows */ 246 error = copyin(ipc.ip_addr, ipc.ip_any, sizeof(int)); 247 break; 248 249 case PT_WRITE_I: /* write the child's text space */ 250 case PT_WRITE_D: /* write the child's data space */ 251 addr = ipc.ip_addr; 252 write_user_windows(); 253 (void) rwindow_save(p); 254 error = copyout(ipc.ip_any, addr, sizeof(int)); 255 if (error && req == PT_WRITE_I) 256 error = writetext(p, addr, ipc.ip_any, sizeof(int)); 257 break; 258 259 case PT_CONTINUE: /* continue the child */ 260 sig = ipc.ip_data; 261 if ((unsigned)sig >= NSIG) { 262 error = EINVAL; 263 break; 264 } 265 pc = (int)ipc.ip_addr; 266 if (pc & 3) { 267 if (pc != 1) { 268 error = EINVAL; 269 break; 270 } 271 } else { 272 tf = p->p_md.md_tf; 273 tf->tf_pc = pc; 274 tf->tf_npc = pc + 4; 275 } 276 p->p_xstat = sig; /* see issig */ 277 wakeup((caddr_t)&ipc); 278 return (1); 279 280 case PT_KILL: /* kill the child process */ 281 wakeup((caddr_t)&ipc); 282 exit(p, (int)p->p_xstat); 283 284 case PT_DETACH: /* stop tracing the child */ 285 sig = ipc.ip_data; 286 if ((unsigned)sig >= NSIG) { 287 error = EINVAL; 288 break; 289 } 290 pc = (int)ipc.ip_addr; 291 if (pc & 3) { 292 if (pc != 1) { 293 error = EINVAL; 294 break; 295 } 296 } else { 297 tf = p->p_md.md_tf; 298 tf->tf_pc = pc; 299 tf->tf_npc = pc + 4; 300 } 301 p->p_xstat = sig; /* see issig */ 302 p->p_flag &= ~STRC; 303 if (p->p_oppid != p->p_pptr->p_pid) { 304 register struct proc *pp = pfind(p->p_oppid); 305 306 if (pp) 307 proc_reparent(p, pp); 308 } 309 p->p_oppid = 0; 310 wakeup((caddr_t)&ipc); 311 return (1); 312 313 case PT_GETREGS: 314 copywords((caddr_t)p->p_md.md_tf, (caddr_t)&ipc.ip_tf, 315 sizeof(struct trapframe)); 316 ipc.ip_tf.tf_global[0] = 0; /* XXX */ 317 break; 318 319 case PT_SETREGS: 320 tf = p->p_md.md_tf; 321 utf = &ipc.ip_tf; 322 if ((utf->tf_pc | utf->tf_npc) & 3) { 323 error = EINVAL; 324 break; 325 } 326 psr = (tf->tf_psr & ~PSR_ICC) | (utf->tf_psr & PSR_ICC); 327 copywords((caddr_t)utf, (caddr_t)tf, sizeof(*tf)); 328 tf->tf_psr = psr; 329 break; 330 331 case PT_GETFPREGS: 332 if ((fs = p->p_md.md_fpstate) == NULL) 333 fs = &initfpstate; 334 else if (p == fpproc) 335 savefpstate(fs); 336 copywords((caddr_t)fs, (caddr_t)&ipc.ip_f, sizeof *fs); 337 break; 338 339 case PT_SETFPREGS: 340 fs = &ipc.ip_f; 341 if ((fs->fs_fsr & FSR_MBZ) != 0 || fs->fs_qsize) { 342 error = EINVAL; 343 break; 344 } 345 oldfs = p->p_md.md_fpstate; 346 if (oldfs == NULL) 347 p->p_md.md_fpstate = oldfs = malloc(sizeof *oldfs, 348 M_SUBPROC, M_WAITOK); 349 else if (p == fpproc) { 350 savefpstate(oldfs); 351 fpproc = NULL; 352 p->p_md.md_tf->tf_psr &= ~PSR_EF; 353 } 354 copywords((caddr_t)fs, (caddr_t)oldfs, sizeof *oldfs); 355 break; 356 357 default: 358 panic("procxmt"); 359 } 360 ipc.ip_error = error; 361 wakeup((caddr_t)&ipc); 362 return (0); 363 } 364