xref: /original-bsd/sys/sparc/sparc/sys_process.c (revision fafeb71d)
1 /*-
2  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratories.
13  *
14  * %sccs.include.proprietary.c%
15  *
16  *	@(#)sys_process.c	7.2 (Berkeley) 07/21/92
17  */
18 
19 #include "sys/param.h"
20 #include "sys/proc.h"
21 #include "sys/vnode.h"
22 #include "sys/buf.h"
23 #include "sys/malloc.h"
24 #include "sys/ptrace.h"
25 #include "sys/user.h"
26 
27 #include "vm/vm.h"
28 #include "vm/vm_page.h"
29 
30 #include "machine/psl.h"
31 #include "machine/reg.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 	int	ip_error;
50 	union {
51 		char	un_any[4];
52 		struct {
53 			int	wd_data;
54 			caddr_t	wd_addr;
55 		} un_wd;
56 		struct	trapframe un_tf;
57 		struct	fpstate un_f;
58 	} ip_un;
59 } ipc;
60 #define	ip_any	ip_un.un_any
61 #define	ip_data	ip_un.un_wd.wd_data
62 #define	ip_addr	ip_un.un_wd.wd_addr
63 #define	ip_tf	ip_un.un_tf
64 #define	ip_f	ip_un.un_f
65 
66 /*
67  * Process debugging system call.
68  */
69 struct ptrace_args {
70 	int	req;
71 	int	pid;
72 	caddr_t	addr;
73 	int	data;
74 };
75 ptrace(curp, uap, retval)
76 	struct proc *curp;
77 	register struct ptrace_args *uap;
78 	int *retval;
79 {
80 	register struct proc *p;
81 	register enum { t_oneword, t_regin, t_regout } type;
82 	register size_t size;
83 	register int error;
84 
85 	if (uap->req == PT_TRACE_ME) {
86 		curp->p_flag |= STRC;
87 		curp->p_oppid = 0;	/* XXX put in the zeroed section */
88 		return (0);
89 	}
90 	if ((p = pfind(uap->pid)) == NULL)
91 		return (ESRCH);
92 	switch (uap->req) {
93 
94 	case PT_READ_I:
95 	case PT_READ_D:
96 	case PT_WRITE_I:
97 	case PT_WRITE_D:
98 	case PT_CONTINUE:
99 	case PT_KILL:
100 	case PT_DETACH:
101 		type = t_oneword;
102 		size = 0;
103 		break;
104 
105 	case PT_ATTACH:
106 		/*
107 		 * Must be root if the process has used set user or
108 		 * group privileges or does not belong to the real
109 		 * user. Must not be already traced.
110 		 */
111 		if ((p->p_flag & SUGID ||
112 		    p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
113 		    (error = suser(p->p_ucred, &p->p_acflag)) != 0)
114 			return (error);
115 		if (p->p_flag & STRC)
116 			return (EALREADY);	/* ??? */
117 		/*
118 		 * It would be nice if the tracing relationship was separate
119 		 * from the parent relationship but that would require
120 		 * another set of links in the proc struct or for "wait"
121 		 * to scan the entire proc table.  To make life easier,
122 		 * we just re-parent the process we're trying to trace.
123 		 * The old parent is remembered so we can put things back
124 		 * on a "detach".
125 		 */
126 		p->p_flag |= STRC;
127 		p->p_oppid = p->p_pptr->p_pid;
128 		proc_reparent(p, curp);
129 		psignal(p, SIGSTOP);
130 		return (0);
131 
132 	case PT_GETREGS:
133 		type = t_regout;
134 		size = sizeof(struct trapframe);
135 		break;
136 
137 	case PT_SETREGS:
138 		type = t_regin;
139 		size = sizeof(struct trapframe);
140 		break;
141 
142 	case PT_GETFPREGS:
143 		type = t_regout;
144 		size = sizeof(struct fpstate);
145 		break;
146 
147 	case PT_SETFPREGS:
148 		type = t_regin;
149 		size = sizeof(struct fpstate);
150 		break;
151 
152 	default:
153 		return (EINVAL);
154 	}
155 	if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & STRC))
156 		return (ESRCH);
157 	while (ipc.ip_lock)
158 		sleep((caddr_t)&ipc, IPCPRI);
159 	ipc.ip_lock = p->p_pid;
160 	ipc.ip_req = uap->req;
161 	ipc.ip_error = 0;
162 	switch (type) {
163 
164 	case t_oneword:
165 		ipc.ip_addr = uap->addr;
166 		ipc.ip_data = uap->data;
167 		break;
168 
169 	case t_regin:
170 		if ((error = copyin(uap->addr, ipc.ip_any, size)) != 0)
171 			return (error);
172 		break;
173 
174 	case t_regout:
175 		break;
176 
177 	default:
178 		panic("ptrace");
179 	}
180 	p->p_flag &= ~SWTED;
181 	do {
182 		if (p->p_stat == SSTOP)
183 			setrun(p);
184 		sleep((caddr_t)&ipc, IPCPRI);
185 	} while (ipc.ip_req > 0);
186 	if ((error = ipc.ip_error) == 0) {
187 		if (type == t_oneword)
188 			*retval = ipc.ip_data;
189 		else if (type == t_regout)
190 			error = copyout(ipc.ip_any, uap->addr, size);
191 	}
192 	ipc.ip_lock = 0;
193 	wakeup((caddr_t)&ipc);
194 	return (error);
195 }
196 
197 /*
198  * Write text space by unprotecting, writing, and reprotecting.
199  */
200 static int
201 writetext(p, addr, data, len)
202 	struct proc *p;
203 	caddr_t addr, data;
204 	int len;
205 {
206 	vm_offset_t sa, ea;
207 	vm_map_t map;
208 	int error;
209 
210 	map = &p->p_vmspace->vm_map;
211 	sa = trunc_page((vm_offset_t)addr);
212 	ea = round_page((vm_offset_t)addr + len - 1);
213 	if (vm_map_protect(map, sa, ea, VM_PROT_DEFAULT, 0) != KERN_SUCCESS)
214 		return (-1);
215 	error = copyout(data, addr, len);
216 	(void) vm_map_protect(map, sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 0);
217 	return (error);
218 }
219 
220 /*
221  * Transmit a tracing request from the parent to the child process
222  * being debugged.  This code runs in the context of the child process
223  * to fulfill the command requested by the parent.
224  */
225 procxmt(p)
226 	register struct proc *p;
227 {
228 	register int req, error, sig, pc, psr;
229 	register caddr_t addr;
230 	register struct trapframe *tf, *utf;
231 	register struct fpstate *fs, *oldfs;
232 	extern struct fpstate initfpstate;
233 
234 	if (ipc.ip_lock != p->p_pid)
235 		return (0);
236 	p->p_slptime = 0;
237 	req = ipc.ip_req;
238 	ipc.ip_req = 0;
239 	error = 0;
240 	switch (req) {
241 
242 	case PT_READ_I:			/* read the child's text space */
243 	case PT_READ_D:			/* read the child's data space */
244 		write_user_windows();
245 		(void) rwindow_save(p);	/* ignore unwritable windows */
246 		error = copyin(ipc.ip_addr, ipc.ip_any, sizeof(int));
247 		break;
248 
249 	case PT_WRITE_I:		/* write the child's text space */
250 	case PT_WRITE_D:		/* write the child's data space */
251 		addr = ipc.ip_addr;
252 		write_user_windows();
253 		(void) rwindow_save(p);
254 		error = copyout(ipc.ip_any, addr, sizeof(int));
255 		if (error && req == PT_WRITE_I)
256 			error = writetext(p, addr, ipc.ip_any, sizeof(int));
257 		break;
258 
259 	case PT_CONTINUE:		/* continue the child */
260 		sig = ipc.ip_data;
261 		if ((unsigned)sig >= NSIG) {
262 			error = EINVAL;
263 			break;
264 		}
265 		pc = (int)ipc.ip_addr;
266 		if (pc & 3) {
267 			if (pc != 1) {
268 				error = EINVAL;
269 				break;
270 			}
271 		} else {
272 			tf = p->p_md.md_tf;
273 			tf->tf_pc = pc;
274 			tf->tf_npc = pc + 4;
275 		}
276 		p->p_xstat = sig;	/* see issig */
277 		wakeup((caddr_t)&ipc);
278 		return (1);
279 
280 	case PT_KILL:			/* kill the child process */
281 		wakeup((caddr_t)&ipc);
282 		exit(p, (int)p->p_xstat);
283 
284 	case PT_DETACH:			/* stop tracing the child */
285 		sig = ipc.ip_data;
286 		if ((unsigned)sig >= NSIG) {
287 			error = EINVAL;
288 			break;
289 		}
290 		pc = (int)ipc.ip_addr;
291 		if (pc & 3) {
292 			if (pc != 1) {
293 				error = EINVAL;
294 				break;
295 			}
296 		} else {
297 			tf = p->p_md.md_tf;
298 			tf->tf_pc = pc;
299 			tf->tf_npc = pc + 4;
300 		}
301 		p->p_xstat = sig;	/* see issig */
302 		p->p_flag &= ~STRC;
303 		if (p->p_oppid != p->p_pptr->p_pid) {
304                         register struct proc *pp = pfind(p->p_oppid);
305 
306                         if (pp)
307                                 proc_reparent(p, pp);
308 		}
309 		p->p_oppid = 0;
310 		wakeup((caddr_t)&ipc);
311 		return (1);
312 
313 	case PT_GETREGS:
314 		copywords((caddr_t)p->p_md.md_tf, (caddr_t)&ipc.ip_tf,
315 			  sizeof(struct trapframe));
316 		ipc.ip_tf.tf_global[0] = 0; /* XXX */
317 		break;
318 
319 	case PT_SETREGS:
320 		tf = p->p_md.md_tf;
321 		utf = &ipc.ip_tf;
322 		if ((utf->tf_pc | utf->tf_npc) & 3) {
323 			error = EINVAL;
324 			break;
325 		}
326 		psr = (tf->tf_psr & ~PSR_ICC) | (utf->tf_psr & PSR_ICC);
327 		copywords((caddr_t)utf, (caddr_t)tf, sizeof(*tf));
328 		tf->tf_psr = psr;
329 		break;
330 
331 	case PT_GETFPREGS:
332 		if ((fs = p->p_md.md_fpstate) == NULL)
333 			fs = &initfpstate;
334 		else if (p == fpproc)
335 			savefpstate(fs);
336 		copywords((caddr_t)fs, (caddr_t)&ipc.ip_f, sizeof *fs);
337 		break;
338 
339 	case PT_SETFPREGS:
340 		fs = &ipc.ip_f;
341 		if ((fs->fs_fsr & FSR_MBZ) != 0 || fs->fs_qsize) {
342 			error = EINVAL;
343 			break;
344 		}
345 		oldfs = p->p_md.md_fpstate;
346 		if (oldfs == NULL)
347 			p->p_md.md_fpstate = oldfs = malloc(sizeof *oldfs,
348 			    M_SUBPROC, M_WAITOK);
349 		else if (p == fpproc) {
350 			savefpstate(oldfs);
351 			fpproc = NULL;
352 			p->p_md.md_tf->tf_psr &= ~PSR_EF;
353 		}
354 		copywords((caddr_t)fs, (caddr_t)oldfs, sizeof *oldfs);
355 		break;
356 
357 	default:
358 		panic("procxmt");
359 	}
360 	ipc.ip_error = error;
361 	wakeup((caddr_t)&ipc);
362 	return (0);
363 }
364