The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/procfs/procfs_ctl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/8.4/sys/fs/procfs/procfs_ctl.c 208186 2010-05-17 08:15:04Z kib $
   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                 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                                 psignal(p, nm->nm_val);
  352                         PROC_UNLOCK(p);
  353                         error = 0;
  354                 }
  355         }
  356 
  357         return (error);
  358 }

Cache object: 2085f32a031db984aa9d8e7c3a0dcf57


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.