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 | |
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 | */ | |
88 | int sipcreg[NIPCREG] = | |
89 | { 0,0,sEDI,sESI,sEBP,sEBX,sEDX,sECX,sEAX,sEIP,sCS,sEFLAGS,sESP,sSS }; | |
90 | ||
91 | struct { | |
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 | |
109 | struct ptrace_args { | |
110 | int req; | |
111 | int pid; | |
112 | int *addr; | |
113 | int data; | |
114 | }; | |
115 | ||
15637ed4 RG |
116 | ptrace(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 | ||
256 | out: | |
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 | ||
266 | procxmt(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 | |
433 | struct 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 */ |
441 | profil(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 | } |