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