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$
   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                 SIGDELSET(p->p_siglist, 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         mtx_lock_spin(&sched_lock);
  290         thread_unsuspend(p); /* If it can run, let it do so. */
  291         mtx_unlock_spin(&sched_lock);
  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                                 mtx_lock_spin(&sched_lock);
  348                                 thread_unsuspend(p);
  349                                 mtx_unlock_spin(&sched_lock);
  350                         } else
  351                                 psignal(p, nm->nm_val);
  352                         PROC_UNLOCK(p);
  353                         error = 0;
  354                 }
  355         }
  356 
  357         return (error);
  358 }

Cache object: cb25990ac48196cc46e783fcbd84f63a


[ 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.