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