update from elf
[unix-history] / usr / src / sys / sparc / sparc / sys_process.c
CommitLineData
c2cada66
CT
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 *
b480239a
KB
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
72539cb1 12 * California, Lawrence Berkeley Laboratory.
b480239a 13 *
c2cada66
CT
14 * %sccs.include.proprietary.c%
15 *
72539cb1 16 * @(#)sys_process.c 7.4 (Berkeley) %G%
c2cada66
CT
17 */
18
5548a02f
KB
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>
c2cada66 26
5548a02f
KB
27#include <vm/vm.h>
28#include <vm/vm_page.h>
c2cada66 29
5548a02f
KB
30#include <machine/psl.h>
31#include <machine/reg.h>
c2cada66
CT
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 */
46struct {
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 */
69struct ptrace_args {
70 int req;
71 int pid;
72 caddr_t addr;
73 int data;
74};
75ptrace(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;
c2cada66
CT
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 /*
72539cb1
CT
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.
c2cada66
CT
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); /* ??? */
72539cb1
CT
116 if (p == curp)
117 return (EINVAL);
c2cada66
CT
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);
72539cb1
CT
130 if (p->p_stat == SSTOP)
131 setrun(p); /* long enough to stop */
c2cada66
CT
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 */
203static int
204writetext(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);
72539cb1 215 ea = round_page((vm_offset_t)addr + len);
c2cada66
CT
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 */
228procxmt(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);
72539cb1 285 exit1(p, (int)p->p_xstat);
c2cada66
CT
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}