Commit | Line | Data |
---|---|---|
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 | |
78ed81a3 | 34 | * $Id$ |
15637ed4 RG |
35 | */ |
36 | ||
78ed81a3 | 37 | #include <stddef.h> |
38 | ||
15637ed4 RG |
39 | #define IPCREG |
40 | #include "param.h" | |
41 | #include "proc.h" | |
42 | #include "vnode.h" | |
43 | #include "buf.h" | |
44 | #include "ptrace.h" | |
45 | ||
78ed81a3 | 46 | #include "machine/eflags.h" |
15637ed4 RG |
47 | #include "machine/reg.h" |
48 | #include "machine/psl.h" | |
49 | #include "vm/vm.h" | |
50 | #include "vm/vm_page.h" | |
51 | ||
52 | #include "user.h" | |
53 | ||
54 | /* | |
55 | * NOTES. | |
56 | * | |
57 | * The following ptrace calls have been defined in addition to | |
58 | * the standard ones found in original <sys/ptrace.h>: | |
59 | * | |
60 | * PT_ATTACH - attach to running process | |
61 | * PT_DETACH - detach from running process | |
62 | * PT_SYSCALL - trace system calls | |
63 | * PT_GETREG - get register file | |
64 | * PT_SETREG - set register file | |
65 | * PT_BREAD_[IDU] - block read from process (not yet implemented) | |
66 | * PT_BWRITE_[IDU] - block write " " | |
67 | * PT_INHERIT - make forked processes inherit trace flags | |
68 | * | |
69 | */ | |
70 | ||
71 | /* Define to prevent extraneous clutter in source */ | |
72 | #ifndef SSTRC | |
73 | #define SSTRC 0 | |
74 | #endif | |
75 | #ifndef SFTRC | |
76 | #define SFTRC 0 | |
77 | #endif | |
78 | ||
79 | /* | |
80 | * `ipcreg' defined in <machine/reg.h> | |
81 | * Should we define a structure with all regs? | |
82 | */ | |
83 | int sipcreg[NIPCREG] = | |
84 | { 0,0,sEDI,sESI,sEBP,sEBX,sEDX,sECX,sEAX,sEIP,sCS,sEFLAGS,sESP,sSS }; | |
85 | ||
86 | struct { | |
87 | int flag; | |
88 | #define IPC_BUSY 1 | |
89 | #define IPC_WANT 2 | |
90 | #define IPC_DONE 4 | |
91 | int req; /* copy of ptrace request */ | |
92 | int *addr; /* copy of ptrace address */ | |
93 | int data; /* copy of ptrace data */ | |
94 | int error; /* errno from `procxmt' */ | |
95 | int regs[NIPCREG]; /* PT_[GS]ETREG */ | |
96 | caddr_t buf; /* PT_BREAD/WRITE */ | |
97 | int buflen; /* " */ | |
98 | } ipc; | |
99 | ||
100 | /* | |
101 | * Process debugging system call. | |
102 | */ | |
78ed81a3 | 103 | |
104 | struct ptrace_args { | |
105 | int req; | |
106 | int pid; | |
107 | int *addr; | |
108 | int data; | |
109 | }; | |
110 | ||
15637ed4 RG |
111 | ptrace(curp, uap, retval) |
112 | struct proc *curp; | |
78ed81a3 | 113 | register struct ptrace_args *uap; |
15637ed4 RG |
114 | int *retval; |
115 | { | |
116 | struct proc *p; | |
117 | int s, error = 0; | |
118 | ||
119 | *retval = 0; | |
120 | if (uap->req == PT_TRACE_ME) { | |
121 | curp->p_flag |= STRC; | |
122 | /*p->p_tptr = p->p_pptr; * What shall we do here ? */ | |
123 | return 0; | |
124 | } | |
125 | if ((p = pfind(uap->pid)) == NULL) { | |
126 | return ESRCH; | |
127 | } | |
128 | ||
129 | #ifdef notyet | |
130 | if (uap->req != PT_ATTACH && ( | |
131 | (p->p_flag & STRC) == 0 || | |
132 | (p->p_tptr && curp != p->p_tptr) || | |
133 | (!p->p_tptr && curp != p->p_pptr))) | |
134 | ||
135 | return ESRCH; | |
136 | #endif | |
137 | ||
138 | ||
139 | #ifdef PT_ATTACH | |
140 | switch (uap->req) { | |
141 | case PT_ATTACH: | |
142 | if (curp->p_ucred->cr_uid != 0 && ( | |
143 | curp->p_ucred->cr_uid != p->p_ucred->cr_uid || | |
144 | curp->p_ucred->cr_uid != p->p_cred->p_svuid)) | |
145 | return EACCES; | |
146 | ||
147 | p->p_tptr = curp; | |
148 | p->p_flag |= STRC; | |
149 | psignal(p, SIGTRAP); | |
150 | return 0; | |
151 | ||
152 | case PT_DETACH: | |
153 | if ((unsigned)uap->data >= NSIG) | |
154 | return EINVAL; | |
155 | p->p_flag &= ~(STRC|SSTRC|SFTRC); | |
156 | p->p_tptr = NULL; | |
157 | psignal(p->p_pptr, SIGCHLD); | |
158 | wakeup((caddr_t)p->p_pptr); | |
159 | s = splhigh(); | |
160 | if (p->p_stat == SSTOP) { | |
161 | p->p_xstat = uap->data; | |
162 | setrun(p); | |
163 | } else if (uap->data) { | |
164 | psignal(p, uap->data); | |
165 | } | |
166 | splx(s); | |
167 | return 0; | |
168 | ||
169 | #ifdef PT_INHERIT | |
170 | case PT_INHERIT: | |
171 | if ((p->p_flag & STRC) == 0) | |
172 | return ESRCH; | |
173 | p->p_flag |= SFTRC; | |
174 | return 0; | |
175 | #endif | |
176 | ||
177 | default: | |
178 | break; | |
179 | } | |
180 | #endif | |
181 | ||
182 | /* Other ptrace calls require target process to be in stopped state */ | |
183 | if ((p->p_flag & STRC) == 0 || p->p_stat != SSTOP) { | |
184 | return ESRCH; | |
185 | } | |
186 | ||
187 | /* Acquire the ipc structure */ | |
188 | while (ipc.flag & IPC_BUSY) { | |
189 | ipc.flag |= IPC_WANT; | |
190 | error = tsleep((caddr_t)&ipc, PWAIT|PCATCH, "ipc", 0); | |
191 | if (error) | |
192 | goto out; | |
193 | } | |
194 | ||
195 | /* Got it, fill it */ | |
196 | ipc.flag = IPC_BUSY; | |
197 | ipc.error = 0; | |
198 | ipc.req = uap->req; | |
199 | ipc.addr = uap->addr; | |
200 | ipc.data = uap->data; | |
201 | ||
202 | #ifdef PT_GETREGS | |
203 | switch (uap->req) { | |
204 | case PT_SETREGS: | |
205 | error = copyin((char *)ipc.addr, (char *)ipc.regs, sizeof(ipc.regs)); | |
206 | if (error) | |
207 | goto out; | |
208 | break; | |
209 | ||
210 | #ifdef notyet /* requires change in number of args to ptrace syscall */ | |
211 | case PT_BWRITE_I: | |
212 | case PT_BWRITE_D: | |
213 | ipc.buflen = uap->data; | |
214 | ipc.buf = kmem_alloc_wait(kernelmap, uap->data); | |
215 | error = copyin((char *)ipc.addr, (char *)ipc.buf, ipc.buflen); | |
216 | if (error) { | |
217 | kmem_free_wakeup(kernelmap, ipc.buf, ipc.buflen); | |
218 | goto out; | |
219 | } | |
220 | #endif | |
221 | default: | |
222 | break; | |
223 | } | |
224 | #endif | |
225 | ||
226 | setrun(p); | |
227 | while ((ipc.flag & IPC_DONE) == 0) { | |
228 | error = tsleep((caddr_t)&ipc, PWAIT|PCATCH, "ipc", 0); | |
229 | if (error) | |
230 | goto out; | |
231 | } | |
232 | ||
233 | *retval = ipc.data; | |
234 | if (error = ipc.error) | |
235 | goto out; | |
236 | ||
237 | #ifdef PT_GETREGS | |
238 | switch (uap->req) { | |
239 | case PT_GETREGS: | |
240 | error = copyout((char *)ipc.regs, (char *)ipc.addr, sizeof(ipc.regs)); | |
241 | break; | |
242 | ||
243 | case PT_BREAD_I: | |
244 | case PT_BREAD_D: | |
245 | /* Not yet */ | |
246 | default: | |
247 | break; | |
248 | } | |
249 | #endif | |
250 | ||
251 | out: | |
252 | /* Release ipc structure */ | |
253 | ipc.flag &= ~IPC_BUSY; | |
254 | if (ipc.flag & IPC_WANT) { | |
255 | ipc.flag &= ~IPC_WANT; | |
256 | wakeup((caddr_t)&ipc); | |
257 | } | |
258 | return error; | |
259 | } | |
260 | ||
261 | procxmt(p) | |
262 | register struct proc *p; | |
263 | { | |
264 | int i, *xreg, rv = 0; | |
78ed81a3 | 265 | #ifdef i386 |
266 | int new_eflags, old_cs, old_ds, old_es, old_ss, old_eflags; | |
267 | int *regs; | |
268 | #endif | |
15637ed4 RG |
269 | |
270 | /* Are we still being traced? */ | |
271 | if ((p->p_flag & STRC) == 0) | |
272 | return 1; | |
273 | ||
274 | p->p_addr->u_kproc.kp_proc = *p; | |
275 | fill_eproc(p, &p->p_addr->u_kproc.kp_eproc); | |
276 | ||
277 | switch (ipc.req) { | |
278 | case PT_READ_I: | |
279 | case PT_READ_D: | |
280 | if (!useracc(ipc.addr, sizeof(ipc.data), B_READ)) { | |
281 | ipc.error = EFAULT; | |
282 | break; | |
283 | } | |
284 | ipc.error = copyin((char *)ipc.addr, (char *)&ipc.data, sizeof(ipc.data)); | |
285 | break; | |
286 | ||
287 | case PT_READ_U: | |
288 | if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) { | |
289 | ipc.error = EFAULT; | |
290 | break; | |
291 | } | |
292 | ipc.data = *(int *)((u_int)p->p_addr + (u_int)ipc.addr); | |
293 | break; | |
294 | ||
295 | case PT_WRITE_I: | |
296 | case PT_WRITE_D: { /* 04 Sep 92*/ | |
297 | vm_prot_t prot; /* current protection of region */ | |
298 | int cow; /* ensure copy-on-write happens */ | |
299 | ||
300 | if (cow = (useracc(ipc.addr, sizeof(ipc.data), B_WRITE) == 0)) { | |
301 | vm_offset_t addr = (vm_offset_t)ipc.addr; | |
302 | vm_size_t size; | |
303 | vm_prot_t max_prot; | |
304 | vm_inherit_t inh; | |
305 | boolean_t shared; | |
306 | vm_object_t object; | |
307 | vm_offset_t objoff; | |
308 | ||
309 | /* | |
310 | * XXX - the useracc check is stronger than the vm | |
311 | * checks because the user page tables are in the map. | |
78ed81a3 | 312 | * Anyway, most of this can be removed now that COW |
313 | * works. | |
15637ed4 RG |
314 | */ |
315 | if (!useracc(ipc.addr, sizeof(ipc.data), B_READ) || | |
316 | vm_region(&p->p_vmspace->vm_map, &addr, &size, | |
317 | &prot, &max_prot, &inh, &shared, | |
318 | &object, &objoff) != KERN_SUCCESS || | |
319 | vm_protect(&p->p_vmspace->vm_map, ipc.addr, | |
320 | sizeof(ipc.data), FALSE, | |
321 | prot|VM_PROT_WRITE) != KERN_SUCCESS || | |
322 | vm_fault(&p->p_vmspace->vm_map,trunc_page(ipc.addr), | |
323 | VM_PROT_WRITE, FALSE) != KERN_SUCCESS) { | |
324 | ||
325 | ipc.error = EFAULT; | |
326 | break; | |
327 | } | |
328 | } | |
329 | ipc.error = copyout((char *)&ipc.data, | |
330 | (char *)ipc.addr, sizeof(ipc.data)); | |
331 | if (cow) | |
332 | if (vm_protect(&p->p_vmspace->vm_map, ipc.addr, | |
333 | sizeof(ipc.data), FALSE, | |
334 | prot) != KERN_SUCCESS) | |
335 | printf("ptrace: oops\n"); | |
336 | break; | |
337 | } | |
338 | ||
339 | case PT_WRITE_U: | |
78ed81a3 | 340 | #ifdef i386 |
341 | regs = p->p_regs; | |
342 | /* | |
343 | * XXX - privileged kernel state is scattered all over the | |
344 | * user area. Only allow write access to areas known to | |
345 | * be safe. | |
346 | */ | |
347 | #define GO_IF_SAFE(min, size) \ | |
348 | if ((u_int)ipc.addr >= (min) \ | |
349 | && (u_int)ipc.addr <= (min) + (size) - sizeof(int)) \ | |
350 | goto pt_write_u | |
351 | /* | |
352 | * Allow writing entire FPU state. | |
353 | */ | |
354 | GO_IF_SAFE(offsetof(struct user, u_pcb) | |
355 | + offsetof(struct pcb, pcb_savefpu), | |
356 | sizeof(struct save87)); | |
357 | /* | |
358 | * Allow writing ordinary registers. Changes to segment | |
359 | * registers and to some bits in %eflags will be silently | |
360 | * ignored. Such changes ought to be an error. | |
361 | */ | |
362 | /* | |
363 | * XXX - there is no define for the base of the user area except USRSTACK. | |
364 | * XXX - USRSTACK is not the base of the user stack. It is the base of the | |
365 | * user area. | |
366 | */ | |
367 | #define USER_OFF(va) ((u_int)(va) - USRSTACK) | |
368 | GO_IF_SAFE(USER_OFF(regs), | |
369 | (curpcb->pcb_flags & FM_TRAP ? tSS + 1 : sSS + 1) | |
370 | * sizeof *regs); | |
371 | ipc.error = EFAULT; | |
372 | break; | |
373 | #else | |
15637ed4 RG |
374 | if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) { |
375 | ipc.error = EFAULT; | |
376 | break; | |
377 | } | |
78ed81a3 | 378 | #endif |
379 | pt_write_u: | |
380 | #ifdef i386 | |
381 | if (curpcb->pcb_flags & FM_TRAP) { | |
382 | old_cs = regs[tCS]; | |
383 | old_ds = regs[tES]; | |
384 | old_es = regs[tES]; | |
385 | old_ss = regs[tSS]; | |
386 | old_eflags = regs[tEFLAGS]; | |
387 | } else { | |
388 | old_cs = regs[sCS]; | |
389 | old_ss = regs[sSS]; | |
390 | old_eflags = regs[sEFLAGS]; | |
391 | } | |
392 | #endif | |
15637ed4 | 393 | *(int *)((u_int)p->p_addr + (u_int)ipc.addr) = ipc.data; |
78ed81a3 | 394 | #ifdef i386 |
395 | /* | |
396 | * Don't allow segment registers to change (although they can | |
397 | * be changed directly to certain values). | |
398 | * Don't allow privileged bits in %eflags to change. Users | |
399 | * have privilege to change TF and NT although although they | |
400 | * usually shouldn't. | |
401 | * XXX - fix PT_SETREGS. | |
402 | * XXX - simplify. Maybe copy through a temporary struct. | |
403 | * Watch out for problems when ipc.addr is not a multiple | |
404 | * of the register size. | |
405 | */ | |
406 | #define EFL_UNPRIVILEGED (EFL_CF | EFL_PF | EFL_AF | EFL_ZF | EFL_SF \ | |
407 | | EFL_TF | EFL_DF | EFL_OF | EFL_NT) | |
408 | if (curpcb->pcb_flags & FM_TRAP) { | |
409 | regs[tCS] = old_cs; | |
410 | regs[tDS] = old_ds; | |
411 | regs[tES] = old_es; | |
412 | regs[tSS] = old_es; | |
413 | new_eflags = regs[tEFLAGS]; | |
414 | regs[tEFLAGS] | |
415 | = (new_eflags & EFL_UNPRIVILEGED) | |
416 | | (old_eflags & ~EFL_UNPRIVILEGED); | |
417 | } else { | |
418 | regs[sCS] = old_cs; | |
419 | regs[sSS] = old_ss; | |
420 | new_eflags = regs[sEFLAGS]; | |
421 | regs[sEFLAGS] | |
422 | = (new_eflags & EFL_UNPRIVILEGED) | |
423 | | (old_eflags & ~EFL_UNPRIVILEGED); | |
424 | } | |
425 | #endif | |
15637ed4 RG |
426 | break; |
427 | ||
428 | case PT_CONTINUE: | |
429 | if (ipc.addr != (int *)1) { | |
430 | #ifdef i386 | |
431 | p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr; | |
432 | #endif | |
433 | } | |
434 | p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */ | |
435 | if ((unsigned)ipc.data >= NSIG) { | |
436 | ipc.error = EINVAL; | |
437 | } else { | |
438 | p->p_xstat = ipc.data; | |
439 | rv = 1; | |
440 | } | |
441 | break; | |
442 | ||
443 | case PT_KILL: | |
444 | p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */ | |
445 | rv = 2; | |
446 | break; | |
447 | ||
448 | case PT_STEP: | |
449 | #ifdef i386 | |
450 | if (ipc.addr != (int *)1) { | |
451 | p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr; | |
452 | } | |
453 | p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEFLAGS:sEFLAGS] |= PSL_T; | |
454 | #endif | |
455 | p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */ | |
456 | p->p_xstat = 0; | |
457 | rv = 1; | |
458 | break; | |
459 | ||
460 | #ifdef PT_SYSCALL | |
461 | case PT_SYSCALL: | |
462 | if (ipc.addr != (int *)1) { | |
463 | #ifdef i386 | |
464 | p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr; | |
465 | #endif | |
466 | } | |
467 | p->p_flag |= SSTRC; | |
468 | p->p_xstat = 0; | |
469 | rv = 1; | |
470 | break; | |
471 | #endif | |
472 | #ifdef PT_GETREGS | |
473 | case PT_GETREGS: | |
474 | #ifdef i386 | |
475 | xreg = (curpcb->pcb_flags&FM_TRAP)?ipcreg:sipcreg; | |
476 | #endif | |
477 | ||
478 | for (i = 0; i < NIPCREG; i++) | |
479 | ipc.regs[i] = p->p_regs[xreg[i]]; | |
480 | break; | |
481 | ||
482 | case PT_SETREGS: | |
483 | #ifdef i386 | |
484 | xreg = (curpcb->pcb_flags&FM_TRAP)?ipcreg:sipcreg; | |
485 | #endif | |
486 | ||
487 | for (i = 0; i < NIPCREG; i++) | |
488 | p->p_regs[xreg[i]] = ipc.regs[i]; | |
489 | break; | |
490 | #endif | |
491 | ||
492 | #ifdef PT_DUMP | |
493 | case PT_DUMP: | |
494 | /* Should be able to specify core file name */ | |
495 | ipc.error = coredump(p); | |
496 | break; | |
497 | #endif | |
498 | ||
499 | default: | |
500 | ipc.error = EINVAL; | |
501 | } | |
502 | ipc.flag |= IPC_DONE; | |
503 | wakeup((caddr_t)&ipc); | |
504 | ||
505 | if (rv == 2) | |
78ed81a3 | 506 | kexit(p, 0); /*???*/ |
15637ed4 RG |
507 | |
508 | return rv; | |
509 | } | |
510 | ||
511 | /* | |
512 | * Enable process profiling system call. | |
513 | */ | |
78ed81a3 | 514 | |
515 | struct profil_args { | |
516 | short *bufbase; /* base of data buffer */ | |
517 | unsigned bufsize; /* size of data buffer */ | |
518 | unsigned pcoffset; /* pc offset (for subtraction) */ | |
519 | unsigned pcscale; /* scaling factor for offset pc */ | |
520 | }; | |
521 | ||
15637ed4 RG |
522 | /* ARGSUSED */ |
523 | profil(p, uap, retval) | |
524 | struct proc *p; | |
78ed81a3 | 525 | register struct profil_args *uap; |
15637ed4 RG |
526 | int *retval; |
527 | { | |
528 | /* from looking at man pages, and include files, looks like | |
529 | * this just sets up the fields of p->p_stats->p_prof... | |
530 | * and those fields come straight from the args. | |
531 | * only thing *we* have to do is check the args for validity... | |
532 | * | |
533 | * cgd | |
534 | */ | |
535 | ||
536 | /* check to make sure that the buffer is OK. addupc (in locore) | |
537 | * checks for faults, but would one be generated, say, writing to | |
538 | * kernel space? probably not -- it just uses "movl"... | |
539 | * | |
540 | * so we've gotta check to make sure that the info set up for | |
541 | * addupc is set right... it's gotta be writable by the user... | |
542 | */ | |
543 | ||
544 | if (useracc(uap->bufbase,uap->bufsize*sizeof(short),B_WRITE) == 0) | |
545 | return EFAULT; | |
546 | ||
547 | p->p_stats->p_prof.pr_base = uap->bufbase; | |
548 | p->p_stats->p_prof.pr_size = uap->bufsize; | |
549 | p->p_stats->p_prof.pr_off = uap->pcoffset; | |
550 | p->p_stats->p_prof.pr_scale = uap->pcscale; | |
551 | ||
552 | return 0; | |
553 | } |