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