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