xref: /csrg-svn/sys/kern/sys_process.c (revision 62864)
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 == &regs[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 == &regs[PC])
22157303Shibler 			goto ok;
22257303Shibler #endif
22357303Shibler 		if (poff == &regs[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