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