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