xref: /openbsd/sys/dev/dt/dtvar.h (revision c2c0b0cf)
1 /*	$OpenBSD: dtvar.h,v 1.19 2024/04/06 11:18:02 mpi Exp $ */
2 
3 /*
4  * Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #ifndef _DT_H_
20 #define _DT_H_
21 
22 #include <sys/ioccom.h>
23 #include <sys/stacktrace.h>
24 #include <sys/time.h>
25 
26 /*
27  * Length of provider/probe/function names, including NUL.
28  */
29 #define DTNAMESIZE	16
30 
31 /*
32  * Length of process name, including NUL.
33  */
34 #define DTMAXCOMLEN	_MAXCOMLEN
35 
36 /*
37  * Maximum number of arguments passed to a function.
38  */
39 #define DTMAXFUNCARGS	10
40 #define DTMAXARGTYPES	5
41 
42 /*
43  * Event state: where to store information when a probe fires.
44  */
45 struct dt_evt {
46 	unsigned int		dtev_pbn;	/* Probe number */
47 	unsigned int		dtev_cpu;	/* CPU id */
48 	pid_t			dtev_pid;	/* ID of current process */
49 	pid_t			dtev_tid;	/* ID of current thread */
50 	struct timespec		dtev_tsp;	/* timestamp (nsecs) */
51 
52 	/*
53 	 * Recorded if the corresponding flag is set.
54 	 */
55 	struct stacktrace	dtev_kstack;	/* kernel stack frame */
56 	struct stacktrace	dtev_ustack;	/* userland stack frame */
57 	char			dtev_comm[DTMAXCOMLEN]; /* current pr. name */
58 	union {
59 		register_t		E_entry[DTMAXFUNCARGS];
60 		struct {
61 			register_t		__retval[2];
62 			int			__error;
63 		} E_return;
64 	} _args;
65 #define dtev_args	_args.E_entry		/* function args. */
66 #define dtev_retval	_args.E_return.__retval	/* function retval */
67 #define dtev_error	_args.E_return.__error	/* function error */
68 };
69 
70 /*
71  * States to record when a probe fires.
72  */
73 #define DTEVT_EXECNAME	(1 << 0)		/* current process name */
74 #define DTEVT_USTACK	(1 << 1)		/* userland stack */
75 #define DTEVT_KSTACK	(1 << 2)		/* kernel stack */
76 #define DTEVT_FUNCARGS	(1 << 3)		/* function arguments */
77 
78 #define	DTEVT_FLAG_BITS		\
79 	"\020"			\
80 	"\001EXECNAME"		\
81 	"\002USTACK"		\
82 	"\003KSTACK"		\
83 	"\004FUNCARGS"		\
84 
85 struct dtioc_probe_info {
86 	uint32_t	dtpi_pbn;		/* probe number */
87 	uint8_t		dtpi_nargs;		/* # of arguments */
88 	char		dtpi_prov[DTNAMESIZE];
89 	char		dtpi_func[DTNAMESIZE];
90 	char		dtpi_name[DTNAMESIZE];
91 };
92 
93 struct dtioc_probe {
94 	size_t			 dtpr_size;	/* size of the buffer */
95 	struct dtioc_probe_info	*dtpr_probes;	/* array of probe info */
96 };
97 
98 struct dtioc_arg_info {
99 	uint32_t	dtai_pbn;		/* probe number */
100 	uint8_t		dtai_argn;		/* arguments number */
101 	char		dtai_argtype[DTNAMESIZE];
102 };
103 
104 struct dtioc_arg {
105 	uint32_t		 dtar_pbn;	/* probe number */
106 	size_t			 dtar_size;	/* size of the buffer */
107 	struct dtioc_arg_info	*dtar_args;	/* array of arg info */
108 };
109 
110 struct dtioc_req {
111 	uint32_t		 dtrq_pbn;	/* probe number */
112 	uint32_t		 dtrq_rate;	/* number of ticks */
113 	uint64_t		 dtrq_evtflags;	/* states to record */
114 };
115 
116 struct dtioc_stat {
117 	uint64_t		 dtst_readevt;	/* events read */
118 	uint64_t		 dtst_dropevt;	/* events dropped */
119 };
120 
121 struct dtioc_getaux {
122 	pid_t			 dtga_pid;	/* process to inspect */
123 	unsigned long		 dtga_auxbase;	/* AUX_base value */
124 };
125 
126 #define DTIOCGPLIST	_IOWR('D', 1, struct dtioc_probe)
127 #define DTIOCGSTATS	_IOR('D', 2, struct dtioc_stat)
128 #define DTIOCRECORD	_IOW('D', 3, int)
129 #define DTIOCPRBENABLE	_IOW('D', 4, struct dtioc_req)
130 #define DTIOCPRBDISABLE	 _IOW('D', 5, struct dtioc_req)
131 #define DTIOCGARGS	_IOWR('D', 6, struct dtioc_arg)
132 #define DTIOCGETAUXBASE	 _IOWR('D', 7, struct dtioc_getaux)
133 
134 #ifdef _KERNEL
135 
136 #include <sys/mutex.h>
137 #include <sys/queue.h>
138 #include <sys/smr.h>
139 
140 /* Flags that make sense for all providers. */
141 #define DTEVT_COMMON	(DTEVT_EXECNAME|DTEVT_KSTACK|DTEVT_USTACK)
142 
143 #define M_DT M_DEVBUF /* XXX FIXME */
144 
145 struct dt_softc;
146 
147 /*
148  * Probe control block, possibly per-CPU.
149  *
150  * At least a PCB is allocated for each probe enabled via the DTIOCPRBENABLE
151  * ioctl(2).  It will hold the events written when the probe fires until
152  * userland read(2)s them.
153  *
154  *  Locks used to protect struct members in this file:
155  *	D	dt_lock
156  *	I	immutable after creation
157  *	K	kernel lock
158  *	K,S	kernel lock for writing and SMR for reading
159  *	m	per-pcb mutex
160  *	c	owned (read & modified) by a single CPU
161  */
162 struct dt_pcb {
163 	SMR_SLIST_ENTRY(dt_pcb)	 dp_pnext;	/* [K,S] next PCB per probe */
164 	TAILQ_ENTRY(dt_pcb)	 dp_snext;	/* [K] next PCB per softc */
165 
166 	/* Event states ring */
167 	unsigned int		 dp_prod;	/* [m] read index */
168 	unsigned int		 dp_cons;	/* [m] write index */
169 	struct dt_evt		*dp_ring;	/* [m] ring of event states */
170 	struct mutex		 dp_mtx;
171 
172 	struct dt_softc		*dp_sc;		/* [I] related softc */
173 	struct dt_probe		*dp_dtp;	/* [I] related probe */
174 	uint64_t		 dp_evtflags;	/* [I] event states to record */
175 
176 	/* Provider specific fields. */
177 	struct clockintr	 dp_clockintr;	/* [D] profiling handle */
178 	uint64_t		 dp_nsecs;	/* [I] profiling period */
179 	struct cpu_info		*dp_cpu;	/* [I] on which CPU */
180 
181 	/* Counters */
182 	uint64_t		 dp_dropevt;	/* [m] # dropped event */
183 };
184 
185 TAILQ_HEAD(dt_pcb_list, dt_pcb);
186 
187 struct dt_pcb	*dt_pcb_alloc(struct dt_probe *, struct dt_softc *);
188 void		 dt_pcb_free(struct dt_pcb *);
189 void		 dt_pcb_purge(struct dt_pcb_list *);
190 
191 struct dt_evt	*dt_pcb_ring_get(struct dt_pcb *, int);
192 void		 dt_pcb_ring_consume(struct dt_pcb *, struct dt_evt *);
193 
194 /*
195  * Probes are entry points in the system where events can be recorded.
196  *
197  *  Locks used to protect struct members in this file:
198  *	I	immutable after creation
199  *	K	kernel lock
200  *	D	dt_lock
201  *	D,S	dt_lock for writing and SMR for reading
202  *	M	dtp mutex
203  */
204 struct dt_probe {
205 	SIMPLEQ_ENTRY(dt_probe)	 dtp_next;	/* [K] global list of probes */
206 	SMR_SLIST_HEAD(, dt_pcb) dtp_pcbs;	/* [D,S] list of enabled PCBs */
207 	struct dt_provider	*dtp_prov;	/* [I] its to provider */
208 	const char		*dtp_func;	/* [I] probe function */
209 	const char		*dtp_name;	/* [I] probe name */
210 	uint32_t		 dtp_pbn;	/* [I] unique ID */
211 	volatile uint32_t	 dtp_recording;	/* [d] is it recording? */
212 	unsigned		 dtp_ref;	/* [m] # of PCBs referencing the probe */
213 
214 	/* Provider specific fields. */
215 	int			 dtp_sysnum;	/* [I] related # of syscall */
216 	const char		*dtp_argtype[DTMAXARGTYPES];
217 						/* [I] type of arguments */
218 	int			 dtp_nargs;	/* [I] # of arguments */
219 	vaddr_t			 dtp_addr;	/* [I] address of breakpoint */
220 };
221 
222 
223 /*
224  * Providers expose a set of probes and a method to record events.
225  */
226 struct dt_provider {
227 	const char		*dtpv_name;	/* [I] provider name */
228 	volatile uint32_t	 dtpv_recording;/* [D] # of recording PCBs */
229 
230 	int		(*dtpv_alloc)(struct dt_probe *, struct dt_softc *,
231 			    struct dt_pcb_list *, struct dtioc_req *);
232 	int		(*dtpv_enter)(struct dt_provider *, ...);
233 	void		(*dtpv_leave)(struct dt_provider *, ...);
234 	int		(*dtpv_dealloc)(struct dt_probe *, struct dt_softc *,
235 			    struct dtioc_req *);
236 };
237 
238 extern struct dt_provider dt_prov_kprobe;
239 
240 int		 dt_prov_profile_init(void);
241 int		 dt_prov_syscall_init(void);
242 int		 dt_prov_static_init(void);
243 int		 dt_prov_kprobe_init(void);
244 
245 struct dt_probe *dt_dev_alloc_probe(const char *, const char *,
246 		    struct dt_provider *);
247 void		 dt_dev_register_probe(struct dt_probe *);
248 
249 void		 dt_clock(struct clockrequest *, void *, void *);
250 
251 extern volatile uint32_t	dt_tracing;	/* currently tracing? */
252 
253 #define DT_ENTER(provname, args...) do {				\
254 	extern struct dt_provider dt_prov_ ## provname ;		\
255 	struct dt_provider *dtpv = &dt_prov_ ## provname ;		\
256 									\
257 	if (__predict_false(dt_tracing) &&				\
258 	    __predict_false(dtpv->dtpv_recording)) {			\
259 		dtpv->dtpv_enter(dtpv, args);				\
260 	}								\
261 } while (0)
262 
263 #define DT_LEAVE(provname, args...) do {				\
264 	extern struct dt_provider dt_prov_ ## provname ;		\
265 	struct dt_provider *dtpv = &dt_prov_ ## provname ;		\
266 									\
267 	if (__predict_false(dt_tracing) &&				\
268 	    __predict_false(dtpv->dtpv_recording)) {			\
269 		dtpv->dtpv_leave(dtpv, args);				\
270 	}								\
271 } while (0)
272 
273 #define _DT_STATIC_P(func, name)	(dt_static_##func##_##name)
274 
275 /*
276  * Probe definition for the static provider.
277  */
278 #define _DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, arg4, n)	\
279 	struct dt_probe _DT_STATIC_P(func, name) = {			\
280 		.dtp_next = { NULL },					\
281 		.dtp_pcbs = { NULL },					\
282 		.dtp_prov = &dt_prov_static,				\
283 		.dtp_func = #func,					\
284 		.dtp_name = #name,					\
285 		.dtp_pbn = 0,						\
286 		.dtp_sysnum = 0,					\
287 		.dtp_argtype = { arg0, arg1, arg2, arg3, arg4 },	\
288 		.dtp_nargs = n,					\
289 	}								\
290 
291 #define	DT_STATIC_PROBE0(func, name)					\
292 	_DT_STATIC_PROBEN(func, name, NULL, NULL, NULL, NULL, NULL, 0)
293 
294 #define	DT_STATIC_PROBE1(func, name, arg0)				\
295 	_DT_STATIC_PROBEN(func, name, arg0, NULL, NULL, NULL, NULL, 1)
296 
297 #define	DT_STATIC_PROBE2(func, name, arg0, arg1)			\
298 	_DT_STATIC_PROBEN(func, name, arg0, arg1, NULL, NULL, NULL, 2)
299 
300 #define	DT_STATIC_PROBE3(func, name, arg0, arg1, arg2)		\
301 	_DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, NULL, NULL, 3)
302 
303 #define	DT_STATIC_PROBE4(func, name, arg0, arg1, arg2, arg3)		\
304 	_DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, NULL, 4)
305 
306 #define	DT_STATIC_PROBE5(func, name, arg0, arg1, arg2, arg3, arg4)	\
307 	_DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, arg4, 5)
308 
309 #define DT_STATIC_ENTER(func, name, args...) do {			\
310 	extern struct dt_probe _DT_STATIC_P(func, name);		\
311 	struct dt_probe *dtp = &_DT_STATIC_P(func, name);		\
312 									\
313 	if (__predict_false(dt_tracing) &&				\
314 	    __predict_false(dtp->dtp_recording)) {			\
315 		struct dt_provider *dtpv = dtp->dtp_prov;		\
316 									\
317 		dtpv->dtpv_enter(dtpv, dtp, args);			\
318 	}								\
319 } while (0)
320 
321 #define _DT_INDEX_P(func)		(dtps_index_##func)
322 
323 #define DT_INDEX_ENTER(func, index, args...) do {			\
324 	extern struct dt_probe **_DT_INDEX_P(func);			\
325 									\
326 	if (__predict_false(dt_tracing) &&				\
327 	    __predict_false(index > 0) &&				\
328 	    __predict_true(_DT_INDEX_P(func) != NULL)) {		\
329 		struct dt_probe *dtp = _DT_INDEX_P(func)[index];	\
330 									\
331 		if(__predict_false(dtp->dtp_recording)) {		\
332 			struct dt_provider *dtpv = dtp->dtp_prov;	\
333 									\
334 			dtpv->dtpv_enter(dtpv, dtp, args);		\
335 		}							\
336 	}								\
337 } while (0)
338 
339 #endif /* !_KERNEL */
340 #endif /* !_DT_H_ */
341