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