1*65521Spendry /* 2*65521Spendry * Copyright (c) 1993 The Regents of the University of California. 3*65521Spendry * Copyright (c) 1993 Jan-Simon Pendry 4*65521Spendry * All rights reserved. 5*65521Spendry * 6*65521Spendry * This code is derived from software contributed to Berkeley by 7*65521Spendry * Jan-Simon Pendry. 8*65521Spendry * 9*65521Spendry * %sccs.include.redist.c% 10*65521Spendry * 11*65521Spendry * @(#)procfs_ctl.c 8.1 (Berkeley) 01/05/94 12*65521Spendry * 13*65521Spendry * From: 14*65521Spendry * $Id: procfs_ctl.c,v 3.2 1993/12/15 09:40:17 jsp Exp $ 15*65521Spendry */ 16*65521Spendry 17*65521Spendry #include <sys/param.h> 18*65521Spendry #include <sys/systm.h> 19*65521Spendry #include <sys/time.h> 20*65521Spendry #include <sys/kernel.h> 21*65521Spendry #include <sys/proc.h> 22*65521Spendry #include <sys/vnode.h> 23*65521Spendry #include <sys/ioctl.h> 24*65521Spendry #include <sys/tty.h> 25*65521Spendry #include <sys/resource.h> 26*65521Spendry #include <sys/resourcevar.h> 27*65521Spendry #include <miscfs/procfs/procfs.h> 28*65521Spendry 29*65521Spendry /* 30*65521Spendry * True iff process (p) is in trace wait state 31*65521Spendry * relative to process (curp) 32*65521Spendry */ 33*65521Spendry #define TRACE_WAIT_P(curp, p) \ 34*65521Spendry ((p)->p_stat == SSTOP && \ 35*65521Spendry (p)->p_pptr == (curp) && \ 36*65521Spendry ((p)->p_flag & P_TRACED)) 37*65521Spendry 38*65521Spendry #ifdef notdef 39*65521Spendry #define FIX_SSTEP(p) { \ 40*65521Spendry procfs_fix_sstep(p); \ 41*65521Spendry } \ 42*65521Spendry } 43*65521Spendry #else 44*65521Spendry #define FIX_SSTEP(p) 45*65521Spendry #endif 46*65521Spendry 47*65521Spendry #define PROCFS_CTL_ATTACH 1 48*65521Spendry #define PROCFS_CTL_DETACH 2 49*65521Spendry #define PROCFS_CTL_STEP 3 50*65521Spendry #define PROCFS_CTL_RUN 4 51*65521Spendry #define PROCFS_CTL_WAIT 5 52*65521Spendry 53*65521Spendry static vfs_namemap_t ctlnames[] = { 54*65521Spendry /* special /proc commands */ 55*65521Spendry { "attach", PROCFS_CTL_ATTACH }, 56*65521Spendry { "detach", PROCFS_CTL_DETACH }, 57*65521Spendry { "step", PROCFS_CTL_STEP }, 58*65521Spendry { "run", PROCFS_CTL_RUN }, 59*65521Spendry { "wait", PROCFS_CTL_WAIT }, 60*65521Spendry { 0 }, 61*65521Spendry }; 62*65521Spendry 63*65521Spendry static vfs_namemap_t signames[] = { 64*65521Spendry /* regular signal names */ 65*65521Spendry { "hup", SIGHUP }, { "int", SIGINT }, 66*65521Spendry { "quit", SIGQUIT }, { "ill", SIGILL }, 67*65521Spendry { "trap", SIGTRAP }, { "abrt", SIGABRT }, 68*65521Spendry { "iot", SIGIOT }, { "emt", SIGEMT }, 69*65521Spendry { "fpe", SIGFPE }, { "kill", SIGKILL }, 70*65521Spendry { "bus", SIGBUS }, { "segv", SIGSEGV }, 71*65521Spendry { "sys", SIGSYS }, { "pipe", SIGPIPE }, 72*65521Spendry { "alrm", SIGALRM }, { "term", SIGTERM }, 73*65521Spendry { "urg", SIGURG }, { "stop", SIGSTOP }, 74*65521Spendry { "tstp", SIGTSTP }, { "cont", SIGCONT }, 75*65521Spendry { "chld", SIGCHLD }, { "ttin", SIGTTIN }, 76*65521Spendry { "ttou", SIGTTOU }, { "io", SIGIO }, 77*65521Spendry { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ }, 78*65521Spendry { "vtalrm", SIGVTALRM }, { "prof", SIGPROF }, 79*65521Spendry { "winch", SIGWINCH }, { "info", SIGINFO }, 80*65521Spendry { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 }, 81*65521Spendry { 0 }, 82*65521Spendry }; 83*65521Spendry 84*65521Spendry static int 85*65521Spendry procfs_control(curp, p, op) 86*65521Spendry struct proc *curp; 87*65521Spendry struct proc *p; 88*65521Spendry int op; 89*65521Spendry { 90*65521Spendry int error; 91*65521Spendry 92*65521Spendry /* 93*65521Spendry * Attach - attaches the target process for debugging 94*65521Spendry * by the calling process. 95*65521Spendry */ 96*65521Spendry if (op == PROCFS_CTL_ATTACH) { 97*65521Spendry /* check whether already being traced */ 98*65521Spendry if (p->p_flag & P_TRACED) 99*65521Spendry return (EBUSY); 100*65521Spendry 101*65521Spendry /* can't trace yourself! */ 102*65521Spendry if (p->p_pid == curp->p_pid) 103*65521Spendry return (EINVAL); 104*65521Spendry 105*65521Spendry /* 106*65521Spendry * Go ahead and set the trace flag. 107*65521Spendry * Save the old parent (it's reset in 108*65521Spendry * _DETACH, and also in kern_exit.c:wait4() 109*65521Spendry * Reparent the process so that the tracing 110*65521Spendry * proc gets to see all the action. 111*65521Spendry * Stop the target. 112*65521Spendry */ 113*65521Spendry p->p_flag |= P_TRACED; 114*65521Spendry p->p_xstat = 0; /* XXX ? */ 115*65521Spendry if (p->p_pptr != curp) { 116*65521Spendry p->p_oppid = p->p_pptr->p_pid; 117*65521Spendry proc_reparent(p, curp); 118*65521Spendry } 119*65521Spendry psignal(p, SIGSTOP); 120*65521Spendry return (0); 121*65521Spendry } 122*65521Spendry 123*65521Spendry /* 124*65521Spendry * Target process must be stopped, owned by (curp) and 125*65521Spendry * be set up for tracing (P_TRACED flag set). 126*65521Spendry * Allow DETACH to take place at any time for sanity. 127*65521Spendry * Allow WAIT any time, of course. 128*65521Spendry */ 129*65521Spendry switch (op) { 130*65521Spendry case PROCFS_CTL_DETACH: 131*65521Spendry case PROCFS_CTL_WAIT: 132*65521Spendry break; 133*65521Spendry 134*65521Spendry default: 135*65521Spendry if (!TRACE_WAIT_P(curp, p)) 136*65521Spendry return (EBUSY); 137*65521Spendry } 138*65521Spendry 139*65521Spendry /* 140*65521Spendry * do single-step fixup if needed 141*65521Spendry */ 142*65521Spendry FIX_SSTEP(p); 143*65521Spendry 144*65521Spendry /* 145*65521Spendry * Don't deliver any signal by default. 146*65521Spendry * To continue with a signal, just send 147*65521Spendry * the signal name to the ctl file 148*65521Spendry */ 149*65521Spendry p->p_xstat = 0; 150*65521Spendry 151*65521Spendry switch (op) { 152*65521Spendry /* 153*65521Spendry * Detach. Cleans up the target process, reparent it if possible 154*65521Spendry * and set it running once more. 155*65521Spendry */ 156*65521Spendry case PROCFS_CTL_DETACH: 157*65521Spendry /* if not being traced, then this is a painless no-op */ 158*65521Spendry if ((p->p_flag & P_TRACED) == 0) 159*65521Spendry return (0); 160*65521Spendry 161*65521Spendry /* not being traced any more */ 162*65521Spendry p->p_flag &= ~P_TRACED; 163*65521Spendry 164*65521Spendry /* give process back to original parent */ 165*65521Spendry if (p->p_oppid != p->p_pptr->p_pid) { 166*65521Spendry struct proc *pp; 167*65521Spendry 168*65521Spendry pp = pfind(p->p_oppid); 169*65521Spendry if (pp) 170*65521Spendry proc_reparent(p, pp); 171*65521Spendry } 172*65521Spendry 173*65521Spendry p->p_oppid = 0; 174*65521Spendry p->p_flag &= ~P_WAITED; /* XXX ? */ 175*65521Spendry wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */ 176*65521Spendry 177*65521Spendry break; 178*65521Spendry 179*65521Spendry /* 180*65521Spendry * Step. Let the target process execute a single instruction. 181*65521Spendry */ 182*65521Spendry case PROCFS_CTL_STEP: 183*65521Spendry procfs_sstep(p); 184*65521Spendry break; 185*65521Spendry 186*65521Spendry /* 187*65521Spendry * Run. Let the target process continue running until a breakpoint 188*65521Spendry * or some other trap. 189*65521Spendry */ 190*65521Spendry case PROCFS_CTL_RUN: 191*65521Spendry break; 192*65521Spendry 193*65521Spendry /* 194*65521Spendry * Wait for the target process to stop. 195*65521Spendry * If the target is not being traced then just wait 196*65521Spendry * to enter 197*65521Spendry */ 198*65521Spendry case PROCFS_CTL_WAIT: 199*65521Spendry error = 0; 200*65521Spendry if (p->p_flag & P_TRACED) { 201*65521Spendry while (error == 0 && 202*65521Spendry (p->p_stat != SSTOP) && 203*65521Spendry (p->p_flag & P_TRACED) && 204*65521Spendry (p->p_pptr == curp)) { 205*65521Spendry error = tsleep((caddr_t) p, 206*65521Spendry PWAIT|PCATCH, "procfsx", 0); 207*65521Spendry } 208*65521Spendry if (error == 0 && !TRACE_WAIT_P(curp, p)) 209*65521Spendry error = EBUSY; 210*65521Spendry } else { 211*65521Spendry while (error == 0 && p->p_stat != SSTOP) { 212*65521Spendry error = tsleep((caddr_t) p, 213*65521Spendry PWAIT|PCATCH, "procfs", 0); 214*65521Spendry } 215*65521Spendry } 216*65521Spendry return (error); 217*65521Spendry 218*65521Spendry default: 219*65521Spendry panic("procfs_control"); 220*65521Spendry } 221*65521Spendry 222*65521Spendry if (p->p_stat == SSTOP) 223*65521Spendry setrunnable(p); 224*65521Spendry return (0); 225*65521Spendry } 226*65521Spendry 227*65521Spendry int 228*65521Spendry procfs_doctl(curp, p, pfs, uio) 229*65521Spendry struct proc *curp; 230*65521Spendry struct pfsnode *pfs; 231*65521Spendry struct uio *uio; 232*65521Spendry struct proc *p; 233*65521Spendry { 234*65521Spendry int len = uio->uio_resid; 235*65521Spendry int xlen; 236*65521Spendry int error; 237*65521Spendry struct sigmap *sm; 238*65521Spendry char msg[PROCFS_CTLLEN+1]; 239*65521Spendry char *cp = msg; 240*65521Spendry vfs_namemap_t *nm; 241*65521Spendry 242*65521Spendry if (uio->uio_rw != UIO_WRITE) 243*65521Spendry return (EOPNOTSUPP); 244*65521Spendry 245*65521Spendry xlen = PROCFS_CTLLEN; 246*65521Spendry error = vfs_getuserstr(uio, msg, &xlen); 247*65521Spendry if (error) 248*65521Spendry return (error); 249*65521Spendry 250*65521Spendry /* 251*65521Spendry * Map signal names into signal generation 252*65521Spendry * or debug control. Unknown commands and/or signals 253*65521Spendry * return EOPNOTSUPP. 254*65521Spendry * 255*65521Spendry * Sending a signal while the process is being debugged 256*65521Spendry * also has the side effect of letting the target continue 257*65521Spendry * to run. There is no way to single-step a signal delivery. 258*65521Spendry */ 259*65521Spendry error = EOPNOTSUPP; 260*65521Spendry 261*65521Spendry nm = vfs_findname(ctlnames, msg, xlen); 262*65521Spendry if (nm) { 263*65521Spendry error = procfs_control(curp, p, nm->nm_val); 264*65521Spendry } else { 265*65521Spendry nm = vfs_findname(signames, msg, xlen); 266*65521Spendry if (nm) { 267*65521Spendry if (TRACE_WAIT_P(curp, p)) { 268*65521Spendry p->p_xstat = nm->nm_val; 269*65521Spendry FIX_SSTEP(p); 270*65521Spendry setrunnable(p); 271*65521Spendry } else { 272*65521Spendry psignal(p, nm->nm_val); 273*65521Spendry } 274*65521Spendry error = 0; 275*65521Spendry } 276*65521Spendry } 277*65521Spendry 278*65521Spendry return (error); 279*65521Spendry } 280