Deleted Added
full compact
procfs_ctl.c (6569) procfs_ctl.c (7090)
1/*
2 * Copyright (c) 1993 Jan-Simon Pendry
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)procfs_ctl.c 8.3 (Berkeley) 1/21/94
38 *
1/*
2 * Copyright (c) 1993 Jan-Simon Pendry
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)procfs_ctl.c 8.3 (Berkeley) 1/21/94
38 *
39 * $Id: procfs_ctl.c,v 1.3 1994/12/31 12:26:50 ache Exp $
39 * $Id: procfs_ctl.c,v 1.4 1995/02/20 15:53:32 davidg Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/time.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/vnode.h>
48#include <sys/ioctl.h>
49#include <sys/tty.h>
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/time.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/vnode.h>
48#include <sys/ioctl.h>
49#include <sys/tty.h>
50#include <sys/ptrace.h>
50#include <sys/resource.h>
51#include <sys/resourcevar.h>
51#include <sys/resource.h>
52#include <sys/resourcevar.h>
53#include <sys/signal.h>
54#include <sys/signalvar.h>
55
56#include <vm/vm.h>
57
52#include <miscfs/procfs/procfs.h>
58#include <miscfs/procfs/procfs.h>
53#include <sys/signal.h> /* for sigmask() */
54
55/*
56 * True iff process (p) is in trace wait state
57 * relative to process (curp)
58 */
59#define TRACE_WAIT_P(curp, p) \
60 ((p)->p_stat == SSTOP && \
61 (p)->p_pptr == (curp) && \
62 ((p)->p_flag & P_TRACED))
63
64#ifdef notdef
65#define FIX_SSTEP(p) { \
66 procfs_fix_sstep(p); \
67 } \
68}
69#else
70#define FIX_SSTEP(p)
71#endif
72
73#define PROCFS_CTL_ATTACH 1
74#define PROCFS_CTL_DETACH 2
75#define PROCFS_CTL_STEP 3
76#define PROCFS_CTL_RUN 4
77#define PROCFS_CTL_WAIT 5
78
79static vfs_namemap_t ctlnames[] = {
80 /* special /proc commands */
81 { "attach", PROCFS_CTL_ATTACH },
82 { "detach", PROCFS_CTL_DETACH },
83 { "step", PROCFS_CTL_STEP },
84 { "run", PROCFS_CTL_RUN },
85 { "wait", PROCFS_CTL_WAIT },
86 { 0 },
87};
88
89static vfs_namemap_t signames[] = {
90 /* regular signal names */
91 { "hup", SIGHUP }, { "int", SIGINT },
92 { "quit", SIGQUIT }, { "ill", SIGILL },
93 { "trap", SIGTRAP }, { "abrt", SIGABRT },
94 { "iot", SIGIOT }, { "emt", SIGEMT },
95 { "fpe", SIGFPE }, { "kill", SIGKILL },
96 { "bus", SIGBUS }, { "segv", SIGSEGV },
97 { "sys", SIGSYS }, { "pipe", SIGPIPE },
98 { "alrm", SIGALRM }, { "term", SIGTERM },
99 { "urg", SIGURG }, { "stop", SIGSTOP },
100 { "tstp", SIGTSTP }, { "cont", SIGCONT },
101 { "chld", SIGCHLD }, { "ttin", SIGTTIN },
102 { "ttou", SIGTTOU }, { "io", SIGIO },
103 { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ },
104 { "vtalrm", SIGVTALRM }, { "prof", SIGPROF },
105 { "winch", SIGWINCH }, { "info", SIGINFO },
106 { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 },
107 { 0 },
108};
109
110static int
111procfs_control(curp, p, op)
112 struct proc *curp;
113 struct proc *p;
114 int op;
115{
116 int error;
117
118 /*
119 * Attach - attaches the target process for debugging
120 * by the calling process.
121 */
122 if (op == PROCFS_CTL_ATTACH) {
123 /* check whether already being traced */
124 if (p->p_flag & P_TRACED)
125 return (EBUSY);
126
127 /* can't trace yourself! */
128 if (p->p_pid == curp->p_pid)
129 return (EINVAL);
130
131 /*
132 * Go ahead and set the trace flag.
133 * Save the old parent (it's reset in
134 * _DETACH, and also in kern_exit.c:wait4()
135 * Reparent the process so that the tracing
136 * proc gets to see all the action.
137 * Stop the target.
138 */
139 p->p_flag |= P_TRACED;
140 faultin(p);
141 p->p_xstat = 0; /* XXX ? */
142 if (p->p_pptr != curp) {
143 p->p_oppid = p->p_pptr->p_pid;
144 proc_reparent(p, curp);
145 }
146 psignal(p, SIGSTOP);
147 return (0);
148 }
149
150 /*
151 * Target process must be stopped, owned by (curp) and
152 * be set up for tracing (P_TRACED flag set).
153 * Allow DETACH to take place at any time for sanity.
154 * Allow WAIT any time, of course.
155 */
156 switch (op) {
157 case PROCFS_CTL_DETACH:
158 case PROCFS_CTL_WAIT:
159 break;
160
161 default:
162 if (!TRACE_WAIT_P(curp, p))
163 return (EBUSY);
164 }
165
166 /*
167 * do single-step fixup if needed
168 */
169 FIX_SSTEP(p);
170
171 /*
172 * Don't deliver any signal by default.
173 * To continue with a signal, just send
174 * the signal name to the ctl file
175 */
176 p->p_xstat = 0;
177
178 switch (op) {
179 /*
180 * Detach. Cleans up the target process, reparent it if possible
181 * and set it running once more.
182 */
183 case PROCFS_CTL_DETACH:
184 /* if not being traced, then this is a painless no-op */
185 if ((p->p_flag & P_TRACED) == 0)
186 return (0);
187
188 /* not being traced any more */
189 p->p_flag &= ~P_TRACED;
190
191 /* remove pending SIGTRAP, else the process will die */
192 p->p_siglist &= ~sigmask (SIGTRAP);
193
194 /* give process back to original parent */
195 if (p->p_oppid != p->p_pptr->p_pid) {
196 struct proc *pp;
197
198 pp = pfind(p->p_oppid);
199 if (pp)
200 proc_reparent(p, pp);
201 }
202
203 p->p_oppid = 0;
204 p->p_flag &= ~P_WAITED; /* XXX ? */
205 wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */
206
207 break;
208
209 /*
210 * Step. Let the target process execute a single instruction.
211 */
212 case PROCFS_CTL_STEP:
213 procfs_sstep(p);
214 break;
215
216 /*
217 * Run. Let the target process continue running until a breakpoint
218 * or some other trap.
219 */
220 case PROCFS_CTL_RUN:
221 break;
222
223 /*
224 * Wait for the target process to stop.
225 * If the target is not being traced then just wait
226 * to enter
227 */
228 case PROCFS_CTL_WAIT:
229 error = 0;
230 if (p->p_flag & P_TRACED) {
231 while (error == 0 &&
232 (p->p_stat != SSTOP) &&
233 (p->p_flag & P_TRACED) &&
234 (p->p_pptr == curp)) {
235 error = tsleep((caddr_t) p,
236 PWAIT|PCATCH, "procfsx", 0);
237 }
238 if (error == 0 && !TRACE_WAIT_P(curp, p))
239 error = EBUSY;
240 } else {
241 while (error == 0 && p->p_stat != SSTOP) {
242 error = tsleep((caddr_t) p,
243 PWAIT|PCATCH, "procfs", 0);
244 }
245 }
246 return (error);
247
248 default:
249 panic("procfs_control");
250 }
251
252 if (p->p_stat == SSTOP)
253 setrunnable(p);
254 return (0);
255}
256
257int
258procfs_doctl(curp, p, pfs, uio)
259 struct proc *curp;
260 struct pfsnode *pfs;
261 struct uio *uio;
262 struct proc *p;
263{
264 int xlen;
265 int error;
266 char msg[PROCFS_CTLLEN+1];
267 vfs_namemap_t *nm;
268
269 if (uio->uio_rw != UIO_WRITE)
270 return (EOPNOTSUPP);
271
272 xlen = PROCFS_CTLLEN;
273 error = vfs_getuserstr(uio, msg, &xlen);
274 if (error)
275 return (error);
276
277 /*
278 * Map signal names into signal generation
279 * or debug control. Unknown commands and/or signals
280 * return EOPNOTSUPP.
281 *
282 * Sending a signal while the process is being debugged
283 * also has the side effect of letting the target continue
284 * to run. There is no way to single-step a signal delivery.
285 */
286 error = EOPNOTSUPP;
287
288 nm = vfs_findname(ctlnames, msg, xlen);
289 if (nm) {
290 error = procfs_control(curp, p, nm->nm_val);
291 } else {
292 nm = vfs_findname(signames, msg, xlen);
293 if (nm) {
294 if (TRACE_WAIT_P(curp, p)) {
295 p->p_xstat = nm->nm_val;
296 FIX_SSTEP(p);
297 setrunnable(p);
298 } else {
299 psignal(p, nm->nm_val);
300 }
301 error = 0;
302 }
303 }
304
305 return (error);
306}
59
60/*
61 * True iff process (p) is in trace wait state
62 * relative to process (curp)
63 */
64#define TRACE_WAIT_P(curp, p) \
65 ((p)->p_stat == SSTOP && \
66 (p)->p_pptr == (curp) && \
67 ((p)->p_flag & P_TRACED))
68
69#ifdef notdef
70#define FIX_SSTEP(p) { \
71 procfs_fix_sstep(p); \
72 } \
73}
74#else
75#define FIX_SSTEP(p)
76#endif
77
78#define PROCFS_CTL_ATTACH 1
79#define PROCFS_CTL_DETACH 2
80#define PROCFS_CTL_STEP 3
81#define PROCFS_CTL_RUN 4
82#define PROCFS_CTL_WAIT 5
83
84static vfs_namemap_t ctlnames[] = {
85 /* special /proc commands */
86 { "attach", PROCFS_CTL_ATTACH },
87 { "detach", PROCFS_CTL_DETACH },
88 { "step", PROCFS_CTL_STEP },
89 { "run", PROCFS_CTL_RUN },
90 { "wait", PROCFS_CTL_WAIT },
91 { 0 },
92};
93
94static vfs_namemap_t signames[] = {
95 /* regular signal names */
96 { "hup", SIGHUP }, { "int", SIGINT },
97 { "quit", SIGQUIT }, { "ill", SIGILL },
98 { "trap", SIGTRAP }, { "abrt", SIGABRT },
99 { "iot", SIGIOT }, { "emt", SIGEMT },
100 { "fpe", SIGFPE }, { "kill", SIGKILL },
101 { "bus", SIGBUS }, { "segv", SIGSEGV },
102 { "sys", SIGSYS }, { "pipe", SIGPIPE },
103 { "alrm", SIGALRM }, { "term", SIGTERM },
104 { "urg", SIGURG }, { "stop", SIGSTOP },
105 { "tstp", SIGTSTP }, { "cont", SIGCONT },
106 { "chld", SIGCHLD }, { "ttin", SIGTTIN },
107 { "ttou", SIGTTOU }, { "io", SIGIO },
108 { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ },
109 { "vtalrm", SIGVTALRM }, { "prof", SIGPROF },
110 { "winch", SIGWINCH }, { "info", SIGINFO },
111 { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 },
112 { 0 },
113};
114
115static int
116procfs_control(curp, p, op)
117 struct proc *curp;
118 struct proc *p;
119 int op;
120{
121 int error;
122
123 /*
124 * Attach - attaches the target process for debugging
125 * by the calling process.
126 */
127 if (op == PROCFS_CTL_ATTACH) {
128 /* check whether already being traced */
129 if (p->p_flag & P_TRACED)
130 return (EBUSY);
131
132 /* can't trace yourself! */
133 if (p->p_pid == curp->p_pid)
134 return (EINVAL);
135
136 /*
137 * Go ahead and set the trace flag.
138 * Save the old parent (it's reset in
139 * _DETACH, and also in kern_exit.c:wait4()
140 * Reparent the process so that the tracing
141 * proc gets to see all the action.
142 * Stop the target.
143 */
144 p->p_flag |= P_TRACED;
145 faultin(p);
146 p->p_xstat = 0; /* XXX ? */
147 if (p->p_pptr != curp) {
148 p->p_oppid = p->p_pptr->p_pid;
149 proc_reparent(p, curp);
150 }
151 psignal(p, SIGSTOP);
152 return (0);
153 }
154
155 /*
156 * Target process must be stopped, owned by (curp) and
157 * be set up for tracing (P_TRACED flag set).
158 * Allow DETACH to take place at any time for sanity.
159 * Allow WAIT any time, of course.
160 */
161 switch (op) {
162 case PROCFS_CTL_DETACH:
163 case PROCFS_CTL_WAIT:
164 break;
165
166 default:
167 if (!TRACE_WAIT_P(curp, p))
168 return (EBUSY);
169 }
170
171 /*
172 * do single-step fixup if needed
173 */
174 FIX_SSTEP(p);
175
176 /*
177 * Don't deliver any signal by default.
178 * To continue with a signal, just send
179 * the signal name to the ctl file
180 */
181 p->p_xstat = 0;
182
183 switch (op) {
184 /*
185 * Detach. Cleans up the target process, reparent it if possible
186 * and set it running once more.
187 */
188 case PROCFS_CTL_DETACH:
189 /* if not being traced, then this is a painless no-op */
190 if ((p->p_flag & P_TRACED) == 0)
191 return (0);
192
193 /* not being traced any more */
194 p->p_flag &= ~P_TRACED;
195
196 /* remove pending SIGTRAP, else the process will die */
197 p->p_siglist &= ~sigmask (SIGTRAP);
198
199 /* give process back to original parent */
200 if (p->p_oppid != p->p_pptr->p_pid) {
201 struct proc *pp;
202
203 pp = pfind(p->p_oppid);
204 if (pp)
205 proc_reparent(p, pp);
206 }
207
208 p->p_oppid = 0;
209 p->p_flag &= ~P_WAITED; /* XXX ? */
210 wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */
211
212 break;
213
214 /*
215 * Step. Let the target process execute a single instruction.
216 */
217 case PROCFS_CTL_STEP:
218 procfs_sstep(p);
219 break;
220
221 /*
222 * Run. Let the target process continue running until a breakpoint
223 * or some other trap.
224 */
225 case PROCFS_CTL_RUN:
226 break;
227
228 /*
229 * Wait for the target process to stop.
230 * If the target is not being traced then just wait
231 * to enter
232 */
233 case PROCFS_CTL_WAIT:
234 error = 0;
235 if (p->p_flag & P_TRACED) {
236 while (error == 0 &&
237 (p->p_stat != SSTOP) &&
238 (p->p_flag & P_TRACED) &&
239 (p->p_pptr == curp)) {
240 error = tsleep((caddr_t) p,
241 PWAIT|PCATCH, "procfsx", 0);
242 }
243 if (error == 0 && !TRACE_WAIT_P(curp, p))
244 error = EBUSY;
245 } else {
246 while (error == 0 && p->p_stat != SSTOP) {
247 error = tsleep((caddr_t) p,
248 PWAIT|PCATCH, "procfs", 0);
249 }
250 }
251 return (error);
252
253 default:
254 panic("procfs_control");
255 }
256
257 if (p->p_stat == SSTOP)
258 setrunnable(p);
259 return (0);
260}
261
262int
263procfs_doctl(curp, p, pfs, uio)
264 struct proc *curp;
265 struct pfsnode *pfs;
266 struct uio *uio;
267 struct proc *p;
268{
269 int xlen;
270 int error;
271 char msg[PROCFS_CTLLEN+1];
272 vfs_namemap_t *nm;
273
274 if (uio->uio_rw != UIO_WRITE)
275 return (EOPNOTSUPP);
276
277 xlen = PROCFS_CTLLEN;
278 error = vfs_getuserstr(uio, msg, &xlen);
279 if (error)
280 return (error);
281
282 /*
283 * Map signal names into signal generation
284 * or debug control. Unknown commands and/or signals
285 * return EOPNOTSUPP.
286 *
287 * Sending a signal while the process is being debugged
288 * also has the side effect of letting the target continue
289 * to run. There is no way to single-step a signal delivery.
290 */
291 error = EOPNOTSUPP;
292
293 nm = vfs_findname(ctlnames, msg, xlen);
294 if (nm) {
295 error = procfs_control(curp, p, nm->nm_val);
296 } else {
297 nm = vfs_findname(signames, msg, xlen);
298 if (nm) {
299 if (TRACE_WAIT_P(curp, p)) {
300 p->p_xstat = nm->nm_val;
301 FIX_SSTEP(p);
302 setrunnable(p);
303 } else {
304 psignal(p, nm->nm_val);
305 }
306 error = 0;
307 }
308 }
309
310 return (error);
311}