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