]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/fs/procfs/procfs_ctl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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         struct thread *temp;
114
115         /*
116          * Attach - attaches the target process for debugging
117          * by the calling process.
118          */
119         if (op == PROCFS_CTL_ATTACH) {
120                 sx_xlock(&proctree_lock);
121                 PROC_LOCK(p);
122                 if ((error = p_candebug(td, p)) != 0)
123                         goto out;
124                 if (p->p_flag & P_TRACED) {
125                         error = EBUSY;
126                         goto out;
127                 }
128
129                 /* Can't trace yourself! */
130                 if (p->p_pid == td->td_proc->p_pid) {
131                         error = EINVAL;
132                         goto out;
133                 }
134
135                 /*
136                  * Go ahead and set the trace flag.
137                  * Save the old parent (it's reset in
138                  *   _DETACH, and also in kern_exit.c:wait4()
139                  * Reparent the process so that the tracing
140                  *   proc gets to see all the action.
141                  * Stop the target.
142                  */
143                 p->p_flag |= P_TRACED;
144                 faultin(p);
145                 p->p_xstat = 0;         /* XXX ? */
146                 if (p->p_pptr != td->td_proc) {
147                         p->p_oppid = p->p_pptr->p_pid;
148                         proc_reparent(p, td->td_proc);
149                 }
150                 kern_psignal(p, SIGSTOP);
151 out:
152                 PROC_UNLOCK(p);
153                 sx_xunlock(&proctree_lock);
154                 return (error);
155         }
156
157         /*
158          * Authorization check: rely on normal debugging protection, except
159          * allow processes to disengage debugging on a process onto which
160          * they have previously attached, but no longer have permission to
161          * debug.
162          */
163         PROC_LOCK(p);
164         if (op != PROCFS_CTL_DETACH &&
165             ((error = p_candebug(td, p)))) {
166                 PROC_UNLOCK(p);
167                 return (error);
168         }
169
170         /*
171          * Target process must be stopped, owned by (td) and
172          * be set up for tracing (P_TRACED flag set).
173          * Allow DETACH to take place at any time for sanity.
174          * Allow WAIT any time, of course.
175          */
176         switch (op) {
177         case PROCFS_CTL_DETACH:
178         case PROCFS_CTL_WAIT:
179                 break;
180
181         default:
182                 if (!TRACE_WAIT_P(td->td_proc, p)) {
183                         PROC_UNLOCK(p);
184                         return (EBUSY);
185                 }
186         }
187
188
189 #ifdef FIX_SSTEP
190         /*
191          * do single-step fixup if needed
192          */
193         FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
194 #endif
195
196         /*
197          * Don't deliver any signal by default.
198          * To continue with a signal, just send
199          * the signal name to the ctl file
200          */
201         p->p_xstat = 0;
202
203         switch (op) {
204         /*
205          * Detach.  Cleans up the target process, reparent it if possible
206          * and set it running once more.
207          */
208         case PROCFS_CTL_DETACH:
209                 /* if not being traced, then this is a painless no-op */
210                 if ((p->p_flag & P_TRACED) == 0) {
211                         PROC_UNLOCK(p);
212                         return (0);
213                 }
214
215                 /* not being traced any more */
216                 p->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
217
218                 /* remove pending SIGTRAP, else the process will die */
219                 sigqueue_delete_proc(p, SIGTRAP);
220                 FOREACH_THREAD_IN_PROC(p, temp)
221                         temp->td_dbgflags &= ~TDB_SUSPEND;
222                 PROC_UNLOCK(p);
223
224                 /* give process back to original parent */
225                 sx_xlock(&proctree_lock);
226                 if (p->p_oppid != p->p_pptr->p_pid) {
227                         struct proc *pp;
228
229                         pp = pfind(p->p_oppid);
230                         PROC_LOCK(p);
231                         if (pp) {
232                                 PROC_UNLOCK(pp);
233                                 proc_reparent(p, pp);
234                         }
235                 } else
236                         PROC_LOCK(p);
237                 p->p_oppid = 0;
238                 p->p_flag &= ~P_WAITED; /* XXX ? */
239                 sx_xunlock(&proctree_lock);
240
241                 wakeup(td->td_proc);    /* XXX for CTL_WAIT below ? */
242
243                 break;
244
245         /*
246          * Step.  Let the target process execute a single instruction.
247          * What does it mean to single step a threaded program?
248          */
249         case PROCFS_CTL_STEP:
250                 error = proc_sstep(FIRST_THREAD_IN_PROC(p));
251                 if (error) {
252                         PROC_UNLOCK(p);
253                         return (error);
254                 }
255                 break;
256
257         /*
258          * Run.  Let the target process continue running until a breakpoint
259          * or some other trap.
260          */
261         case PROCFS_CTL_RUN:
262                 p->p_flag &= ~P_STOPPED_SIG;    /* this uses SIGSTOP */
263                 break;
264
265         /*
266          * Wait for the target process to stop.
267          * If the target is not being traced then just wait
268          * to enter
269          */
270         case PROCFS_CTL_WAIT:
271                 if (p->p_flag & P_TRACED) {
272                         while (error == 0 &&
273                                         (P_SHOULDSTOP(p)) &&
274                                         (p->p_flag & P_TRACED) &&
275                                         (p->p_pptr == td->td_proc))
276                                 error = msleep(p, &p->p_mtx,
277                                                 PWAIT|PCATCH, "procfsx", 0);
278                         if (error == 0 && !TRACE_WAIT_P(td->td_proc, p))
279                                 error = EBUSY;
280                 } else {
281                         while (error == 0 && P_SHOULDSTOP(p))
282                                 error = msleep(p, &p->p_mtx,
283                                                 PWAIT|PCATCH, "procfs", 0);
284                 }
285                 PROC_UNLOCK(p);
286                 return (error);
287         default:
288                 panic("procfs_control");
289         }
290
291         PROC_SLOCK(p);
292         thread_unsuspend(p); /* If it can run, let it do so. */
293         PROC_SUNLOCK(p);
294         PROC_UNLOCK(p);
295         return (0);
296 }
297
298 static struct namemap *
299 findname(struct namemap *nm, char *buf, int buflen)
300 {
301
302         for (; nm->nm_name; nm++)
303                 if (bcmp(buf, nm->nm_name, buflen+1) == 0)
304                         return (nm);
305
306         return (0);
307 }
308
309 int
310 procfs_doprocctl(PFS_FILL_ARGS)
311 {
312         int error;
313         struct namemap *nm;
314
315         if (uio == NULL || uio->uio_rw != UIO_WRITE)
316                 return (EOPNOTSUPP);
317
318         /*
319          * Map signal names into signal generation
320          * or debug control.  Unknown commands and/or signals
321          * return EOPNOTSUPP.
322          *
323          * Sending a signal while the process is being debugged
324          * also has the side effect of letting the target continue
325          * to run.  There is no way to single-step a signal delivery.
326          */
327         error = EOPNOTSUPP;
328
329         sbuf_trim(sb);
330         sbuf_finish(sb);
331         nm = findname(ctlnames, sbuf_data(sb), sbuf_len(sb));
332         if (nm) {
333                 printf("procfs: got a %s command\n", sbuf_data(sb));
334                 error = procfs_control(td, p, nm->nm_val);
335         } else {
336                 nm = findname(signames, sbuf_data(sb), sbuf_len(sb));
337                 if (nm) {
338                         printf("procfs: got a sig%s\n", sbuf_data(sb));
339                         PROC_LOCK(p);
340
341                         if (TRACE_WAIT_P(td->td_proc, p)) {
342                                 p->p_xstat = nm->nm_val;
343 #ifdef FIX_SSTEP
344                                 FIX_SSTEP(FIRST_THREAD_IN_PROC(p));
345 #endif
346                                 p->p_flag &= ~P_STOPPED_SIG;
347                                 PROC_SLOCK(p);
348                                 thread_unsuspend(p);
349                                 PROC_SUNLOCK(p);
350                         } else
351                                 kern_psignal(p, nm->nm_val);
352                         PROC_UNLOCK(p);
353                         error = 0;
354                 }
355         }
356
357         return (error);
358 }