Commit | Line | Data |
---|---|---|
5dc2581e | 1 | /*- |
7a6e4544 KB |
2 | * Copyright (c) 1982, 1986, 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
adb35f79 KB |
4 | * (c) UNIX System Laboratories, Inc. |
5 | * All or some portions of this file are derived from material licensed | |
6 | * to the University of California by American Telephone and Telegraph | |
7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
8 | * the permission of UNIX System Laboratories, Inc. | |
5dc2581e KB |
9 | * |
10 | * %sccs.include.proprietary.c% | |
da7c5cc6 | 11 | * |
adb35f79 | 12 | * @(#)sys_process.c 8.5 (Berkeley) %G% |
da7c5cc6 | 13 | */ |
961945a8 | 14 | |
ff32eb64 | 15 | #define IPCREG |
38a01dbe KB |
16 | #include <sys/param.h> |
17 | #include <sys/proc.h> | |
18 | #include <sys/vnode.h> | |
19 | #include <sys/buf.h> | |
20 | #include <sys/ptrace.h> | |
9ce4de2d | 21 | |
38a01dbe KB |
22 | #include <machine/reg.h> |
23 | #include <machine/psl.h> | |
24 | #include <vm/vm.h> | |
25 | #include <vm/vm_page.h> | |
de5931fb | 26 | |
38a01dbe | 27 | #include <sys/user.h> |
d301d150 | 28 | |
4147b3f6 BJ |
29 | /* |
30 | * Priority for tracing | |
31 | */ | |
32 | #define IPCPRI PZERO | |
33 | ||
34 | /* | |
35 | * Tracing variables. | |
36 | * Used to pass trace command from | |
37 | * parent to child being traced. | |
38 | * This data base cannot be | |
39 | * shared and is locked | |
40 | * per user. | |
41 | */ | |
42 | struct { | |
43 | int ip_lock; | |
44 | int ip_req; | |
80527497 | 45 | caddr_t ip_addr; |
4147b3f6 BJ |
46 | int ip_data; |
47 | } ipc; | |
48 | ||
49 | /* | |
3f75397a | 50 | * Process debugging system call. |
4147b3f6 | 51 | */ |
afc12c69 CT |
52 | struct ptrace_args { |
53 | int req; | |
80527497 KM |
54 | pid_t pid; |
55 | caddr_t addr; | |
afc12c69 CT |
56 | int data; |
57 | }; | |
8c7d0e2a KM |
58 | ptrace(curp, uap, retval) |
59 | struct proc *curp; | |
afc12c69 | 60 | register struct ptrace_args *uap; |
8c7d0e2a KM |
61 | int *retval; |
62 | { | |
63 | register struct proc *p; | |
ee8c7b71 | 64 | int error; |
4147b3f6 | 65 | |
48c729cb | 66 | if (uap->req <= 0) { |
cf5ef508 | 67 | curp->p_flag |= P_TRACED; |
48c729cb MH |
68 | return (0); |
69 | } | |
ee8c7b71 | 70 | p = pfind(uap->pid); |
48c729cb MH |
71 | if (p == 0) |
72 | return (ESRCH); | |
ee8c7b71 KM |
73 | if (uap->req == PT_ATTACH) { |
74 | /* | |
45f54c1f KB |
75 | * Must be root if the process has used set user or group |
76 | * privileges or does not belong to the real user. Must | |
77 | * not be already traced. Can't attach to ourselves. | |
ee8c7b71 | 78 | */ |
cf5ef508 | 79 | if ((p->p_flag & P_SUGID || |
ee8c7b71 KM |
80 | p->p_cred->p_ruid != curp->p_cred->p_ruid) && |
81 | (error = suser(p->p_ucred, &p->p_acflag)) != 0) | |
82 | return (error); | |
cf5ef508 | 83 | if (p->p_flag & P_TRACED) |
ee8c7b71 | 84 | return (EALREADY); /* ??? */ |
45f54c1f KB |
85 | if (p->p_pid == curp->p_pid) |
86 | return (EINVAL); | |
ee8c7b71 KM |
87 | /* |
88 | * It would be nice if the tracing relationship was separate | |
89 | * from the parent relationship but that would require | |
90 | * another set of links in the proc struct or for "wait" | |
91 | * to scan the entire proc table. To make life easier, | |
92 | * we just re-parent the process we're trying to trace. | |
93 | * The old parent is remembered so we can put things back | |
94 | * on a "detach". | |
95 | */ | |
cf5ef508 | 96 | p->p_flag |= P_TRACED; |
ee8c7b71 KM |
97 | p->p_oppid = p->p_pptr->p_pid; |
98 | proc_reparent(p, curp); | |
99 | psignal(p, SIGSTOP); | |
100 | return (0); | |
101 | } | |
cf5ef508 | 102 | if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & P_TRACED)) |
d9c2f47f | 103 | return (ESRCH); |
4147b3f6 BJ |
104 | while (ipc.ip_lock) |
105 | sleep((caddr_t)&ipc, IPCPRI); | |
106 | ipc.ip_lock = p->p_pid; | |
107 | ipc.ip_data = uap->data; | |
108 | ipc.ip_addr = uap->addr; | |
109 | ipc.ip_req = uap->req; | |
cf5ef508 | 110 | p->p_flag &= ~P_WAITED; |
4147b3f6 BJ |
111 | while (ipc.ip_req > 0) { |
112 | if (p->p_stat==SSTOP) | |
cb84e0ab | 113 | setrunnable(p); |
4147b3f6 BJ |
114 | sleep((caddr_t)&ipc, IPCPRI); |
115 | } | |
8c7d0e2a | 116 | *retval = ipc.ip_data; |
4147b3f6 BJ |
117 | ipc.ip_lock = 0; |
118 | wakeup((caddr_t)&ipc); | |
8c7d0e2a | 119 | if (ipc.ip_req < 0) |
d9c2f47f MK |
120 | return (EIO); |
121 | return (0); | |
4147b3f6 BJ |
122 | } |
123 | ||
e128a701 | 124 | #define PHYSOFF(p, o) ((caddr_t)(p) + (o)) |
b4d15838 KM |
125 | #if defined(hp300) || defined(luna68k) |
126 | #define PHYSALIGNED(a) (((int)(a) & (sizeof(short) - 1)) == 0) | |
127 | #else | |
128 | #define PHYSALIGNED(a) (((int)(a) & (sizeof(int) - 1)) == 0) | |
129 | #endif | |
e128a701 | 130 | |
6ce8aff2 WN |
131 | #if defined(i386) |
132 | #undef PC | |
133 | #undef SP | |
134 | #undef PS | |
135 | #undef R0 | |
136 | #undef R1 | |
137 | ||
138 | #define PC tEIP | |
139 | #define SP tESP | |
140 | #define PS tEFLAGS | |
141 | #define R0 tEDX | |
142 | #define R1 tECX | |
143 | #endif | |
883d0f83 | 144 | |
4147b3f6 | 145 | /* |
3f75397a KM |
146 | * Transmit a tracing request from the parent to the child process |
147 | * being debugged. This code runs in the context of the child process | |
148 | * to fulfill the command requested by the parent. | |
4147b3f6 | 149 | */ |
cf5ef508 | 150 | trace_req(p) |
82655668 | 151 | register struct proc *p; |
4147b3f6 | 152 | { |
214b997f | 153 | register int i, *poff, *regs; |
e128a701 | 154 | extern char kstack[]; |
4147b3f6 | 155 | |
82655668 | 156 | if (ipc.ip_lock != p->p_pid) |
4147b3f6 | 157 | return (0); |
82655668 | 158 | p->p_slptime = 0; |
214b997f MH |
159 | regs = p->p_md.md_regs; |
160 | p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */ | |
4147b3f6 BJ |
161 | i = ipc.ip_req; |
162 | ipc.ip_req = 0; | |
163 | switch (i) { | |
164 | ||
01b0e233 | 165 | case PT_READ_I: /* read the child's text space */ |
4147b3f6 BJ |
166 | if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) |
167 | goto error; | |
168 | ipc.ip_data = fuiword((caddr_t)ipc.ip_addr); | |
169 | break; | |
170 | ||
01b0e233 | 171 | case PT_READ_D: /* read the child's data space */ |
4147b3f6 BJ |
172 | if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ)) |
173 | goto error; | |
174 | ipc.ip_data = fuword((caddr_t)ipc.ip_addr); | |
175 | break; | |
176 | ||
01b0e233 | 177 | case PT_READ_U: /* read the child's u. */ |
4147b3f6 | 178 | i = (int)ipc.ip_addr; |
b4d15838 | 179 | if ((u_int) i > ctob(UPAGES)-sizeof(int) || !PHYSALIGNED(i)) |
4147b3f6 | 180 | goto error; |
eadb8ef2 | 181 | ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i); |
4147b3f6 BJ |
182 | break; |
183 | ||
01b0e233 | 184 | case PT_WRITE_I: /* write the child's text space */ |
883d0f83 | 185 | if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) { |
9db58063 KM |
186 | vm_offset_t sa, ea; |
187 | int rv; | |
188 | ||
189 | sa = trunc_page((vm_offset_t)ipc.ip_addr); | |
d6cefe4b | 190 | ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)); |
d7db4999 | 191 | rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, |
9db58063 KM |
192 | VM_PROT_DEFAULT, FALSE); |
193 | if (rv == KERN_SUCCESS) { | |
883d0f83 | 194 | i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data); |
d7db4999 MK |
195 | (void) vm_map_protect(&p->p_vmspace->vm_map, |
196 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, | |
197 | FALSE); | |
9db58063 | 198 | } |
883d0f83 | 199 | } |
4147b3f6 BJ |
200 | if (i < 0) |
201 | goto error; | |
4147b3f6 BJ |
202 | break; |
203 | ||
01b0e233 | 204 | case PT_WRITE_D: /* write the child's data space */ |
4147b3f6 BJ |
205 | if (suword((caddr_t)ipc.ip_addr, 0) < 0) |
206 | goto error; | |
207 | (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data); | |
208 | break; | |
209 | ||
01b0e233 | 210 | case PT_WRITE_U: /* write the child's u. */ |
4147b3f6 | 211 | i = (int)ipc.ip_addr; |
d89b7f8b | 212 | #ifdef mips |
b4d15838 | 213 | poff = (int *)PHYSOFF(p->p_addr, i); |
d89b7f8b | 214 | #else |
e128a701 | 215 | poff = (int *)PHYSOFF(kstack, i); |
d89b7f8b | 216 | #endif |
883d0f83 | 217 | for (i=0; i<NIPCREG; i++) |
214b997f | 218 | if (poff == ®s[ipcreg[i]]) |
4147b3f6 | 219 | goto ok; |
2a81c17c | 220 | #if defined(hp300) || defined(luna68k) |
214b997f MH |
221 | /* |
222 | * In the new frame layout, PS/PC are skewed by 2 bytes. | |
223 | */ | |
224 | regs = (int *)((short *)regs + 1); | |
225 | if (poff == ®s[PC]) | |
226 | goto ok; | |
227 | #endif | |
228 | if (poff == ®s[PS]) { | |
883d0f83 | 229 | ipc.ip_data |= PSL_USERSET; |
dc57440c | 230 | ipc.ip_data &= ~PSL_USERCLR; |
bf47fbca MK |
231 | #ifdef PSL_CM_CLR |
232 | if (ipc.ip_data & PSL_CM) | |
233 | ipc.ip_data &= ~PSL_CM_CLR; | |
234 | #endif | |
4147b3f6 BJ |
235 | goto ok; |
236 | } | |
7c02c1d3 | 237 | #if defined(hp300) || defined(luna68k) |
dc57440c | 238 | #ifdef FPCOPROC |
e128a701 MK |
239 | if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs && |
240 | poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar) | |
dc57440c KM |
241 | goto ok; |
242 | #endif | |
243 | #endif | |
4147b3f6 BJ |
244 | goto error; |
245 | ||
246 | ok: | |
82655668 | 247 | *poff = ipc.ip_data; |
4147b3f6 BJ |
248 | break; |
249 | ||
01b0e233 MK |
250 | case PT_STEP: /* single step the child */ |
251 | case PT_CONTINUE: /* continue the child */ | |
92ee7b5c | 252 | #ifndef mips |
214b997f | 253 | regs = (int *)((short *)regs + 1); |
92ee7b5c | 254 | #endif |
ee8c7b71 KM |
255 | if ((unsigned)ipc.ip_data >= NSIG) |
256 | goto error; | |
4147b3f6 | 257 | if ((int)ipc.ip_addr != 1) |
214b997f | 258 | regs[PC] = (int)ipc.ip_addr; |
cf5ef508 | 259 | p->p_xstat = ipc.ip_data; /* see issignal */ |
92ee7b5c KM |
260 | #ifdef mips |
261 | if (i == PT_STEP && cpu_singlestep(p)) | |
262 | goto error; | |
263 | #else | |
d89b7f8b MT |
264 | #ifdef PSL_T |
265 | /* need something more machine independent here... */ | |
01b0e233 | 266 | if (i == PT_STEP) |
214b997f | 267 | regs[PS] |= PSL_T; |
92ee7b5c | 268 | #endif |
d89b7f8b | 269 | #endif |
4147b3f6 BJ |
270 | wakeup((caddr_t)&ipc); |
271 | return (1); | |
272 | ||
01b0e233 | 273 | case PT_KILL: /* kill the child process */ |
4147b3f6 | 274 | wakeup((caddr_t)&ipc); |
817f339a | 275 | exit1(p, (int)p->p_xstat); |
4147b3f6 | 276 | |
ee8c7b71 | 277 | case PT_DETACH: /* stop tracing the child */ |
214b997f | 278 | regs = (int *)((short *)regs + 1); |
ee8c7b71 KM |
279 | if ((unsigned)ipc.ip_data >= NSIG) |
280 | goto error; | |
281 | if ((int)ipc.ip_addr != 1) | |
214b997f | 282 | regs[PC] = (int)ipc.ip_addr; |
cf5ef508 KB |
283 | p->p_xstat = ipc.ip_data; /* see issignal */ |
284 | p->p_flag &= ~P_TRACED; | |
ee8c7b71 KM |
285 | if (p->p_oppid != p->p_pptr->p_pid) { |
286 | register struct proc *pp = pfind(p->p_oppid); | |
287 | ||
288 | if (pp) | |
289 | proc_reparent(p, pp); | |
290 | } | |
291 | p->p_oppid = 0; | |
292 | wakeup((caddr_t)&ipc); | |
293 | return (1); | |
294 | ||
4147b3f6 BJ |
295 | default: |
296 | error: | |
297 | ipc.ip_req = -1; | |
298 | } | |
299 | wakeup((caddr_t)&ipc); | |
300 | return (0); | |
301 | } |