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 71struct namemap { 72 const char *nm_name; 73 int nm_val; 74}; 75 76static 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 86static 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 107static int procfs_control(struct thread *td, struct proc *p, int op); 108 109static int 110procfs_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); 151out: 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 298static struct namemap * 299findname(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 309int 310procfs_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} 359