Extend filters to support any conditionnal test including global variables.
authormpi <mpi@openbsd.org>
Wed, 21 Apr 2021 10:53:17 +0000 (10:53 +0000)
committermpi <mpi@openbsd.org>
Wed, 21 Apr 2021 10:53:17 +0000 (10:53 +0000)
Stop using in-kernel filtering for the moment except for not tracing the
tracer.

Keep track of the number of filtered events.

usr.sbin/btrace/bt_parse.y
usr.sbin/btrace/btrace.c

index 3fcb212..44f4204 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bt_parse.y,v 1.28 2021/04/21 10:34:36 mpi Exp $       */
+/*     $OpenBSD: bt_parse.y,v 1.29 2021/04/21 10:53:17 mpi Exp $       */
 
 /*
  * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
@@ -61,6 +61,7 @@ struct bt_rule        *br_new(struct bt_probe *, struct bt_filter *, struct bt_stmt *,
 struct bt_filter *bf_new(enum bt_argtype, enum bt_filtervar, int);
 struct bt_probe        *bp_new(const char *, const char *, const char *, int32_t);
 struct bt_arg  *ba_append(struct bt_arg *, struct bt_arg *);
+struct bt_arg  *ba_op(enum bt_argtype, struct bt_arg *, struct bt_arg *);
 struct bt_stmt *bs_new(enum bt_action, struct bt_arg *, struct bt_var *);
 struct bt_stmt *bs_append(struct bt_stmt *, struct bt_stmt *);
 
@@ -124,7 +125,7 @@ static int pflag;
 %type  <v.i>           BUILTIN F_DELETE F_PRINT FUNC0 FUNC1 FUNCN OP1 OP4
 %type  <v.i>           MOP0 MOP1
 %type  <v.probe>       probe probename
-%type  <v.filter>      predicate
+%type  <v.filter>      predicate conditional
 %type  <v.stmt>        action stmt stmtlist
 %type  <v.arg>         expr vargs mentry mexpr printargs term globalvar variable
 %type  <v.rtype>       beginend
@@ -187,10 +188,12 @@ gvar              : '@' STRING                    { $$ = $2; }
 lvar           : '$' STRING                    { $$ = $2; }
 
 
+conditional    : variable              { $$ = bc_new(NULL, B_AT_OP_NE, $1); }
+               | term testop variable          { $$ = bc_new($1, $2, $3); }
+               ;
+
 predicate      : /* empty */                   { $$ = NULL; }
-               | '/' fval testop staticval '/' { $$ = bf_new($3, $2, $4); }
-               | '/' staticval testop fval '/' { $$ = bf_new($3, $4, $2); }
-               | '/' variable '/'              { $$ = bc_new($2); }
+               | '/' conditional '/'           { $$ = $2; }
                ;
 
 mentry         : gvar '[' vargs ']'            { $$ = bm_find($1, $3); }
@@ -319,7 +322,7 @@ bf_new(enum bt_argtype op, enum bt_filtervar var, int val)
 
 /* Create a new condition */
 struct bt_filter *
-bc_new(struct bt_arg *ba)
+bc_new(struct bt_arg *term, enum bt_argtype op, struct bt_arg *ba)
 {
        struct bt_filter *bf;
 
@@ -327,7 +330,7 @@ bc_new(struct bt_arg *ba)
        if (bf == NULL)
                err(1, "bt_filter: calloc");
 
-       bf->bf_condition = bs_new(B_AC_TEST, ba, NULL);
+       bf->bf_condition = bs_new(B_AC_TEST, ba_op(op, term, ba), NULL);
 
        return bf;
 }
@@ -391,9 +394,9 @@ ba_append(struct bt_arg *da0, struct bt_arg *da1)
 
 /* Create an operator argument */
 struct bt_arg *
-ba_op(enum bt_argtype type, struct bt_arg *da0, struct bt_arg *da1)
+ba_op(enum bt_argtype op, struct bt_arg *da0, struct bt_arg *da1)
 {
-       return ba_new(ba_append(da0, da1), type);
+       return ba_new(ba_append(da0, da1), op);
 }
 
 /* Create a new statement: function call or assignment. */
index 17bb7b1..296f2e2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: btrace.c,v 1.32 2021/04/21 10:26:18 mpi Exp $ */
+/*     $OpenBSD: btrace.c,v 1.33 2021/04/21 10:53:17 mpi Exp $ */
 
 /*
  * Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
@@ -92,6 +92,7 @@ void                   stmt_time(struct bt_stmt *, struct dt_evt *);
 void                    stmt_zero(struct bt_stmt *);
 struct bt_arg          *ba_read(struct bt_arg *);
 const char             *ba2hash(struct bt_arg *, struct dt_evt *);
+long                    baexpr2long(struct bt_arg *, struct dt_evt *);
 const char             *ba2bucket(struct bt_arg *, struct bt_arg *,
                             struct dt_evt *, long *);
 int                     ba2dtflags(struct bt_arg *);
@@ -109,6 +110,7 @@ struct dtioc_probe_info     *dt_dtpis;      /* array of available probes */
 size_t                  dt_ndtpi;      /* # of elements in the array */
 
 struct dt_evt           bt_devt;       /* fake event for BEGIN/END */
+uint64_t                bt_filtered;   /* # of events filtered out */
 
 int                     vargs[1];
 int                     verbose = 0;
@@ -380,6 +382,7 @@ rules_do(int fd)
 
                printf("%llu events read\n", dtst.dtst_readevt);
                printf("%llu events dropped\n", dtst.dtst_dropevt);
