149589Sbostic /*- 249589Sbostic * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. 349589Sbostic * All rights reserved. 423385Smckusick * 549589Sbostic * %sccs.include.proprietary.c% 649589Sbostic * 7*57303Shibler * @(#)sys_process.c 7.35 (Berkeley) 12/27/92 823385Smckusick */ 97426Sroot 1030376Skarels #define IPCREG 1156517Sbostic #include <sys/param.h> 1256517Sbostic #include <sys/proc.h> 1356517Sbostic #include <sys/vnode.h> 1456517Sbostic #include <sys/buf.h> 1556517Sbostic #include <sys/ptrace.h> 167426Sroot 1756517Sbostic #include <machine/reg.h> 1856517Sbostic #include <machine/psl.h> 1956517Sbostic #include <vm/vm.h> 2056517Sbostic #include <vm/vm_page.h> 2137520Smckusick 2256517Sbostic #include <sys/user.h> 2348438Skarels 247501Sroot /* 257501Sroot * Priority for tracing 267501Sroot */ 277501Sroot #define IPCPRI PZERO 287501Sroot 297501Sroot /* 307501Sroot * Tracing variables. 317501Sroot * Used to pass trace command from 327501Sroot * parent to child being traced. 337501Sroot * This data base cannot be 347501Sroot * shared and is locked 357501Sroot * per user. 367501Sroot */ 377501Sroot struct { 387501Sroot int ip_lock; 397501Sroot int ip_req; 407501Sroot int *ip_addr; 417501Sroot int ip_data; 427501Sroot } ipc; 437501Sroot 447501Sroot /* 4549674Smckusick * Process debugging system call. 467501Sroot */ 4754931Storek struct ptrace_args { 4854931Storek int req; 4954931Storek int pid; 5054931Storek int *addr; 5154931Storek int data; 5254931Storek }; 5343378Smckusick ptrace(curp, uap, retval) 5443378Smckusick struct proc *curp; 5554931Storek register struct ptrace_args *uap; 5643378Smckusick int *retval; 5743378Smckusick { 5843378Smckusick register struct proc *p; 5954340Smckusick int error; 607501Sroot 6156312Shibler if (uap->req <= 0) { 6256312Shibler curp->p_flag |= STRC; 6356312Shibler return (0); 6456312Shibler } 6554340Smckusick p = pfind(uap->pid); 6656312Shibler if (p == 0) 6756312Shibler return (ESRCH); 6854340Smckusick if (uap->req == PT_ATTACH) { 6954340Smckusick /* 7056626Sbostic * Must be root if the process has used set user or group 7156626Sbostic * privileges or does not belong to the real user. Must 7256626Sbostic * not be already traced. Can't attach to ourselves. 7354340Smckusick */ 7454340Smckusick if ((p->p_flag & SUGID || 7554340Smckusick p->p_cred->p_ruid != curp->p_cred->p_ruid) && 7654340Smckusick (error = suser(p->p_ucred, &p->p_acflag)) != 0) 7754340Smckusick return (error); 7854340Smckusick if (p->p_flag & STRC) 7954340Smckusick return (EALREADY); /* ??? */ 8056626Sbostic if (p->p_pid == curp->p_pid) 8156626Sbostic return (EINVAL); 8254340Smckusick /* 8354340Smckusick * It would be nice if the tracing relationship was separate 8454340Smckusick * from the parent relationship but that would require 8554340Smckusick * another set of links in the proc struct or for "wait" 8654340Smckusick * to scan the entire proc table. To make life easier, 8754340Smckusick * we just re-parent the process we're trying to trace. 8854340Smckusick * The old parent is remembered so we can put things back 8954340Smckusick * on a "detach". 9054340Smckusick */ 9154340Smckusick p->p_flag |= STRC; 9254340Smckusick p->p_oppid = p->p_pptr->p_pid; 9354340Smckusick proc_reparent(p, curp); 9454340Smckusick psignal(p, SIGSTOP); 9554340Smckusick return (0); 9654340Smckusick } 9756312Shibler if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & STRC)) 9844405Skarels return (ESRCH); 997501Sroot while (ipc.ip_lock) 1007501Sroot sleep((caddr_t)&ipc, IPCPRI); 1017501Sroot ipc.ip_lock = p->p_pid; 1027501Sroot ipc.ip_data = uap->data; 1037501Sroot ipc.ip_addr = uap->addr; 1047501Sroot ipc.ip_req = uap->req; 1057501Sroot p->p_flag &= ~SWTED; 1067501Sroot while (ipc.ip_req > 0) { 1077501Sroot if (p->p_stat==SSTOP) 1087501Sroot setrun(p); 1097501Sroot sleep((caddr_t)&ipc, IPCPRI); 1107501Sroot } 11143378Smckusick *retval = ipc.ip_data; 1127501Sroot ipc.ip_lock = 0; 1137501Sroot wakeup((caddr_t)&ipc); 11443378Smckusick if (ipc.ip_req < 0) 11544405Skarels return (EIO); 11644405Skarels return (0); 1177501Sroot } 1187501Sroot 11949246Skarels #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) 12049246Skarels 12145882Swilliam #if defined(i386) 12245882Swilliam #undef PC 12345882Swilliam #undef SP 12445882Swilliam #undef PS 12545882Swilliam #undef R0 12645882Swilliam #undef R1 1278952Sroot 12845882Swilliam #define PC tEIP 12945882Swilliam #define SP tESP 13045882Swilliam #define PS tEFLAGS 13145882Swilliam #define R0 tEDX 13245882Swilliam #define R1 tECX 13345882Swilliam #endif 13445882Swilliam 1357501Sroot /* 13649674Smckusick * Transmit a tracing request from the parent to the child process 13749674Smckusick * being debugged. This code runs in the context of the child process 13849674Smckusick * to fulfill the command requested by the parent. 1397501Sroot */ 14042928Smckusick procxmt(p) 14142928Smckusick register struct proc *p; 1427501Sroot { 143*57303Shibler register int i, *poff, *regs; 14449246Skarels extern char kstack[]; 1457501Sroot 14642928Smckusick if (ipc.ip_lock != p->p_pid) 1477501Sroot return (0); 14842928Smckusick p->p_slptime = 0; 149*57303Shibler regs = p->p_md.md_regs; 150*57303Shibler p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */ 1517501Sroot i = ipc.ip_req; 1527501Sroot ipc.ip_req = 0; 1537501Sroot switch (i) { 1547501Sroot 15526278Skarels case PT_READ_I: /* read the child's text space */ 1567501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1577501Sroot goto error; 1587501Sroot ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 1597501Sroot break; 1607501Sroot 16126278Skarels case PT_READ_D: /* read the child's data space */ 1627501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1637501Sroot goto error; 1647501Sroot ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 1657501Sroot break; 1667501Sroot 16726278Skarels case PT_READ_U: /* read the child's u. */ 1687501Sroot i = (int)ipc.ip_addr; 16949246Skarels if ((u_int) i > ctob(UPAGES)-sizeof(int) || (i & 1) != 0) 1707501Sroot goto error; 17149101Skarels ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); 1727501Sroot break; 1737501Sroot 17426278Skarels case PT_WRITE_I: /* write the child's text space */ 1758952Sroot if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { 17645735Smckusick vm_offset_t sa, ea; 17745735Smckusick int rv; 17845735Smckusick 17945735Smckusick sa = trunc_page((vm_offset_t)ipc.ip_addr); 18055270Smckusick ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)); 18147543Skarels rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 18245735Smckusick VM_PROT_DEFAULT, FALSE); 18345735Smckusick if (rv == KERN_SUCCESS) { 1848952Sroot i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); 18547543Skarels (void) vm_map_protect(&p->p_vmspace->vm_map, 18647543Skarels sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 18747543Skarels FALSE); 18845735Smckusick } 1898952Sroot } 1907501Sroot if (i < 0) 1917501Sroot goto error; 1927501Sroot break; 1937501Sroot 19426278Skarels case PT_WRITE_D: /* write the child's data space */ 1957501Sroot if (suword((caddr_t)ipc.ip_addr, 0) < 0) 1967501Sroot goto error; 1977501Sroot (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); 1987501Sroot break; 1997501Sroot 20026278Skarels case PT_WRITE_U: /* write the child's u. */ 2017501Sroot i = (int)ipc.ip_addr; 20252178Smarc #ifdef mips 20352178Smarc poff = (int *)PHYSOFF(curproc->p_addr, i); 20452178Smarc #else 20549246Skarels poff = (int *)PHYSOFF(kstack, i); 20652178Smarc #endif 2078952Sroot for (i=0; i<NIPCREG; i++) 208*57303Shibler if (poff == ®s[ipcreg[i]]) 2097501Sroot goto ok; 210*57303Shibler #if defined(hp300) 211*57303Shibler /* 212*57303Shibler * In the new frame layout, PS/PC are skewed by 2 bytes. 213*57303Shibler */ 214*57303Shibler regs = (int *)((short *)regs + 1); 215*57303Shibler if (poff == ®s[PC]) 216*57303Shibler goto ok; 217*57303Shibler #endif 218*57303Shibler if (poff == ®s[PS]) { 2198952Sroot ipc.ip_data |= PSL_USERSET; 22041991Smckusick ipc.ip_data &= ~PSL_USERCLR; 22132863Skarels #ifdef PSL_CM_CLR 22232863Skarels if (ipc.ip_data & PSL_CM) 22332863Skarels ipc.ip_data &= ~PSL_CM_CLR; 22432863Skarels #endif 2257501Sroot goto ok; 2267501Sroot } 22753873Smckusick #if defined(hp300) || defined(luna68k) 22841991Smckusick #ifdef FPCOPROC 22949246Skarels if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 23049246Skarels poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 23141991Smckusick goto ok; 23241991Smckusick #endif 23341991Smckusick #endif 2347501Sroot goto error; 2357501Sroot 2367501Sroot ok: 23742928Smckusick *poff = ipc.ip_data; 2387501Sroot break; 2397501Sroot 24026278Skarels case PT_STEP: /* single step the child */ 24126278Skarels case PT_CONTINUE: /* continue the child */ 242*57303Shibler regs = (int *)((short *)regs + 1); 24354340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 24454340Smckusick goto error; 2457501Sroot if ((int)ipc.ip_addr != 1) 246*57303Shibler regs[PC] = (int)ipc.ip_addr; 24743895Skarels p->p_xstat = ipc.ip_data; /* see issig */ 24852178Smarc #ifdef PSL_T 24952178Smarc /* need something more machine independent here... */ 25026278Skarels if (i == PT_STEP) 251*57303Shibler regs[PS] |= PSL_T; 25252178Smarc #endif 2537501Sroot wakeup((caddr_t)&ipc); 2547501Sroot return (1); 2557501Sroot 25626278Skarels case PT_KILL: /* kill the child process */ 2577501Sroot wakeup((caddr_t)&ipc); 25845111Smckusick exit(p, (int)p->p_xstat); 2597501Sroot 26054340Smckusick case PT_DETACH: /* stop tracing the child */ 261*57303Shibler regs = (int *)((short *)regs + 1); 26254340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 26354340Smckusick goto error; 26454340Smckusick if ((int)ipc.ip_addr != 1) 265*57303Shibler regs[PC] = (int)ipc.ip_addr; 26654340Smckusick p->p_xstat = ipc.ip_data; /* see issig */ 26754340Smckusick p->p_flag &= ~STRC; 26854340Smckusick if (p->p_oppid != p->p_pptr->p_pid) { 26954340Smckusick register struct proc *pp = pfind(p->p_oppid); 27054340Smckusick 27154340Smckusick if (pp) 27254340Smckusick proc_reparent(p, pp); 27354340Smckusick } 27454340Smckusick p->p_oppid = 0; 27554340Smckusick wakeup((caddr_t)&ipc); 27654340Smckusick return (1); 27754340Smckusick 2787501Sroot default: 2797501Sroot error: 2807501Sroot ipc.ip_req = -1; 2817501Sroot } 2827501Sroot wakeup((caddr_t)&ipc); 2837501Sroot return (0); 2847501Sroot } 285