xref: /openbsd-src/usr.sbin/btrace/btrace.c (revision 139d07b5d2b54520acbf93ed1ea9df2b42a216fe)
1*139d07b5Smpi /*	$OpenBSD: btrace.c,v 1.95 2025/01/23 11:17:32 mpi Exp $ */
223160851Smpi 
323160851Smpi /*
466f34ae4Smpi  * Copyright (c) 2019 - 2023 Martin Pieuchot <mpi@openbsd.org>
523160851Smpi  *
623160851Smpi  * Permission to use, copy, modify, and distribute this software for any
723160851Smpi  * purpose with or without fee is hereby granted, provided that the above
823160851Smpi  * copyright notice and this permission notice appear in all copies.
923160851Smpi  *
1023160851Smpi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1123160851Smpi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1223160851Smpi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1323160851Smpi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1423160851Smpi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1523160851Smpi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1623160851Smpi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1723160851Smpi  */
1823160851Smpi 
1923160851Smpi #include <sys/ioctl.h>
206968164dSmpi #include <sys/stat.h>
2123160851Smpi #include <sys/syscall.h>
2223160851Smpi #include <sys/queue.h>
2323160851Smpi 
2423160851Smpi #include <assert.h>
2523160851Smpi #include <err.h>
2623160851Smpi #include <errno.h>
2723160851Smpi #include <fcntl.h>
2823160851Smpi #include <limits.h>
2923160851Smpi #include <locale.h>
305247768dSmpi #include <paths.h>
3123160851Smpi #include <signal.h>
3223160851Smpi #include <stdarg.h>
33ea0c567aSmpi #include <stdbool.h>
3423160851Smpi #include <stdio.h>
3523160851Smpi #include <stdlib.h>
3623160851Smpi #include <string.h>
37a378a2aaSmpi #include <time.h>
3823160851Smpi #include <unistd.h>
3923160851Smpi 
4023160851Smpi #include <dev/dt/dtvar.h>
4123160851Smpi 
4223160851Smpi #include "btrace.h"
4323160851Smpi #include "bt_parser.h"
4423160851Smpi 
459c84395dSmpi #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
469c84395dSmpi #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
479c84395dSmpi 
4823160851Smpi /*
4923160851Smpi  * Maximum number of operands an arithmetic operation can have.  This
5023160851Smpi  * is necessary to stop infinite recursion when evaluating expressions.
5123160851Smpi  */
5223160851Smpi #define __MAXOPERANDS	5
5323160851Smpi 
5423160851Smpi #define __PATH_DEVDT "/dev/dt"
5523160851Smpi 
5623160851Smpi __dead void		 usage(void);
576968164dSmpi char			*read_btfile(const char *, size_t *);
5823160851Smpi 
5923160851Smpi /*
6023160851Smpi  * Retrieve & parse probe information.
6123160851Smpi  */
6223160851Smpi void			 dtpi_cache(int);
6381b6d302Sbluhm void			 dtpi_print_list(int);
644ed6f7c2Sguenther const char		*dtpi_func(struct dtioc_probe_info *);
6523160851Smpi int			 dtpi_is_unit(const char *);
6623160851Smpi struct dtioc_probe_info	*dtpi_get_by_value(const char *, const char *,
6723160851Smpi 			     const char *);
6823160851Smpi 
6923160851Smpi /*
7023160851Smpi  * Main loop and rule evaluation.
7123160851Smpi  */
72ffce2a54Smpi void			 probe_bail(struct bt_probe *);
73ffce2a54Smpi const char		*probe_name(struct bt_probe *);
746ca6ae3fSmpi void			 rules_do(int);
75a4c6ec8cScheloha int			 rules_setup(int);
76a4c6ec8cScheloha int			 rules_apply(int, struct dt_evt *);
7723160851Smpi void			 rules_teardown(int);
78a4c6ec8cScheloha int			 rule_eval(struct bt_rule *, struct dt_evt *);
791b29203bSmpi void			 rule_printmaps(struct bt_rule *);
8023160851Smpi 
8123160851Smpi /*
8223160851Smpi  * Language builtins & functions.
8323160851Smpi  */
8423160851Smpi uint64_t		 builtin_nsecs(struct dt_evt *);
8523160851Smpi const char		*builtin_arg(struct dt_evt *, enum bt_argtype);
86b005393aSdv struct bt_arg		*fn_str(struct bt_arg *, struct dt_evt *, char *);
87a4c6ec8cScheloha int			 stmt_eval(struct bt_stmt *, struct dt_evt *);
889c84395dSmpi void			 stmt_bucketize(struct bt_stmt *, struct dt_evt *);
8923160851Smpi void			 stmt_clear(struct bt_stmt *);
9023160851Smpi void			 stmt_delete(struct bt_stmt *, struct dt_evt *);
9123160851Smpi void			 stmt_insert(struct bt_stmt *, struct dt_evt *);
9223160851Smpi void			 stmt_print(struct bt_stmt *, struct dt_evt *);
9323160851Smpi void			 stmt_store(struct bt_stmt *, struct dt_evt *);
94ea0c567aSmpi bool			 stmt_test(struct bt_stmt *, struct dt_evt *);
95a378a2aaSmpi void			 stmt_time(struct bt_stmt *, struct dt_evt *);
9623160851Smpi void			 stmt_zero(struct bt_stmt *);
9723160851Smpi struct bt_arg		*ba_read(struct bt_arg *);
9866f34ae4Smpi struct bt_arg		*baeval(struct bt_arg *, struct dt_evt *);
996f386ca5Smpi const char		*ba2hash(struct bt_arg *, struct dt_evt *);
100822ace7eSmpi long			 baexpr2long(struct bt_arg *, struct dt_evt *);
1019c84395dSmpi const char		*ba2bucket(struct bt_arg *, struct bt_arg *,
1029c84395dSmpi 			     struct dt_evt *, long *);
1036f386ca5Smpi int			 ba2dtflags(struct bt_arg *);
10423160851Smpi 
10523160851Smpi /*
10623160851Smpi  * Debug routines.
10723160851Smpi  */
10823160851Smpi __dead void		 xabort(const char *, ...);
10923160851Smpi void			 debug(const char *, ...);
11023160851Smpi void			 debugx(const char *, ...);
11189f39301Smpi void			 debug_dump_term(struct bt_arg *);
11289f39301Smpi void			 debug_dump_expr(struct bt_arg *);
11323160851Smpi void			 debug_dump_filter(struct bt_rule *);
11423160851Smpi 
11523160851Smpi struct dtioc_probe_info	*dt_dtpis;	/* array of available probes */
11623160851Smpi size_t			 dt_ndtpi;	/* # of elements in the array */
11781b6d302Sbluhm struct dtioc_arg_info  **dt_args;	/* array of probe arguments */
11823160851Smpi 
119d2392c66Smpi struct dt_evt		 bt_devt;	/* fake event for BEGIN/END */
1209e79f3a0Sdv #define EVENT_BEGIN	 0
1219e79f3a0Sdv #define EVENT_END	 (unsigned int)(-1)
122822ace7eSmpi uint64_t		 bt_filtered;	/* # of events filtered out */
123d2392c66Smpi 
1245e6104a1Sclaudio struct syms		*kelf, *uelf;
1255e6104a1Sclaudio 
12658afdee7Sdv char			**vargs;
12758afdee7Sdv int			 nargs = 0;
12823160851Smpi int			 verbose = 0;
1295e6104a1Sclaudio int			 dtfd;
13023160851Smpi volatile sig_atomic_t	 quit_pending;
13123160851Smpi 
13223160851Smpi static void
13323160851Smpi signal_handler(int sig)
13423160851Smpi {
13523160851Smpi 	quit_pending = sig;
13623160851Smpi }
13723160851Smpi 
13823160851Smpi 
13923160851Smpi int
14023160851Smpi main(int argc, char *argv[])
14123160851Smpi {
14223160851Smpi 	int fd = -1, ch, error = 0;
14323160851Smpi 	const char *filename = NULL, *btscript = NULL;
1446ca6ae3fSmpi 	int showprobes = 0, noaction = 0;
1456968164dSmpi 	size_t btslen = 0;
14623160851Smpi 
14723160851Smpi 	setlocale(LC_ALL, "");
14823160851Smpi 
149b69b24c5Sjmatthew 	while ((ch = getopt(argc, argv, "e:lnp:v")) != -1) {
15023160851Smpi 		switch (ch) {
15123160851Smpi 		case 'e':
15223160851Smpi 			btscript = optarg;
1536968164dSmpi 			btslen = strlen(btscript);
15423160851Smpi 			break;
15523160851Smpi 		case 'l':
15623160851Smpi 			showprobes = 1;
15723160851Smpi 			break;
158b69b24c5Sjmatthew 		case 'n':
159b69b24c5Sjmatthew 			noaction = 1;
160b69b24c5Sjmatthew 			break;
1615e6104a1Sclaudio 		case 'p':
1625e6104a1Sclaudio 			uelf = kelf_open(optarg);
1635e6104a1Sclaudio 			break;
16423160851Smpi 		case 'v':
16523160851Smpi 			verbose++;
16623160851Smpi 			break;
16723160851Smpi 		default:
16823160851Smpi 			usage();
16923160851Smpi 		}
17023160851Smpi 	}
17123160851Smpi 
17223160851Smpi 	argc -= optind;
17323160851Smpi 	argv += optind;
17423160851Smpi 
1755247768dSmpi 	if (argc > 0 && btscript == NULL)
17623160851Smpi 		filename = argv[0];
1775247768dSmpi 
1785247768dSmpi 	 /* Cannot pledge due to special ioctl()s */
1795247768dSmpi 	if (unveil(__PATH_DEVDT, "r") == -1)
1805247768dSmpi 		err(1, "unveil %s", __PATH_DEVDT);
1815247768dSmpi 	if (unveil(_PATH_KSYMS, "r") == -1)
1825247768dSmpi 		err(1, "unveil %s", _PATH_KSYMS);
1835247768dSmpi 	if (filename != NULL) {
1845247768dSmpi 		if (unveil(filename, "r") == -1)
1855247768dSmpi 			err(1, "unveil %s", filename);
1865247768dSmpi 	}
1875247768dSmpi 	if (unveil(NULL, NULL) == -1)
1885247768dSmpi 		err(1, "unveil");
1895247768dSmpi 
1905247768dSmpi 	if (filename != NULL) {
1916968164dSmpi 		btscript = read_btfile(filename, &btslen);
19223160851Smpi 		argc--;
19323160851Smpi 		argv++;
19423160851Smpi 	}
19523160851Smpi 
19658afdee7Sdv 	nargs = argc;
19758afdee7Sdv 	vargs = argv;
1986ca6ae3fSmpi 
19958afdee7Sdv 	if (btscript == NULL && !showprobes)
20023160851Smpi 		usage();
20123160851Smpi 
20223160851Smpi 	if (btscript != NULL) {
2036968164dSmpi 		error = btparse(btscript, btslen, filename, 1);
20423160851Smpi 		if (error)
20523160851Smpi 			return error;
20623160851Smpi 	}
20723160851Smpi 
208b69b24c5Sjmatthew 	if (noaction)
209b69b24c5Sjmatthew 		return error;
210b69b24c5Sjmatthew 
21123160851Smpi 	if (showprobes || g_nprobes > 0) {
21223160851Smpi 		fd = open(__PATH_DEVDT, O_RDONLY);
21323160851Smpi 		if (fd == -1)
21423160851Smpi 			err(1, "could not open %s", __PATH_DEVDT);
2155e6104a1Sclaudio 		dtfd = fd;
21623160851Smpi 	}
21723160851Smpi 
21823160851Smpi 	if (showprobes) {
21923160851Smpi 		dtpi_cache(fd);
22081b6d302Sbluhm 		dtpi_print_list(fd);
22123160851Smpi 	}
22223160851Smpi 
22323160851Smpi 	if (!TAILQ_EMPTY(&g_rules))
2246ca6ae3fSmpi 		rules_do(fd);
22523160851Smpi 
22623160851Smpi 	if (fd != -1)
22723160851Smpi 		close(fd);
22823160851Smpi 
22923160851Smpi 	return error;
23023160851Smpi }
23123160851Smpi 
23223160851Smpi __dead void
23323160851Smpi usage(void)
23423160851Smpi {
235b065c5c7Sclaudio 	fprintf(stderr, "usage: %s [-lnv] [-e program | file] [-p file] "
236b065c5c7Sclaudio 	    "[argument ...]\n", getprogname());
23723160851Smpi 	exit(1);
23823160851Smpi }
23923160851Smpi 
24023160851Smpi char *
2416968164dSmpi read_btfile(const char *filename, size_t *len)
24223160851Smpi {
24323160851Smpi 	FILE *fp;
2446968164dSmpi 	char *fcontent;
2456968164dSmpi 	struct stat st;
2466968164dSmpi 	size_t fsize;
2476968164dSmpi 
2486968164dSmpi 	if (stat(filename, &st))
2496968164dSmpi 		err(1, "can't stat '%s'", filename);
2506968164dSmpi 
2516968164dSmpi 	fsize = st.st_size;
252aa1e5e88Sbluhm 	fcontent = malloc(fsize + 1);
2536968164dSmpi 	if (fcontent == NULL)
2546968164dSmpi 		err(1, "malloc");
25523160851Smpi 
25623160851Smpi 	fp = fopen(filename, "r");
25723160851Smpi 	if (fp == NULL)
25823160851Smpi 		err(1, "can't open '%s'", filename);
25923160851Smpi 
2606968164dSmpi 	if (fread(fcontent, 1, fsize, fp) != fsize)
26123160851Smpi 		err(1, "can't read '%s'", filename);
262aa1e5e88Sbluhm 	fcontent[fsize] = '\0';
26323160851Smpi 
26423160851Smpi 	fclose(fp);
2656968164dSmpi 	*len = fsize;
26623160851Smpi 	return fcontent;
26723160851Smpi }
26823160851Smpi 
26923160851Smpi void
27023160851Smpi dtpi_cache(int fd)
27123160851Smpi {
27223160851Smpi 	struct dtioc_probe dtpr;
27323160851Smpi 
27423160851Smpi 	if (dt_dtpis != NULL)
27523160851Smpi 		return;
27623160851Smpi 
27723160851Smpi 	memset(&dtpr, 0, sizeof(dtpr));
27823160851Smpi 	if (ioctl(fd, DTIOCGPLIST, &dtpr))
27923160851Smpi 		err(1, "DTIOCGPLIST");
28023160851Smpi 
28181b6d302Sbluhm 	dt_ndtpi = dtpr.dtpr_size / sizeof(*dt_dtpis);
28223160851Smpi 	dt_dtpis = reallocarray(NULL, dt_ndtpi, sizeof(*dt_dtpis));
28323160851Smpi 	if (dt_dtpis == NULL)
28481b6d302Sbluhm 		err(1, NULL);
28523160851Smpi 
28623160851Smpi 	dtpr.dtpr_probes = dt_dtpis;
28723160851Smpi 	if (ioctl(fd, DTIOCGPLIST, &dtpr))
28823160851Smpi 		err(1, "DTIOCGPLIST");
28923160851Smpi }
29023160851Smpi 
29123160851Smpi void
29281b6d302Sbluhm dtai_cache(int fd, struct dtioc_probe_info *dtpi)
29381b6d302Sbluhm {
29481b6d302Sbluhm 	struct dtioc_arg dtar;
29581b6d302Sbluhm 
29681b6d302Sbluhm 	if (dt_args == NULL) {
29781b6d302Sbluhm 		dt_args = calloc(dt_ndtpi, sizeof(*dt_args));
29881b6d302Sbluhm 		if (dt_args == NULL)
29981b6d302Sbluhm 			err(1, NULL);
30081b6d302Sbluhm 	}
30181b6d302Sbluhm 
30281b6d302Sbluhm 	if (dt_args[dtpi->dtpi_pbn - 1] != NULL)
30381b6d302Sbluhm 		return;
30481b6d302Sbluhm 
30581b6d302Sbluhm 	dt_args[dtpi->dtpi_pbn - 1] = reallocarray(NULL, dtpi->dtpi_nargs,
30681b6d302Sbluhm 	    sizeof(**dt_args));
30781b6d302Sbluhm 	if (dt_args[dtpi->dtpi_pbn - 1] == NULL)
30881b6d302Sbluhm 		err(1, NULL);
30981b6d302Sbluhm 
31081b6d302Sbluhm 	dtar.dtar_pbn = dtpi->dtpi_pbn;
31181b6d302Sbluhm 	dtar.dtar_size = dtpi->dtpi_nargs * sizeof(**dt_args);
31281b6d302Sbluhm 	dtar.dtar_args = dt_args[dtpi->dtpi_pbn - 1];
31381b6d302Sbluhm 	if (ioctl(fd, DTIOCGARGS, &dtar))
31481b6d302Sbluhm 		err(1, "DTIOCGARGS");
31581b6d302Sbluhm }
31681b6d302Sbluhm 
31781b6d302Sbluhm void
31881b6d302Sbluhm dtpi_print_list(int fd)
31923160851Smpi {
32023160851Smpi 	struct dtioc_probe_info *dtpi;
32181b6d302Sbluhm 	struct dtioc_arg_info *dtai;
32281b6d302Sbluhm 	size_t i, j;
32323160851Smpi 
32423160851Smpi 	dtpi = dt_dtpis;
32523160851Smpi 	for (i = 0; i < dt_ndtpi; i++, dtpi++) {
32681b6d302Sbluhm 		printf("%s:%s:%s", dtpi->dtpi_prov, dtpi_func(dtpi),
32723160851Smpi 		    dtpi->dtpi_name);
32881b6d302Sbluhm 		if (strncmp(dtpi->dtpi_prov, "tracepoint", DTNAMESIZE) == 0) {
32981b6d302Sbluhm 			dtai_cache(fd, dtpi);
33081b6d302Sbluhm 			dtai = dt_args[dtpi->dtpi_pbn - 1];
33181b6d302Sbluhm 			printf("(");
33281b6d302Sbluhm 			for (j = 0; j < dtpi->dtpi_nargs; j++, dtai++) {
33381b6d302Sbluhm 				if (j > 0)
33481b6d302Sbluhm 					printf(", ");
33581b6d302Sbluhm 				printf("%s", dtai->dtai_argtype);
33681b6d302Sbluhm 			}
33781b6d302Sbluhm 			printf(")");
33881b6d302Sbluhm 		}
33981b6d302Sbluhm 		printf("\n");
34023160851Smpi 	}
34123160851Smpi }
34223160851Smpi 
3434ed6f7c2Sguenther const char *
34423160851Smpi dtpi_func(struct dtioc_probe_info *dtpi)
34523160851Smpi {
34623160851Smpi 	char *sysnb, func[DTNAMESIZE];
34723160851Smpi 	const char *errstr;
34823160851Smpi 	int idx;
34923160851Smpi 
35023160851Smpi 	if (strncmp(dtpi->dtpi_prov, "syscall", DTNAMESIZE))
35123160851Smpi 		return dtpi->dtpi_func;
35223160851Smpi 
35323160851Smpi 	/* Translate syscall names */
35423160851Smpi 	strlcpy(func, dtpi->dtpi_func, sizeof(func));
35523160851Smpi 	sysnb = func;
35623160851Smpi 	if (strsep(&sysnb, "%") == NULL)
35723160851Smpi 		return dtpi->dtpi_func;
35823160851Smpi 
35923160851Smpi 	idx = strtonum(sysnb, 1, SYS_MAXSYSCALL, &errstr);
36023160851Smpi 	if (errstr != NULL)
36123160851Smpi 		return dtpi->dtpi_func;
36223160851Smpi 
36323160851Smpi 	return syscallnames[idx];
36423160851Smpi }
36523160851Smpi 
36623160851Smpi struct dtioc_probe_info *
36723160851Smpi dtpi_get_by_value(const char *prov, const char *func, const char *name)
36823160851Smpi {
36923160851Smpi 	struct dtioc_probe_info *dtpi;
37023160851Smpi 	size_t i;
37123160851Smpi 
37223160851Smpi 	dtpi = dt_dtpis;
37323160851Smpi 	for (i = 0; i < dt_ndtpi; i++, dtpi++) {
374*139d07b5Smpi 		if (prov != NULL) {
375*139d07b5Smpi 			if (strncmp(prov, dtpi->dtpi_prov, DTNAMESIZE))
37623160851Smpi 				continue;
37723160851Smpi 		}
378*139d07b5Smpi 		if (func != NULL && name != NULL) {
379*139d07b5Smpi 			if (strncmp(func, dtpi_func(dtpi), DTNAMESIZE))
380*139d07b5Smpi 				continue;
38123160851Smpi 			if (strncmp(name, dtpi->dtpi_name, DTNAMESIZE))
38223160851Smpi 				continue;
383*139d07b5Smpi 		}
38423160851Smpi 
38523160851Smpi 		debug("matched probe %s:%s:%s\n", dtpi->dtpi_prov,
38623160851Smpi 		    dtpi_func(dtpi), dtpi->dtpi_name);
38723160851Smpi 		return dtpi;
38823160851Smpi 	}
38923160851Smpi 
39023160851Smpi 	return NULL;
39123160851Smpi }
39223160851Smpi 
393*139d07b5Smpi static uint64_t
394*139d07b5Smpi bp_nsecs_to_unit(struct bt_probe *bp)
395*139d07b5Smpi {
396*139d07b5Smpi 	static const struct {
397*139d07b5Smpi 		const char *name;
398*139d07b5Smpi 		enum { UNIT_HZ, UNIT_US, UNIT_MS, UNIT_S } id;
399*139d07b5Smpi 	} units[] = {
400*139d07b5Smpi 		{ .name = "hz", .id = UNIT_HZ },
401*139d07b5Smpi 		{ .name = "us", .id = UNIT_US },
402*139d07b5Smpi 		{ .name = "ms", .id = UNIT_MS },
403*139d07b5Smpi 		{ .name = "s", .id = UNIT_S },
404*139d07b5Smpi 	};
405*139d07b5Smpi 	size_t i;
406*139d07b5Smpi 
407*139d07b5Smpi 	for (i = 0; i < nitems(units); i++) {
408*139d07b5Smpi 		if (strcmp(units[i].name, bp->bp_unit) == 0) {
409*139d07b5Smpi 			switch (units[i].id) {
410*139d07b5Smpi 			case UNIT_HZ:
411*139d07b5Smpi 				return (1000000000LLU / bp->bp_nsecs);
412*139d07b5Smpi 			case UNIT_US:
413*139d07b5Smpi 				return (bp->bp_nsecs / 1000LLU);
414*139d07b5Smpi 			case UNIT_MS:
415*139d07b5Smpi 				return (bp->bp_nsecs / 1000000LLU);
416*139d07b5Smpi 			case UNIT_S:
417*139d07b5Smpi 				return (bp->bp_nsecs / 1000000000LLU);
418*139d07b5Smpi 			}
419*139d07b5Smpi 		}
420*139d07b5Smpi 	}
421*139d07b5Smpi 	return 0;
422*139d07b5Smpi }
423*139d07b5Smpi 
42423160851Smpi void
425ffce2a54Smpi probe_bail(struct bt_probe *bp)
426ffce2a54Smpi {
427ffce2a54Smpi 	errx(1, "Cannot register multiple probes of the same type: '%s'",
428ffce2a54Smpi 	    probe_name(bp));
429ffce2a54Smpi }
430ffce2a54Smpi 
431ffce2a54Smpi const char *
432ffce2a54Smpi probe_name(struct bt_probe *bp)
433ffce2a54Smpi {
434ffce2a54Smpi 	static char buf[64];
435ffce2a54Smpi 
436ffce2a54Smpi 	if (bp->bp_type == B_PT_BEGIN)
437ffce2a54Smpi 		return "BEGIN";
438ffce2a54Smpi 
439ffce2a54Smpi 	if (bp->bp_type == B_PT_END)
440ffce2a54Smpi 		return "END";
441ffce2a54Smpi 
442ffce2a54Smpi 	assert(bp->bp_type == B_PT_PROBE);
443ffce2a54Smpi 
444*139d07b5Smpi 	if (bp->bp_nsecs) {
445*139d07b5Smpi 		snprintf(buf, sizeof(buf), "%s:%s:%llu", bp->bp_prov,
446*139d07b5Smpi 		    bp->bp_unit, bp_nsecs_to_unit(bp));
447ffce2a54Smpi 	} else {
448ffce2a54Smpi 		snprintf(buf, sizeof(buf), "%s:%s:%s", bp->bp_prov,
449ffce2a54Smpi 		    bp->bp_unit, bp->bp_name);
450ffce2a54Smpi 	}
451ffce2a54Smpi 
452ffce2a54Smpi 	return buf;
453ffce2a54Smpi }
454ffce2a54Smpi 
455ffce2a54Smpi void
4566ca6ae3fSmpi rules_do(int fd)
45723160851Smpi {
45823160851Smpi 	struct sigaction sa;
459a4c6ec8cScheloha 	int halt = 0;
46023160851Smpi 
46123160851Smpi 	memset(&sa, 0, sizeof(sa));
46223160851Smpi 	sigemptyset(&sa.sa_mask);
46323160851Smpi 	sa.sa_flags = 0;
46423160851Smpi 	sa.sa_handler = signal_handler;
46523160851Smpi 	if (sigaction(SIGINT, &sa, NULL))
46623160851Smpi 		err(1, "sigaction");
4677ba68130Sjca 	if (sigaction(SIGTERM, &sa, NULL))
4687ba68130Sjca 		err(1, "sigaction");
46923160851Smpi 
470a4c6ec8cScheloha 	halt = rules_setup(fd);
47123160851Smpi 
472a4c6ec8cScheloha 	while (!quit_pending && !halt && g_nprobes > 0) {
47323160851Smpi 		static struct dt_evt devtbuf[64];
47423160851Smpi 		ssize_t rlen;
47523160851Smpi 		size_t i;
47623160851Smpi 
477813b934aSmpi 		rlen = read(fd, devtbuf, sizeof(devtbuf));
47823160851Smpi 		if (rlen == -1) {
4799c84395dSmpi 			if (errno == EINTR && quit_pending) {
4809c84395dSmpi 				printf("\n");
48123160851Smpi 				break;
4829c84395dSmpi 			}
48323160851Smpi 			err(1, "read");
48423160851Smpi 		}
48523160851Smpi 
48623160851Smpi 		if ((rlen % sizeof(struct dt_evt)) != 0)
48723160851Smpi 			err(1, "incorrect read");
48823160851Smpi 
489a4c6ec8cScheloha 		for (i = 0; i < rlen / sizeof(struct dt_evt); i++) {
490a4c6ec8cScheloha 			halt = rules_apply(fd, &devtbuf[i]);
491a4c6ec8cScheloha 			if (halt)
492a4c6ec8cScheloha 				break;
493a4c6ec8cScheloha 		}
49423160851Smpi 	}
49523160851Smpi 
49623160851Smpi 	rules_teardown(fd);
49723160851Smpi 
49823160851Smpi 	if (verbose && fd != -1) {
49923160851Smpi 		struct dtioc_stat dtst;
50023160851Smpi 
50123160851Smpi 		memset(&dtst, 0, sizeof(dtst));
50223160851Smpi 		if (ioctl(fd, DTIOCGSTATS, &dtst))
50323160851Smpi 			warn("DTIOCGSTATS");
50423160851Smpi 
5057369eb9dSmpi 		fprintf(stderr, "%llu events read\n", dtst.dtst_readevt);
5067369eb9dSmpi 		fprintf(stderr, "%llu events dropped\n", dtst.dtst_dropevt);
5077369eb9dSmpi 		fprintf(stderr, "%llu events filtered\n", bt_filtered);
508bb6b0345Smpi 		fprintf(stderr, "%llu clock ticks skipped\n",
509bb6b0345Smpi 			dtst.dtst_skiptick);
510bb6b0345Smpi 		fprintf(stderr, "%llu recursive events dropped\n",
511bb6b0345Smpi 			dtst.dtst_recurevt);
51223160851Smpi 	}
51323160851Smpi }
51423160851Smpi 
515ab34c090Sclaudio static uint64_t
516ab34c090Sclaudio rules_action_scan(struct bt_stmt *bs)
517ab34c090Sclaudio {
518ab34c090Sclaudio 	struct bt_arg *ba;
519ca41b749Smpi 	struct bt_cond *bc;
520ab34c090Sclaudio 	uint64_t evtflags = 0;
521ab34c090Sclaudio 
522ab34c090Sclaudio 	while (bs != NULL) {
523ab34c090Sclaudio 		SLIST_FOREACH(ba, &bs->bs_args, ba_next)
524ab34c090Sclaudio 			evtflags |= ba2dtflags(ba);
525ab34c090Sclaudio 
526ab34c090Sclaudio 		/* Also check the value for map/hist insertion */
527ab34c090Sclaudio 		switch (bs->bs_act) {
528ab34c090Sclaudio 		case B_AC_BUCKETIZE:
529ab34c090Sclaudio 		case B_AC_INSERT:
530ab34c090Sclaudio 			ba = (struct bt_arg *)bs->bs_var;
531ab34c090Sclaudio 			evtflags |= ba2dtflags(ba);
532ab34c090Sclaudio 			break;
533ab34c090Sclaudio 		case B_AC_TEST:
534ca41b749Smpi 			bc = (struct bt_cond *)bs->bs_var;
535ca41b749Smpi 			evtflags |= rules_action_scan(bc->bc_condbs);
536ca41b749Smpi 			evtflags |= rules_action_scan(bc->bc_elsebs);
537ab34c090Sclaudio 			break;
538ab34c090Sclaudio 		default:
539ab34c090Sclaudio 			break;
540ab34c090Sclaudio 		}
541ab34c090Sclaudio 
542ab34c090Sclaudio 		bs = SLIST_NEXT(bs, bs_next);
543ab34c090Sclaudio 	}
544ab34c090Sclaudio 
545ab34c090Sclaudio 	return evtflags;
546ab34c090Sclaudio }
547ab34c090Sclaudio 
548a4c6ec8cScheloha int
5496ca6ae3fSmpi rules_setup(int fd)
55023160851Smpi {
55123160851Smpi 	struct dtioc_probe_info *dtpi;
55223160851Smpi 	struct dtioc_req *dtrq;
553ffce2a54Smpi 	struct bt_rule *r, *rbegin = NULL, *rend = NULL;
55423160851Smpi 	struct bt_probe *bp;
55523160851Smpi 	struct bt_stmt *bs;
5566f84e5f7Smpi 	struct bt_arg *ba;
557a4c6ec8cScheloha 	int dokstack = 0, halt = 0, on = 1;
5581694fc34Smpi 	uint64_t evtflags;
55923160851Smpi 
56023160851Smpi 	TAILQ_FOREACH(r, &g_rules, br_next) {
5611694fc34Smpi 		evtflags = 0;
56223160851Smpi 
5636f84e5f7Smpi 		if (r->br_filter != NULL &&
5646f84e5f7Smpi 		    r->br_filter->bf_condition != NULL)  {
5656f84e5f7Smpi 
5666f84e5f7Smpi 			bs = r->br_filter->bf_condition;
5676f84e5f7Smpi 			ba = SLIST_FIRST(&bs->bs_args);
5686f84e5f7Smpi 
5696f84e5f7Smpi 			evtflags |= ba2dtflags(ba);
5706f84e5f7Smpi 		}
5716f84e5f7Smpi 
572ab34c090Sclaudio 		evtflags |= rules_action_scan(SLIST_FIRST(&r->br_action));
57323160851Smpi 
5741694fc34Smpi 		SLIST_FOREACH(bp, &r->br_probes, bp_next) {
575ffce2a54Smpi 			debug("parsed probe '%s'", probe_name(bp));
5761694fc34Smpi 			debug_dump_filter(r);
5771694fc34Smpi 
5781694fc34Smpi 			if (bp->bp_type != B_PT_PROBE) {
579ffce2a54Smpi 				if (bp->bp_type == B_PT_BEGIN) {
580ffce2a54Smpi 					if (rbegin != NULL)
581ffce2a54Smpi 						probe_bail(bp);
5821694fc34Smpi 					rbegin = r;
583ffce2a54Smpi 				}
584ffce2a54Smpi 				if (bp->bp_type == B_PT_END) {
585ffce2a54Smpi 					if (rend != NULL)
586ffce2a54Smpi 						probe_bail(bp);
587ffce2a54Smpi 					rend = r;
588ffce2a54Smpi 				}
5891694fc34Smpi 				continue;
5901694fc34Smpi 			}
5911694fc34Smpi 
5921694fc34Smpi 			dtpi_cache(fd);
5931694fc34Smpi 			dtpi = dtpi_get_by_value(bp->bp_prov, bp->bp_func,
5941694fc34Smpi 			    bp->bp_name);
5951694fc34Smpi 			if (dtpi == NULL) {
5961694fc34Smpi 				errx(1, "probe '%s:%s:%s' not found",
5971694fc34Smpi 				    bp->bp_prov, bp->bp_func, bp->bp_name);
5981694fc34Smpi 			}
5991694fc34Smpi 
6001694fc34Smpi 			dtrq = calloc(1, sizeof(*dtrq));
6011694fc34Smpi 			if (dtrq == NULL)
6021694fc34Smpi 				err(1, "dtrq: 1alloc");
6031694fc34Smpi 
6041694fc34Smpi 			bp->bp_pbn = dtpi->dtpi_pbn;
6051694fc34Smpi 			dtrq->dtrq_pbn = dtpi->dtpi_pbn;
606*139d07b5Smpi 			dtrq->dtrq_nsecs = bp->bp_nsecs;
6071694fc34Smpi 			dtrq->dtrq_evtflags = evtflags;
60866793fc5Smpi 			if (dtrq->dtrq_evtflags & DTEVT_KSTACK)
60966793fc5Smpi 				dokstack = 1;
6101694fc34Smpi 			bp->bp_cookie = dtrq;
6111694fc34Smpi 		}
61223160851Smpi 	}
61323160851Smpi 
61423160851Smpi 	if (dokstack)
6155e6104a1Sclaudio 		kelf = kelf_open(_PATH_KSYMS);
61623160851Smpi 
617d2392c66Smpi 	/* Initialize "fake" event for BEGIN/END */
6189e79f3a0Sdv 	bt_devt.dtev_pbn = EVENT_BEGIN;
61914cb6e73Sderaadt 	strlcpy(bt_devt.dtev_comm, getprogname(), sizeof(bt_devt.dtev_comm));
620d2392c66Smpi 	bt_devt.dtev_pid = getpid();
621d2392c66Smpi 	bt_devt.dtev_tid = getthrid();
62224fbf86fSdv 	clock_gettime(CLOCK_REALTIME, &bt_devt.dtev_tsp);
623d2392c66Smpi 
62423160851Smpi 	if (rbegin)
625a4c6ec8cScheloha 		halt = rule_eval(rbegin, &bt_devt);
62623160851Smpi 
62723160851Smpi 	/* Enable all probes */
62823160851Smpi 	TAILQ_FOREACH(r, &g_rules, br_next) {
6291694fc34Smpi 		SLIST_FOREACH(bp, &r->br_probes, bp_next) {
6301694fc34Smpi 			if (bp->bp_type != B_PT_PROBE)
63123160851Smpi 				continue;
63223160851Smpi 
6331694fc34Smpi 			dtrq = bp->bp_cookie;
634ffce2a54Smpi 			if (ioctl(fd, DTIOCPRBENABLE, dtrq)) {
635ffce2a54Smpi 				if (errno == EEXIST)
636ffce2a54Smpi 					probe_bail(bp);
63723160851Smpi 				err(1, "DTIOCPRBENABLE");
63823160851Smpi 			}
6391694fc34Smpi 		}
640ffce2a54Smpi 	}
64123160851Smpi 
64223160851Smpi 	if (g_nprobes > 0) {
64323160851Smpi 		if (ioctl(fd, DTIOCRECORD, &on))
64423160851Smpi 			err(1, "DTIOCRECORD");
64523160851Smpi 	}
646a4c6ec8cScheloha 
647a4c6ec8cScheloha 	return halt;
64823160851Smpi }
64923160851Smpi 
650a4c6ec8cScheloha /*
651a4c6ec8cScheloha  * Returns non-zero if the program should halt.
652a4c6ec8cScheloha  */
653a4c6ec8cScheloha int
65481b6d302Sbluhm rules_apply(int fd, struct dt_evt *dtev)
65523160851Smpi {
65623160851Smpi 	struct bt_rule *r;
6571694fc34Smpi 	struct bt_probe *bp;
65823160851Smpi 
65923160851Smpi 	TAILQ_FOREACH(r, &g_rules, br_next) {
6601694fc34Smpi 		SLIST_FOREACH(bp, &r->br_probes, bp_next) {
6611694fc34Smpi 			if (bp->bp_type != B_PT_PROBE ||
6621694fc34Smpi 			    bp->bp_pbn != dtev->dtev_pbn)
66323160851Smpi 				continue;
66400f5894bSdv 
66581b6d302Sbluhm 			dtai_cache(fd, &dt_dtpis[dtev->dtev_pbn - 1]);
666a4c6ec8cScheloha 			if (rule_eval(r, dtev))
667a4c6ec8cScheloha 				return 1;
66823160851Smpi 		}
66923160851Smpi 	}
670a4c6ec8cScheloha 	return 0;
6711694fc34Smpi }
67223160851Smpi 
67323160851Smpi void
67423160851Smpi rules_teardown(int fd)
67523160851Smpi {
67623160851Smpi 	struct dtioc_req *dtrq;
6771694fc34Smpi 	struct bt_probe *bp;
67823160851Smpi 	struct bt_rule *r, *rend = NULL;
67923160851Smpi 	int dokstack = 0, off = 0;
68023160851Smpi 
68123160851Smpi 	if (g_nprobes > 0) {
68223160851Smpi 		if (ioctl(fd, DTIOCRECORD, &off))
68323160851Smpi 			err(1, "DTIOCRECORD");
68423160851Smpi 	}
68523160851Smpi 
68623160851Smpi 	TAILQ_FOREACH(r, &g_rules, br_next) {
6871694fc34Smpi 		SLIST_FOREACH(bp, &r->br_probes, bp_next) {
6881694fc34Smpi 			if (bp->bp_type != B_PT_PROBE) {
6891694fc34Smpi 				if (bp->bp_type == B_PT_END)
69023160851Smpi 					rend = r;
69123160851Smpi 				continue;
69223160851Smpi 			}
69323160851Smpi 
6941694fc34Smpi 			dtrq = bp->bp_cookie;
6951694fc34Smpi 			if (ioctl(fd, DTIOCPRBDISABLE, dtrq))
6961694fc34Smpi 				err(1, "DTIOCPRBDISABLE");
69723160851Smpi 			if (dtrq->dtrq_evtflags & DTEVT_KSTACK)
69823160851Smpi 				dokstack = 1;
69923160851Smpi 		}
7001694fc34Smpi 	}
70123160851Smpi 
7025e6104a1Sclaudio 	kelf_close(kelf);
7035e6104a1Sclaudio 	kelf = NULL;
7045e6104a1Sclaudio 	kelf_close(uelf);
7055e6104a1Sclaudio 	uelf = NULL;
70623160851Smpi 
70724fbf86fSdv 	/* Update "fake" event for BEGIN/END */
7089e79f3a0Sdv 	bt_devt.dtev_pbn = EVENT_END;
70924fbf86fSdv 	clock_gettime(CLOCK_REALTIME, &bt_devt.dtev_tsp);
71024fbf86fSdv 
71123160851Smpi 	if (rend)
712d2392c66Smpi 		rule_eval(rend, &bt_devt);
713a31d03f7Smpi 
71442cd3088Smpi 	/* Print non-empty map & hist */
7151b29203bSmpi 	TAILQ_FOREACH(r, &g_rules, br_next)
7161b29203bSmpi 		rule_printmaps(r);
7171b29203bSmpi }
71823160851Smpi 
719a4c6ec8cScheloha /*
720a4c6ec8cScheloha  * Returns non-zero if the program should halt.
721a4c6ec8cScheloha  */
722a4c6ec8cScheloha int
72323160851Smpi rule_eval(struct bt_rule *r, struct dt_evt *dtev)
72423160851Smpi {
72523160851Smpi 	struct bt_stmt *bs;
7261694fc34Smpi 	struct bt_probe *bp;
72723160851Smpi 
7281694fc34Smpi 	SLIST_FOREACH(bp, &r->br_probes, bp_next) {
729ffce2a54Smpi 		debug("eval rule '%s'", probe_name(bp));
730a31d03f7Smpi 		debug_dump_filter(r);
7311694fc34Smpi 	}
73223160851Smpi 
733ea0c567aSmpi 	if (r->br_filter != NULL && r->br_filter->bf_condition != NULL) {
734822ace7eSmpi 		if (stmt_test(r->br_filter->bf_condition, dtev) == false) {
735822ace7eSmpi 			bt_filtered++;
736a4c6ec8cScheloha 			return 0;
737ea0c567aSmpi 		}
738822ace7eSmpi 	}
739ea0c567aSmpi 
74023160851Smpi 	SLIST_FOREACH(bs, &r->br_action, bs_next) {
741a4c6ec8cScheloha 		if (stmt_eval(bs, dtev))
742a4c6ec8cScheloha 			return 1;
74323160851Smpi 	}
744a4c6ec8cScheloha 
745a4c6ec8cScheloha 	return 0;
74623160851Smpi }
74723160851Smpi 
7481b29203bSmpi void
7491b29203bSmpi rule_printmaps(struct bt_rule *r)
7501b29203bSmpi {
7511b29203bSmpi 	struct bt_stmt *bs;
7521b29203bSmpi 
7531b29203bSmpi 	SLIST_FOREACH(bs, &r->br_action, bs_next) {
7541b29203bSmpi 		struct bt_arg *ba;
7551b29203bSmpi 
7561b29203bSmpi 		SLIST_FOREACH(ba, &bs->bs_args, ba_next) {
757244912e4Smpi 			struct bt_var *bv = ba->ba_value;
758d2392c66Smpi 			struct map *map;
759244912e4Smpi 
7609c84395dSmpi 			if (ba->ba_type != B_AT_MAP && ba->ba_type != B_AT_HIST)
7611b29203bSmpi 				continue;
7621b29203bSmpi 
763d2392c66Smpi 			map = (struct map *)bv->bv_value;
764d2392c66Smpi 			if (map == NULL)
765d2392c66Smpi 				continue;
766244912e4Smpi 
7679c84395dSmpi 			if (ba->ba_type == B_AT_MAP)
768244912e4Smpi 				map_print(map, SIZE_T_MAX, bv_name(bv));
7699c84395dSmpi 			else
7709c84395dSmpi 				hist_print((struct hist *)map, bv_name(bv));
771244912e4Smpi 			map_clear(map);
772244912e4Smpi 			bv->bv_value = NULL;
773244912e4Smpi 		}
7741b29203bSmpi 	}
7751b29203bSmpi }
7761b29203bSmpi 
777a378a2aaSmpi time_t
778a378a2aaSmpi builtin_gettime(struct dt_evt *dtev)
779a378a2aaSmpi {
780a378a2aaSmpi 	struct timespec ts;
781a378a2aaSmpi 
782a378a2aaSmpi 	if (dtev == NULL) {
783a378a2aaSmpi 		clock_gettime(CLOCK_REALTIME, &ts);
784a378a2aaSmpi 		return ts.tv_sec;
785a378a2aaSmpi 	}
786a378a2aaSmpi 
787a378a2aaSmpi 	return dtev->dtev_tsp.tv_sec;
788a378a2aaSmpi }
789a378a2aaSmpi 
79023160851Smpi static inline uint64_t
79123160851Smpi TIMESPEC_TO_NSEC(struct timespec *ts)
79223160851Smpi {
79323160851Smpi 	return (ts->tv_sec * 1000000000L + ts->tv_nsec);
79423160851Smpi }
79523160851Smpi 
79623160851Smpi uint64_t
79723160851Smpi builtin_nsecs(struct dt_evt *dtev)
79823160851Smpi {
79928f863d2Scheloha 	struct timespec ts;
80023160851Smpi 
80123160851Smpi 	if (dtev == NULL) {
80228f863d2Scheloha 		clock_gettime(CLOCK_REALTIME, &ts);
80328f863d2Scheloha 		return TIMESPEC_TO_NSEC(&ts);
80428f863d2Scheloha 	}
80523160851Smpi 
80628f863d2Scheloha 	return TIMESPEC_TO_NSEC(&dtev->dtev_tsp);
80723160851Smpi }
80823160851Smpi 
80923160851Smpi const char *
8105e6104a1Sclaudio builtin_stack(struct dt_evt *dtev, int kernel, unsigned long offset)
81123160851Smpi {
81223160851Smpi 	struct stacktrace *st = &dtev->dtev_kstack;
8135e6104a1Sclaudio 	static char buf[4096];
8145e6104a1Sclaudio 	const char *last = "\nkernel\n";
8155e6104a1Sclaudio 	char *bp;
81623160851Smpi 	size_t i;
81727f0efdaSbluhm 	int sz;
81823160851Smpi 
8195e6104a1Sclaudio 	if (!kernel) {
8205e6104a1Sclaudio 		st = &dtev->dtev_ustack;
8215e6104a1Sclaudio 		last = "\nuserland\n";
8225e6104a1Sclaudio 	} else if (st->st_count == 0) {
8231897e8bfSbluhm 		return "\nuserland\n";
8245e6104a1Sclaudio 	}
82523160851Smpi 
82627f0efdaSbluhm 	buf[0] = '\0';
82727f0efdaSbluhm 	bp = buf;
82827f0efdaSbluhm 	sz = sizeof(buf);
82923160851Smpi 	for (i = 0; i < st->st_count; i++) {
83027f0efdaSbluhm 		int l;
83127f0efdaSbluhm 
8325e6104a1Sclaudio 		if (!kernel)
8335e6104a1Sclaudio 			l = kelf_snprintsym(uelf, bp, sz - 1, st->st_pc[i],
8345e6104a1Sclaudio 			    offset);
8355e6104a1Sclaudio 		else
8365e6104a1Sclaudio 			l = kelf_snprintsym(kelf, bp, sz - 1, st->st_pc[i],
8375e6104a1Sclaudio 			    offset);
83827f0efdaSbluhm 		if (l < 0)
83927f0efdaSbluhm 			break;
84027f0efdaSbluhm 		if (l >= sz - 1) {
84127f0efdaSbluhm 			bp += sz - 1;
84227f0efdaSbluhm 			sz = 1;
84327f0efdaSbluhm 			break;
84423160851Smpi 		}
84527f0efdaSbluhm 		bp += l;
84627f0efdaSbluhm 		sz -= l;
84727f0efdaSbluhm 	}
8485e6104a1Sclaudio 	snprintf(bp, sz, "%s", last);
84923160851Smpi 
85023160851Smpi 	return buf;
85123160851Smpi }
85223160851Smpi 
85323160851Smpi const char *
85423160851Smpi builtin_arg(struct dt_evt *dtev, enum bt_argtype dat)
85523160851Smpi {
85623160851Smpi 	static char buf[sizeof("18446744073709551615")]; /* UINT64_MAX */
85775c43f25Smpi 	struct dtioc_probe_info *dtpi;
85881b6d302Sbluhm 	struct dtioc_arg_info *dtai;
85981b6d302Sbluhm 	const char *argtype, *fmt;
86075c43f25Smpi 	unsigned int argn;
86181b6d302Sbluhm 	long value;
86223160851Smpi 
86300f5894bSdv 	argn = dat - B_AT_BI_ARG0;
86475c43f25Smpi 	dtpi = &dt_dtpis[dtev->dtev_pbn - 1];
86575c43f25Smpi 	if (dtpi == NULL || argn >= dtpi->dtpi_nargs)
86675c43f25Smpi 		return "0";
86775c43f25Smpi 
86875c43f25Smpi 	dtai = dt_args[dtev->dtev_pbn - 1];
86981b6d302Sbluhm 	argtype = dtai[argn].dtai_argtype;
87081b6d302Sbluhm 
87181b6d302Sbluhm 	if (strncmp(argtype, "int", DTNAMESIZE) == 0) {
87281b6d302Sbluhm 		fmt = "%d";
87381b6d302Sbluhm 		value = (int)dtev->dtev_args[argn];
87481b6d302Sbluhm 	} else {
87581b6d302Sbluhm 		fmt = "%lu";
87681b6d302Sbluhm 		value = dtev->dtev_args[argn];
87781b6d302Sbluhm 	}
87881b6d302Sbluhm 
87900f5894bSdv 	snprintf(buf, sizeof(buf), fmt, dtev->dtev_args[argn]);
880199e5b12Smpi 
88123160851Smpi 	return buf;
88223160851Smpi }
88323160851Smpi 
884a4c6ec8cScheloha /*
885a4c6ec8cScheloha  * Returns non-zero if the program should halt.
886a4c6ec8cScheloha  */
887a4c6ec8cScheloha int
8884846dae3Smpi stmt_eval(struct bt_stmt *bs, struct dt_evt *dtev)
8894846dae3Smpi {
890ca41b749Smpi 	struct bt_stmt *bbs;
891ca41b749Smpi 	struct bt_cond *bc;
892a4c6ec8cScheloha 	int halt = 0;
893a4c6ec8cScheloha 
8944846dae3Smpi 	switch (bs->bs_act) {
8954846dae3Smpi 	case B_AC_BUCKETIZE:
8964846dae3Smpi 		stmt_bucketize(bs, dtev);
8974846dae3Smpi 		break;
8984846dae3Smpi 	case B_AC_CLEAR:
8994846dae3Smpi 		stmt_clear(bs);
9004846dae3Smpi 		break;
9014846dae3Smpi 	case B_AC_DELETE:
9024846dae3Smpi 		stmt_delete(bs, dtev);
9034846dae3Smpi 		break;
9044846dae3Smpi 	case B_AC_EXIT:
905a4c6ec8cScheloha 		halt = 1;
9064846dae3Smpi 		break;
9074846dae3Smpi 	case B_AC_INSERT:
9084846dae3Smpi 		stmt_insert(bs, dtev);
9094846dae3Smpi 		break;
9104846dae3Smpi 	case B_AC_PRINT:
9114846dae3Smpi 		stmt_print(bs, dtev);
9124846dae3Smpi 		break;
9134846dae3Smpi 	case B_AC_PRINTF:
9144846dae3Smpi 		stmt_printf(bs, dtev);
9154846dae3Smpi 		break;
9164846dae3Smpi 	case B_AC_STORE:
9174846dae3Smpi 		stmt_store(bs, dtev);
9184846dae3Smpi 		break;
9194846dae3Smpi 	case B_AC_TEST:
920ca41b749Smpi 		bc = (struct bt_cond *)bs->bs_var;
921ca41b749Smpi 		if (stmt_test(bs, dtev) == true)
922ca41b749Smpi 			bbs = bc->bc_condbs;
923ca41b749Smpi 		else
924ca41b749Smpi 			bbs = bc->bc_elsebs;
925ca41b749Smpi 
926ca41b749Smpi 		while (bbs != NULL) {
927ca41b749Smpi 			if (stmt_eval(bbs, dtev))
928ca41b749Smpi 				return 1;
929ca41b749Smpi 			bbs = SLIST_NEXT(bbs, bs_next);
930ca41b749Smpi 		}
9314846dae3Smpi 		break;
9324846dae3Smpi 	case B_AC_TIME:
9334846dae3Smpi 		stmt_time(bs, dtev);
9344846dae3Smpi 		break;
9354846dae3Smpi 	case B_AC_ZERO:
9364846dae3Smpi 		stmt_zero(bs);
9374846dae3Smpi 		break;
9384846dae3Smpi 	default:
9394846dae3Smpi 		xabort("no handler for action type %d", bs->bs_act);
9404846dae3Smpi 	}
941a4c6ec8cScheloha 	return halt;
9424846dae3Smpi }
9434846dae3Smpi 
9449c84395dSmpi /*
9459c84395dSmpi  * Increment a bucket:	{ @h = hist(v); } or { @h = lhist(v, min, max, step); }
9469c84395dSmpi  *
9479c84395dSmpi  * In this case 'h' is represented by `bv' and '(min, max, step)' by `brange'.
9489c84395dSmpi  */
9499c84395dSmpi void
9509c84395dSmpi stmt_bucketize(struct bt_stmt *bs, struct dt_evt *dtev)
9519c84395dSmpi {
9529c84395dSmpi 	struct bt_arg *brange, *bhist = SLIST_FIRST(&bs->bs_args);
9539c84395dSmpi 	struct bt_arg *bval = (struct bt_arg *)bs->bs_var;
9549c84395dSmpi 	struct bt_var *bv = bhist->ba_value;
95566f34ae4Smpi 	struct hist *hist;
9569c84395dSmpi 	const char *bucket;
9579c84395dSmpi 	long step = 0;
9589c84395dSmpi 
9599c84395dSmpi 	assert(bhist->ba_type == B_AT_HIST);
9609c84395dSmpi 	assert(SLIST_NEXT(bval, ba_next) == NULL);
9619c84395dSmpi 
9629c84395dSmpi 	brange = bhist->ba_key;
9639c84395dSmpi 	bucket = ba2bucket(bval, brange, dtev, &step);
9649c84395dSmpi 	if (bucket == NULL) {
9659c84395dSmpi 		debug("hist=%p '%s' value=%lu out of range\n", bv->bv_value,
9669c84395dSmpi 		    bv_name(bv), ba2long(bval, dtev));
9679c84395dSmpi 		return;
9689c84395dSmpi 	}
969a31d03f7Smpi 	debug("hist=%p '%s' increment bucket '%s'\n", bv->bv_value,
9709c84395dSmpi 	    bv_name(bv), bucket);
9719c84395dSmpi 
97266f34ae4Smpi 	/* hist is NULL before first insert or after clear() */
97366f34ae4Smpi 	hist = (struct hist *)bv->bv_value;
97466f34ae4Smpi 	if (hist == NULL)
97566f34ae4Smpi 		hist = hist_new(step);
97666f34ae4Smpi 
97766f34ae4Smpi 	hist_increment(hist, bucket);
97866f34ae4Smpi 
97966f34ae4Smpi 	debug("hist=%p '%s' increment bucket=%p '%s' bval=%p\n", hist,
98066f34ae4Smpi 	    bv_name(bv), brange, bucket, bval);
98166f34ae4Smpi 
98266f34ae4Smpi 	bv->bv_value = (struct bt_arg *)hist;
983d2392c66Smpi 	bv->bv_type = B_VT_HIST;
9849c84395dSmpi }
9859c84395dSmpi 
986a77acc3dSmpi 
987a77acc3dSmpi /*
988a77acc3dSmpi  * Empty a map:		{ clear(@map); }
989a77acc3dSmpi  */
99023160851Smpi void
99123160851Smpi stmt_clear(struct bt_stmt *bs)
99223160851Smpi {
99323160851Smpi 	struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
99423160851Smpi 	struct bt_var *bv = ba->ba_value;
9957ccb822dSmpi 	struct map *map;
99623160851Smpi 
99723160851Smpi 	assert(bs->bs_var == NULL);
998e504d9bfSmpi 	assert(ba->ba_type == B_AT_VAR);
99923160851Smpi 
10007ccb822dSmpi 	map = (struct map *)bv->bv_value;
10017ccb822dSmpi 	if (map == NULL)
10027ccb822dSmpi 		return;
10037ccb822dSmpi 
10042e354f38Smpi 	if (bv->bv_type != B_VT_MAP && bv->bv_type != B_VT_HIST)
10052e354f38Smpi 		errx(1, "invalid variable type for clear(%s)", ba_name(ba));
10062e354f38Smpi 
10077ccb822dSmpi 	map_clear(map);
1008244912e4Smpi 	bv->bv_value = NULL;
100923160851Smpi 
10107ccb822dSmpi 	debug("map=%p '%s' clear\n", map, bv_name(bv));
101123160851Smpi }
101223160851Smpi 
101323160851Smpi /*
101423160851Smpi  * Map delete:	 	{ delete(@map[key]); }
101523160851Smpi  *
101623160851Smpi  * In this case 'map' is represented by `bv' and 'key' by `bkey'.
101723160851Smpi  */
101823160851Smpi void
101923160851Smpi stmt_delete(struct bt_stmt *bs, struct dt_evt *dtev)
102023160851Smpi {
102188be68dbSmpi 	struct bt_arg *bkey, *bmap = SLIST_FIRST(&bs->bs_args);
102288be68dbSmpi 	struct bt_var *bv = bmap->ba_value;
10237ccb822dSmpi 	struct map *map;
1024b9f00a1bSmpi 	const char *hash;
102523160851Smpi 
102688be68dbSmpi 	assert(bmap->ba_type == B_AT_MAP);
102788be68dbSmpi 	assert(bs->bs_var == NULL);
102888be68dbSmpi 
10297ccb822dSmpi 	map = (struct map *)bv->bv_value;
10307ccb822dSmpi 	if (map == NULL)
10317ccb822dSmpi 		return;
10327ccb822dSmpi 
103388be68dbSmpi 	bkey = bmap->ba_key;
1034b9f00a1bSmpi 	hash = ba2hash(bkey, dtev);
10357ccb822dSmpi 	debug("map=%p '%s' delete key=%p '%s'\n", map, bv_name(bv), bkey, hash);
103623160851Smpi 
10377ccb822dSmpi 	map_delete(map, hash);
103823160851Smpi }
103923160851Smpi 
104023160851Smpi /*
104123160851Smpi  * Map insert:	 	{ @map[key] = 42; }
104223160851Smpi  *
104323160851Smpi  * In this case 'map' is represented by `bv', 'key' by `bkey' and
104423160851Smpi  * '42' by `bval'.
104523160851Smpi  */
104623160851Smpi void
104723160851Smpi stmt_insert(struct bt_stmt *bs, struct dt_evt *dtev)
104823160851Smpi {
104988be68dbSmpi 	struct bt_arg *bkey, *bmap = SLIST_FIRST(&bs->bs_args);
105088be68dbSmpi 	struct bt_arg *bval = (struct bt_arg *)bs->bs_var;
105188be68dbSmpi 	struct bt_var *bv = bmap->ba_value;
10527ccb822dSmpi 	struct map *map;
1053b9f00a1bSmpi 	const char *hash;
105466f34ae4Smpi 	long val;
105523160851Smpi 
105688be68dbSmpi 	assert(bmap->ba_type == B_AT_MAP);
105788be68dbSmpi 	assert(SLIST_NEXT(bval, ba_next) == NULL);
105823160851Smpi 
105988be68dbSmpi 	bkey = bmap->ba_key;
1060b9f00a1bSmpi 	hash = ba2hash(bkey, dtev);
10617ccb822dSmpi 
10627ccb822dSmpi 	/* map is NULL before first insert or after clear() */
10637ccb822dSmpi 	map = (struct map *)bv->bv_value;
106466f34ae4Smpi 	if (map == NULL)
106566f34ae4Smpi 		map = map_new();
106666f34ae4Smpi 
106766f34ae4Smpi 	/* Operate on existring value for count(), max(), min() and sum(). */
106866f34ae4Smpi 	switch (bval->ba_type) {
106966f34ae4Smpi 	case B_AT_MF_COUNT:
107066f34ae4Smpi 		val = ba2long(map_get(map, hash), NULL);
107166f34ae4Smpi 		val++;
107266f34ae4Smpi 		bval = ba_new(val, B_AT_LONG);
107366f34ae4Smpi 		break;
107466f34ae4Smpi 	case B_AT_MF_MAX:
107566f34ae4Smpi 		val = ba2long(map_get(map, hash), NULL);
107666f34ae4Smpi 		val = MAXIMUM(val, ba2long(bval->ba_value, dtev));
107766f34ae4Smpi 		bval = ba_new(val, B_AT_LONG);
107866f34ae4Smpi 		break;
107966f34ae4Smpi 	case B_AT_MF_MIN:
108066f34ae4Smpi 		val = ba2long(map_get(map, hash), NULL);
108166f34ae4Smpi 		val = MINIMUM(val, ba2long(bval->ba_value, dtev));
108266f34ae4Smpi 		bval = ba_new(val, B_AT_LONG);
108366f34ae4Smpi 		break;
108466f34ae4Smpi 	case B_AT_MF_SUM:
108566f34ae4Smpi 		val = ba2long(map_get(map, hash), NULL);
108666f34ae4Smpi 		val += ba2long(bval->ba_value, dtev);
108766f34ae4Smpi 		bval = ba_new(val, B_AT_LONG);
108866f34ae4Smpi 		break;
108966f34ae4Smpi 	default:
10901a48bdffSmpi 		bval = baeval(bval, dtev);
109166f34ae4Smpi 		break;
109266f34ae4Smpi 	}
109366f34ae4Smpi 
109466f34ae4Smpi 	map_insert(map, hash, bval);
10957ccb822dSmpi 
10967ccb822dSmpi 	debug("map=%p '%s' insert key=%p '%s' bval=%p\n", map,
1097b9f00a1bSmpi 	    bv_name(bv), bkey, hash, bval);
109888be68dbSmpi 
10997ccb822dSmpi 	bv->bv_value = (struct bt_arg *)map;
1100d2392c66Smpi 	bv->bv_type = B_VT_MAP;
110123160851Smpi }
110223160851Smpi 
110323160851Smpi /*
1104d2392c66Smpi  * Print variables:	{ print(890); print(@map[, 8]); print(comm); }
110523160851Smpi  *
110623160851Smpi  * In this case the global variable 'map' is pointed at by `ba'
110723160851Smpi  * and '8' is represented by `btop'.
110823160851Smpi  */
110923160851Smpi void
111023160851Smpi stmt_print(struct bt_stmt *bs, struct dt_evt *dtev)
111123160851Smpi {
111223160851Smpi 	struct bt_arg *btop, *ba = SLIST_FIRST(&bs->bs_args);
111323160851Smpi 	struct bt_var *bv = ba->ba_value;
11147ccb822dSmpi 	struct map *map;
111523160851Smpi 	size_t top = SIZE_T_MAX;
111623160851Smpi 
111723160851Smpi 	assert(bs->bs_var == NULL);
111823160851Smpi 
111923160851Smpi 	/* Parse optional `top' argument. */
112023160851Smpi 	btop = SLIST_NEXT(ba, ba_next);
112123160851Smpi 	if (btop != NULL) {
112223160851Smpi 		assert(SLIST_NEXT(btop, ba_next) == NULL);
112323160851Smpi 		top = ba2long(btop, dtev);
112423160851Smpi 	}
1125d2392c66Smpi 
1126d2392c66Smpi 	/* Static argument. */
1127d2392c66Smpi 	if (ba->ba_type != B_AT_VAR) {
1128d2392c66Smpi 		assert(btop == NULL);
1129d2392c66Smpi 		printf("%s\n", ba2str(ba, dtev));
1130d2392c66Smpi 		return;
1131d2392c66Smpi 	}
1132d2392c66Smpi 
11337ccb822dSmpi 	map = (struct map *)bv->bv_value;
11347ccb822dSmpi 	if (map == NULL)
1135d2392c66Smpi 		return;
1136d2392c66Smpi 
11377ccb822dSmpi 	debug("map=%p '%s' print (top=%d)\n", bv->bv_value, bv_name(bv), top);
11387ccb822dSmpi 
1139d2392c66Smpi 	if (bv->bv_type == B_VT_MAP)
11407ccb822dSmpi 		map_print(map, top, bv_name(bv));
1141d2392c66Smpi 	else if (bv->bv_type == B_VT_HIST)
11427ccb822dSmpi 		hist_print((struct hist *)map, bv_name(bv));
1143d2392c66Smpi 	else
1144d2392c66Smpi 		printf("%s\n", ba2str(ba, dtev));
114523160851Smpi }
114623160851Smpi 
114723160851Smpi /*
1148ea0c567aSmpi  * Variable store: 	{ @var = 3; }
114923160851Smpi  *
115023160851Smpi  * In this case '3' is represented by `ba', the argument of a STORE
115123160851Smpi  * action.
115223160851Smpi  *
115323160851Smpi  * If the argument depends of the value of an event (builtin) or is
115423160851Smpi  * the result of an operation, its evaluation is stored in a new `ba'.
115523160851Smpi  */
115623160851Smpi void
115723160851Smpi stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
115823160851Smpi {
115923160851Smpi 	struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
116066f34ae4Smpi 	struct bt_var *bvar, *bv = bs->bs_var;
1161db30eb4fSmpi 	struct map *map;
116223160851Smpi 
116323160851Smpi 	assert(SLIST_NEXT(ba, ba_next) == NULL);
116423160851Smpi 
116523160851Smpi 	switch (ba->ba_type) {
1166d2392c66Smpi 	case B_AT_STR:
1167d2392c66Smpi 		bv->bv_value = ba;
1168d2392c66Smpi 		bv->bv_type = B_VT_STR;
1169d2392c66Smpi 		break;
117023160851Smpi 	case B_AT_LONG:
117123160851Smpi 		bv->bv_value = ba;
1172d2392c66Smpi 		bv->bv_type = B_VT_LONG;
117323160851Smpi 		break;
117466f34ae4Smpi 	case B_AT_VAR:
117566f34ae4Smpi 		bvar = ba->ba_value;
117666f34ae4Smpi 		bv->bv_type = bvar->bv_type;
117766f34ae4Smpi 		bv->bv_value = bvar->bv_value;
117866f34ae4Smpi 		break;
1179db30eb4fSmpi 	case B_AT_MAP:
1180db30eb4fSmpi 		bvar = ba->ba_value;
1181db30eb4fSmpi 		map = (struct map *)bvar->bv_value;
1182db30eb4fSmpi 		/* Uninitialized map */
1183db30eb4fSmpi 		if (map == NULL)
1184db30eb4fSmpi 			bv->bv_value = 0;
1185db30eb4fSmpi 		else
1186db30eb4fSmpi 			bv->bv_value = map_get(map, ba2hash(ba->ba_key, dtev));
1187db30eb4fSmpi 		bv->bv_type = B_VT_LONG; /* XXX should we type map? */
1188db30eb4fSmpi 		break;
118966f34ae4Smpi 	case B_AT_TUPLE:
119066f34ae4Smpi 		bv->bv_value = baeval(ba, dtev);
119166f34ae4Smpi 		bv->bv_type = B_VT_TUPLE;
119266f34ae4Smpi 		break;
11938e126920Smpi 	case B_AT_BI_PID:
11948e126920Smpi 	case B_AT_BI_TID:
119545154bcbSmpi 	case B_AT_BI_CPU:
119623160851Smpi 	case B_AT_BI_NSECS:
119745154bcbSmpi 	case B_AT_BI_RETVAL:
1198805b8a65Smpi 	case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
1199a31d03f7Smpi 	case B_AT_OP_PLUS ... B_AT_OP_LOR:
120066f34ae4Smpi 		bv->bv_value = baeval(ba, dtev);
1201d2392c66Smpi 		bv->bv_type = B_VT_LONG;
120223160851Smpi 		break;
120345154bcbSmpi 	case B_AT_BI_COMM:
120445154bcbSmpi 	case B_AT_BI_KSTACK:
120545154bcbSmpi 	case B_AT_BI_USTACK:
120645154bcbSmpi 	case B_AT_BI_PROBE:
1207b005393aSdv 	case B_AT_FN_STR:
120866f34ae4Smpi 		bv->bv_value = baeval(ba, dtev);
1209b005393aSdv 		bv->bv_type = B_VT_STR;
1210b005393aSdv 		break;
121123160851Smpi 	default:
121223160851Smpi 		xabort("store not implemented for type %d", ba->ba_type);
121323160851Smpi 	}
121423160851Smpi 
121566f34ae4Smpi 	debug("bv=%p var '%s' store (%p)='%s'\n", bv, bv_name(bv), bv->bv_value,
121666f34ae4Smpi 	    ba2str(bv->bv_value, dtev));
121723160851Smpi }
121823160851Smpi 
1219a378a2aaSmpi /*
1220b005393aSdv  * String conversion	{ str($1); string($1, 3); }
1221b005393aSdv  *
1222b005393aSdv  * Since fn_str is currently only called in ba2str, *buf should be a pointer
1223b005393aSdv  * to the static buffer provided by ba2str.
1224b005393aSdv  */
1225b005393aSdv struct bt_arg *
1226b005393aSdv fn_str(struct bt_arg *ba, struct dt_evt *dtev, char *buf)
1227b005393aSdv {
1228b005393aSdv 	struct bt_arg *arg, *index;
1229b005393aSdv 	ssize_t len = STRLEN;
1230b005393aSdv 
1231b005393aSdv 	assert(ba->ba_type == B_AT_FN_STR);
1232b005393aSdv 
1233b005393aSdv 	arg = (struct bt_arg*)ba->ba_value;
1234b005393aSdv 	assert(arg != NULL);
1235b005393aSdv 
1236b005393aSdv 	index = SLIST_NEXT(arg, ba_next);
1237b005393aSdv 	if (index != NULL) {
1238b005393aSdv 		/* Should have only 1 optional argument. */
1239b005393aSdv 		assert(SLIST_NEXT(index, ba_next) == NULL);
1240b005393aSdv 		len = MINIMUM(ba2long(index, dtev) + 1, STRLEN);
1241b005393aSdv 	}
1242b005393aSdv 
1243b005393aSdv 	/* All negative lengths behave the same as a zero length. */
1244b005393aSdv 	if (len < 1)
1245b005393aSdv 		return ba_new("", B_AT_STR);
1246b005393aSdv 
1247b005393aSdv 	strlcpy(buf, ba2str(arg, dtev), len);
1248b005393aSdv 	return ba_new(buf, B_AT_STR);
1249b005393aSdv }
1250b005393aSdv 
1251b005393aSdv /*
1252ea0c567aSmpi  * Expression test:	{ if (expr) stmt; }
1253ea0c567aSmpi  */
1254ea0c567aSmpi bool
1255ea0c567aSmpi stmt_test(struct bt_stmt *bs, struct dt_evt *dtev)
1256ea0c567aSmpi {
125789f39301Smpi 	struct bt_arg *ba;
1258ea0c567aSmpi 
1259ea0c567aSmpi 	if (bs == NULL)
1260ea0c567aSmpi 		return true;
1261ea0c567aSmpi 
126289f39301Smpi 	ba = SLIST_FIRST(&bs->bs_args);
1263ea0c567aSmpi 
126489f39301Smpi 	return baexpr2long(ba, dtev) != 0;
1265ea0c567aSmpi }
1266ea0c567aSmpi 
1267ea0c567aSmpi /*
1268a378a2aaSmpi  * Print time: 		{ time("%H:%M:%S"); }
1269a378a2aaSmpi  */
1270a378a2aaSmpi void
1271a378a2aaSmpi stmt_time(struct bt_stmt *bs, struct dt_evt *dtev)
1272a378a2aaSmpi {
1273a378a2aaSmpi 	struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
1274a378a2aaSmpi 	time_t time;
1275a378a2aaSmpi 	struct tm *tm;
1276a378a2aaSmpi 	char buf[64];
1277a378a2aaSmpi 
1278a378a2aaSmpi 	assert(bs->bs_var == NULL);
1279e504d9bfSmpi 	assert(ba->ba_type == B_AT_STR);
1280a378a2aaSmpi 	assert(strlen(ba2str(ba, dtev)) < (sizeof(buf) - 1));
1281a378a2aaSmpi 
1282a378a2aaSmpi 	time = builtin_gettime(dtev);
1283a378a2aaSmpi 	tm = localtime(&time);
1284a378a2aaSmpi 	strftime(buf, sizeof(buf), ba2str(ba, dtev), tm);
1285a378a2aaSmpi 	printf("%s", buf);
1286a378a2aaSmpi }
1287a378a2aaSmpi 
1288a77acc3dSmpi /*
1289a77acc3dSmpi  * Set entries to 0:	{ zero(@map); }
1290a77acc3dSmpi  */
129123160851Smpi void
129223160851Smpi stmt_zero(struct bt_stmt *bs)
129323160851Smpi {
129423160851Smpi 	struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
129523160851Smpi 	struct bt_var *bv = ba->ba_value;
12967ccb822dSmpi 	struct map *map;
129723160851Smpi 
129823160851Smpi 	assert(bs->bs_var == NULL);
1299e504d9bfSmpi 	assert(ba->ba_type == B_AT_VAR);
130023160851Smpi 
13017ccb822dSmpi 	map = (struct map *)bv->bv_value;
13027ccb822dSmpi 	if (map == NULL)
13037ccb822dSmpi 		return;
130423160851Smpi 
13052e354f38Smpi 	if (bv->bv_type != B_VT_MAP && bv->bv_type != B_VT_HIST)
13062e354f38Smpi 		errx(1, "invalid variable type for zero(%s)", ba_name(ba));
13072e354f38Smpi 
13087ccb822dSmpi 	map_zero(map);
13097ccb822dSmpi 
13107ccb822dSmpi 	debug("map=%p '%s' zero\n", map, bv_name(bv));
131123160851Smpi }
131288be68dbSmpi 
131323160851Smpi struct bt_arg *
131423160851Smpi ba_read(struct bt_arg *ba)
131523160851Smpi {
131623160851Smpi 	struct bt_var *bv = ba->ba_value;
131723160851Smpi 
131823160851Smpi 	assert(ba->ba_type == B_AT_VAR);
13199936fd19Smpi 	debug("bv=%p read '%s' (%p)\n", bv, bv_name(bv), bv->bv_value);
132023160851Smpi 
1321b303712aSmpi 	/* Handle map/hist access after clear(). */
1322b303712aSmpi 	if (bv->bv_value == NULL)
1323b303712aSmpi 		return &g_nullba;
1324b303712aSmpi 
132523160851Smpi 	return bv->bv_value;
132623160851Smpi }
132723160851Smpi 
132866f34ae4Smpi // XXX
132966f34ae4Smpi extern struct bt_arg	*ba_append(struct bt_arg *, struct bt_arg *);
133066f34ae4Smpi 
133166f34ae4Smpi /*
133266f34ae4Smpi  * Return a new argument that doesn't depend on `dtev'.  This is used
133366f34ae4Smpi  * when storing values in variables, maps, etc.
133466f34ae4Smpi  */
133566f34ae4Smpi struct bt_arg *
133666f34ae4Smpi baeval(struct bt_arg *bval, struct dt_evt *dtev)
133766f34ae4Smpi {
133866f34ae4Smpi 	struct bt_arg *ba, *bh = NULL;
133966f34ae4Smpi 
134066f34ae4Smpi 	switch (bval->ba_type) {
134166f34ae4Smpi 	case B_AT_VAR:
134266f34ae4Smpi 		ba = baeval(ba_read(bval), NULL);
134366f34ae4Smpi 		break;
134466f34ae4Smpi 	case B_AT_LONG:
134566f34ae4Smpi 	case B_AT_BI_PID:
134666f34ae4Smpi 	case B_AT_BI_TID:
134766f34ae4Smpi 	case B_AT_BI_CPU:
134866f34ae4Smpi 	case B_AT_BI_NSECS:
134966f34ae4Smpi 	case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
135066f34ae4Smpi 	case B_AT_BI_RETVAL:
135166f34ae4Smpi 	case B_AT_OP_PLUS ... B_AT_OP_LOR:
135266f34ae4Smpi 		ba = ba_new(ba2long(bval, dtev), B_AT_LONG);
135366f34ae4Smpi 		break;
135466f34ae4Smpi 	case B_AT_STR:
135566f34ae4Smpi 	case B_AT_BI_COMM:
135666f34ae4Smpi 	case B_AT_BI_KSTACK:
135766f34ae4Smpi 	case B_AT_BI_USTACK:
135866f34ae4Smpi 	case B_AT_BI_PROBE:
135966f34ae4Smpi 	case B_AT_FN_STR:
136066f34ae4Smpi 		ba = ba_new(ba2str(bval, dtev), B_AT_STR);
136166f34ae4Smpi 		break;
136266f34ae4Smpi 	case B_AT_TUPLE:
136366f34ae4Smpi 		ba = bval->ba_value;
136466f34ae4Smpi 		do {
136566f34ae4Smpi 			bh = ba_append(bh, baeval(ba, dtev));
136666f34ae4Smpi 		} while ((ba = SLIST_NEXT(ba, ba_next)) != NULL);
136766f34ae4Smpi 		ba = ba_new(bh, B_AT_TUPLE);
136866f34ae4Smpi 		break;
136966f34ae4Smpi 	default:
137066f34ae4Smpi 		xabort("no eval support for type %d", bval->ba_type);
137166f34ae4Smpi 	}
137266f34ae4Smpi 
137366f34ae4Smpi 	return ba;
137466f34ae4Smpi }
137566f34ae4Smpi 
137666f34ae4Smpi /*
137766f34ae4Smpi  * Return a string of coma-separated values
137866f34ae4Smpi  */
13796f386ca5Smpi const char *
13806f386ca5Smpi ba2hash(struct bt_arg *ba, struct dt_evt *dtev)
13816f386ca5Smpi {
138242858fb0Smpi 	static char buf[KLEN];
13836f386ca5Smpi 	char *hash;
13846f386ca5Smpi 	int l, len;
13856f386ca5Smpi 
138627f0efdaSbluhm 	buf[0] = '\0';
13876f386ca5Smpi 	l = snprintf(buf, sizeof(buf), "%s", ba2str(ba, dtev));
13886f386ca5Smpi 	if (l < 0 || (size_t)l > sizeof(buf)) {
13896f386ca5Smpi 		warn("string too long %d > %lu", l, sizeof(buf));
13906f386ca5Smpi 		return buf;
13916f386ca5Smpi 	}
13926f386ca5Smpi 
13936f386ca5Smpi 	len = 0;
13946f386ca5Smpi 	while ((ba = SLIST_NEXT(ba, ba_next)) != NULL) {
13956f386ca5Smpi 		len += l;
13966f386ca5Smpi 		hash = buf + len;
13976f386ca5Smpi 
13986f386ca5Smpi 		l = snprintf(hash, sizeof(buf) - len, ", %s", ba2str(ba, dtev));
13996f386ca5Smpi 		if (l < 0 || (size_t)l > (sizeof(buf) - len)) {
14006f386ca5Smpi 			warn("hash too long %d > %lu", l + len, sizeof(buf));
14016f386ca5Smpi 			break;
14026f386ca5Smpi 		}
14036f386ca5Smpi 	}
14046f386ca5Smpi 
14056f386ca5Smpi 	return buf;
14066f386ca5Smpi }
14076f386ca5Smpi 
14089c84395dSmpi static unsigned long
14099c84395dSmpi next_pow2(unsigned long x)
14109c84395dSmpi {
14119c84395dSmpi 	size_t i;
14129c84395dSmpi 
14139c84395dSmpi 	x--;
14149c84395dSmpi 	for (i = 0; i < (sizeof(x)  * 8) - 1; i++)
14159c84395dSmpi 		x |= (x >> 1);
14169c84395dSmpi 
14179c84395dSmpi 	return x + 1;
14189c84395dSmpi }
14199c84395dSmpi 
14209c84395dSmpi /*
14219c84395dSmpi  * Return the ceiling value the interval holding `ba' or NULL if it is
14229c84395dSmpi  * out of the (min, max) values.
14239c84395dSmpi  */
14249c84395dSmpi const char *
14259c84395dSmpi ba2bucket(struct bt_arg *ba, struct bt_arg *brange, struct dt_evt *dtev,
14269c84395dSmpi     long *pstep)
14279c84395dSmpi {
142842858fb0Smpi 	static char buf[KLEN];
14299c84395dSmpi 	long val, bucket;
14309c84395dSmpi 	int l;
14319c84395dSmpi 
14329c84395dSmpi 	val = ba2long(ba, dtev);
14339c84395dSmpi 	if (brange == NULL)
14349c84395dSmpi 		bucket = next_pow2(val);
14359c84395dSmpi 	else {
14369c84395dSmpi 		long min, max, step;
14379c84395dSmpi 
14389c84395dSmpi 		assert(brange->ba_type == B_AT_LONG);
14399c84395dSmpi 		min = ba2long(brange, NULL);
14409c84395dSmpi 
14419c84395dSmpi 		brange = SLIST_NEXT(brange, ba_next);
14429c84395dSmpi 		assert(brange->ba_type == B_AT_LONG);
14439c84395dSmpi 		max = ba2long(brange, NULL);
14449c84395dSmpi 
14459c84395dSmpi 		if ((val < min) || (val > max))
14469c84395dSmpi 			return NULL;
14479c84395dSmpi 
14489c84395dSmpi 		brange = SLIST_NEXT(brange, ba_next);
14499c84395dSmpi 		assert(brange->ba_type == B_AT_LONG);
14509c84395dSmpi 		step = ba2long(brange, NULL);
14519c84395dSmpi 
14529c84395dSmpi 		bucket = ((val / step) + 1) * step;
14539c84395dSmpi 		*pstep = step;
14549c84395dSmpi 	}
14559c84395dSmpi 
145627f0efdaSbluhm 	buf[0] = '\0';
14579c84395dSmpi 	l = snprintf(buf, sizeof(buf), "%lu", bucket);
14589c84395dSmpi 	if (l < 0 || (size_t)l > sizeof(buf)) {
14599c84395dSmpi 		warn("string too long %d > %lu", l, sizeof(buf));
14609c84395dSmpi 		return buf;
14619c84395dSmpi 	}
14629c84395dSmpi 
14639c84395dSmpi 	return buf;
14649c84395dSmpi }
14659c84395dSmpi 
146623160851Smpi /*
1467822ace7eSmpi  * Evaluate the operation encoded in `ba' and return its result.
146823160851Smpi  */
1469822ace7eSmpi long
147023160851Smpi baexpr2long(struct bt_arg *ba, struct dt_evt *dtev)
147123160851Smpi {
147223160851Smpi 	static long recursions;
147389f39301Smpi 	struct bt_arg *lhs, *rhs;
147489f39301Smpi 	long lval, rval, result;
147523160851Smpi 
147623160851Smpi 	if (++recursions >= __MAXOPERANDS)
147723160851Smpi 		errx(1, "too many operands (>%d) in expression", __MAXOPERANDS);
147823160851Smpi 
147989f39301Smpi 	lhs = ba->ba_value;
148089f39301Smpi 	rhs = SLIST_NEXT(lhs, ba_next);
1481822ace7eSmpi 
14826f84e5f7Smpi 	/*
14836f84e5f7Smpi 	 * String comparison also use '==' and '!='.
14846f84e5f7Smpi 	 */
14856f84e5f7Smpi 	if (lhs->ba_type == B_AT_STR ||
14866f84e5f7Smpi 	    (rhs != NULL && rhs->ba_type == B_AT_STR)) {
14876f84e5f7Smpi 	    	char lstr[STRLEN], rstr[STRLEN];
14886f84e5f7Smpi 
14896f84e5f7Smpi 		strlcpy(lstr, ba2str(lhs, dtev), sizeof(lstr));
14906f84e5f7Smpi 		strlcpy(rstr, ba2str(rhs, dtev), sizeof(rstr));
14916f84e5f7Smpi 
14926f84e5f7Smpi 	    	result = strncmp(lstr, rstr, STRLEN) == 0;
14936f84e5f7Smpi 
14946f84e5f7Smpi 		switch (ba->ba_type) {
14956f84e5f7Smpi 		case B_AT_OP_EQ:
14966f84e5f7Smpi 			break;
14976f84e5f7Smpi 		case B_AT_OP_NE:
14986f84e5f7Smpi 	    		result = !result;
14996f84e5f7Smpi 			break;
15006f84e5f7Smpi 		default:
15016f84e5f7Smpi 			warnx("operation '%d' unsupported on strings",
15026f84e5f7Smpi 			    ba->ba_type);
15036f84e5f7Smpi 			result = 1;
15046f84e5f7Smpi 		}
15056f84e5f7Smpi 
15066f84e5f7Smpi 		debug("ba=%p eval '(%s %s %s) = %d'\n", ba, lstr, ba_name(ba),
15076f84e5f7Smpi 		   rstr, result);
15086f84e5f7Smpi 
15096f84e5f7Smpi 		goto out;
15106f84e5f7Smpi 	}
15116f84e5f7Smpi 
151289f39301Smpi 	lval = ba2long(lhs, dtev);
151389f39301Smpi 	if (rhs == NULL) {
151489f39301Smpi 		rval = 0;
1515822ace7eSmpi 	} else {
151689f39301Smpi 		assert(SLIST_NEXT(rhs, ba_next) == NULL);
151789f39301Smpi 		rval = ba2long(rhs, dtev);
1518822ace7eSmpi 	}
151923160851Smpi 
152023160851Smpi 	switch (ba->ba_type) {
1521a31d03f7Smpi 	case B_AT_OP_PLUS:
152289f39301Smpi 		result = lval + rval;
152323160851Smpi 		break;
152423160851Smpi 	case B_AT_OP_MINUS:
152589f39301Smpi 		result = lval - rval;
152623160851Smpi 		break;
152723160851Smpi 	case B_AT_OP_MULT:
152889f39301Smpi 		result = lval * rval;
152923160851Smpi 		break;
153023160851Smpi 	case B_AT_OP_DIVIDE:
153189f39301Smpi 		result = lval / rval;
153223160851Smpi 		break;
1533b9c158acScheloha 	case B_AT_OP_MODULO:
1534b9c158acScheloha 		result = lval % rval;
1535b9c158acScheloha 		break;
1536a31d03f7Smpi 	case B_AT_OP_BAND:
153789f39301Smpi 		result = lval & rval;
153889f39301Smpi 		break;
153989f39301Smpi 	case B_AT_OP_XOR:
154089f39301Smpi 		result = lval ^ rval;
154128fab4caSjasper 		break;
1542a31d03f7Smpi 	case B_AT_OP_BOR:
154389f39301Smpi 		result = lval | rval;
154428fab4caSjasper 		break;
1545a31d03f7Smpi 	case B_AT_OP_EQ:
154689f39301Smpi 		result = (lval == rval);
1547a31d03f7Smpi 		break;
1548a31d03f7Smpi 	case B_AT_OP_NE:
154989f39301Smpi 		result = (lval != rval);
1550a31d03f7Smpi 		break;
1551a31d03f7Smpi 	case B_AT_OP_LE:
155289f39301Smpi 		result = (lval <= rval);
1553a31d03f7Smpi 		break;
155425efc3b0Smpi 	case B_AT_OP_LT:
155589f39301Smpi 		result = (lval < rval);
155625efc3b0Smpi 		break;
1557a31d03f7Smpi 	case B_AT_OP_GE:
155889f39301Smpi 		result = (lval >= rval);
1559a31d03f7Smpi 		break;
156025efc3b0Smpi 	case B_AT_OP_GT:
156189f39301Smpi 		result = (lval > rval);
156225efc3b0Smpi 		break;
1563a31d03f7Smpi 	case B_AT_OP_LAND:
156489f39301Smpi 		result = (lval && rval);
1565a31d03f7Smpi 		break;
1566a31d03f7Smpi 	case B_AT_OP_LOR:
156789f39301Smpi 		result = (lval || rval);
1568a31d03f7Smpi 		break;
156923160851Smpi 	default:
157082be1593Smpi 		xabort("unsupported operation %d", ba->ba_type);
157123160851Smpi 	}
157223160851Smpi 
15736f84e5f7Smpi 	debug("ba=%p eval '(%ld %s %ld) = %d'\n", ba, lval, ba_name(ba),
157489f39301Smpi 	   rval, result);
157523160851Smpi 
15766f84e5f7Smpi out:
157723160851Smpi 	--recursions;
157823160851Smpi 
157923160851Smpi 	return result;
158023160851Smpi }
158123160851Smpi 
1582a31d03f7Smpi const char *
1583a31d03f7Smpi ba_name(struct bt_arg *ba)
1584a31d03f7Smpi {
1585a31d03f7Smpi 	switch (ba->ba_type) {
15866f84e5f7Smpi 	case B_AT_STR:
15876f84e5f7Smpi 		return (const char *)ba->ba_value;
15886f84e5f7Smpi 	case B_AT_LONG:
15896f84e5f7Smpi 		return ba2str(ba, NULL);
15905dead9d9Smpi 	case B_AT_NIL:
15915dead9d9Smpi 		return "0";
1592822ace7eSmpi 	case B_AT_VAR:
1593822ace7eSmpi 	case B_AT_MAP:
15946f84e5f7Smpi 	case B_AT_HIST:
1595822ace7eSmpi 		break;
1596a31d03f7Smpi 	case B_AT_BI_PID:
1597a31d03f7Smpi 		return "pid";
1598a31d03f7Smpi 	case B_AT_BI_TID:
1599a31d03f7Smpi 		return "tid";
160089f39301Smpi 	case B_AT_BI_COMM:
160189f39301Smpi 		return "comm";
160289f39301Smpi 	case B_AT_BI_CPU:
160389f39301Smpi 		return "cpu";
160489f39301Smpi 	case B_AT_BI_NSECS:
160589f39301Smpi 		return "nsecs";
160689f39301Smpi 	case B_AT_BI_KSTACK:
160789f39301Smpi 		return "kstack";
160889f39301Smpi 	case B_AT_BI_USTACK:
160989f39301Smpi 		return "ustack";
161089f39301Smpi 	case B_AT_BI_ARG0:
161189f39301Smpi 		return "arg0";
161289f39301Smpi 	case B_AT_BI_ARG1:
161389f39301Smpi 		return "arg1";
161489f39301Smpi 	case B_AT_BI_ARG2:
161589f39301Smpi 		return "arg2";
161689f39301Smpi 	case B_AT_BI_ARG3:
161789f39301Smpi 		return "arg3";
161889f39301Smpi 	case B_AT_BI_ARG4:
161989f39301Smpi 		return "arg4";
162089f39301Smpi 	case B_AT_BI_ARG5:
162189f39301Smpi 		return "arg5";
162289f39301Smpi 	case B_AT_BI_ARG6:
162389f39301Smpi 		return "arg6";
162489f39301Smpi 	case B_AT_BI_ARG7:
162589f39301Smpi 		return "arg7";
162689f39301Smpi 	case B_AT_BI_ARG8:
162789f39301Smpi 		return "arg8";
162889f39301Smpi 	case B_AT_BI_ARG9:
162989f39301Smpi 		return "arg9";
163089f39301Smpi 	case B_AT_BI_ARGS:
163189f39301Smpi 		return "args";
163289f39301Smpi 	case B_AT_BI_RETVAL:
163389f39301Smpi 		return "retval";
1634ca210abeSclaudio 	case B_AT_BI_PROBE:
1635ca210abeSclaudio 		return "probe";
1636b005393aSdv 	case B_AT_FN_STR:
1637b005393aSdv 		return "str";
1638a31d03f7Smpi 	case B_AT_OP_PLUS:
1639a31d03f7Smpi 		return "+";
1640a31d03f7Smpi 	case B_AT_OP_MINUS:
1641a31d03f7Smpi 		return "-";
1642a31d03f7Smpi 	case B_AT_OP_MULT:
1643a31d03f7Smpi 		return "*";
1644a31d03f7Smpi 	case B_AT_OP_DIVIDE:
1645a31d03f7Smpi 		return "/";
1646b9c158acScheloha 	case B_AT_OP_MODULO:
1647b9c158acScheloha 		return "%";
1648a31d03f7Smpi 	case B_AT_OP_BAND:
1649a31d03f7Smpi 		return "&";
165089f39301Smpi 	case B_AT_OP_XOR:
165189f39301Smpi 		return "^";
1652a31d03f7Smpi 	case B_AT_OP_BOR:
1653a31d03f7Smpi 		return "|";
1654a31d03f7Smpi 	case B_AT_OP_EQ:
1655a31d03f7Smpi 		return "==";
1656a31d03f7Smpi 	case B_AT_OP_NE:
1657a31d03f7Smpi 		return "!=";
1658a31d03f7Smpi 	case B_AT_OP_LE:
1659a31d03f7Smpi 		return "<=";
166025efc3b0Smpi 	case B_AT_OP_LT:
166125efc3b0Smpi 		return "<";
1662a31d03f7Smpi 	case B_AT_OP_GE:
1663a31d03f7Smpi 		return ">=";
166425efc3b0Smpi 	case B_AT_OP_GT:
166525efc3b0Smpi 		return ">";
1666a31d03f7Smpi 	case B_AT_OP_LAND:
1667a31d03f7Smpi 		return "&&";
1668a31d03f7Smpi 	case B_AT_OP_LOR:
1669a31d03f7Smpi 		return "||";
1670a31d03f7Smpi 	default:
167182be1593Smpi 		xabort("unsupported type %d", ba->ba_type);
1672a31d03f7Smpi 	}
1673a31d03f7Smpi 
16746f84e5f7Smpi 	assert(ba->ba_type == B_AT_VAR || ba->ba_type == B_AT_MAP ||
16756f84e5f7Smpi 	    ba->ba_type == B_AT_HIST);
1676822ace7eSmpi 
1677822ace7eSmpi 	static char buf[64];
1678822ace7eSmpi 	size_t sz;
1679822ace7eSmpi 	int l;
1680822ace7eSmpi 
1681822ace7eSmpi 	buf[0] = '@';
1682822ace7eSmpi 	buf[1] = '\0';
1683822ace7eSmpi 	sz = sizeof(buf) - 1;
1684822ace7eSmpi 	l = snprintf(buf+1, sz, "%s", bv_name(ba->ba_value));
1685822ace7eSmpi 	if (l < 0 || (size_t)l > sz) {
1686822ace7eSmpi 		warn("string too long %d > %zu", l, sz);
1687822ace7eSmpi 		return buf;
1688822ace7eSmpi 	}
1689822ace7eSmpi 
1690822ace7eSmpi 	if (ba->ba_type == B_AT_MAP) {
1691822ace7eSmpi 		sz -= l;
1692822ace7eSmpi 		l = snprintf(buf+1+l, sz, "[%s]", ba_name(ba->ba_key));
1693822ace7eSmpi 		if (l < 0 || (size_t)l > sz) {
1694822ace7eSmpi 			warn("string too long %d > %zu", l, sz);
1695822ace7eSmpi 			return buf;
1696822ace7eSmpi 		}
1697822ace7eSmpi 	}
1698822ace7eSmpi 
1699822ace7eSmpi 	return buf;
1700a31d03f7Smpi }
1701a31d03f7Smpi 
170223160851Smpi /*
170323160851Smpi  * Return the representation of `ba' as long.
170423160851Smpi  */
170523160851Smpi long
170623160851Smpi ba2long(struct bt_arg *ba, struct dt_evt *dtev)
170723160851Smpi {
170803b76035Smpi 	struct bt_var *bv;
170923160851Smpi 	long val;
171023160851Smpi 
171123160851Smpi 	switch (ba->ba_type) {
17120cfb5c4bSmpi 	case B_AT_STR:
17130cfb5c4bSmpi 		val = (*ba2str(ba, dtev) == '\0') ? 0 : 1;
17140cfb5c4bSmpi 		break;
171523160851Smpi 	case B_AT_LONG:
171623160851Smpi 		val = (long)ba->ba_value;
171723160851Smpi 		break;
171823160851Smpi 	case B_AT_VAR:
171923160851Smpi 		ba = ba_read(ba);
172023160851Smpi 		val = (long)ba->ba_value;
172123160851Smpi 		break;
172203b76035Smpi 	case B_AT_MAP:
172303b76035Smpi 		bv = ba->ba_value;
17243a50f0a9Sjmc 		/* Uninitialized map */
1725a31d03f7Smpi 		if (bv->bv_value == NULL)
1726a31d03f7Smpi 			return 0;
172703b76035Smpi 		val = ba2long(map_get((struct map *)bv->bv_value,
17289cf6efbeSmpi 		    ba2hash(ba->ba_key, dtev)), dtev);
172903b76035Smpi 		break;
173058afdee7Sdv 	case B_AT_NIL:
173158afdee7Sdv 		val = 0L;
173258afdee7Sdv 		break;
1733822ace7eSmpi 	case B_AT_BI_PID:
1734822ace7eSmpi 		val = dtev->dtev_pid;
1735822ace7eSmpi 		break;
1736822ace7eSmpi 	case B_AT_BI_TID:
1737822ace7eSmpi 		val = dtev->dtev_tid;
1738822ace7eSmpi 		break;
1739db788fbbSdv 	case B_AT_BI_CPU:
1740db788fbbSdv 		val = dtev->dtev_cpu;
1741db788fbbSdv 		break;
174223160851Smpi 	case B_AT_BI_NSECS:
174323160851Smpi 		val = builtin_nsecs(dtev);
174423160851Smpi 		break;
17458a02394dSmpi 	case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
174663d5bccfSjasper 		val = dtev->dtev_args[ba->ba_type - B_AT_BI_ARG0];
17478a02394dSmpi 		break;
1748405649c2Smpi 	case B_AT_BI_RETVAL:
174963d5bccfSjasper 		val = dtev->dtev_retval[0];
1750405649c2Smpi 		break;
1751ca210abeSclaudio 	case B_AT_BI_PROBE:
1752ca210abeSclaudio 		val = dtev->dtev_pbn;
1753ca210abeSclaudio 		break;
1754a31d03f7Smpi 	case B_AT_OP_PLUS ... B_AT_OP_LOR:
175523160851Smpi 		val = baexpr2long(ba, dtev);
175623160851Smpi 		break;
175723160851Smpi 	default:
175823160851Smpi 		xabort("no long conversion for type %d", ba->ba_type);
175923160851Smpi 	}
176023160851Smpi 
176123160851Smpi 	return  val;
176223160851Smpi }
176323160851Smpi 
176423160851Smpi /*
176523160851Smpi  * Return the representation of `ba' as string.
176623160851Smpi  */
176723160851Smpi const char *
176823160851Smpi ba2str(struct bt_arg *ba, struct dt_evt *dtev)
176923160851Smpi {
1770b005393aSdv 	static char buf[STRLEN];
1771244912e4Smpi 	struct bt_var *bv;
1772ca210abeSclaudio 	struct dtioc_probe_info *dtpi;
177366f34ae4Smpi 	unsigned long idx;
177423160851Smpi 	const char *str;
177523160851Smpi 
177627f0efdaSbluhm 	buf[0] = '\0';
177723160851Smpi 	switch (ba->ba_type) {
177823160851Smpi 	case B_AT_STR:
177923160851Smpi 		str = (const char *)ba->ba_value;
178023160851Smpi 		break;
178123160851Smpi 	case B_AT_LONG:
178227f0efdaSbluhm 		snprintf(buf, sizeof(buf), "%ld",(long)ba->ba_value);
178323160851Smpi 		str = buf;
178423160851Smpi 		break;
178566f34ae4Smpi 	case B_AT_TUPLE:
178666f34ae4Smpi 		snprintf(buf, sizeof(buf), "(%s)", ba2hash(ba->ba_value, dtev));
178766f34ae4Smpi 		str = buf;
178866f34ae4Smpi 		break;
178966f34ae4Smpi 	case B_AT_TMEMBER:
179066f34ae4Smpi 		idx = (unsigned long)ba->ba_key;
179166f34ae4Smpi 		bv = ba->ba_value;
179266f34ae4Smpi 		/* Uninitialized tuple */
179366f34ae4Smpi 		if (bv->bv_value == NULL) {
179466f34ae4Smpi 			str = buf;
179566f34ae4Smpi 			break;
179666f34ae4Smpi 		}
179766f34ae4Smpi 		ba = bv->bv_value;
179866f34ae4Smpi 		assert(ba->ba_type == B_AT_TUPLE);
179966f34ae4Smpi 		ba = ba->ba_value;
180066f34ae4Smpi 		while (ba != NULL && idx-- > 0) {
180166f34ae4Smpi 			ba = SLIST_NEXT(ba, ba_next);
180266f34ae4Smpi 		}
180366f34ae4Smpi 		str = ba2str(ba, dtev);
180466f34ae4Smpi 		break;
180558afdee7Sdv 	case B_AT_NIL:
180658afdee7Sdv 		str = "";
180758afdee7Sdv 		break;
180823160851Smpi 	case B_AT_BI_KSTACK:
18095e6104a1Sclaudio 		str = builtin_stack(dtev, 1, 0);
181023160851Smpi 		break;
181123160851Smpi 	case B_AT_BI_USTACK:
18125e6104a1Sclaudio 		str = builtin_stack(dtev, 0, dt_get_offset(dtev->dtev_pid));
181323160851Smpi 		break;
181423160851Smpi 	case B_AT_BI_COMM:
181523160851Smpi 		str = dtev->dtev_comm;
181623160851Smpi 		break;
18170948ba6cSmpi 	case B_AT_BI_CPU:
181827f0efdaSbluhm 		snprintf(buf, sizeof(buf), "%u", dtev->dtev_cpu);
18190948ba6cSmpi 		str = buf;
18200948ba6cSmpi 		break;
182123160851Smpi 	case B_AT_BI_PID:
182227f0efdaSbluhm 		snprintf(buf, sizeof(buf), "%d", dtev->dtev_pid);
182323160851Smpi 		str = buf;
182423160851Smpi 		break;
182523160851Smpi 	case B_AT_BI_TID:
182627f0efdaSbluhm 		snprintf(buf, sizeof(buf), "%d", dtev->dtev_tid);
182723160851Smpi 		str = buf;
182823160851Smpi 		break;
182923160851Smpi 	case B_AT_BI_NSECS:
183027f0efdaSbluhm 		snprintf(buf, sizeof(buf), "%llu", builtin_nsecs(dtev));
183123160851Smpi 		str = buf;
183223160851Smpi 		break;
183323160851Smpi 	case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
183423160851Smpi 		str = builtin_arg(dtev, ba->ba_type);
183523160851Smpi 		break;
183623160851Smpi 	case B_AT_BI_RETVAL:
183763d5bccfSjasper 		snprintf(buf, sizeof(buf), "%ld", (long)dtev->dtev_retval[0]);
183823160851Smpi 		str = buf;
183923160851Smpi 		break;
1840ca210abeSclaudio 	case B_AT_BI_PROBE:
18419e79f3a0Sdv 		if (dtev->dtev_pbn == EVENT_BEGIN) {
18429e79f3a0Sdv 			str = "BEGIN";
18439e79f3a0Sdv 			break;
18449e79f3a0Sdv 		} else if (dtev->dtev_pbn == EVENT_END) {
18459e79f3a0Sdv 			str = "END";
18469e79f3a0Sdv 			break;
18479e79f3a0Sdv 		}
184881b6d302Sbluhm 		dtpi = &dt_dtpis[dtev->dtev_pbn - 1];
1849ca210abeSclaudio 		if (dtpi != NULL)
1850ca210abeSclaudio 			snprintf(buf, sizeof(buf), "%s:%s:%s",
1851ca210abeSclaudio 			    dtpi->dtpi_prov, dtpi_func(dtpi), dtpi->dtpi_name);
1852ca210abeSclaudio 		else
1853ca210abeSclaudio 			snprintf(buf, sizeof(buf), "%u", dtev->dtev_pbn);
1854ca210abeSclaudio 		str = buf;
1855ca210abeSclaudio 		break;
185688be68dbSmpi 	case B_AT_MAP:
1857244912e4Smpi 		bv = ba->ba_value;
18583a50f0a9Sjmc 		/* Uninitialized map */
18590291cf98Smpi 		if (bv->bv_value == NULL) {
18600291cf98Smpi 			str = buf;
18610291cf98Smpi 			break;
18620291cf98Smpi 		}
1863244912e4Smpi 		str = ba2str(map_get((struct map *)bv->bv_value,
18649cf6efbeSmpi 		    ba2hash(ba->ba_key, dtev)), dtev);
186588be68dbSmpi 		break;
186623160851Smpi 	case B_AT_VAR:
186723160851Smpi 		str = ba2str(ba_read(ba), dtev);
186823160851Smpi 		break;
1869b005393aSdv 	case B_AT_FN_STR:
1870b005393aSdv 		str = (const char*)(fn_str(ba, dtev, buf))->ba_value;
1871b005393aSdv 		break;
1872a31d03f7Smpi 	case B_AT_OP_PLUS ... B_AT_OP_LOR:
187327f0efdaSbluhm 		snprintf(buf, sizeof(buf), "%ld", ba2long(ba, dtev));
187423160851Smpi 		str = buf;
187523160851Smpi 		break;
187623160851Smpi 	case B_AT_MF_COUNT:
18770dac42ecSmpi 	case B_AT_MF_MAX:
18780dac42ecSmpi 	case B_AT_MF_MIN:
18790dac42ecSmpi 	case B_AT_MF_SUM:
188023160851Smpi 		assert(0);
188123160851Smpi 		break;
188223160851Smpi 	default:
188323160851Smpi 		xabort("no string conversion for type %d", ba->ba_type);
188423160851Smpi 	}
188523160851Smpi 
188623160851Smpi 	return str;
188723160851Smpi }
188823160851Smpi 
188966793fc5Smpi int
18909751739cSmpi ba2flags(struct bt_arg *ba)
189166793fc5Smpi {
18926f386ca5Smpi 	int flags = 0;
189366793fc5Smpi 
18949751739cSmpi 	assert(ba->ba_type != B_AT_MAP);
18959751739cSmpi 	assert(ba->ba_type != B_AT_TUPLE);
18966f84e5f7Smpi 
18979751739cSmpi 	switch (ba->ba_type) {
189866793fc5Smpi 	case B_AT_STR:
189966793fc5Smpi 	case B_AT_LONG:
190066f34ae4Smpi 	case B_AT_TMEMBER:
190166793fc5Smpi 	case B_AT_VAR:
19029c84395dSmpi 	case B_AT_HIST:
1903e694d233Sjasper 	case B_AT_NIL:
190466793fc5Smpi 		break;
190566793fc5Smpi 	case B_AT_BI_KSTACK:
19066f386ca5Smpi 		flags |= DTEVT_KSTACK;
190766793fc5Smpi 		break;
190866793fc5Smpi 	case B_AT_BI_USTACK:
19096f386ca5Smpi 		flags |= DTEVT_USTACK;
191066793fc5Smpi 		break;
191166793fc5Smpi 	case B_AT_BI_COMM:
19126f386ca5Smpi 		flags |= DTEVT_EXECNAME;
191366793fc5Smpi 		break;
19140948ba6cSmpi 	case B_AT_BI_CPU:
191566793fc5Smpi 	case B_AT_BI_PID:
191666793fc5Smpi 	case B_AT_BI_TID:
191766793fc5Smpi 	case B_AT_BI_NSECS:
191866793fc5Smpi 		break;
191966793fc5Smpi 	case B_AT_BI_ARG0 ... B_AT_BI_ARG9:
19206f386ca5Smpi 		flags |= DTEVT_FUNCARGS;
192166793fc5Smpi 		break;
192266793fc5Smpi 	case B_AT_BI_RETVAL:
1923ca210abeSclaudio 	case B_AT_BI_PROBE:
192466793fc5Smpi 		break;
192566793fc5Smpi 	case B_AT_MF_COUNT:
192666793fc5Smpi 	case B_AT_MF_MAX:
192766793fc5Smpi 	case B_AT_MF_MIN:
192866793fc5Smpi 	case B_AT_MF_SUM:
1929b005393aSdv 	case B_AT_FN_STR:
19306f84e5f7Smpi 		break;
1931a31d03f7Smpi 	case B_AT_OP_PLUS ... B_AT_OP_LOR:
19329751739cSmpi 		flags |= ba2dtflags(ba->ba_value);
193366793fc5Smpi 		break;
193466793fc5Smpi 	default:
19359751739cSmpi 		xabort("invalid argument type %d", ba->ba_type);
193666793fc5Smpi 	}
19379751739cSmpi 
19389751739cSmpi 	return flags;
19399751739cSmpi }
19409751739cSmpi 
19419751739cSmpi /*
19429751739cSmpi  * Return dt(4) flags indicating which data should be recorded by the
19439751739cSmpi  * kernel, if any, for a given `ba'.
19449751739cSmpi  */
19459751739cSmpi int
19469751739cSmpi ba2dtflags(struct bt_arg *ba)
19479751739cSmpi {
19489751739cSmpi 	static long recursions;
19499751739cSmpi 	struct bt_arg *bval;
19509751739cSmpi 	int flags = 0;
19519751739cSmpi 
19529751739cSmpi 	if (++recursions >= __MAXOPERANDS)
19539751739cSmpi 		errx(1, "too many operands (>%d) in expression", __MAXOPERANDS);
19549751739cSmpi 
19559751739cSmpi 	do {
19569751739cSmpi 		if (ba->ba_type == B_AT_MAP)
19579751739cSmpi 			flags |= ba2flags(ba->ba_key);
19589751739cSmpi 		else if (ba->ba_type == B_AT_TUPLE) {
19599751739cSmpi 			bval = ba->ba_value;
19609751739cSmpi 			do {
19619751739cSmpi 				flags |= ba2flags(bval);
19629751739cSmpi 			} while ((bval = SLIST_NEXT(bval, ba_next)) != NULL);
19639751739cSmpi 		} else
19649751739cSmpi 			flags |= ba2flags(ba);
19659751739cSmpi 
19666f386ca5Smpi 	} while ((ba = SLIST_NEXT(ba, ba_next)) != NULL);
196766793fc5Smpi 
19686f84e5f7Smpi 	--recursions;
19696f84e5f7Smpi 
19706f386ca5Smpi 	return flags;
197166793fc5Smpi }
197266793fc5Smpi 
197323160851Smpi long
197423160851Smpi bacmp(struct bt_arg *a, struct bt_arg *b)
197523160851Smpi {
197604d13988Smpi 	char astr[STRLEN];
197766f34ae4Smpi 	long val;
197866f34ae4Smpi 
1979ab34c090Sclaudio 	if (a->ba_type != b->ba_type)
1980ab34c090Sclaudio 		return a->ba_type - b->ba_type;
198123160851Smpi 
1982ab34c090Sclaudio 	switch (a->ba_type) {
1983ab34c090Sclaudio 	case B_AT_LONG:
198423160851Smpi 		return ba2long(a, NULL) - ba2long(b, NULL);
1985ab34c090Sclaudio 	case B_AT_STR:
198604d13988Smpi 		strlcpy(astr, ba2str(a, NULL), sizeof(astr));
198704d13988Smpi 		return strcmp(astr, ba2str(b, NULL));
198866f34ae4Smpi 	case B_AT_TUPLE:
198966f34ae4Smpi 		/* Compare two lists of arguments one by one. */
199004d13988Smpi 		a = a->ba_value;
199104d13988Smpi 		b = b->ba_value;
199266f34ae4Smpi 		do {
199366f34ae4Smpi 			val = bacmp(a, b);
199466f34ae4Smpi 			if (val != 0)
199566f34ae4Smpi 				break;
199666f34ae4Smpi 
199766f34ae4Smpi 			a = SLIST_NEXT(a, ba_next);
199866f34ae4Smpi 			b = SLIST_NEXT(b, ba_next);
199966f34ae4Smpi 			if (a == NULL && b != NULL)
200066f34ae4Smpi 				val = -1;
200166f34ae4Smpi 			else if (a != NULL && b == NULL)
200266f34ae4Smpi 				val = 1;
200366f34ae4Smpi 		} while (a != NULL && b != NULL);
200466f34ae4Smpi 
200566f34ae4Smpi 		return val;
2006ab34c090Sclaudio 	default:
200766f34ae4Smpi 		xabort("no compare support for type %d", a->ba_type);
2008ab34c090Sclaudio 	}
200923160851Smpi }
201023160851Smpi 
201123160851Smpi __dead void
201223160851Smpi xabort(const char *fmt, ...)
201323160851Smpi {
201423160851Smpi 	va_list ap;
201523160851Smpi 
201623160851Smpi 	va_start(ap, fmt);
201723160851Smpi 	vfprintf(stderr, fmt, ap);
201823160851Smpi 	va_end(ap);
201923160851Smpi 
202023160851Smpi 	fprintf(stderr, "\n");
202123160851Smpi 	abort();
202223160851Smpi }
202323160851Smpi 
202423160851Smpi void
202523160851Smpi debug(const char *fmt, ...)
202623160851Smpi {
202723160851Smpi 	va_list ap;
202823160851Smpi 
202923160851Smpi 	if (verbose < 2)
203023160851Smpi 		return;
203123160851Smpi 
203223160851Smpi 	fprintf(stderr, "debug: ");
203323160851Smpi 
203423160851Smpi 	va_start(ap, fmt);
203523160851Smpi 	vfprintf(stderr, fmt, ap);
203623160851Smpi 	va_end(ap);
203723160851Smpi }
203823160851Smpi 
203923160851Smpi void
204023160851Smpi debugx(const char *fmt, ...)
204123160851Smpi {
204223160851Smpi 	va_list ap;
204323160851Smpi 
204423160851Smpi 	if (verbose < 2)
204523160851Smpi 		return;
204623160851Smpi 
204723160851Smpi 	va_start(ap, fmt);
204823160851Smpi 	vfprintf(stderr, fmt, ap);
204923160851Smpi 	va_end(ap);
205023160851Smpi }
205123160851Smpi 
205223160851Smpi void
205389f39301Smpi debug_dump_term(struct bt_arg *ba)
205489f39301Smpi {
205589f39301Smpi 	switch (ba->ba_type) {
205689f39301Smpi 	case B_AT_LONG:
205789f39301Smpi 		debugx("%s", ba2str(ba, NULL));
205889f39301Smpi 		break;
205989f39301Smpi 	case B_AT_OP_PLUS ... B_AT_OP_LOR:
206089f39301Smpi 		debug_dump_expr(ba);
206189f39301Smpi 		break;
206289f39301Smpi 	default:
206389f39301Smpi 		debugx("%s", ba_name(ba));
206489f39301Smpi 	}
206589f39301Smpi }
206689f39301Smpi 
206789f39301Smpi void
206889f39301Smpi debug_dump_expr(struct bt_arg *ba)
206989f39301Smpi {
207089f39301Smpi 	struct bt_arg *lhs, *rhs;
207189f39301Smpi 
207289f39301Smpi 	lhs = ba->ba_value;
207389f39301Smpi 	rhs = SLIST_NEXT(lhs, ba_next);
207489f39301Smpi 
207589f39301Smpi 	/* Left */
207689f39301Smpi 	debug_dump_term(lhs);
207789f39301Smpi 
207889f39301Smpi 	/* Right */
207989f39301Smpi 	if (rhs != NULL) {
208089f39301Smpi 		debugx(" %s ", ba_name(ba));
208189f39301Smpi 		debug_dump_term(rhs);
208289f39301Smpi 	} else {
208389f39301Smpi 		if (ba->ba_type != B_AT_OP_NE)
208489f39301Smpi 			debugx(" %s NULL", ba_name(ba));
208589f39301Smpi 	}
208689f39301Smpi }
208789f39301Smpi 
208889f39301Smpi void
208923160851Smpi debug_dump_filter(struct bt_rule *r)
209023160851Smpi {
209189f39301Smpi 	struct bt_stmt *bs;
2092a31d03f7Smpi 
20931694fc34Smpi 	if (verbose < 2)
20941694fc34Smpi 		return;
20951694fc34Smpi 
209689f39301Smpi 	if (r->br_filter == NULL) {
209723160851Smpi 		debugx("\n");
209889f39301Smpi 		return;
209989f39301Smpi 	}
210089f39301Smpi 
210189f39301Smpi 	bs = r->br_filter->bf_condition;
210289f39301Smpi 
210389f39301Smpi 	debugx(" /");
210489f39301Smpi 	debug_dump_expr(SLIST_FIRST(&bs->bs_args));
210589f39301Smpi 	debugx("/\n");
210623160851Smpi }
210723160851Smpi 
21085e6104a1Sclaudio unsigned long
21095e6104a1Sclaudio dt_get_offset(pid_t pid)
21105e6104a1Sclaudio {
21115e6104a1Sclaudio 	static struct dtioc_getaux	cache[32];
21125e6104a1Sclaudio 	static int			next;
21135e6104a1Sclaudio 	struct dtioc_getaux		*aux = NULL;
21145e6104a1Sclaudio 	int				 i;
21155e6104a1Sclaudio 
21165e6104a1Sclaudio 	for (i = 0; i < 32; i++) {
21175e6104a1Sclaudio 		if (cache[i].dtga_pid != pid)
21185e6104a1Sclaudio 			continue;
21195e6104a1Sclaudio 		aux = cache + i;
21205e6104a1Sclaudio 		break;
21215e6104a1Sclaudio 	}
21225e6104a1Sclaudio 
21235e6104a1Sclaudio 	if (aux == NULL) {
21245e6104a1Sclaudio 		aux = &cache[next++];
21255e6104a1Sclaudio 		next %= 32;
21265e6104a1Sclaudio 
21275e6104a1Sclaudio 		aux->dtga_pid = pid;
21285e6104a1Sclaudio 		if (ioctl(dtfd, DTIOCGETAUXBASE, aux))
21295e6104a1Sclaudio 			aux->dtga_auxbase = 0;
21305e6104a1Sclaudio 	}
21315e6104a1Sclaudio 
21325e6104a1Sclaudio 	return aux->dtga_auxbase;
21335e6104a1Sclaudio }
2134