149589Sbostic /*-
263178Sbostic * Copyright (c) 1982, 1986, 1989, 1993
363178Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923385Smckusick *
1049589Sbostic * %sccs.include.proprietary.c%
1149589Sbostic *
12*68315Scgd * @(#)sys_process.c 8.6 (Berkeley) 02/14/95
1323385Smckusick */
147426Sroot
1530376Skarels #define IPCREG
1656517Sbostic #include <sys/param.h>
17*68315Scgd #include <sys/systm.h>
1856517Sbostic #include <sys/proc.h>
1956517Sbostic #include <sys/vnode.h>
2056517Sbostic #include <sys/buf.h>
2156517Sbostic #include <sys/ptrace.h>
227426Sroot
23*68315Scgd #include <sys/mount.h>
24*68315Scgd #include <sys/syscallargs.h>
25*68315Scgd
2656517Sbostic #include <machine/reg.h>
2756517Sbostic #include <machine/psl.h>
2856517Sbostic #include <vm/vm.h>
2956517Sbostic #include <vm/vm_page.h>
3037520Smckusick
3156517Sbostic #include <sys/user.h>
3248438Skarels
337501Sroot /*
347501Sroot * Priority for tracing
357501Sroot */
367501Sroot #define IPCPRI PZERO
377501Sroot
387501Sroot /*
397501Sroot * Tracing variables.
407501Sroot * Used to pass trace command from
417501Sroot * parent to child being traced.
427501Sroot * This data base cannot be
437501Sroot * shared and is locked
447501Sroot * per user.
457501Sroot */
467501Sroot struct {
477501Sroot int ip_lock;
487501Sroot int ip_req;
4961237Smckusick caddr_t ip_addr;
507501Sroot int ip_data;
517501Sroot } ipc;
527501Sroot
537501Sroot /*
5449674Smckusick * Process debugging system call.
557501Sroot */
5643378Smckusick ptrace(curp, uap, retval)
5743378Smckusick struct proc *curp;
58*68315Scgd struct ptrace_args /* {
59*68315Scgd syscallarg(int) req;
60*68315Scgd syscallarg(pid_t) pid;
61*68315Scgd syscallarg(caddr_t) addr;
62*68315Scgd syscallarg(int) data;
63*68315Scgd } */ *uap;
64*68315Scgd register_t *retval;
6543378Smckusick {
6643378Smckusick register struct proc *p;
6754340Smckusick int error;
687501Sroot
69*68315Scgd if (SCARG(uap, req) <= 0) {
7064588Sbostic curp->p_flag |= P_TRACED;
7156312Shibler return (0);
7256312Shibler }
73*68315Scgd p = pfind(SCARG(uap, pid));
7456312Shibler if (p == 0)
7556312Shibler return (ESRCH);
76*68315Scgd if (SCARG(uap, req) == PT_ATTACH) {
7754340Smckusick /*
7856626Sbostic * Must be root if the process has used set user or group
7956626Sbostic * privileges or does not belong to the real user. Must
8056626Sbostic * not be already traced. Can't attach to ourselves.
8154340Smckusick */
8264588Sbostic if ((p->p_flag & P_SUGID ||
8354340Smckusick p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
8454340Smckusick (error = suser(p->p_ucred, &p->p_acflag)) != 0)
8554340Smckusick return (error);
8664588Sbostic if (p->p_flag & P_TRACED)
8754340Smckusick return (EALREADY); /* ??? */
8856626Sbostic if (p->p_pid == curp->p_pid)
8956626Sbostic return (EINVAL);
9054340Smckusick /*
9154340Smckusick * It would be nice if the tracing relationship was separate
9254340Smckusick * from the parent relationship but that would require
9354340Smckusick * another set of links in the proc struct or for "wait"
9454340Smckusick * to scan the entire proc table. To make life easier,
9554340Smckusick * we just re-parent the process we're trying to trace.
9654340Smckusick * The old parent is remembered so we can put things back
9754340Smckusick * on a "detach".
9854340Smckusick */
9964588Sbostic p->p_flag |= P_TRACED;
10054340Smckusick p->p_oppid = p->p_pptr->p_pid;
10154340Smckusick proc_reparent(p, curp);
10254340Smckusick psignal(p, SIGSTOP);
10354340Smckusick return (0);
10454340Smckusick }
10564588Sbostic if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & P_TRACED))
10644405Skarels return (ESRCH);
1077501Sroot while (ipc.ip_lock)
1087501Sroot sleep((caddr_t)&ipc, IPCPRI);
1097501Sroot ipc.ip_lock = p->p_pid;
110*68315Scgd ipc.ip_data = SCARG(uap, data);
111*68315Scgd ipc.ip_addr = SCARG(uap, addr);
112*68315Scgd ipc.ip_req = SCARG(uap, req);
11364588Sbostic p->p_flag &= ~P_WAITED;
1147501Sroot while (ipc.ip_req > 0) {
1157501Sroot if (p->p_stat==SSTOP)
11664539Sbostic setrunnable(p);
1177501Sroot sleep((caddr_t)&ipc, IPCPRI);
1187501Sroot }
11943378Smckusick *retval = ipc.ip_data;
1207501Sroot ipc.ip_lock = 0;
1217501Sroot wakeup((caddr_t)&ipc);
12243378Smckusick if (ipc.ip_req < 0)
12344405Skarels return (EIO);
12444405Skarels return (0);
1257501Sroot }
1267501Sroot
12749246Skarels #define PHYSOFF(p, o) ((caddr_t)(p) + (o))
12862864Smckusick #if defined(hp300) || defined(luna68k)
12962864Smckusick #define PHYSALIGNED(a) (((int)(a) & (sizeof(short) - 1)) == 0)
13062864Smckusick #else
13162864Smckusick #define PHYSALIGNED(a) (((int)(a) & (sizeof(int) - 1)) == 0)
13262864Smckusick #endif
13349246Skarels
13445882Swilliam #if defined(i386)
13545882Swilliam #undef PC
13645882Swilliam #undef SP
13745882Swilliam #undef PS
13845882Swilliam #undef R0
13945882Swilliam #undef R1
1408952Sroot
14145882Swilliam #define PC tEIP
14245882Swilliam #define SP tESP
14345882Swilliam #define PS tEFLAGS
14445882Swilliam #define R0 tEDX
14545882Swilliam #define R1 tECX
14645882Swilliam #endif
14745882Swilliam
1487501Sroot /*
14949674Smckusick * Transmit a tracing request from the parent to the child process
15049674Smckusick * being debugged. This code runs in the context of the child process
15149674Smckusick * to fulfill the command requested by the parent.
1527501Sroot */
trace_req(p)15364588Sbostic trace_req(p)
15442928Smckusick register struct proc *p;
1557501Sroot {
15657303Shibler register int i, *poff, *regs;
15749246Skarels extern char kstack[];
1587501Sroot
15942928Smckusick if (ipc.ip_lock != p->p_pid)
1607501Sroot return (0);
16142928Smckusick p->p_slptime = 0;
16257303Shibler regs = p->p_md.md_regs;
16357303Shibler p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */
1647501Sroot i = ipc.ip_req;
1657501Sroot ipc.ip_req = 0;
1667501Sroot switch (i) {
1677501Sroot
16826278Skarels case PT_READ_I: /* read the child's text space */
1697501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
1707501Sroot goto error;
1717501Sroot ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
1727501Sroot break;
1737501Sroot
17426278Skarels case PT_READ_D: /* read the child's data space */
1757501Sroot if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
1767501Sroot goto error;
1777501Sroot ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
1787501Sroot break;
1797501Sroot
18026278Skarels case PT_READ_U: /* read the child's u. */
1817501Sroot i = (int)ipc.ip_addr;
18262864Smckusick if ((u_int) i > ctob(UPAGES)-sizeof(int) || !PHYSALIGNED(i))
1837501Sroot goto error;
18449101Skarels ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i);
1857501Sroot break;
1867501Sroot
18726278Skarels case PT_WRITE_I: /* write the child's text space */
1888952Sroot if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
18945735Smckusick vm_offset_t sa, ea;
19045735Smckusick int rv;
19145735Smckusick
19245735Smckusick sa = trunc_page((vm_offset_t)ipc.ip_addr);
19355270Smckusick ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int));
19447543Skarels rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
19545735Smckusick VM_PROT_DEFAULT, FALSE);
19645735Smckusick if (rv == KERN_SUCCESS) {
1978952Sroot i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
19847543Skarels (void) vm_map_protect(&p->p_vmspace->vm_map,
19947543Skarels sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
20047543Skarels FALSE);
20145735Smckusick }
2028952Sroot }
2037501Sroot if (i < 0)
2047501Sroot goto error;
2057501Sroot break;
2067501Sroot
20726278Skarels case PT_WRITE_D: /* write the child's data space */
2087501Sroot if (suword((caddr_t)ipc.ip_addr, 0) < 0)
2097501Sroot goto error;
2107501Sroot (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
2117501Sroot break;
2127501Sroot
21326278Skarels case PT_WRITE_U: /* write the child's u. */
2147501Sroot i = (int)ipc.ip_addr;
21552178Smarc #ifdef mips
21662864Smckusick poff = (int *)PHYSOFF(p->p_addr, i);
21752178Smarc #else
21849246Skarels poff = (int *)PHYSOFF(kstack, i);
21952178Smarc #endif
2208952Sroot for (i=0; i<NIPCREG; i++)
22157303Shibler if (poff == ®s[ipcreg[i]])
2227501Sroot goto ok;
22359935Sakito #if defined(hp300) || defined(luna68k)
22457303Shibler /*
22557303Shibler * In the new frame layout, PS/PC are skewed by 2 bytes.
22657303Shibler */
22757303Shibler regs = (int *)((short *)regs + 1);
22857303Shibler if (poff == ®s[PC])
22957303Shibler goto ok;
23057303Shibler #endif
23157303Shibler if (poff == ®s[PS]) {
2328952Sroot ipc.ip_data |= PSL_USERSET;
23341991Smckusick ipc.ip_data &= ~PSL_USERCLR;
23432863Skarels #ifdef PSL_CM_CLR
23532863Skarels if (ipc.ip_data & PSL_CM)
23632863Skarels ipc.ip_data &= ~PSL_CM_CLR;
23732863Skarels #endif
2387501Sroot goto ok;
2397501Sroot }
24053873Smckusick #if defined(hp300) || defined(luna68k)
24141991Smckusick #ifdef FPCOPROC
24249246Skarels if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs &&
24349246Skarels poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar)
24441991Smckusick goto ok;
24541991Smckusick #endif
24641991Smckusick #endif
2477501Sroot goto error;
2487501Sroot
2497501Sroot ok:
25042928Smckusick *poff = ipc.ip_data;
2517501Sroot break;
2527501Sroot
25326278Skarels case PT_STEP: /* single step the child */
25426278Skarels case PT_CONTINUE: /* continue the child */
25565503Smckusick #ifndef mips
25657303Shibler regs = (int *)((short *)regs + 1);
25765503Smckusick #endif
25854340Smckusick if ((unsigned)ipc.ip_data >= NSIG)
25954340Smckusick goto error;
2607501Sroot if ((int)ipc.ip_addr != 1)
26157303Shibler regs[PC] = (int)ipc.ip_addr;
26264588Sbostic p->p_xstat = ipc.ip_data; /* see issignal */
26365503Smckusick #ifdef mips
26465503Smckusick if (i == PT_STEP && cpu_singlestep(p))
26565503Smckusick goto error;
26665503Smckusick #else
26752178Smarc #ifdef PSL_T
26852178Smarc /* need something more machine independent here... */
26926278Skarels if (i == PT_STEP)
27057303Shibler regs[PS] |= PSL_T;
27152178Smarc #endif
27265503Smckusick #endif
2737501Sroot wakeup((caddr_t)&ipc);
2747501Sroot return (1);
2757501Sroot
27626278Skarels case PT_KILL: /* kill the child process */
2777501Sroot wakeup((caddr_t)&ipc);
27857864Sralph exit1(p, (int)p->p_xstat);
2797501Sroot
28054340Smckusick case PT_DETACH: /* stop tracing the child */
28157303Shibler regs = (int *)((short *)regs + 1);
28254340Smckusick if ((unsigned)ipc.ip_data >= NSIG)
28354340Smckusick goto error;
28454340Smckusick if ((int)ipc.ip_addr != 1)
28557303Shibler regs[PC] = (int)ipc.ip_addr;
28664588Sbostic p->p_xstat = ipc.ip_data; /* see issignal */
28764588Sbostic p->p_flag &= ~P_TRACED;
28854340Smckusick if (p->p_oppid != p->p_pptr->p_pid) {
28954340Smckusick register struct proc *pp = pfind(p->p_oppid);
29054340Smckusick
29154340Smckusick if (pp)
29254340Smckusick proc_reparent(p, pp);
29354340Smckusick }
29454340Smckusick p->p_oppid = 0;
29554340Smckusick wakeup((caddr_t)&ipc);
29654340Smckusick return (1);
29754340Smckusick
2987501Sroot default:
2997501Sroot error:
3007501Sroot ipc.ip_req = -1;
3017501Sroot }
3027501Sroot wakeup((caddr_t)&ipc);
3037501Sroot return (0);
3047501Sroot }
305