149589Sbostic /*- 263178Sbostic * Copyright (c) 1982, 1986, 1989, 1993 363178Sbostic * The Regents of the University of California. All rights reserved. 4*65771Sbostic * (c) UNIX System Laboratories, Inc. 5*65771Sbostic * All or some portions of this file are derived from material licensed 6*65771Sbostic * to the University of California by American Telephone and Telegraph 7*65771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8*65771Sbostic * the permission of UNIX System Laboratories, Inc. 923385Smckusick * 1049589Sbostic * %sccs.include.proprietary.c% 1149589Sbostic * 12*65771Sbostic * @(#)sys_process.c 8.5 (Berkeley) 01/21/94 1323385Smckusick */ 147426Sroot 1530376Skarels #define IPCREG 1656517Sbostic #include <sys/param.h> 1756517Sbostic #include <sys/proc.h> 1856517Sbostic #include <sys/vnode.h> 1956517Sbostic #include <sys/buf.h> 2056517Sbostic #include <sys/ptrace.h> 217426Sroot 2256517Sbostic #include <machine/reg.h> 2356517Sbostic #include <machine/psl.h> 2456517Sbostic #include <vm/vm.h> 2556517Sbostic #include <vm/vm_page.h> 2637520Smckusick 2756517Sbostic #include <sys/user.h> 2848438Skarels 297501Sroot /* 307501Sroot * Priority for tracing 317501Sroot */ 327501Sroot #define IPCPRI PZERO 337501Sroot 347501Sroot /* 357501Sroot * Tracing variables. 367501Sroot * Used to pass trace command from 377501Sroot * parent to child being traced. 387501Sroot * This data base cannot be 397501Sroot * shared and is locked 407501Sroot * per user. 417501Sroot */ 427501Sroot struct { 437501Sroot int ip_lock; 447501Sroot int ip_req; 4561237Smckusick caddr_t ip_addr; 467501Sroot int ip_data; 477501Sroot } ipc; 487501Sroot 497501Sroot /* 5049674Smckusick * Process debugging system call. 517501Sroot */ 5254931Storek struct ptrace_args { 5354931Storek int req; 5461237Smckusick pid_t pid; 5561237Smckusick caddr_t addr; 5654931Storek int data; 5754931Storek }; 5843378Smckusick ptrace(curp, uap, retval) 5943378Smckusick struct proc *curp; 6054931Storek register struct ptrace_args *uap; 6143378Smckusick int *retval; 6243378Smckusick { 6343378Smckusick register struct proc *p; 6454340Smckusick int error; 657501Sroot 6656312Shibler if (uap->req <= 0) { 6764588Sbostic curp->p_flag |= P_TRACED; 6856312Shibler return (0); 6956312Shibler } 7054340Smckusick p = pfind(uap->pid); 7156312Shibler if (p == 0) 7256312Shibler return (ESRCH); 7354340Smckusick if (uap->req == PT_ATTACH) { 7454340Smckusick /* 7556626Sbostic * Must be root if the process has used set user or group 7656626Sbostic * privileges or does not belong to the real user. Must 7756626Sbostic * not be already traced. Can't attach to ourselves. 7854340Smckusick */ 7964588Sbostic if ((p->p_flag & P_SUGID || 8054340Smckusick p->p_cred->p_ruid != curp->p_cred->p_ruid) && 8154340Smckusick (error = suser(p->p_ucred, &p->p_acflag)) != 0) 8254340Smckusick return (error); 8364588Sbostic if (p->p_flag & P_TRACED) 8454340Smckusick return (EALREADY); /* ??? */ 8556626Sbostic if (p->p_pid == curp->p_pid) 8656626Sbostic return (EINVAL); 8754340Smckusick /* 8854340Smckusick * It would be nice if the tracing relationship was separate 8954340Smckusick * from the parent relationship but that would require 9054340Smckusick * another set of links in the proc struct or for "wait" 9154340Smckusick * to scan the entire proc table. To make life easier, 9254340Smckusick * we just re-parent the process we're trying to trace. 9354340Smckusick * The old parent is remembered so we can put things back 9454340Smckusick * on a "detach". 9554340Smckusick */ 9664588Sbostic p->p_flag |= P_TRACED; 9754340Smckusick p->p_oppid = p->p_pptr->p_pid; 9854340Smckusick proc_reparent(p, curp); 9954340Smckusick psignal(p, SIGSTOP); 10054340Smckusick return (0); 10154340Smckusick } 10264588Sbostic if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & P_TRACED)) 10344405Skarels return (ESRCH); 1047501Sroot while (ipc.ip_lock) 1057501Sroot sleep((caddr_t)&ipc, IPCPRI); 1067501Sroot ipc.ip_lock = p->p_pid; 1077501Sroot ipc.ip_data = uap->data; 1087501Sroot ipc.ip_addr = uap->addr; 1097501Sroot ipc.ip_req = uap->req; 11064588Sbostic p->p_flag &= ~P_WAITED; 1117501Sroot while (ipc.ip_req > 0) { 1127501Sroot if (p->p_stat==SSTOP) 11364539Sbostic setrunnable(p); 1147501Sroot sleep((caddr_t)&ipc, IPCPRI); 1157501Sroot } 11643378Smckusick *retval = ipc.ip_data; 1177501Sroot ipc.ip_lock = 0; 1187501Sroot wakeup((caddr_t)&ipc); 11943378Smckusick if (ipc.ip_req < 0) 12044405Skarels return (EIO); 12144405Skarels return (0); 1227501Sroot } 1237501Sroot 12449246Skarels #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) 12562864Smckusick #if defined(hp300) || defined(luna68k) 12662864Smckusick #define PHYSALIGNED(a) (((int)(a) & (sizeof(short) - 1)) == 0) 12762864Smckusick #else 12862864Smckusick #define PHYSALIGNED(a) (((int)(a) & (sizeof(int) - 1)) == 0) 12962864Smckusick #endif 13049246Skarels 13145882Swilliam #if defined(i386) 13245882Swilliam #undef PC 13345882Swilliam #undef SP 13445882Swilliam #undef PS 13545882Swilliam #undef R0 13645882Swilliam #undef R1 1378952Sroot 13845882Swilliam #define PC tEIP 13945882Swilliam #define SP tESP 14045882Swilliam #define PS tEFLAGS 14145882Swilliam #define R0 tEDX 14245882Swilliam #define R1 tECX 14345882Swilliam #endif 14445882Swilliam 1457501Sroot /* 14649674Smckusick * Transmit a tracing request from the parent to the child process 14749674Smckusick * being debugged. This code runs in the context of the child process 14849674Smckusick * to fulfill the command requested by the parent. 1497501Sroot */ 15064588Sbostic trace_req(p) 15142928Smckusick register struct proc *p; 1527501Sroot { 15357303Shibler register int i, *poff, *regs; 15449246Skarels extern char kstack[]; 1557501Sroot 15642928Smckusick if (ipc.ip_lock != p->p_pid) 1577501Sroot return (0); 15842928Smckusick p->p_slptime = 0; 15957303Shibler regs = p->p_md.md_regs; 16057303Shibler p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */ 1617501Sroot i = ipc.ip_req; 1627501Sroot ipc.ip_req = 0; 1637501Sroot switch (i) { 1647501Sroot 16526278Skarels case PT_READ_I: /* read the child's text space */ 1667501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1677501Sroot goto error; 1687501Sroot ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); 1697501Sroot break; 1707501Sroot 17126278Skarels case PT_READ_D: /* read the child's data space */ 1727501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) 1737501Sroot goto error; 1747501Sroot ipc.ip_data = fuword((caddr_t)ipc.ip_addr); 1757501Sroot break; 1767501Sroot 17726278Skarels case PT_READ_U: /* read the child's u. */ 1787501Sroot i = (int)ipc.ip_addr; 17962864Smckusick if ((u_int) i > ctob(UPAGES)-sizeof(int) || !PHYSALIGNED(i)) 1807501Sroot goto error; 18149101Skarels ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); 1827501Sroot break; 1837501Sroot 18426278Skarels case PT_WRITE_I: /* write the child's text space */ 1858952Sroot if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { 18645735Smckusick vm_offset_t sa, ea; 18745735Smckusick int rv; 18845735Smckusick 18945735Smckusick sa = trunc_page((vm_offset_t)ipc.ip_addr); 19055270Smckusick ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)); 19147543Skarels rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, 19245735Smckusick VM_PROT_DEFAULT, FALSE); 19345735Smckusick if (rv == KERN_SUCCESS) { 1948952Sroot i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); 19547543Skarels (void) vm_map_protect(&p->p_vmspace->vm_map, 19647543Skarels sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 19747543Skarels FALSE); 19845735Smckusick } 1998952Sroot } 2007501Sroot if (i < 0) 2017501Sroot goto error; 2027501Sroot break; 2037501Sroot 20426278Skarels case PT_WRITE_D: /* write the child's data space */ 2057501Sroot if (suword((caddr_t)ipc.ip_addr, 0) < 0) 2067501Sroot goto error; 2077501Sroot (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); 2087501Sroot break; 2097501Sroot 21026278Skarels case PT_WRITE_U: /* write the child's u. */ 2117501Sroot i = (int)ipc.ip_addr; 21252178Smarc #ifdef mips 21362864Smckusick poff = (int *)PHYSOFF(p->p_addr, i); 21452178Smarc #else 21549246Skarels poff = (int *)PHYSOFF(kstack, i); 21652178Smarc #endif 2178952Sroot for (i=0; i<NIPCREG; i++) 21857303Shibler if (poff == ®s[ipcreg[i]]) 2197501Sroot goto ok; 22059935Sakito #if defined(hp300) || defined(luna68k) 22157303Shibler /* 22257303Shibler * In the new frame layout, PS/PC are skewed by 2 bytes. 22357303Shibler */ 22457303Shibler regs = (int *)((short *)regs + 1); 22557303Shibler if (poff == ®s[PC]) 22657303Shibler goto ok; 22757303Shibler #endif 22857303Shibler if (poff == ®s[PS]) { 2298952Sroot ipc.ip_data |= PSL_USERSET; 23041991Smckusick ipc.ip_data &= ~PSL_USERCLR; 23132863Skarels #ifdef PSL_CM_CLR 23232863Skarels if (ipc.ip_data & PSL_CM) 23332863Skarels ipc.ip_data &= ~PSL_CM_CLR; 23432863Skarels #endif 2357501Sroot goto ok; 2367501Sroot } 23753873Smckusick #if defined(hp300) || defined(luna68k) 23841991Smckusick #ifdef FPCOPROC 23949246Skarels if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && 24049246Skarels poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) 24141991Smckusick goto ok; 24241991Smckusick #endif 24341991Smckusick #endif 2447501Sroot goto error; 2457501Sroot 2467501Sroot ok: 24742928Smckusick *poff = ipc.ip_data; 2487501Sroot break; 2497501Sroot 25026278Skarels case PT_STEP: /* single step the child */ 25126278Skarels case PT_CONTINUE: /* continue the child */ 25265503Smckusick #ifndef mips 25357303Shibler regs = (int *)((short *)regs + 1); 25465503Smckusick #endif 25554340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 25654340Smckusick goto error; 2577501Sroot if ((int)ipc.ip_addr != 1) 25857303Shibler regs[PC] = (int)ipc.ip_addr; 25964588Sbostic p->p_xstat = ipc.ip_data; /* see issignal */ 26065503Smckusick #ifdef mips 26165503Smckusick if (i == PT_STEP && cpu_singlestep(p)) 26265503Smckusick goto error; 26365503Smckusick #else 26452178Smarc #ifdef PSL_T 26552178Smarc /* need something more machine independent here... */ 26626278Skarels if (i == PT_STEP) 26757303Shibler regs[PS] |= PSL_T; 26852178Smarc #endif 26965503Smckusick #endif 2707501Sroot wakeup((caddr_t)&ipc); 2717501Sroot return (1); 2727501Sroot 27326278Skarels case PT_KILL: /* kill the child process */ 2747501Sroot wakeup((caddr_t)&ipc); 27557864Sralph exit1(p, (int)p->p_xstat); 2767501Sroot 27754340Smckusick case PT_DETACH: /* stop tracing the child */ 27857303Shibler regs = (int *)((short *)regs + 1); 27954340Smckusick if ((unsigned)ipc.ip_data >= NSIG) 28054340Smckusick goto error; 28154340Smckusick if ((int)ipc.ip_addr != 1) 28257303Shibler regs[PC] = (int)ipc.ip_addr; 28364588Sbostic p->p_xstat = ipc.ip_data; /* see issignal */ 28464588Sbostic p->p_flag &= ~P_TRACED; 28554340Smckusick if (p->p_oppid != p->p_pptr->p_pid) { 28654340Smckusick register struct proc *pp = pfind(p->p_oppid); 28754340Smckusick 28854340Smckusick if (pp) 28954340Smckusick proc_reparent(p, pp); 29054340Smckusick } 29154340Smckusick p->p_oppid = 0; 29254340Smckusick wakeup((caddr_t)&ipc); 29354340Smckusick return (1); 29454340Smckusick 2957501Sroot default: 2967501Sroot error: 2977501Sroot ipc.ip_req = -1; 2987501Sroot } 2997501Sroot wakeup((caddr_t)&ipc); 3007501Sroot return (0); 3017501Sroot } 302