xref: /csrg-svn/sys/kern/sys_process.c (revision 54340)
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*54340Smckusick  *	@(#)sys_process.c	7.27 (Berkeley) 06/23/92
823385Smckusick  */
97426Sroot 
1030376Skarels #define IPCREG
1117095Sbloom #include "param.h"
1217095Sbloom #include "proc.h"
1337728Smckusick #include "vnode.h"
1417095Sbloom #include "buf.h"
1526278Skarels #include "ptrace.h"
167426Sroot 
1737520Smckusick #include "machine/reg.h"
1837520Smckusick #include "machine/psl.h"
1948438Skarels #include "vm/vm.h"
2047543Skarels #include "vm/vm_page.h"
2137520Smckusick 
2248438Skarels #include "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;
407501Sroot 	int	*ip_addr;
417501Sroot 	int	ip_data;
427501Sroot } ipc;
437501Sroot 
447501Sroot /*
4549674Smckusick  * Process debugging system call.
467501Sroot  */
4743378Smckusick ptrace(curp, uap, retval)
4843378Smckusick 	struct proc *curp;
4943378Smckusick 	register struct args {
507501Sroot 		int	req;
517501Sroot 		int	pid;
527501Sroot 		int	*addr;
537501Sroot 		int	data;
547501Sroot 	} *uap;
5543378Smckusick 	int *retval;
5643378Smckusick {
5743378Smckusick 	register struct proc *p;
58*54340Smckusick 	int error;
597501Sroot 
60*54340Smckusick 	p = pfind(uap->pid);
61*54340Smckusick 	if (uap->req == PT_ATTACH) {
62*54340Smckusick 		/*
63*54340Smckusick 		 * Must be root if the process has used set user or
64*54340Smckusick 		 * group privileges or does not belong to the real
65*54340Smckusick 		 * user. Must not be already traced.
66*54340Smckusick 		 */
67*54340Smckusick 		if ((p->p_flag & SUGID ||
68*54340Smckusick 		    p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
69*54340Smckusick 		    (error = suser(p->p_ucred, &p->p_acflag)) != 0)
70*54340Smckusick 			return (error);
71*54340Smckusick 		if (p->p_flag & STRC)
72*54340Smckusick 			return (EALREADY);	/* ??? */
73*54340Smckusick 		/*
74*54340Smckusick 		 * It would be nice if the tracing relationship was separate
75*54340Smckusick 		 * from the parent relationship but that would require
76*54340Smckusick 		 * another set of links in the proc struct or for "wait"
77*54340Smckusick 		 * to scan the entire proc table.  To make life easier,
78*54340Smckusick 		 * we just re-parent the process we're trying to trace.
79*54340Smckusick 		 * The old parent is remembered so we can put things back
80*54340Smckusick 		 * on a "detach".
81*54340Smckusick 		 */
82*54340Smckusick 		p->p_flag |= STRC;
83*54340Smckusick 		p->p_oppid = p->p_pptr->p_pid;
84*54340Smckusick 		proc_reparent(p, curp);
85*54340Smckusick 		psignal(p, SIGSTOP);
86*54340Smckusick 		return (0);
87*54340Smckusick 	}
887501Sroot 	if (uap->req <= 0) {
8943378Smckusick 		curp->p_flag |= STRC;
9044405Skarels 		return (0);
917501Sroot 	}
9247543Skarels 	if (p == 0 || p->p_stat != SSTOP || p->p_pptr != curp ||
9343378Smckusick 	    !(p->p_flag & STRC))
9444405Skarels 		return (ESRCH);
957501Sroot 	while (ipc.ip_lock)
967501Sroot 		sleep((caddr_t)&ipc, IPCPRI);
977501Sroot 	ipc.ip_lock = p->p_pid;
987501Sroot 	ipc.ip_data = uap->data;
997501Sroot 	ipc.ip_addr = uap->addr;
1007501Sroot 	ipc.ip_req = uap->req;
1017501Sroot 	p->p_flag &= ~SWTED;
1027501Sroot 	while (ipc.ip_req > 0) {
1037501Sroot 		if (p->p_stat==SSTOP)
1047501Sroot 			setrun(p);
1057501Sroot 		sleep((caddr_t)&ipc, IPCPRI);
1067501Sroot 	}
10743378Smckusick 	*retval = ipc.ip_data;
1087501Sroot 	ipc.ip_lock = 0;
1097501Sroot 	wakeup((caddr_t)&ipc);
11043378Smckusick 	if (ipc.ip_req < 0)
11144405Skarels 		return (EIO);
11244405Skarels 	return (0);
1137501Sroot }
1147501Sroot 
11549246Skarels #define	PHYSOFF(p, o) ((caddr_t)(p) + (o))
11649246Skarels 
11745882Swilliam #if defined(i386)
11845882Swilliam #undef        PC
11945882Swilliam #undef        SP
12045882Swilliam #undef        PS
12145882Swilliam #undef        R0
12245882Swilliam #undef        R1
1238952Sroot 
12445882Swilliam #define       PC      tEIP
12545882Swilliam #define       SP      tESP
12645882Swilliam #define       PS      tEFLAGS
12745882Swilliam #define       R0      tEDX
12845882Swilliam #define       R1      tECX
12945882Swilliam #endif
13045882Swilliam 
1317501Sroot /*
13249674Smckusick  * Transmit a tracing request from the parent to the child process
13349674Smckusick  * being debugged. This code runs in the context of the child process
13449674Smckusick  * to fulfill the command requested by the parent.
1357501Sroot  */
13642928Smckusick procxmt(p)
13742928Smckusick 	register struct proc *p;
1387501Sroot {
13942928Smckusick 	register int i, *poff;
14049246Skarels 	extern char kstack[];
1417501Sroot 
14242928Smckusick 	if (ipc.ip_lock != p->p_pid)
1437501Sroot 		return (0);
14442928Smckusick 	p->p_slptime = 0;
14552374Smckusick 	p->p_addr->u_kproc.kp_proc.p_md.md_regs = p->p_md.md_regs; /* u.u_ar0 */
1467501Sroot 	i = ipc.ip_req;
1477501Sroot 	ipc.ip_req = 0;
1487501Sroot 	switch (i) {
1497501Sroot 
15026278Skarels 	case PT_READ_I:			/* read the child's text space */
1517501Sroot 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
1527501Sroot 			goto error;
1537501Sroot 		ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
1547501Sroot 		break;
1557501Sroot 
15626278Skarels 	case PT_READ_D:			/* read the child's data space */
1577501Sroot 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
1587501Sroot 			goto error;
1597501Sroot 		ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
1607501Sroot 		break;
1617501Sroot 
16226278Skarels 	case PT_READ_U:			/* read the child's u. */
16341991Smckusick #ifdef HPUXCOMPAT
16449101Skarels 		if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE)
16541991Smckusick 			i = hpuxtobsduoff(ipc.ip_addr);
16641991Smckusick 		else
16741991Smckusick #endif
1687501Sroot 		i = (int)ipc.ip_addr;
16949246Skarels 		if ((u_int) i > ctob(UPAGES)-sizeof(int) || (i & 1) != 0)
1707501Sroot 			goto error;
17149101Skarels 		ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i);
1727501Sroot 		break;
1737501Sroot 
17426278Skarels 	case PT_WRITE_I:		/* write the child's text space */
1758952Sroot 		if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
17645735Smckusick 			vm_offset_t sa, ea;
17745735Smckusick 			int rv;
17845735Smckusick 
17945735Smckusick 			sa = trunc_page((vm_offset_t)ipc.ip_addr);
18045735Smckusick 			ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)-1);
18147543Skarels 			rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
18245735Smckusick 					VM_PROT_DEFAULT, FALSE);
18345735Smckusick 			if (rv == KERN_SUCCESS) {
1848952Sroot 				i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
18547543Skarels 				(void) vm_map_protect(&p->p_vmspace->vm_map,
18647543Skarels 					sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
18747543Skarels 					FALSE);
18845735Smckusick 			}
1898952Sroot 		}
1907501Sroot 		if (i < 0)
1917501Sroot 			goto error;
1927501Sroot 		break;
1937501Sroot 
19426278Skarels 	case PT_WRITE_D:		/* write the child's data space */
1957501Sroot 		if (suword((caddr_t)ipc.ip_addr, 0) < 0)
1967501Sroot 			goto error;
1977501Sroot 		(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
1987501Sroot 		break;
1997501Sroot 
20026278Skarels 	case PT_WRITE_U:		/* write the child's u. */
20141991Smckusick #ifdef HPUXCOMPAT
20249101Skarels 		if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE)
20341991Smckusick 			i = hpuxtobsduoff(ipc.ip_addr);
20441991Smckusick 		else
20541991Smckusick #endif
2067501Sroot 		i = (int)ipc.ip_addr;
20752178Smarc #ifdef mips
20852178Smarc 		poff = (int *)PHYSOFF(curproc->p_addr, i);
20952178Smarc #else
21049246Skarels 		poff = (int *)PHYSOFF(kstack, i);
21152178Smarc #endif
2128952Sroot 		for (i=0; i<NIPCREG; i++)
21352374Smckusick 			if (poff == &p->p_md.md_regs[ipcreg[i]])
2147501Sroot 				goto ok;
21552374Smckusick 		if (poff == &p->p_md.md_regs[PS]) {
2168952Sroot 			ipc.ip_data |= PSL_USERSET;
21741991Smckusick 			ipc.ip_data &= ~PSL_USERCLR;
21832863Skarels #ifdef PSL_CM_CLR
21932863Skarels 			if (ipc.ip_data & PSL_CM)
22032863Skarels 				ipc.ip_data &= ~PSL_CM_CLR;
22132863Skarels #endif
2227501Sroot 			goto ok;
2237501Sroot 		}
22453873Smckusick #if defined(hp300) || defined(luna68k)
22541991Smckusick #ifdef FPCOPROC
22649246Skarels 		if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs &&
22749246Skarels 		    poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar)
22841991Smckusick 			goto ok;
22941991Smckusick #endif
23041991Smckusick #endif
2317501Sroot 		goto error;
2327501Sroot 
2337501Sroot 	ok:
23442928Smckusick 		*poff = ipc.ip_data;
2357501Sroot 		break;
2367501Sroot 
23726278Skarels 	case PT_STEP:			/* single step the child */
23826278Skarels 	case PT_CONTINUE:		/* continue the child */
239*54340Smckusick 		if ((unsigned)ipc.ip_data >= NSIG)
240*54340Smckusick 			goto error;
2417501Sroot 		if ((int)ipc.ip_addr != 1)
24252374Smckusick 			p->p_md.md_regs[PC] = (int)ipc.ip_addr;
24343895Skarels 		p->p_xstat = ipc.ip_data;	/* see issig */
24452178Smarc #ifdef PSL_T
24552178Smarc 		/* need something more machine independent here... */
24626278Skarels 		if (i == PT_STEP)
24752374Smckusick 			p->p_md.md_regs[PS] |= PSL_T;
24852178Smarc #endif
2497501Sroot 		wakeup((caddr_t)&ipc);
2507501Sroot 		return (1);
2517501Sroot 
25226278Skarels 	case PT_KILL:			/* kill the child process */
2537501Sroot 		wakeup((caddr_t)&ipc);
25445111Smckusick 		exit(p, (int)p->p_xstat);
2557501Sroot 
256*54340Smckusick 	case PT_DETACH:			/* stop tracing the child */
257*54340Smckusick 		if ((unsigned)ipc.ip_data >= NSIG)
258*54340Smckusick 			goto error;
259*54340Smckusick 		if ((int)ipc.ip_addr != 1)
260*54340Smckusick 			p->p_md.md_regs[PC] = (int)ipc.ip_addr;
261*54340Smckusick 		p->p_xstat = ipc.ip_data;	/* see issig */
262*54340Smckusick 		p->p_flag &= ~STRC;
263*54340Smckusick 		if (p->p_oppid != p->p_pptr->p_pid) {
264*54340Smckusick                         register struct proc *pp = pfind(p->p_oppid);
265*54340Smckusick 
266*54340Smckusick                         if (pp)
267*54340Smckusick                                 proc_reparent(p, pp);
268*54340Smckusick 		}
269*54340Smckusick 		p->p_oppid = 0;
270*54340Smckusick 		wakeup((caddr_t)&ipc);
271*54340Smckusick 		return (1);
272*54340Smckusick 
2737501Sroot 	default:
2747501Sroot 	error:
2757501Sroot 		ipc.ip_req = -1;
2767501Sroot 	}
2777501Sroot 	wakeup((caddr_t)&ipc);
2787501Sroot 	return (0);
2797501Sroot }
28049534Smckusick 
28149674Smckusick /*
28249674Smckusick  * Process debugging system call.
28349674Smckusick  */
28449534Smckusick /* ARGSUSED */
28549534Smckusick profil(p, uap, retval)
28649534Smckusick 	struct proc *p;
28749534Smckusick 	register struct args {
28849534Smckusick 		short	*bufbase;
28949534Smckusick 		unsigned bufsize;
29049534Smckusick 		unsigned pcoffset;
29149534Smckusick 		unsigned pcscale;
29249534Smckusick 	} *uap;
29349534Smckusick 	int *retval;
29449534Smckusick {
29549534Smckusick 	register struct uprof *upp = &p->p_stats->p_prof;
29649534Smckusick 
29749534Smckusick 	upp->pr_base = uap->bufbase;
29849534Smckusick 	upp->pr_size = uap->bufsize;
29949534Smckusick 	upp->pr_off = uap->pcoffset;
30049534Smckusick 	upp->pr_scale = uap->pcscale;
30154131Smckusick 	if (uap->pcscale)
30254131Smckusick 		startprofclock(p);
30349534Smckusick 	return (0);
30449534Smckusick }
305