+               printf("%llu events filtered\n", bt_filtered);
        }
 }
 
@@ -551,8 +554,10 @@ rule_eval(struct bt_rule *r, struct dt_evt *dtev)
        debug_dump_filter(r);
 
        if (r->br_filter != NULL && r->br_filter->bf_condition != NULL) {
-               if (stmt_test(r->br_filter->bf_condition, dtev) == false)
+               if (stmt_test(r->br_filter->bf_condition, dtev) == false) {
+                       bt_filtered++;
                        return;
+               }
        }
 
        SLIST_FOREACH(bs, &r->br_action, bs_next) {
@@ -889,19 +894,15 @@ stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
 bool
 stmt_test(struct bt_stmt *bs, struct dt_evt *dtev)
 {
-       struct bt_arg *ba;
-       long val;
+       struct bt_arg *bop;
 
        if (bs == NULL)
                return true;
 
        assert(bs->bs_var == NULL);
-       ba = SLIST_FIRST(&bs->bs_args);
-       val = ba2long(ba, dtev);
+       bop = SLIST_FIRST(&bs->bs_args);
 
-       debug("ba=%p test (%ld != 0)\n", ba, val);
-
-       return val != 0;
+       return baexpr2long(bop, dtev) != 0;
 }
 
 /*
@@ -1042,10 +1043,9 @@ ba2bucket(struct bt_arg *ba, struct bt_arg *brange, struct dt_evt *dtev,
 }
 
 /*
- * Helper to evaluate the operation encoded in `ba' and return its
- * result.
+ * Evaluate the operation encoded in `ba' and return its result.
  */
-static inline long
+long
 baexpr2long(struct bt_arg *ba, struct dt_evt *dtev)
 {
        static long recursions;
@@ -1056,12 +1056,16 @@ baexpr2long(struct bt_arg *ba, struct dt_evt *dtev)
                errx(1, "too many operands (>%d) in expression", __MAXOPERANDS);
 
        a = ba->ba_value;
-       b = SLIST_NEXT(a, ba_next);
+       first = ba2long(a, dtev);
 
-       assert(SLIST_NEXT(b, ba_next) == NULL);
+       b = SLIST_NEXT(a, ba_next);
 
-       first = ba2long(a, dtev);
-       second = ba2long(b, dtev);
+       if (b == NULL) {
+               second = 0;
+       } else {
+               assert(SLIST_NEXT(b, ba_next) == NULL);
+               second = ba2long(b, dtev);
+       }
 
        switch (ba->ba_type) {
        case B_AT_OP_PLUS:
@@ -1116,6 +1120,9 @@ const char *
 ba_name(struct bt_arg *ba)
 {
        switch (ba->ba_type) {
+       case B_AT_VAR:
+       case B_AT_MAP:
+               break;
        case B_AT_BI_PID:
                return "pid";
        case B_AT_BI_TID:
@@ -1145,10 +1152,34 @@ ba_name(struct bt_arg *ba)
        case B_AT_OP_LOR:
                return "||";
        default:
-               break;
+               xabort("unsuported type %d", ba->ba_type);
        }
 
-       return ba2str(ba, NULL);
+       assert(ba->ba_type == B_AT_VAR || ba->ba_type == B_AT_MAP);
+
+       static char buf[64];
+       size_t sz;
+       int l;
+
+       buf[0] = '@';
+       buf[1] = '\0';
+       sz = sizeof(buf) - 1;
+       l = snprintf(buf+1, sz, "%s", bv_name(ba->ba_value));
+       if (l < 0 || (size_t)l > sz) {
+               warn("string too long %d > %zu", l, sz);
+               return buf;
+       }
+
+       if (ba->ba_type == B_AT_MAP) {
+               sz -= l;
+               l = snprintf(buf+1+l, sz, "[%s]", ba_name(ba->ba_key));
+               if (l < 0 || (size_t)l > sz) {
+                       warn("string too long %d > %zu", l, sz);
+                       return buf;
+               }
+       }
+
+       return buf;
 }
 
 /*
@@ -1176,6 +1207,12 @@ ba2long(struct bt_arg *ba, struct dt_evt *dtev)
                val = ba2long(map_get((struct map *)bv->bv_value,
                    ba2str(ba->ba_key, dtev)), dtev);
                break;
+       case B_AT_BI_PID:
+               val = dtev->dtev_pid;
+               break;
+       case B_AT_BI_TID:
+               val = dtev->dtev_tid;
+               break;
        case B_AT_BI_NSECS:
                val = builtin_nsecs(dtev);
                break;
@@ -1405,11 +1442,14 @@ debug_dump_filter(struct bt_rule *r)
                        debugx(" / %s %s %u /", debug_getfiltervar(df),
                            debug_getfilterop(df), df->bf_val);
                } else {
-                       struct bt_arg *ba = SLIST_FIRST(&bs->bs_args);
-                       struct bt_var *bv = ba->ba_value;
+                       struct bt_arg *bop = SLIST_FIRST(&bs->bs_args);
+                       struct bt_arg *a, *b;
+
+                       a = bop->ba_value;
+                       b = SLIST_NEXT(a, ba_next);
 
-                       debugx(" / %s[%s] != 0 /.", bv_name(bv),
-                           ba_name(ba->ba_key));
+                       debugx(" / %s %s %s /", ba_name(a), ba_name(bop),
+                           (b != NULL) ? ba_name(b) : "NULL");
                }
        }
        debugx("\n");