Fixed warning from gcc1 (but not gcc2 for some reason).
[unix-history] / sys / kern / sys_process.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)sys_process.c 7.22 (Berkeley) 5/11/91
34 *
35 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
36 * -------------------- ----- ----------------------
37 * CURRENT PATCH LEVEL: 1 00137
38 * -------------------- ----- ----------------------
39 *
40 * 04 Sep 92 Paul Kranenburg Fixed copy-on-write checking for pages
41 * other than anonymous (text pages, etc.)
42 * 08 Apr 93 Bruce Evans Several VM system fixes
43 */
44
45#define IPCREG
46#include "param.h"
47#include "proc.h"
48#include "vnode.h"
49#include "buf.h"
50#include "ptrace.h"
51
52#include "machine/reg.h"
53#include "machine/psl.h"
54#include "vm/vm.h"
55#include "vm/vm_page.h"
56
57#include "user.h"
58
59/*
60 * NOTES.
61 *
62 * The following ptrace calls have been defined in addition to
63 * the standard ones found in original <sys/ptrace.h>:
64 *
65 * PT_ATTACH - attach to running process
66 * PT_DETACH - detach from running process
67 * PT_SYSCALL - trace system calls
68 * PT_GETREG - get register file
69 * PT_SETREG - set register file
70 * PT_BREAD_[IDU] - block read from process (not yet implemented)
71 * PT_BWRITE_[IDU] - block write " "
72 * PT_INHERIT - make forked processes inherit trace flags
73 *
74 */
75
76/* Define to prevent extraneous clutter in source */
77#ifndef SSTRC
78#define SSTRC 0
79#endif
80#ifndef SFTRC
81#define SFTRC 0
82#endif
83
84/*
85 * `ipcreg' defined in <machine/reg.h>
86 * Should we define a structure with all regs?
87 */
88int sipcreg[NIPCREG] =
89 { 0,0,sEDI,sESI,sEBP,sEBX,sEDX,sECX,sEAX,sEIP,sCS,sEFLAGS,sESP,sSS };
90
91struct {
92 int flag;
93#define IPC_BUSY 1
94#define IPC_WANT 2
95#define IPC_DONE 4
96 int req; /* copy of ptrace request */
97 int *addr; /* copy of ptrace address */
98 int data; /* copy of ptrace data */
99 int error; /* errno from `procxmt' */
100 int regs[NIPCREG]; /* PT_[GS]ETREG */
101 caddr_t buf; /* PT_BREAD/WRITE */
102 int buflen; /* " */
103} ipc;
104
105/*
106 * Process debugging system call.
107 */
3c7eb27c
DG
108
109struct ptrace_args {
110 int req;
111 int pid;
112 int *addr;
113 int data;
114};
115
15637ed4
RG
116ptrace(curp, uap, retval)
117 struct proc *curp;
3c7eb27c 118 register struct ptrace_args *uap;
15637ed4
RG
119 int *retval;
120{
121 struct proc *p;
122 int s, error = 0;
123
124 *retval = 0;
125 if (uap->req == PT_TRACE_ME) {
126 curp->p_flag |= STRC;
127 /*p->p_tptr = p->p_pptr; * What shall we do here ? */
128 return 0;
129 }
130 if ((p = pfind(uap->pid)) == NULL) {
131 return ESRCH;
132 }
133
134#ifdef notyet
135 if (uap->req != PT_ATTACH && (
136 (p->p_flag & STRC) == 0 ||
137 (p->p_tptr && curp != p->p_tptr) ||
138 (!p->p_tptr && curp != p->p_pptr)))
139
140 return ESRCH;
141#endif
142
143
144#ifdef PT_ATTACH
145 switch (uap->req) {
146 case PT_ATTACH:
147 if (curp->p_ucred->cr_uid != 0 && (
148 curp->p_ucred->cr_uid != p->p_ucred->cr_uid ||
149 curp->p_ucred->cr_uid != p->p_cred->p_svuid))
150 return EACCES;
151
152 p->p_tptr = curp;
153 p->p_flag |= STRC;
154 psignal(p, SIGTRAP);
155 return 0;
156
157 case PT_DETACH:
158 if ((unsigned)uap->data >= NSIG)
159 return EINVAL;
160 p->p_flag &= ~(STRC|SSTRC|SFTRC);
161 p->p_tptr = NULL;
162 psignal(p->p_pptr, SIGCHLD);
163 wakeup((caddr_t)p->p_pptr);
164 s = splhigh();
165 if (p->p_stat == SSTOP) {
166 p->p_xstat = uap->data;
167 setrun(p);
168 } else if (uap->data) {
169 psignal(p, uap->data);
170 }
171 splx(s);
172 return 0;
173
174#ifdef PT_INHERIT
175 case PT_INHERIT:
176 if ((p->p_flag & STRC) == 0)
177 return ESRCH;
178 p->p_flag |= SFTRC;
179 return 0;
180#endif
181
182 default:
183 break;
184 }
185#endif
186
187 /* Other ptrace calls require target process to be in stopped state */
188 if ((p->p_flag & STRC) == 0 || p->p_stat != SSTOP) {
189 return ESRCH;
190 }
191
192 /* Acquire the ipc structure */
193 while (ipc.flag & IPC_BUSY) {
194 ipc.flag |= IPC_WANT;
195 error = tsleep((caddr_t)&ipc, PWAIT|PCATCH, "ipc", 0);
196 if (error)
197 goto out;
198 }
199
200 /* Got it, fill it */
201 ipc.flag = IPC_BUSY;
202 ipc.error = 0;
203 ipc.req = uap->req;
204 ipc.addr = uap->addr;
205 ipc.data = uap->data;
206
207#ifdef PT_GETREGS
208 switch (uap->req) {
209 case PT_SETREGS:
210 error = copyin((char *)ipc.addr, (char *)ipc.regs, sizeof(ipc.regs));
211 if (error)
212 goto out;
213 break;
214
215#ifdef notyet /* requires change in number of args to ptrace syscall */
216 case PT_BWRITE_I:
217 case PT_BWRITE_D:
218 ipc.buflen = uap->data;
219 ipc.buf = kmem_alloc_wait(kernelmap, uap->data);
220 error = copyin((char *)ipc.addr, (char *)ipc.buf, ipc.buflen);
221 if (error) {
222 kmem_free_wakeup(kernelmap, ipc.buf, ipc.buflen);
223 goto out;
224 }
225#endif
226 default:
227 break;
228 }
229#endif
230
231 setrun(p);
232 while ((ipc.flag & IPC_DONE) == 0) {
233 error = tsleep((caddr_t)&ipc, PWAIT|PCATCH, "ipc", 0);
234 if (error)
235 goto out;
236 }
237
238 *retval = ipc.data;
239 if (error = ipc.error)
240 goto out;
241
242#ifdef PT_GETREGS
243 switch (uap->req) {
244 case PT_GETREGS:
245 error = copyout((char *)ipc.regs, (char *)ipc.addr, sizeof(ipc.regs));
246 break;
247
248 case PT_BREAD_I:
249 case PT_BREAD_D:
250 /* Not yet */
251 default:
252 break;
253 }
254#endif
255
256out:
257 /* Release ipc structure */
258 ipc.flag &= ~IPC_BUSY;
259 if (ipc.flag & IPC_WANT) {
260 ipc.flag &= ~IPC_WANT;
261 wakeup((caddr_t)&ipc);
262 }
263 return error;
264}
265
266procxmt(p)
267 register struct proc *p;
268{
269 int i, *xreg, rv = 0;
270
271 /* Are we still being traced? */
272 if ((p->p_flag & STRC) == 0)
273 return 1;
274
275 p->p_addr->u_kproc.kp_proc = *p;
276 fill_eproc(p, &p->p_addr->u_kproc.kp_eproc);
277
278 switch (ipc.req) {
279 case PT_READ_I:
280 case PT_READ_D:
281 if (!useracc(ipc.addr, sizeof(ipc.data), B_READ)) {
282 ipc.error = EFAULT;
283 break;
284 }
285 ipc.error = copyin((char *)ipc.addr, (char *)&ipc.data, sizeof(ipc.data));
286 break;
287
288 case PT_READ_U:
289 if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) {
290 ipc.error = EFAULT;
291 break;
292 }
293 ipc.data = *(int *)((u_int)p->p_addr + (u_int)ipc.addr);
294 break;
295
296 case PT_WRITE_I:
297 case PT_WRITE_D: { /* 04 Sep 92*/
298 vm_prot_t prot; /* current protection of region */
299 int cow; /* ensure copy-on-write happens */
300
301 if (cow = (useracc(ipc.addr, sizeof(ipc.data), B_WRITE) == 0)) {
302 vm_offset_t addr = (vm_offset_t)ipc.addr;
303 vm_size_t size;
304 vm_prot_t max_prot;
305 vm_inherit_t inh;
306 boolean_t shared;
307 vm_object_t object;
308 vm_offset_t objoff;
309
310 /*
311 * XXX - the useracc check is stronger than the vm
312 * checks because the user page tables are in the map.
313 */
314 if (!useracc(ipc.addr, sizeof(ipc.data), B_READ) ||
315 vm_region(&p->p_vmspace->vm_map, &addr, &size,
316 &prot, &max_prot, &inh, &shared,
317 &object, &objoff) != KERN_SUCCESS ||
318 vm_protect(&p->p_vmspace->vm_map, ipc.addr,
319 sizeof(ipc.data), FALSE,
320 prot|VM_PROT_WRITE) != KERN_SUCCESS ||
321 vm_fault(&p->p_vmspace->vm_map,trunc_page(ipc.addr),
322 VM_PROT_WRITE, FALSE) != KERN_SUCCESS) {
323
324 ipc.error = EFAULT;
325 break;
326 }
327 }
328 ipc.error = copyout((char *)&ipc.data,
329 (char *)ipc.addr, sizeof(ipc.data));
330 if (cow)
331 if (vm_protect(&p->p_vmspace->vm_map, ipc.addr,
332 sizeof(ipc.data), FALSE,
333 prot) != KERN_SUCCESS)
334 printf("ptrace: oops\n");
335 break;
336 }
337
338 case PT_WRITE_U:
339 if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) {
340 ipc.error = EFAULT;
341 break;
342 }
343 *(int *)((u_int)p->p_addr + (u_int)ipc.addr) = ipc.data;
344 break;
345
346 case PT_CONTINUE:
347 if (ipc.addr != (int *)1) {
348#ifdef i386
349 p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr;
350#endif
351 }
352 p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */
353 if ((unsigned)ipc.data >= NSIG) {
354 ipc.error = EINVAL;
355 } else {
356 p->p_xstat = ipc.data;
357 rv = 1;
358 }
359 break;
360
361 case PT_KILL:
362 p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */
363 rv = 2;
364 break;
365
366 case PT_STEP:
367#ifdef i386
368 if (ipc.addr != (int *)1) {
369 p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr;
370 }
371 p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEFLAGS:sEFLAGS] |= PSL_T;
372#endif
373 p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */
374 p->p_xstat = 0;
375 rv = 1;
376 break;
377
378#ifdef PT_SYSCALL
379 case PT_SYSCALL:
380 if (ipc.addr != (int *)1) {
381#ifdef i386
382 p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr;
383#endif
384 }
385 p->p_flag |= SSTRC;
386 p->p_xstat = 0;
387 rv = 1;
388 break;
389#endif
390#ifdef PT_GETREGS
391 case PT_GETREGS:
392#ifdef i386
393 xreg = (curpcb->pcb_flags&FM_TRAP)?ipcreg:sipcreg;
394#endif
395
396 for (i = 0; i < NIPCREG; i++)
397 ipc.regs[i] = p->p_regs[xreg[i]];
398 break;
399
400 case PT_SETREGS:
401#ifdef i386
402 xreg = (curpcb->pcb_flags&FM_TRAP)?ipcreg:sipcreg;
403#endif
404
405 for (i = 0; i < NIPCREG; i++)
406 p->p_regs[xreg[i]] = ipc.regs[i];
407 break;
408#endif
409
410#ifdef PT_DUMP
411 case PT_DUMP:
412 /* Should be able to specify core file name */
413 ipc.error = coredump(p);
414 break;
415#endif
416
417 default:
418 ipc.error = EINVAL;
419 }
420 ipc.flag |= IPC_DONE;
421 wakeup((caddr_t)&ipc);
422
423 if (rv == 2)
424 exit(p, 0); /*???*/
425
426 return rv;
427}
428
429/*
430 * Enable process profiling system call.
431 */
3c7eb27c
DG
432
433struct profil_args {
434 short *bufbase; /* base of data buffer */
435 unsigned bufsize; /* size of data buffer */
436 unsigned pcoffset; /* pc offset (for subtraction) */
437 unsigned pcscale; /* scaling factor for offset pc */
438};
439
15637ed4
RG
440/* ARGSUSED */
441profil(p, uap, retval)
442 struct proc *p;
3c7eb27c 443 register struct profil_args *uap;
15637ed4
RG
444 int *retval;
445{
446 /* from looking at man pages, and include files, looks like
447 * this just sets up the fields of p->p_stats->p_prof...
448 * and those fields come straight from the args.
449 * only thing *we* have to do is check the args for validity...
450 *
451 * cgd
452 */
453
454 /* check to make sure that the buffer is OK. addupc (in locore)
455 * checks for faults, but would one be generated, say, writing to
456 * kernel space? probably not -- it just uses "movl"...
457 *
458 * so we've gotta check to make sure that the info set up for
459 * addupc is set right... it's gotta be writable by the user...
460 */
461
462 if (useracc(uap->bufbase,uap->bufsize*sizeof(short),B_WRITE) == 0)
463 return EFAULT;
464
465 p->p_stats->p_prof.pr_base = uap->bufbase;
466 p->p_stats->p_prof.pr_size = uap->bufsize;
467 p->p_stats->p_prof.pr_off = uap->pcoffset;
468 p->p_stats->p_prof.pr_scale = uap->pcscale;
469
470 return 0;
471}