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