xref: /openbsd/sys/dev/dt/dt_dev.c (revision 91b2ecf6)
1*91b2ecf6Smpi /*	$OpenBSD: dt_dev.c,v 1.1 2020/01/21 16:16:23 mpi Exp $ */
2*91b2ecf6Smpi 
3*91b2ecf6Smpi /*
4*91b2ecf6Smpi  * Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
5*91b2ecf6Smpi  *
6*91b2ecf6Smpi  * Permission to use, copy, modify, and distribute this software for any
7*91b2ecf6Smpi  * purpose with or without fee is hereby granted, provided that the above
8*91b2ecf6Smpi  * copyright notice and this permission notice appear in all copies.
9*91b2ecf6Smpi  *
10*91b2ecf6Smpi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*91b2ecf6Smpi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*91b2ecf6Smpi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*91b2ecf6Smpi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*91b2ecf6Smpi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*91b2ecf6Smpi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*91b2ecf6Smpi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*91b2ecf6Smpi  */
18*91b2ecf6Smpi 
19*91b2ecf6Smpi #include <sys/types.h>
20*91b2ecf6Smpi #include <sys/systm.h>
21*91b2ecf6Smpi #include <sys/param.h>
22*91b2ecf6Smpi #include <sys/device.h>
23*91b2ecf6Smpi #include <sys/malloc.h>
24*91b2ecf6Smpi #include <sys/proc.h>
25*91b2ecf6Smpi 
26*91b2ecf6Smpi #include <dev/dt/dtvar.h>
27*91b2ecf6Smpi 
28*91b2ecf6Smpi /*
29*91b2ecf6Smpi  * How many frames are used by the profiling code?  For example
30*91b2ecf6Smpi  * on amd64:
31*91b2ecf6Smpi  *
32*91b2ecf6Smpi  * From syscall provider:
33*91b2ecf6Smpi  *
34*91b2ecf6Smpi  *	dt_prov_syscall_entry+0x141
35*91b2ecf6Smpi  *	syscall+0x205		<--- start here
36*91b2ecf6Smpi  *	Xsyscall+0x128
37*91b2ecf6Smpi  *
38*91b2ecf6Smpi  * From profile provider:
39*91b2ecf6Smpi  *
40*91b2ecf6Smpi  *	dt_prov_profile_enter+0x6e
41*91b2ecf6Smpi  *	hardclock+0x12c
42*91b2ecf6Smpi  *	clockintr+0x59
43*91b2ecf6Smpi  *	intr_handler+0x6e
44*91b2ecf6Smpi  *	Xresume_legacy0+0x1d3
45*91b2ecf6Smpi  *	cpu_idle_cycle+0x1b	<---- start here.
46*91b2ecf6Smpi  *	proc_trampoline+0x1c
47*91b2ecf6Smpi  */
48*91b2ecf6Smpi #if notyet
49*91b2ecf6Smpi #define DT_HOOK_FRAME_ADDRESS	__builtin_frame_address(4)
50*91b2ecf6Smpi #else
51*91b2ecf6Smpi #define DT_HOOK_FRAME_ADDRESS	__builtin_frame_address(0)
52*91b2ecf6Smpi #endif
53*91b2ecf6Smpi 
54*91b2ecf6Smpi #define DT_EVTRING_SIZE	16	/* # of slots in per PCB event ring */
55*91b2ecf6Smpi 
56*91b2ecf6Smpi #define DPRINTF(x...) /* nothing */
57*91b2ecf6Smpi 
58*91b2ecf6Smpi /*
59*91b2ecf6Smpi  * Descriptor associated with each program opening /dev/dt.  It is used
60*91b2ecf6Smpi  * to keep track of enabled PCBs.
61*91b2ecf6Smpi  *
62*91b2ecf6Smpi  *  Locks used to protect struct members in this file:
63*91b2ecf6Smpi  *	m	per-softc mutex
64*91b2ecf6Smpi  *	k	kernel lock
65*91b2ecf6Smpi  */
66*91b2ecf6Smpi struct dt_softc {
67*91b2ecf6Smpi 	SLIST_ENTRY(dt_softc)	 ds_next;	/* [k] descriptor list */
68*91b2ecf6Smpi 	int			 ds_unit;	/* [I] D_CLONE unique unit */
69*91b2ecf6Smpi 	pid_t			 ds_pid;	/* [I] PID of tracing program */
70*91b2ecf6Smpi 
71*91b2ecf6Smpi 	struct mutex		 ds_mtx;
72*91b2ecf6Smpi 
73*91b2ecf6Smpi 	struct dt_pcb_list	 ds_pcbs;	/* [k] list of enabled PCBs */
74*91b2ecf6Smpi 	struct dt_evt		*ds_bufqueue;	/* [k] copy evts to userland */
75*91b2ecf6Smpi 	size_t			 ds_bufqlen;	/* [k] length of the queue */
76*91b2ecf6Smpi 	int			 ds_recording;	/* [k] currently recording? */
77*91b2ecf6Smpi 	int			 ds_evtcnt;	/* [m] # of readable evts */
78*91b2ecf6Smpi 
79*91b2ecf6Smpi 	/* Counters */
80*91b2ecf6Smpi 	uint64_t		 ds_readevt;	/* [m] # of events read */
81*91b2ecf6Smpi 	uint64_t		 ds_dropevt;	/* [m] # of events dropped */
82*91b2ecf6Smpi };
83*91b2ecf6Smpi 
84*91b2ecf6Smpi SLIST_HEAD(, dt_softc) dtdev_list;	/* [k] list of open /dev/dt nodes */
85*91b2ecf6Smpi 
86*91b2ecf6Smpi /*
87*91b2ecf6Smpi  * Probes are created during dt_attach() and never modified/freed during
88*91b2ecf6Smpi  * the lifetime of the system.  That's why we consider them as [I]mmutable.
89*91b2ecf6Smpi  */
90*91b2ecf6Smpi unsigned int			dt_nprobes;	/* [I] # of probes available */
91*91b2ecf6Smpi SIMPLEQ_HEAD(, dt_probe)	dt_probe_list;	/* [I] list of probes */
92*91b2ecf6Smpi 
93*91b2ecf6Smpi struct rwlock			dt_lock = RWLOCK_INITIALIZER("dtlk");
94*91b2ecf6Smpi volatile uint32_t		dt_tracing = 0;	/* [d] # of processes tracing */
95*91b2ecf6Smpi 
96*91b2ecf6Smpi void	dtattach(struct device *, struct device *, void *);
97*91b2ecf6Smpi int	dtopen(dev_t, int, int, struct proc *);
98*91b2ecf6Smpi int	dtclose(dev_t, int, int, struct proc *);
99*91b2ecf6Smpi int	dtread(dev_t, struct uio *, int);
100*91b2ecf6Smpi int	dtioctl(dev_t, u_long, caddr_t, int, struct proc *);
101*91b2ecf6Smpi 
102*91b2ecf6Smpi struct	dt_softc *dtlookup(int);
103*91b2ecf6Smpi 
104*91b2ecf6Smpi int	dt_ioctl_list_probes(struct dt_softc *, struct dtioc_probe *);
105*91b2ecf6Smpi int	dt_ioctl_get_stats(struct dt_softc *, struct dtioc_stat *);
106*91b2ecf6Smpi int	dt_ioctl_record_start(struct dt_softc *);
107*91b2ecf6Smpi void	dt_ioctl_record_stop(struct dt_softc *);
108*91b2ecf6Smpi int	dt_ioctl_probe_enable(struct dt_softc *, struct dtioc_req *);
109*91b2ecf6Smpi void	dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *);
110*91b2ecf6Smpi 
111*91b2ecf6Smpi int	dt_enter(void);
112*91b2ecf6Smpi void	dt_leave(uint32_t);
113*91b2ecf6Smpi 
114*91b2ecf6Smpi int	dt_pcb_ring_copy(struct dt_pcb *, struct dt_evt *, size_t, uint64_t *);
115*91b2ecf6Smpi 
116*91b2ecf6Smpi void
117*91b2ecf6Smpi dtattach(struct device *parent, struct device *self, void *aux)
118*91b2ecf6Smpi {
119*91b2ecf6Smpi 	SLIST_INIT(&dtdev_list);
120*91b2ecf6Smpi 	SIMPLEQ_INIT(&dt_probe_list);
121*91b2ecf6Smpi 
122*91b2ecf6Smpi 	/* Init providers */
123*91b2ecf6Smpi 	dt_nprobes += dt_prov_profile_init();
124*91b2ecf6Smpi 	dt_nprobes += dt_prov_syscall_init();
125*91b2ecf6Smpi 	dt_nprobes += dt_prov_static_init();
126*91b2ecf6Smpi 
127*91b2ecf6Smpi 	printf("dt: %u probes\n", dt_nprobes);
128*91b2ecf6Smpi }
129*91b2ecf6Smpi 
130*91b2ecf6Smpi int
131*91b2ecf6Smpi dtopen(dev_t dev, int flags, int mode, struct proc *p)
132*91b2ecf6Smpi {
133*91b2ecf6Smpi 	struct dt_softc *sc;
134*91b2ecf6Smpi 	int unit = minor(dev);
135*91b2ecf6Smpi 
136*91b2ecf6Smpi 	KASSERT(dtlookup(unit) == NULL);
137*91b2ecf6Smpi 
138*91b2ecf6Smpi 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
139*91b2ecf6Smpi 	if (sc == NULL)
140*91b2ecf6Smpi 		return ENOMEM;
141*91b2ecf6Smpi 
142*91b2ecf6Smpi 	/*
143*91b2ecf6Smpi 	 * Enough space to empty 2 full rings of events in a single read.
144*91b2ecf6Smpi 	 */
145*91b2ecf6Smpi 	sc->ds_bufqlen = 2 * DT_EVTRING_SIZE;
146*91b2ecf6Smpi 	sc->ds_bufqueue = mallocarray(sc->ds_bufqlen, sizeof(*sc->ds_bufqueue),
147*91b2ecf6Smpi 	    M_DEVBUF, M_WAITOK|M_CANFAIL);
148*91b2ecf6Smpi 	if (sc->ds_bufqueue == NULL)
149*91b2ecf6Smpi 		goto bad;
150*91b2ecf6Smpi 
151*91b2ecf6Smpi 	sc->ds_unit = unit;
152*91b2ecf6Smpi 	sc->ds_pid = p->p_p->ps_pid;
153*91b2ecf6Smpi 	TAILQ_INIT(&sc->ds_pcbs);
154*91b2ecf6Smpi 	mtx_init(&sc->ds_mtx, IPL_HIGH);
155*91b2ecf6Smpi 	sc->ds_evtcnt = 0;
156*91b2ecf6Smpi 	sc->ds_readevt = 0;
157*91b2ecf6Smpi 	sc->ds_dropevt = 0;
158*91b2ecf6Smpi 
159*91b2ecf6Smpi 	SLIST_INSERT_HEAD(&dtdev_list, sc, ds_next);
160*91b2ecf6Smpi 
161*91b2ecf6Smpi 	DPRINTF("dt%d: pid %d open\n", sc->ds_unit, sc->ds_pid);
162*91b2ecf6Smpi 
163*91b2ecf6Smpi 	return 0;
164*91b2ecf6Smpi 
165*91b2ecf6Smpi bad:
166*91b2ecf6Smpi 	free(sc, M_DEVBUF, sizeof(*sc));
167*91b2ecf6Smpi 	return ENOMEM;
168*91b2ecf6Smpi }
169*91b2ecf6Smpi 
170*91b2ecf6Smpi int
171*91b2ecf6Smpi dtclose(dev_t dev, int flags, int mode, struct proc *p)
172*91b2ecf6Smpi {
173*91b2ecf6Smpi 	struct dt_softc *sc;
174*91b2ecf6Smpi 	int unit = minor(dev);
175*91b2ecf6Smpi 
176*91b2ecf6Smpi 	sc = dtlookup(unit);
177*91b2ecf6Smpi 	KASSERT(sc != NULL);
178*91b2ecf6Smpi 
179*91b2ecf6Smpi 	DPRINTF("dt%d: pid %d close\n", sc->ds_unit, sc->ds_pid);
180*91b2ecf6Smpi 
181*91b2ecf6Smpi 	SLIST_REMOVE(&dtdev_list, sc, dt_softc, ds_next);
182*91b2ecf6Smpi 	dt_ioctl_record_stop(sc);
183*91b2ecf6Smpi 	dt_pcb_purge(&sc->ds_pcbs);
184*91b2ecf6Smpi 
185*91b2ecf6Smpi 	free(sc->ds_bufqueue, M_DEVBUF,
186*91b2ecf6Smpi 	    sc->ds_bufqlen * sizeof(*sc->ds_bufqueue));
187*91b2ecf6Smpi 	free(sc, M_DEVBUF, sizeof(*sc));
188*91b2ecf6Smpi 
189*91b2ecf6Smpi 	return 0;
190*91b2ecf6Smpi }
191*91b2ecf6Smpi 
192*91b2ecf6Smpi int
193*91b2ecf6Smpi dtread(dev_t dev, struct uio *uio, int flags)
194*91b2ecf6Smpi {
195*91b2ecf6Smpi 	struct dt_softc *sc;
196*91b2ecf6Smpi 	struct dt_evt *estq;
197*91b2ecf6Smpi 	struct dt_pcb *dp;
198*91b2ecf6Smpi 	int error, unit = minor(dev);
199*91b2ecf6Smpi 	size_t qlen, count, read = 0;
200*91b2ecf6Smpi 	uint64_t dropped = 0;
201*91b2ecf6Smpi 
202*91b2ecf6Smpi 	sc = dtlookup(unit);
203*91b2ecf6Smpi 	KASSERT(sc != NULL);
204*91b2ecf6Smpi 
205*91b2ecf6Smpi 	count = howmany(uio->uio_resid, sizeof(struct dt_evt));
206*91b2ecf6Smpi 	if (count < 1)
207*91b2ecf6Smpi 		return (EMSGSIZE);
208*91b2ecf6Smpi 
209*91b2ecf6Smpi 	mtx_enter(&sc->ds_mtx);
210*91b2ecf6Smpi 	while (!sc->ds_evtcnt) {
211*91b2ecf6Smpi 		error = msleep(sc, &sc->ds_mtx, PWAIT|PCATCH, "dtread", 0);
212*91b2ecf6Smpi 		if (error == EINTR || error == ERESTART)
213*91b2ecf6Smpi 			break;
214*91b2ecf6Smpi 	}
215*91b2ecf6Smpi 	mtx_leave(&sc->ds_mtx);
216*91b2ecf6Smpi 
217*91b2ecf6Smpi 	if (error)
218*91b2ecf6Smpi 		return error;
219*91b2ecf6Smpi 
220*91b2ecf6Smpi 	estq = sc->ds_bufqueue;
221*91b2ecf6Smpi 	qlen = MIN(sc->ds_bufqlen, count);
222*91b2ecf6Smpi 
223*91b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
224*91b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
225*91b2ecf6Smpi 		count = dt_pcb_ring_copy(dp, estq, qlen, &dropped);
226*91b2ecf6Smpi 		read += count;
227*91b2ecf6Smpi 		estq += count; /* pointer aritmetic */
228*91b2ecf6Smpi 		qlen -= count;
229*91b2ecf6Smpi 		if (qlen == 0)
230*91b2ecf6Smpi 			break;
231*91b2ecf6Smpi 	}
232*91b2ecf6Smpi 	if (read > 0)
233*91b2ecf6Smpi 		uiomove(sc->ds_bufqueue, read * sizeof(struct dt_evt), uio);
234*91b2ecf6Smpi 
235*91b2ecf6Smpi 	mtx_enter(&sc->ds_mtx);
236*91b2ecf6Smpi 	sc->ds_evtcnt -= read;
237*91b2ecf6Smpi 	sc->ds_readevt += read;
238*91b2ecf6Smpi 	sc->ds_dropevt += dropped;
239*91b2ecf6Smpi 	mtx_leave(&sc->ds_mtx);
240*91b2ecf6Smpi 
241*91b2ecf6Smpi 	return 0;
242*91b2ecf6Smpi }
243*91b2ecf6Smpi 
244*91b2ecf6Smpi int
245*91b2ecf6Smpi dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
246*91b2ecf6Smpi {
247*91b2ecf6Smpi 	struct dt_softc *sc;
248*91b2ecf6Smpi 	int unit = minor(dev);
249*91b2ecf6Smpi 	int on, error = 0;
250*91b2ecf6Smpi 
251*91b2ecf6Smpi 	sc = dtlookup(unit);
252*91b2ecf6Smpi 	KASSERT(sc != NULL);
253*91b2ecf6Smpi 
254*91b2ecf6Smpi 	switch (cmd) {
255*91b2ecf6Smpi 	case DTIOCGPLIST:
256*91b2ecf6Smpi 		return dt_ioctl_list_probes(sc, (struct dtioc_probe *)addr);
257*91b2ecf6Smpi 	case DTIOCGSTATS:
258*91b2ecf6Smpi 		return dt_ioctl_get_stats(sc, (struct dtioc_stat *)addr);
259*91b2ecf6Smpi 	case DTIOCRECORD:
260*91b2ecf6Smpi 	case DTIOCPRBENABLE:
261*91b2ecf6Smpi 		/* root only ioctl(2) */
262*91b2ecf6Smpi 		break;
263*91b2ecf6Smpi 	default:
264*91b2ecf6Smpi 		return ENOTTY;
265*91b2ecf6Smpi 	}
266*91b2ecf6Smpi 
267*91b2ecf6Smpi 	if ((error = suser(p)) != 0)
268*91b2ecf6Smpi 		return error;
269*91b2ecf6Smpi 
270*91b2ecf6Smpi 	switch (cmd) {
271*91b2ecf6Smpi 	case DTIOCRECORD:
272*91b2ecf6Smpi 		on = *(int *)addr;
273*91b2ecf6Smpi 		if (on)
274*91b2ecf6Smpi 			error = dt_ioctl_record_start(sc);
275*91b2ecf6Smpi 		else
276*91b2ecf6Smpi 			dt_ioctl_record_stop(sc);
277*91b2ecf6Smpi 		break;
278*91b2ecf6Smpi 	case DTIOCPRBENABLE:
279*91b2ecf6Smpi 		error = dt_ioctl_probe_enable(sc, (struct dtioc_req *)addr);
280*91b2ecf6Smpi 		break;
281*91b2ecf6Smpi 	default:
282*91b2ecf6Smpi 		KASSERT(0);
283*91b2ecf6Smpi 	}
284*91b2ecf6Smpi 
285*91b2ecf6Smpi 	return error;
286*91b2ecf6Smpi }
287*91b2ecf6Smpi 
288*91b2ecf6Smpi struct dt_softc *
289*91b2ecf6Smpi dtlookup(int unit)
290*91b2ecf6Smpi {
291*91b2ecf6Smpi 	struct dt_softc *sc;
292*91b2ecf6Smpi 
293*91b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
294*91b2ecf6Smpi 
295*91b2ecf6Smpi 	SLIST_FOREACH(sc, &dtdev_list, ds_next) {
296*91b2ecf6Smpi 		if (sc->ds_unit == unit)
297*91b2ecf6Smpi 			break;
298*91b2ecf6Smpi 	}
299*91b2ecf6Smpi 
300*91b2ecf6Smpi 	return sc;
301*91b2ecf6Smpi }
302*91b2ecf6Smpi 
303*91b2ecf6Smpi int
304*91b2ecf6Smpi dtioc_req_isvalid(struct dtioc_req *dtrq)
305*91b2ecf6Smpi {
306*91b2ecf6Smpi 	switch (dtrq->dtrq_filter.dtf_operand) {
307*91b2ecf6Smpi 	case DT_OP_NONE:
308*91b2ecf6Smpi 	case DT_OP_EQ:
309*91b2ecf6Smpi 	case DT_OP_NE:
310*91b2ecf6Smpi 		break;
311*91b2ecf6Smpi 	default:
312*91b2ecf6Smpi 		return 0;
313*91b2ecf6Smpi 	}
314*91b2ecf6Smpi 
315*91b2ecf6Smpi 	switch (dtrq->dtrq_filter.dtf_variable) {
316*91b2ecf6Smpi 	case DT_FV_NONE:
317*91b2ecf6Smpi 	case DT_FV_PID:
318*91b2ecf6Smpi 	case DT_FV_TID:
319*91b2ecf6Smpi 		break;
320*91b2ecf6Smpi 	default:
321*91b2ecf6Smpi 		return 0;
322*91b2ecf6Smpi 	}
323*91b2ecf6Smpi 
324*91b2ecf6Smpi 	return 1;
325*91b2ecf6Smpi }
326*91b2ecf6Smpi 
327*91b2ecf6Smpi int
328*91b2ecf6Smpi dt_ioctl_list_probes(struct dt_softc *sc, struct dtioc_probe *dtpr)
329*91b2ecf6Smpi {
330*91b2ecf6Smpi 	struct dtioc_probe_info info, *dtpi;
331*91b2ecf6Smpi 	struct dt_probe *dtp;
332*91b2ecf6Smpi 	size_t size;
333*91b2ecf6Smpi 	int error = 0;
334*91b2ecf6Smpi 
335*91b2ecf6Smpi 	if (dtpr->dtpr_size == 0) {
336*91b2ecf6Smpi 		dtpr->dtpr_size = dt_nprobes * sizeof(*dtpi);
337*91b2ecf6Smpi 		return 0;
338*91b2ecf6Smpi 	}
339*91b2ecf6Smpi 
340*91b2ecf6Smpi 	size = dtpr->dtpr_size;
341*91b2ecf6Smpi 	dtpi = dtpr->dtpr_probes;
342*91b2ecf6Smpi 	memset(&info, 0, sizeof(info));
343*91b2ecf6Smpi 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
344*91b2ecf6Smpi 		if (size < sizeof(*dtpi)) {
345*91b2ecf6Smpi 			error = ENOSPC;
346*91b2ecf6Smpi 			break;
347*91b2ecf6Smpi 		}
348*91b2ecf6Smpi 		info.dtpi_pbn = dtp->dtp_pbn;
349*91b2ecf6Smpi 		strlcpy(info.dtpi_prov, dtp->dtp_prov->dtpv_name,
350*91b2ecf6Smpi 		    sizeof(info.dtpi_prov));
351*91b2ecf6Smpi 		strlcpy(info.dtpi_func, dtp->dtp_func, sizeof(info.dtpi_func));
352*91b2ecf6Smpi 		strlcpy(info.dtpi_name, dtp->dtp_name, sizeof(info.dtpi_name));
353*91b2ecf6Smpi 		error = copyout(&info, dtpi, sizeof(*dtpi));
354*91b2ecf6Smpi 		if (error)
355*91b2ecf6Smpi 			break;
356*91b2ecf6Smpi 		size -= sizeof(*dtpi);
357*91b2ecf6Smpi 		dtpi++;
358*91b2ecf6Smpi 	};
359*91b2ecf6Smpi 
360*91b2ecf6Smpi 	return error;
361*91b2ecf6Smpi }
362*91b2ecf6Smpi 
363*91b2ecf6Smpi int
364*91b2ecf6Smpi dt_ioctl_get_stats(struct dt_softc *sc, struct dtioc_stat *dtst)
365*91b2ecf6Smpi {
366*91b2ecf6Smpi 	mtx_enter(&sc->ds_mtx);
367*91b2ecf6Smpi 	dtst->dtst_readevt = sc->ds_readevt;
368*91b2ecf6Smpi 	dtst->dtst_dropevt = sc->ds_dropevt;
369*91b2ecf6Smpi 	mtx_leave(&sc->ds_mtx);
370*91b2ecf6Smpi 
371*91b2ecf6Smpi 	return 0;
372*91b2ecf6Smpi }
373*91b2ecf6Smpi 
374*91b2ecf6Smpi int
375*91b2ecf6Smpi dt_ioctl_record_start(struct dt_softc *sc)
376*91b2ecf6Smpi {
377*91b2ecf6Smpi 	struct dt_pcb *dp;
378*91b2ecf6Smpi 	int count;
379*91b2ecf6Smpi 
380*91b2ecf6Smpi 	if (sc->ds_recording)
381*91b2ecf6Smpi 		return EBUSY;
382*91b2ecf6Smpi 
383*91b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
384*91b2ecf6Smpi  	if (TAILQ_EMPTY(&sc->ds_pcbs))
385*91b2ecf6Smpi 		return ENOENT;
386*91b2ecf6Smpi 
387*91b2ecf6Smpi 	count = dt_enter();
388*91b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
389*91b2ecf6Smpi 		struct dt_probe *dtp = dp->dp_dtp;
390*91b2ecf6Smpi 
391*91b2ecf6Smpi 		rw_assert_wrlock(&dt_lock);
392*91b2ecf6Smpi 		SMR_SLIST_INSERT_HEAD_LOCKED(&dtp->dtp_pcbs, dp, dp_pnext);
393*91b2ecf6Smpi 		dtp->dtp_recording++;
394*91b2ecf6Smpi 		dtp->dtp_prov->dtpv_recording++;
395*91b2ecf6Smpi 	}
396*91b2ecf6Smpi 	dt_leave(count);
397*91b2ecf6Smpi 
398*91b2ecf6Smpi 	sc->ds_recording = 1;
399*91b2ecf6Smpi 	dt_tracing++;
400*91b2ecf6Smpi 
401*91b2ecf6Smpi 	return 0;
402*91b2ecf6Smpi }
403*91b2ecf6Smpi 
404*91b2ecf6Smpi void
405*91b2ecf6Smpi dt_ioctl_record_stop(struct dt_softc *sc)
406*91b2ecf6Smpi {
407*91b2ecf6Smpi 	struct dt_pcb *dp;
408*91b2ecf6Smpi 	int count;
409*91b2ecf6Smpi 
410*91b2ecf6Smpi 	KASSERT(suser(curproc) == 0);
411*91b2ecf6Smpi 
412*91b2ecf6Smpi 	if (!sc->ds_recording)
413*91b2ecf6Smpi 		return;
414*91b2ecf6Smpi 
415*91b2ecf6Smpi 	DPRINTF("dt%d: pid %d disable\n", sc->ds_unit, sc->ds_pid);
416*91b2ecf6Smpi 
417*91b2ecf6Smpi 	dt_tracing--;
418*91b2ecf6Smpi 	sc->ds_recording = 0;
419*91b2ecf6Smpi 
420*91b2ecf6Smpi 	count = dt_enter();
421*91b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
422*91b2ecf6Smpi 		struct dt_probe *dtp = dp->dp_dtp;
423*91b2ecf6Smpi 
424*91b2ecf6Smpi 		rw_assert_wrlock(&dt_lock);
425*91b2ecf6Smpi 		dtp->dtp_recording--;
426*91b2ecf6Smpi 		dtp->dtp_prov->dtpv_recording--;
427*91b2ecf6Smpi 		SMR_SLIST_REMOVE_LOCKED(&dtp->dtp_pcbs, dp, dt_pcb, dp_pnext);
428*91b2ecf6Smpi 	}
429*91b2ecf6Smpi 	dt_leave(count);
430*91b2ecf6Smpi }
431*91b2ecf6Smpi 
432*91b2ecf6Smpi int
433*91b2ecf6Smpi dt_ioctl_probe_enable(struct dt_softc *sc, struct dtioc_req *dtrq)
434*91b2ecf6Smpi {
435*91b2ecf6Smpi 	struct dt_pcb_list plist;
436*91b2ecf6Smpi 	struct dt_probe *dtp;
437*91b2ecf6Smpi 	struct dt_pcb *dp;
438*91b2ecf6Smpi 	int error;
439*91b2ecf6Smpi 
440*91b2ecf6Smpi 	KASSERT(suser(curproc) == 0);
441*91b2ecf6Smpi 
442*91b2ecf6Smpi 	if (!dtioc_req_isvalid(dtrq))
443*91b2ecf6Smpi 		return EINVAL;
444*91b2ecf6Smpi 
445*91b2ecf6Smpi 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
446*91b2ecf6Smpi 		if (dtp->dtp_pbn == dtrq->dtrq_pbn)
447*91b2ecf6Smpi 			break;
448*91b2ecf6Smpi 	}
449*91b2ecf6Smpi 	if (dtp == NULL)
450*91b2ecf6Smpi 		return ENOENT;
451*91b2ecf6Smpi 
452*91b2ecf6Smpi 	TAILQ_INIT(&plist);
453*91b2ecf6Smpi 	error = dtp->dtp_prov->dtpv_alloc(dtp, sc, &plist, dtrq);
454*91b2ecf6Smpi 	if (error)
455*91b2ecf6Smpi 		return error;
456*91b2ecf6Smpi 
457*91b2ecf6Smpi 	DPRINTF("dt%d: pid %d enable %u : %b\n", sc->ds_unit, sc->ds_pid,
458*91b2ecf6Smpi 	    dtrq->dtrq_pbn, (unsigned int)dtrq->dtrq_evtflags, DTEVT_FLAG_BITS);
459*91b2ecf6Smpi 
460*91b2ecf6Smpi 	/* Append all PCBs to this instance */
461*91b2ecf6Smpi 	while ((dp = TAILQ_FIRST(&plist)) != NULL) {
462*91b2ecf6Smpi 		TAILQ_REMOVE(&plist, dp, dp_snext);
463*91b2ecf6Smpi 		TAILQ_INSERT_HEAD(&sc->ds_pcbs, dp, dp_snext);
464*91b2ecf6Smpi 	}
465*91b2ecf6Smpi 
466*91b2ecf6Smpi 	return 0;
467*91b2ecf6Smpi }
468*91b2ecf6Smpi 
469*91b2ecf6Smpi int
470*91b2ecf6Smpi dt_enter(void)
471*91b2ecf6Smpi {
472*91b2ecf6Smpi 	uint32_t count;
473*91b2ecf6Smpi 
474*91b2ecf6Smpi 	rw_enter_write(&dt_lock);
475*91b2ecf6Smpi 	count = dt_tracing;
476*91b2ecf6Smpi 	dt_tracing = 0;
477*91b2ecf6Smpi 
478*91b2ecf6Smpi 	smr_barrier();
479*91b2ecf6Smpi 
480*91b2ecf6Smpi 	return count;
481*91b2ecf6Smpi }
482*91b2ecf6Smpi 
483*91b2ecf6Smpi void
484*91b2ecf6Smpi dt_leave(uint32_t count)
485*91b2ecf6Smpi {
486*91b2ecf6Smpi 	dt_tracing = count;
487*91b2ecf6Smpi 	rw_exit_write(&dt_lock);
488*91b2ecf6Smpi }
489*91b2ecf6Smpi 
490*91b2ecf6Smpi struct dt_probe *
491*91b2ecf6Smpi dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv)
492*91b2ecf6Smpi {
493*91b2ecf6Smpi 	struct dt_probe *dtp;
494*91b2ecf6Smpi 
495*91b2ecf6Smpi 	dtp = malloc(sizeof(*dtp), M_DT, M_NOWAIT|M_ZERO);
496*91b2ecf6Smpi 	if (dtp == NULL)
497*91b2ecf6Smpi 		return NULL;
498*91b2ecf6Smpi 
499*91b2ecf6Smpi 	SMR_SLIST_INIT(&dtp->dtp_pcbs);
500*91b2ecf6Smpi 	dtp->dtp_prov = dtpv;
501*91b2ecf6Smpi 	dtp->dtp_func = func;
502*91b2ecf6Smpi 	dtp->dtp_name = name;
503*91b2ecf6Smpi 	dtp->dtp_sysnum = -1;
504*91b2ecf6Smpi 
505*91b2ecf6Smpi 	return dtp;
506*91b2ecf6Smpi }
507*91b2ecf6Smpi 
508*91b2ecf6Smpi void
509*91b2ecf6Smpi dt_dev_register_probe(struct dt_probe *dtp)
510*91b2ecf6Smpi {
511*91b2ecf6Smpi 	static uint64_t probe_nb;
512*91b2ecf6Smpi 
513*91b2ecf6Smpi 	dtp->dtp_pbn = ++probe_nb;
514*91b2ecf6Smpi 	SIMPLEQ_INSERT_TAIL(&dt_probe_list, dtp, dtp_next);
515*91b2ecf6Smpi }
516*91b2ecf6Smpi 
517*91b2ecf6Smpi struct dt_pcb *
518*91b2ecf6Smpi dt_pcb_alloc(struct dt_probe *dtp, struct dt_softc *sc)
519*91b2ecf6Smpi {
520*91b2ecf6Smpi 	struct dt_pcb *dp;
521*91b2ecf6Smpi 
522*91b2ecf6Smpi 	dp = malloc(sizeof(*dp), M_DT, M_WAITOK|M_CANFAIL|M_ZERO);
523*91b2ecf6Smpi 	if (dp == NULL)
524*91b2ecf6Smpi 		goto bad;
525*91b2ecf6Smpi 
526*91b2ecf6Smpi 	dp->dp_ring = mallocarray(DT_EVTRING_SIZE, sizeof(*dp->dp_ring), M_DT,
527*91b2ecf6Smpi 	    M_WAITOK|M_CANFAIL|M_ZERO);
528*91b2ecf6Smpi 	if (dp->dp_ring == NULL)
529*91b2ecf6Smpi 		goto bad;
530*91b2ecf6Smpi 
531*91b2ecf6Smpi 	mtx_init(&dp->dp_mtx, IPL_HIGH);
532*91b2ecf6Smpi 	dp->dp_sc = sc;
533*91b2ecf6Smpi 	dp->dp_dtp = dtp;
534*91b2ecf6Smpi 	return dp;
535*91b2ecf6Smpi bad:
536*91b2ecf6Smpi 	dt_pcb_free(dp);
537*91b2ecf6Smpi 	return NULL;
538*91b2ecf6Smpi }
539*91b2ecf6Smpi 
540*91b2ecf6Smpi void
541*91b2ecf6Smpi dt_pcb_free(struct dt_pcb *dp)
542*91b2ecf6Smpi {
543*91b2ecf6Smpi 	if (dp == NULL)
544*91b2ecf6Smpi 		return;
545*91b2ecf6Smpi 	free(dp->dp_ring, M_DT, DT_EVTRING_SIZE * sizeof(*dp->dp_ring));
546*91b2ecf6Smpi 	free(dp, M_DT, sizeof(*dp));
547*91b2ecf6Smpi }
548*91b2ecf6Smpi 
549*91b2ecf6Smpi void
550*91b2ecf6Smpi dt_pcb_purge(struct dt_pcb_list *plist)
551*91b2ecf6Smpi {
552*91b2ecf6Smpi 	struct dt_pcb *dp;
553*91b2ecf6Smpi 
554*91b2ecf6Smpi 	while ((dp = TAILQ_FIRST(plist)) != NULL) {
555*91b2ecf6Smpi 		TAILQ_REMOVE(plist, dp, dp_snext);
556*91b2ecf6Smpi 		dt_pcb_free(dp);
557*91b2ecf6Smpi 	}
558*91b2ecf6Smpi }
559*91b2ecf6Smpi 
560*91b2ecf6Smpi int
561*91b2ecf6Smpi dt_pcb_filter(struct dt_pcb *dp)
562*91b2ecf6Smpi {
563*91b2ecf6Smpi 	struct dt_filter *dtf = &dp->dp_filter;
564*91b2ecf6Smpi 	struct proc *p = curproc;
565*91b2ecf6Smpi 	unsigned int var;
566*91b2ecf6Smpi 	int match = 1;
567*91b2ecf6Smpi 
568*91b2ecf6Smpi 	/* Filter out tracing program. */
569*91b2ecf6Smpi 	if (dp->dp_sc->ds_pid == p->p_p->ps_pid)
570*91b2ecf6Smpi 		return 1;
571*91b2ecf6Smpi 
572*91b2ecf6Smpi 	switch (dtf->dtf_variable) {
573*91b2ecf6Smpi 	case DT_FV_PID:
574*91b2ecf6Smpi 		var = p->p_p->ps_pid;
575*91b2ecf6Smpi 		break;
576*91b2ecf6Smpi 	case DT_FV_TID:
577*91b2ecf6Smpi 		var = p->p_tid;
578*91b2ecf6Smpi 		break;
579*91b2ecf6Smpi 	case DT_FV_NONE:
580*91b2ecf6Smpi 		break;
581*91b2ecf6Smpi 	default:
582*91b2ecf6Smpi 		KASSERT(0);
583*91b2ecf6Smpi 	}
584*91b2ecf6Smpi 
585*91b2ecf6Smpi 	switch (dtf->dtf_operand) {
586*91b2ecf6Smpi 	case DT_OP_EQ:
587*91b2ecf6Smpi 		match = !!(var == dtf->dtf_value);
588*91b2ecf6Smpi 		break;
589*91b2ecf6Smpi 	case DT_OP_NE:
590*91b2ecf6Smpi 		match = !!(var != dtf->dtf_value);
591*91b2ecf6Smpi 		break;
592*91b2ecf6Smpi 	case DT_OP_NONE:
593*91b2ecf6Smpi 		break;
594*91b2ecf6Smpi 	default:
595*91b2ecf6Smpi 		KASSERT(0);
596*91b2ecf6Smpi 	}
597*91b2ecf6Smpi 
598*91b2ecf6Smpi 	return !match;
599*91b2ecf6Smpi }
600*91b2ecf6Smpi 
601*91b2ecf6Smpi 
602*91b2ecf6Smpi /*
603*91b2ecf6Smpi  * Get a reference to the next free event state from the ring.
604*91b2ecf6Smpi  */
605*91b2ecf6Smpi struct dt_evt *
606*91b2ecf6Smpi dt_pcb_ring_get(struct dt_pcb *dp)
607*91b2ecf6Smpi {
608*91b2ecf6Smpi 	struct proc *p = curproc;
609*91b2ecf6Smpi 	struct dt_evt *dtev;
610*91b2ecf6Smpi 	int distance;
611*91b2ecf6Smpi 
612*91b2ecf6Smpi 	if (dt_pcb_filter(dp))
613*91b2ecf6Smpi 		return NULL;
614*91b2ecf6Smpi 
615*91b2ecf6Smpi 	mtx_enter(&dp->dp_mtx);
616*91b2ecf6Smpi 	distance = dp->dp_prod - dp->dp_cons;
617*91b2ecf6Smpi 	if (distance == 1 || distance == (1 - DT_EVTRING_SIZE)) {
618*91b2ecf6Smpi 		/* read(2) isn't finished */
619*91b2ecf6Smpi 		dp->dp_dropevt++;
620*91b2ecf6Smpi 		mtx_leave(&dp->dp_mtx);
621*91b2ecf6Smpi 		return NULL;
622*91b2ecf6Smpi 	}
623*91b2ecf6Smpi 
624*91b2ecf6Smpi 	/*
625*91b2ecf6Smpi 	 * Save states in next free event slot.
626*91b2ecf6Smpi 	 */
627*91b2ecf6Smpi 	dtev = &dp->dp_ring[dp->dp_cons];
628*91b2ecf6Smpi 	memset(dtev, 0, sizeof(*dtev));
629*91b2ecf6Smpi 
630*91b2ecf6Smpi 	dtev->dtev_pbn = dp->dp_dtp->dtp_pbn;
631*91b2ecf6Smpi 	dtev->dtev_cpu = cpu_number();
632*91b2ecf6Smpi 	dtev->dtev_pid = p->p_p->ps_pid;
633*91b2ecf6Smpi 	dtev->dtev_tid = p->p_tid;
634*91b2ecf6Smpi 	nanotime(&dtev->dtev_tsp);
635*91b2ecf6Smpi 
636*91b2ecf6Smpi 	if (ISSET(dp->dp_evtflags, DTEVT_EXECNAME))
637*91b2ecf6Smpi 		memcpy(dtev->dtev_comm, p->p_p->ps_comm, DTMAXCOMLEN - 1);
638*91b2ecf6Smpi 
639*91b2ecf6Smpi 	if (ISSET(dp->dp_evtflags, DTEVT_KSTACK|DTEVT_USTACK)) {
640*91b2ecf6Smpi #if notyet
641*91b2ecf6Smpi 		stacktrace_save_at(&dtev->dtev_kstack, DT_HOOK_FRAME_ADDRESS);
642*91b2ecf6Smpi #else
643*91b2ecf6Smpi 		stacktrace_save(&dtev->dtev_kstack);
644*91b2ecf6Smpi #endif
645*91b2ecf6Smpi 	}
646*91b2ecf6Smpi 
647*91b2ecf6Smpi 	return dtev;
648*91b2ecf6Smpi }
649*91b2ecf6Smpi 
650*91b2ecf6Smpi void
651*91b2ecf6Smpi dt_pcb_ring_consume(struct dt_pcb *dp, struct dt_evt *dtev)
652*91b2ecf6Smpi {
653*91b2ecf6Smpi 	MUTEX_ASSERT_LOCKED(&dp->dp_mtx);
654*91b2ecf6Smpi 	KASSERT(dtev == &dp->dp_ring[dp->dp_cons]);
655*91b2ecf6Smpi 
656*91b2ecf6Smpi 	dp->dp_cons = (dp->dp_cons + 1) % DT_EVTRING_SIZE;
657*91b2ecf6Smpi 	mtx_leave(&dp->dp_mtx);
658*91b2ecf6Smpi 
659*91b2ecf6Smpi 	mtx_enter(&dp->dp_sc->ds_mtx);
660*91b2ecf6Smpi 	dp->dp_sc->ds_evtcnt++;
661*91b2ecf6Smpi 	mtx_leave(&dp->dp_sc->ds_mtx);
662*91b2ecf6Smpi 	wakeup(dp->dp_sc);
663*91b2ecf6Smpi }
664*91b2ecf6Smpi 
665*91b2ecf6Smpi /*
666*91b2ecf6Smpi  * Copy at most `qlen' events from `dp', producing the same amount
667*91b2ecf6Smpi  * of free slots.
668*91b2ecf6Smpi  */
669*91b2ecf6Smpi int
670*91b2ecf6Smpi dt_pcb_ring_copy(struct dt_pcb *dp, struct dt_evt *estq, size_t qlen,
671*91b2ecf6Smpi     uint64_t *dropped)
672*91b2ecf6Smpi {
673*91b2ecf6Smpi 	size_t count, copied = 0;
674*91b2ecf6Smpi 	unsigned int cons, prod;
675*91b2ecf6Smpi 
676*91b2ecf6Smpi 	KASSERT(qlen > 0);
677*91b2ecf6Smpi 
678*91b2ecf6Smpi 	mtx_enter(&dp->dp_mtx);
679*91b2ecf6Smpi 	cons = dp->dp_cons;
680*91b2ecf6Smpi 	prod = dp->dp_prod;
681*91b2ecf6Smpi 
682*91b2ecf6Smpi 	if (cons < prod)
683*91b2ecf6Smpi 		count = DT_EVTRING_SIZE - prod;
684*91b2ecf6Smpi 	else
685*91b2ecf6Smpi 		count = cons - prod;
686*91b2ecf6Smpi 
687*91b2ecf6Smpi 	if (count == 0)
688*91b2ecf6Smpi 		goto out;
689*91b2ecf6Smpi 
690*91b2ecf6Smpi 	*dropped += dp->dp_dropevt;
691*91b2ecf6Smpi 	dp->dp_dropevt = 0;
692*91b2ecf6Smpi 
693*91b2ecf6Smpi 	count = MIN(count, qlen);
694*91b2ecf6Smpi 
695*91b2ecf6Smpi 	memcpy(&estq[0], &dp->dp_ring[prod], count * sizeof(*estq));
696*91b2ecf6Smpi 	copied += count;
697*91b2ecf6Smpi 
698*91b2ecf6Smpi 	/* Produce */
699*91b2ecf6Smpi 	prod = (prod + count) % DT_EVTRING_SIZE;
700*91b2ecf6Smpi 
701*91b2ecf6Smpi 	/* If the queue is full or the ring didn't wrap, stop here. */
702*91b2ecf6Smpi 	if (qlen == copied || prod != 0 || cons == 0)
703*91b2ecf6Smpi 		goto out;
704*91b2ecf6Smpi 
705*91b2ecf6Smpi 	count = MIN(cons, (qlen - copied));
706*91b2ecf6Smpi 	memcpy(&estq[copied], &dp->dp_ring[0], count * sizeof(*estq));
707*91b2ecf6Smpi 	copied += count;
708*91b2ecf6Smpi 	prod += count;
709*91b2ecf6Smpi 
710*91b2ecf6Smpi out:
711*91b2ecf6Smpi 	dp->dp_prod = prod;
712*91b2ecf6Smpi 	mtx_leave(&dp->dp_mtx);
713*91b2ecf6Smpi 	return copied;
714*91b2ecf6Smpi }
715