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