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