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*62864Smckusick * @(#)sys_process.c 7.39 (Berkeley) 06/09/93 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; 4061237Smckusick caddr_t ip_addr; 417501Sroot int ip_data; 427501Sroot } ipc; 437501Sroot 447501Sroot /* 4549674Smckusick * Process debugging system call. 467501Sroot */ 4754931Storek struct ptrace_args { 4854931Storek int req; 4961237Smckusick pid_t pid; 5061237Smckusick caddr_t 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)) 120*62864Smckusick #if defined(hp300) || defined(luna68k) 121*62864Smckusick #define PHYSALIGNED(a) (((int)(a) & (sizeof(short) - 1)) == 0) 122*62864Smckusick #else 123*62864Smckusick #define PHYSALIGNED(a) (((int)(a) & (sizeof(int) - 1)) == 0) 124*62864Smckusick #endif 12549246Skarels 12645882Swilliam #if defined(i386) 12745882Swilliam #undef PC 12845882Swilliam #undef SP 12945882Swilliam #undef PS 13045882Swilliam #undef R0 13145882Swilliam #undef R1 1328952Sroot 13345882Swilliam #define PC tEIP 13445882Swilliam #define SP tESP 13545882Swilliam #define PS tEFLAGS 13645882Swilliam #define R0 tEDX 13745882Swilliam #define R1 tECX 13845882Swilliam #endif 13945882Swilliam 1407501Sroot /* 14149674Smckusick * Transmit a tracing request from the parent to the child process 14249674Smckusick * being debugged. This code runs in the context of the child process 14349674Smckusick * to fulfill the command requested by the parent. 1447501Sroot */ 14542928Smckusick procxmt(p) 14642928Smckusick register struct proc *p; 1477501Sroot { 14857303Shibler register int i, *poff, *regs; 14949246Skarels extern char kstack[]; 1507501Sroot 15142928Smckusick if (ipc.ip_lock != p->p_pid) 1527501Sroot return (0); 15342928Smckusick p->p_slptime = 0; 15457303Shibler regs = p->p_md.md_regs; 15557303Shibler p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */ 1567501Sroot i = ipc.ip_req; 1577501Sroot ipc.ip_req = 0; 1587501Sroot switch (i) { 1597501Sroot 16026278Skarels case PT_READ_I: /* read the child's text space */ 1617501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1627501Sroot goto error; 1637501Sroot ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 1647501Sroot break; 1657501Sroot 16626278Skarels case PT_READ_D: /* read the child's data space */ 1677501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1687501Sroot goto error; 1697501Sroot ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 1707501Sroot break; 1717501Sroot 17226278Skarels case PT_READ_U: /* read the child's u. */ 1737501Sroot i = (int)ipc.ip_addr; 174*62864Smckusick if ((u_int) i > ctob(UPAGES)-sizeof(int) || !PHYSALIGNED(i)) 1757501Sroot goto error; 17649101Skarels ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); 1777501Sroot break; 1787501Sroot 17926278Skarels case PT_WRITE_I: /* write the child's text space */ 1808952Sroot if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { 18145735Smckusick vm_offset_t sa, ea; 18245735Smckusick int rv; 18345735Smckusick 18445735Smckusick sa = trunc_page((vm_offset_t)ipc.ip_addr); 18555270Smckusick ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)); 18647543Skarels rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 18745735Smckusick VM_PROT_DEFAULT, FALSE); 18845735Smckusick if (rv == KERN_SUCCESS) { 1898952Sroot i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); 19047543Skarels (void) vm_map_protect(&p->p_vmspace->vm_map, 19147543Skarels sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 19247543Skarels FALSE); 19345735Smckusick } 1948952Sroot } 1957501Sroot if (i < 0) 1967501Sroot goto error; 1977501Sroot break; 1987501Sroot 19926278Skarels case PT_WRITE_D: /* write the child's data space */ 2007501Sroot if (suword((caddr_t)ipc.ip_addr, 0) < 0) 2017501Sroot goto error; 2027501Sroot (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); 2037501Sroot break; 2047501Sroot 20526278Skarels case PT_WRITE_U: /* write the child's u. */ 2067501Sroot i = (int)ipc.ip_addr; 20752178Smarc #ifdef mips 208*62864Smckusick poff = (int *)PHYSOFF(p->p_addr, i); 20952178Smarc #else 21049246Skarels poff = (int *)PHYSOFF(kstack, i); 21152178Smarc #endif 2128952Sroot for (i=0; i<NIPCREG; i++) 21357303Shibler if (poff == ®s[ipcreg[i]]) 2147501Sroot goto ok; 21559935Sakito #if defined(hp300) || defined(luna68k) 21657303Shibler /* 21757303Shibler * In the new frame layout, PS/PC are skewed by 2 bytes. 21857303Shibler */ 21957303Shibler regs = (int *)((short *)regs + 1); 22057303Shibler if (poff == ®s[PC]) 22157303Shibler goto ok; 22257303Shibler #endif 22357303Shibler if (poff == ®s[PS]) { 2248952Sroot ipc.ip_data |= PSL_USERSET; 22541991Smckusick ipc.ip_data &= ~PSL_USERCLR; 22632863Skarels #ifdef PSL_CM_CLR 22732863Skarels if (ipc.ip_data & PSL_CM) 22832863Skarels ipc.ip_data &= ~PSL_CM_CLR; 22932863Skarels #endif 2307501Sroot goto ok; 2317501Sroot } 23253873Smckusick #if defined(hp300) || defined(luna68k) 23341991Smckusick #ifdef FPCOPROC 23449246Skarels if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 23549246Skarels poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 23641991Smckusick goto ok; 23741991Smckusick #endif 23841991Smckusick #endif 2397501Sroot goto error; 2407501Sroot 2417501Sroot ok: 24242928Smckusick *poff = ipc.ip_data; 2437501Sroot break; 2447501Sroot 24526278Skarels case PT_STEP: /* single step the child */ 24626278Skarels case PT_CONTINUE: /* continue the child */ 24757303Shibler regs = (int *)((short *)regs + 1); 24854340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 24954340Smckusick goto error; 2507501Sroot if ((int)ipc.ip_addr != 1) 25157303Shibler regs[PC] = (int)ipc.ip_addr; 25243895Skarels p->p_xstat = ipc.ip_data; /* see issig */ 25352178Smarc #ifdef PSL_T 25452178Smarc /* need something more machine independent here... */ 25526278Skarels if (i == PT_STEP) 25657303Shibler regs[PS] |= PSL_T; 25752178Smarc #endif 2587501Sroot wakeup((caddr_t)&ipc); 2597501Sroot return (1); 2607501Sroot 26126278Skarels case PT_KILL: /* kill the child process */ 2627501Sroot wakeup((caddr_t)&ipc); 26357864Sralph exit1(p, (int)p->p_xstat); 2647501Sroot 26554340Smckusick case PT_DETACH: /* stop tracing the child */ 26657303Shibler regs = (int *)((short *)regs + 1); 26754340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 26854340Smckusick goto error; 26954340Smckusick if ((int)ipc.ip_addr != 1) 27057303Shibler regs[PC] = (int)ipc.ip_addr; 27154340Smckusick p->p_xstat = ipc.ip_data; /* see issig */ 27254340Smckusick p->p_flag &= ~STRC; 27354340Smckusick if (p->p_oppid != p->p_pptr->p_pid) { 27454340Smckusick register struct proc *pp = pfind(p->p_oppid); 27554340Smckusick 27654340Smckusick if (pp) 27754340Smckusick proc_reparent(p, pp); 27854340Smckusick } 27954340Smckusick p->p_oppid = 0; 28054340Smckusick wakeup((caddr_t)&ipc); 28154340Smckusick return (1); 28254340Smckusick 2837501Sroot default: 2847501Sroot error: 2857501Sroot ipc.ip_req = -1; 2867501Sroot } 2877501Sroot wakeup((caddr_t)&ipc); 2887501Sroot return (0); 2897501Sroot } 290