xref: /csrg-svn/sys/kern/sys_process.c (revision 54352)
1 /*-
2  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  *
7  *	@(#)sys_process.c	7.28 (Berkeley) 06/24/92
8  */
9 
10 #define IPCREG
11 #include "param.h"
12 #include "proc.h"
13 #include "vnode.h"
14 #include "buf.h"
15 #include "ptrace.h"
16 
17 #include "machine/reg.h"
18 #include "machine/psl.h"
19 #include "vm/vm.h"
20 #include "vm/vm_page.h"
21 
22 #include "user.h"
23 
24 /*
25  * Priority for tracing
26  */
27 #define	IPCPRI	PZERO
28 
29 /*
30  * Tracing variables.
31  * Used to pass trace command from
32  * parent to child being traced.
33  * This data base cannot be
34  * shared and is locked
35  * per user.
36  */
37 struct {
38 	int	ip_lock;
39 	int	ip_req;
40 	int	*ip_addr;
41 	int	ip_data;
42 } ipc;
43 
44 /*
45  * Process debugging system call.
46  */
47 ptrace(curp, uap, retval)
48 	struct proc *curp;
49 	register struct args {
50 		int	req;
51 		int	pid;
52 		int	*addr;
53 		int	data;
54 	} *uap;
55 	int *retval;
56 {
57 	register struct proc *p;
58 	int error;
59 
60 	p = pfind(uap->pid);
61 	if (uap->req == PT_ATTACH) {
62 		/*
63 		 * Must be root if the process has used set user or
64 		 * group privileges or does not belong to the real
65 		 * user. Must not be already traced.
66 		 */
67 		if ((p->p_flag & SUGID ||
68 		    p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
69 		    (error = suser(p->p_ucred, &p->p_acflag)) != 0)
70 			return (error);
71 		if (p->p_flag & STRC)
72 			return (EALREADY);	/* ??? */
73 		/*
74 		 * It would be nice if the tracing relationship was separate
75 		 * from the parent relationship but that would require
76 		 * another set of links in the proc struct or for "wait"
77 		 * to scan the entire proc table.  To make life easier,
78 		 * we just re-parent the process we're trying to trace.
79 		 * The old parent is remembered so we can put things back
80 		 * on a "detach".
81 		 */
82 		p->p_flag |= STRC;
83 		p->p_oppid = p->p_pptr->p_pid;
84 		proc_reparent(p, curp);
85 		psignal(p, SIGSTOP);
86 		return (0);
87 	}
88 	if (uap->req <= 0) {
89 		curp->p_flag |= STRC;
90 		return (0);
91 	}
92 	if (p == 0 || p->p_stat != SSTOP || p->p_pptr != curp ||
93 	    !(p->p_flag & STRC))
94 		return (ESRCH);
95 	while (ipc.ip_lock)
96 		sleep((caddr_t)&ipc, IPCPRI);
97 	ipc.ip_lock = p->p_pid;
98 	ipc.ip_data = uap->data;
99 	ipc.ip_addr = uap->addr;
100 	ipc.ip_req = uap->req;
101 	p->p_flag &= ~SWTED;
102 	while (ipc.ip_req > 0) {
103 		if (p->p_stat==SSTOP)
104 			setrun(p);
105 		sleep((caddr_t)&ipc, IPCPRI);
106 	}
107 	*retval = ipc.ip_data;
108 	ipc.ip_lock = 0;
109 	wakeup((caddr_t)&ipc);
110 	if (ipc.ip_req < 0)
111 		return (EIO);
112 	return (0);
113 }
114 
115 #define	PHYSOFF(p, o) ((caddr_t)(p) + (o))
116 
117 #if defined(i386)
118 #undef        PC
119 #undef        SP
120 #undef        PS
121 #undef        R0
122 #undef        R1
123 
124 #define       PC      tEIP
125 #define       SP      tESP
126 #define       PS      tEFLAGS
127 #define       R0      tEDX
128 #define       R1      tECX
129 #endif
130 
131 /*
132  * Transmit a tracing request from the parent to the child process
133  * being debugged. This code runs in the context of the child process
134  * to fulfill the command requested by the parent.
135  */
136 procxmt(p)
137 	register struct proc *p;
138 {
139 	register int i, *poff;
140 	extern char kstack[];
141 
142 	if (ipc.ip_lock != p->p_pid)
143 		return (0);
144 	p->p_slptime = 0;
145 	p->p_addr->u_kproc.kp_proc.p_md.md_regs = p->p_md.md_regs; /* u.u_ar0 */
146 	i = ipc.ip_req;
147 	ipc.ip_req = 0;
148 	switch (i) {
149 
150 	case PT_READ_I:			/* read the child's text space */
151 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
152 			goto error;
153 		ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
154 		break;
155 
156 	case PT_READ_D:			/* read the child's data space */
157 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
158 			goto error;
159 		ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
160 		break;
161 
162 	case PT_READ_U:			/* read the child's u. */
163 #ifdef HPUXCOMPAT
164 		if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE)
165 			i = hpuxtobsduoff(ipc.ip_addr);
166 		else
167 #endif
168 		i = (int)ipc.ip_addr;
169 		if ((u_int) i > ctob(UPAGES)-sizeof(int) || (i & 1) != 0)
170 			goto error;
171 		ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i);
172 		break;
173 
174 	case PT_WRITE_I:		/* write the child's text space */
175 		if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
176 			vm_offset_t sa, ea;
177 			int rv;
178 
179 			sa = trunc_page((vm_offset_t)ipc.ip_addr);
180 			ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)-1);
181 			rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
182 					VM_PROT_DEFAULT, FALSE);
183 			if (rv == KERN_SUCCESS) {
184 				i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
185 				(void) vm_map_protect(&p->p_vmspace->vm_map,
186 					sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
187 					FALSE);
188 			}
189 		}
190 		if (i < 0)
191 			goto error;
192 		break;
193 
194 	case PT_WRITE_D:		/* write the child's data space */
195 		if (suword((caddr_t)ipc.ip_addr, 0) < 0)
196 			goto error;
197 		(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
198 		break;
199 
200 	case PT_WRITE_U:		/* write the child's u. */
201 #ifdef HPUXCOMPAT
202 		if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE)
203 			i = hpuxtobsduoff(ipc.ip_addr);
204 		else
205 #endif
206 		i = (int)ipc.ip_addr;
207 #ifdef mips
208 		poff = (int *)PHYSOFF(curproc->p_addr, i);
209 #else
210 		poff = (int *)PHYSOFF(kstack, i);
211 #endif
212 		for (i=0; i<NIPCREG; i++)
213 			if (poff == &p->p_md.md_regs[ipcreg[i]])
214 				goto ok;
215 		if (poff == &p->p_md.md_regs[PS]) {
216 			ipc.ip_data |= PSL_USERSET;
217 			ipc.ip_data &= ~PSL_USERCLR;
218 #ifdef PSL_CM_CLR
219 			if (ipc.ip_data & PSL_CM)
220 				ipc.ip_data &= ~PSL_CM_CLR;
221 #endif
222 			goto ok;
223 		}
224 #if defined(hp300) || defined(luna68k)
225 #ifdef FPCOPROC
226 		if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs &&
227 		    poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar)
228 			goto ok;
229 #endif
230 #endif
231 		goto error;
232 
233 	ok:
234 		*poff = ipc.ip_data;
235 		break;
236 
237 	case PT_STEP:			/* single step the child */
238 	case PT_CONTINUE:		/* continue the child */
239 		if ((unsigned)ipc.ip_data >= NSIG)
240 			goto error;
241 		if ((int)ipc.ip_addr != 1)
242 			p->p_md.md_regs[PC] = (int)ipc.ip_addr;
243 		p->p_xstat = ipc.ip_data;	/* see issig */
244 #ifdef PSL_T
245 		/* need something more machine independent here... */
246 		if (i == PT_STEP)
247 			p->p_md.md_regs[PS] |= PSL_T;
248 #endif
249 		wakeup((caddr_t)&ipc);
250 		return (1);
251 
252 	case PT_KILL:			/* kill the child process */
253 		wakeup((caddr_t)&ipc);
254 		exit(p, (int)p->p_xstat);
255 
256 	case PT_DETACH:			/* stop tracing the child */
257 		if ((unsigned)ipc.ip_data >= NSIG)
258 			goto error;
259 		if ((int)ipc.ip_addr != 1)
260 			p->p_md.md_regs[PC] = (int)ipc.ip_addr;
261 		p->p_xstat = ipc.ip_data;	/* see issig */
262 		p->p_flag &= ~STRC;
263 		if (p->p_oppid != p->p_pptr->p_pid) {
264                         register struct proc *pp = pfind(p->p_oppid);
265 
266                         if (pp)
267                                 proc_reparent(p, pp);
268 		}
269 		p->p_oppid = 0;
270 		wakeup((caddr_t)&ipc);
271 		return (1);
272 
273 	default:
274 	error:
275 		ipc.ip_req = -1;
276 	}
277 	wakeup((caddr_t)&ipc);
278 	return (0);
279 }
280 
281 /*
282  * Process debugging system call.
283  */
284 /* ARGSUSED */
285 profil(p, uap, retval)
286 	struct proc *p;
287 	register struct args {
288 		short	*bufbase;
289 		unsigned bufsize;
290 		unsigned pcoffset;
291 		unsigned pcscale;
292 	} *uap;
293 	int *retval;
294 {
295 	register struct uprof *upp;
296 	int s;
297 
298 	upp = &p->p_stats->p_prof;
299 	s = splhigh();	/* block profile interrupts while changing state */
300 	upp->pr_base = uap->bufbase;
301 	upp->pr_size = uap->bufsize;
302 	upp->pr_off = uap->pcoffset;
303 	upp->pr_scale = uap->pcscale;
304 	if (uap->pcscale) {
305 		if ((p->p_flag & SPROFIL) == 0)
306 			startprofclock(p);
307 	} else {
308 		if (p->p_flag & SPROFIL)
309 			stopprofclock(p);
310 	}
311 	splx(s);
312 	return (0);
313 }
314