xref: /csrg-svn/sys/miscfs/procfs/procfs_ctl.c (revision 65521)
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