]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/fs/procfs/procfs_ctl.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / fs / procfs / procfs_ctl.c
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  * 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  *      @(#)procfs_ctl.c        8.4 (Berkeley) 6/15/94
34  *
35  * From:
36  *      $Id: procfs_ctl.c,v 1.51 2003/12/07 17:40:00 des Exp $
37  * $FreeBSD$
38  */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/proc.h>
45 #include <sys/ptrace.h>
46 #include <sys/sbuf.h>
47 #include <sys/signalvar.h>
48 #include <sys/sx.h>
49 #include <sys/uio.h>
50
51 #include <fs/pseudofs/pseudofs.h>
52 #include <fs/procfs/procfs.h>
53
54 #include <vm/vm.h>
55
56 /*
57  * True iff process (p) is in trace wait state
58  * relative to process (curp)
59  */
60 #define TRACE_WAIT_P(curp, p) \
61          (P_SHOULDSTOP(p) && \
62          (p)->p_pptr == (curp) && \
63          ((p)->p_flag & P_TRACED))
64
65 #define PROCFS_CTL_ATTACH       1
66 #define PROCFS_CTL_DETACH       2
67 #define PROCFS_CTL_STEP         3
68 #define PROCFS_CTL_RUN          4
69 #define PROCFS_CTL_WAIT         5
70
71 struct namemap {
72         const char *nm_name;
73         int nm_val;
74 };
75
76 static struct namemap ctlnames[] = {
77         /* special /proc commands */
78         { "attach",     PROCFS_CTL_ATTACH },
79         { "detach",     PROCFS_CTL_DETACH },
80         { "step",       PROCFS_CTL_STEP },
81         { "run",        PROCFS_CTL_RUN },
82         { "wait",       PROCFS_CTL_WAIT },
83         { 0 },
84 };
85
86 static struct namemap signames[] = {
87         /* regular signal names */
88         { "hup",        SIGHUP },       { "int",        SIGINT },
89         { "quit",       SIGQUIT },      { "ill",        SIGILL },
90         { "trap",       SIGTRAP },      { "abrt",       SIGABRT },
91         { "iot",        SIGIOT },       { "emt",        SIGEMT },
92         { "fpe",        SIGFPE },       { "kill",       SIGKILL },
93         { "bus",        SIGBUS },       { "segv",       SIGSEGV },
94         { "sys",        SIGSYS },       { "pipe",       SIGPIPE },
95         { "alrm",       SIGALRM },      { "term",       SIGTERM },
96         { "urg",        SIGURG },       { "stop",       SIGSTOP },
97         { "tstp",       SIGTSTP },      { "cont",       SIGCONT },
98         { "chld",       SIGCHLD },      { "ttin",       SIGTTIN },
99         { "ttou",       SIGTTOU },      { "io",         SIGIO },
100         { "xcpu",       SIGXCPU },      { "xfsz",       SIGXFSZ },
101         { "vtalrm",     SIGVTALRM },    { "prof",       SIGPROF },
102         { "winch",      SIGWINCH },     { "info",       SIGINFO },
103         { "usr1",       SIGUSR1 },      { "usr2",       SIGUSR2 },
104         { 0 },
105 };
106
107 static int      procfs_control(struct thread *td, struct proc *p, int op);
108
109 static int
110 procfs_control(struct thread *td, struct proc *p, int op)
111 {
112         int error = 0;
113
114         /*
115          * Attach - attaches the target process for debugging
116          * by the calling process.
117          */
118         if (op == PROCFS_CTL_ATTACH) {
119                 sx_xlock(&proctree_lock);
120                 PROC_LOCK(p);
121                 if ((error = p_candebug(td, p)) != 0)
122                         goto out;
123                 if (p->p_flag & P_TRACED) {
124                         error = EBUSY;
125                         goto out;
126                 }
127
128                 /* Can't trace yourself! */
129                 if (p->p_pid == td->td_proc->p_pid) {
130                         error = EINVAL;
131                         goto out;
132                 }
133
134                 /*
135                  * Go ahead and set the trace flag.
136                  * Save the old parent (it's reset in
137                  *   _DETACH, and also in kern_exit.c:wait4()
138                  * Reparent the process so that the tracing
139                  *   proc gets to see all the action.
140                  * Stop the target.
141                  */
142                 p->p_flag |= P_TRACED;
143                 faultin(p);
144                 p->p_xstat = 0;         /* XXX ? */
145                 if (p->p_pptr != td->td_proc) {
146                         p->p_oppid = p->p_pptr->p_pid;
147                         proc_reparent(p, td->td_proc);
148                 }
149                 psignal(p, SIGSTOP);
150 out:
151                 PROC_UNLOCK(p);
152                 sx_xunlock(&proctree_lock);
153                 return (error);
154         }
155
156         /*
157          * Authorization check: rely on normal debugging protection, except
158          * allow processes to disengage debugging on a process onto which
159          * they have previously attached, but no longer have permission to
160          * debug.
161          */
162         PROC_LOCK(p);
163         if (op != PROCFS_CTL_DETACH &&
164             ((error = p_candebug(td, p)))) {
165                 PROC_UNLOCK(p);
166                 return (error);
167         }
168
169         /*
170          * Target process must be stopped, owned by (td) and
171          * be set up for tracing (P_TRACED flag set).
172          * Allow DETACH to take place at any time for sanity.
173          * Allow WAIT any time, of course.
174          */
175         switch (op) {
176         case PROCFS_CTL_DETACH:
177         case PROCFS_CTL_WAIT:
178                 break;
179
180         default:
181                 if (!TRACE_WAIT_P(td->td_proc, p)) {
182                         PROC_UNLOCK(p);
183                         return (EBUSY);
184                 }
185         }
186
187
188 #ifdef FIX_SSTEP
189         /*
190          * do single-step fixup if needed
191          */
192         FIX_SSTEP(FIRST_THREAD_IN_PROC(p));     /* XXXKSE */
193 #endif
194
195         /*
196          * Don't deliver any signal by default.
197          * To continue with a signal, just send
198          * the signal name to the ctl file
199          */
200         p->p_xstat = 0;
201
202         switch (op) {
203         /*
204          * Detach.  Cleans up the target process, reparent it if possible
205          * and set it running once more.
206          */
207         case PROCFS_CTL_DETACH:
208                 /* if not being traced, then this is a painless no-op */
209                 if ((p->p_flag & P_TRACED) == 0) {
210                         PROC_UNLOCK(p);
211                         return (0);
212                 }
213
214                 /* not being traced any more */
215                 p->p_flag &= ~P_TRACED;
216
217                 /* remove pending SIGTRAP, else the process will die */
218                 sigqueue_delete_proc(p, SIGTRAP);
219                 PROC_UNLOCK(p);
220
221                 /* give process back to original parent */
222                 sx_xlock(&proctree_lock);
223                 if (p->p_oppid != p->p_pptr->p_pid) {
224                         struct proc *pp;
225
226                         pp = pfind(p->p_oppid);
227                         PROC_LOCK(p);
228                         if (pp) {
229                                 PROC_UNLOCK(pp);
230                                 proc_reparent(p, pp);
231                         }
232                 } else
233                         PROC_LOCK(p);
234                 p->p_oppid = 0;
235                 p->p_flag &= ~P_WAITED; /* XXX ? */
236                 PROC_UNLOCK(p);
237                 sx_xunlock(&proctree_lock);
238
239                 wakeup(td->td_proc);    /* XXX for CTL_WAIT below ? */
240
241                 break;
242
243         /*
244          * Step.  Let the target process execute a single instruction.
245          * What does it mean to single step a threaded program?
246          */
247         case PROCFS_CTL_STEP:
248                 error = proc_sstep(FIRST_THREAD_IN_PROC(p)); /* XXXKSE */
249                 PROC_UNLOCK(p);
250                 if (error)
251                         return (error);
252                 break;
253
254         /*
255          * Run.  Let the target process continue running until a breakpoint
256          * or some other trap.
257          */
258         case PROCFS_CTL_RUN:
259                 p->p_flag &= ~P_STOPPED_SIG;    /* this uses SIGSTOP */
260                 PROC_UNLOCK(p);
261                 break;
262
263         /*
264          * Wait for the target process to stop.
265          * If the target is not being traced then just wait
266          * to enter
267          */
268         case PROCFS_CTL_WAIT:
269                 if (p->p_flag & P_TRACED) {
270                         while (error == 0 &&
271                                         (P_SHOULDSTOP(p)) &&
272                                         (p->p_flag & P_TRACED) &&
273                                         (p->p_pptr == td->td_proc))
274                                 error = msleep(p, &p->p_mtx,
275                                                 PWAIT|PCATCH, "procfsx", 0);
276                         if (error == 0 && !TRACE_WAIT_P(td->td_proc, p))
277                                 error = EBUSY;
278                 } else {
279                         while (error == 0 && P_SHOULDSTOP(p))
280                                 error = msleep(p, &p->p_mtx,
281                                                 PWAIT|PCATCH, "procfs", 0);
282                 }
283                 PROC_UNLOCK(p);
284                 return (error);
285         default:
286                 panic("procfs_control");
287         }
288
289         PROC_SLOCK(p);
290         thread_unsuspend(p); /* If it can run, let it do so. */
291         PROC_SUNLOCK(p);
292         return (0);
293 }
294
295 static struct namemap *
296 findname(struct namemap *nm, char *buf, int buflen)
297 {
298
299         for (; nm->nm_name; nm++)
300                 if (bcmp(buf, nm->nm_name, buflen+1) == 0)
301                         return (nm);
302
303         return (0);
304 }
305
306 int
307 procfs_doprocctl(PFS_FILL_ARGS)
308 {
309         int error;
310         struct namemap *nm;
311
312         if (uio == NULL || uio->uio_rw != UIO_WRITE)
313                 return (EOPNOTSUPP);
314
315         /*
316          * Map signal names into signal generation
317          * or debug control.  Unknown commands and/or signals
318          * return EOPNOTSUPP.
319          *
320          * Sending a signal while the process is being debugged
321          * also has the side effect of letting the target continue
322          * to run.  There is no way to single-step a signal delivery.
323          */
324         error = EOPNOTSUPP;
325
326         sbuf_trim(sb);
327         sbuf_finish(sb);
328         nm = findname(ctlnames, sbuf_data(sb), sbuf_len(sb));
329         if (nm) {
330                 printf("procfs: got a %s command\n", sbuf_data(sb));
331                 error = procfs_control(td, p, nm->nm_val);
332         } else {
333                 nm = findname(signames, sbuf_data(sb), sbuf_len(sb));
334                 if (nm) {
335                         printf("procfs: got a sig%s\n", sbuf_data(sb));
336                         PROC_LOCK(p);
337
338                         /* This is very broken XXXKSE: */
339                         if (TRACE_WAIT_P(td->td_proc, p)) {
340                                 p->p_xstat = nm->nm_val;
341 #ifdef FIX_SSTEP
342                                 /* XXXKSE: */
343                                 FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
344 #endif
345                                 /* XXXKSE: */
346                                 p->p_flag &= ~P_STOPPED_SIG;
347                                 PROC_SLOCK(p);
348                                 thread_unsuspend(p);
349                                 PROC_SUNLOCK(p);
350                         } else
351                                 psignal(p, nm->nm_val);
352                         PROC_UNLOCK(p);
353                         error = 0;
354                 }
355         }
356
357         return (error);
358 }