Extend binary operators support, required for more filter features.
authormpi <mpi@openbsd.org>
Mon, 8 Feb 2021 09:46:45 +0000 (09:46 +0000)
committermpi <mpi@openbsd.org>
Mon, 8 Feb 2021 09:46:45 +0000 (09:46 +0000)
Improve debugging of filters and print operator names in debug output.

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

index 607d6dc..64a6cc9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bt_parse.y,v 1.22 2021/02/01 11:26:28 mpi Exp $       */
+/*     $OpenBSD: bt_parse.y,v 1.23 2021/02/08 09:46:45 mpi Exp $       */
 
 /*
  * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
@@ -55,7 +55,7 @@ SLIST_HEAD(, bt_var)   g_variables;
 
 struct bt_rule *br_new(struct bt_probe *, struct bt_filter *, struct bt_stmt *,
                     enum bt_rtype);
-struct bt_filter *bf_new(enum bt_operand, enum bt_filtervar, int);
+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_stmt *bs_new(enum bt_action, struct bt_arg *, struct bt_var *);
@@ -102,7 +102,7 @@ static int   yylex(void);
 static int pflag;
 %}
 
-%token ERROR OP_EQ OP_NEQ BEGIN END HZ
+%token ERROR OP_EQ OP_NE OP_LE OP_GE OP_LAND OP_LOR BEGIN END HZ
 /* Builtins */
 %token BUILTIN PID TID
 /* Functions and Map operators */
@@ -111,7 +111,7 @@ static int pflag;
 %token <v.number>      NUMBER
 
 %type  <v.string>      gvar
-%type  <v.i>           filterval oper builtin
+%type  <v.i>           fval testop binop builtin
 %type  <v.i>           BUILTIN F_DELETE F_PRINT FUNC0 FUNC1 FUNCN OP1 OP4
 %type  <v.i>           MOP0 MOP1
 %type  <v.probe>       probe probeval
@@ -147,17 +147,30 @@ probeval  : STRING ':' STRING ':' STRING  { $$ = bp_new($1, $3, $5, 0); }
                ;
 
 
-filterval      : PID                           { $$ = B_FV_PID; }
+fval           : PID                           { $$ = B_FV_PID; }
                | TID                           { $$ = B_FV_TID; }
                ;
 
-oper           : OP_EQ                         { $$ = B_OP_EQ; }
-               | OP_NEQ                        { $$ = B_OP_NE; }
+testop         : OP_EQ                         { $$ = B_AT_OP_EQ; }
+               | OP_NE                         { $$ = B_AT_OP_NE; }
+               | OP_LE                         { $$ = B_AT_OP_LE; }
+               | OP_GE                         { $$ = B_AT_OP_GE; }
+               | OP_LAND                       { $$ = B_AT_OP_LAND; }
+               | OP_LOR                        { $$ = B_AT_OP_LOR; }
+               ;
+
+binop          : testop
+               | '+'                           { $$ = B_AT_OP_PLUS; }
+               | '-'                           { $$ = B_AT_OP_MINUS; }
+               | '*'                           { $$ = B_AT_OP_MULT; }
+               | '/'                           { $$ = B_AT_OP_DIVIDE; }
+               | '&'                           { $$ = B_AT_OP_BAND; }
+               | '|'                           { $$ = B_AT_OP_BOR; }
                ;
 
 predicate      : /* empty */                   { $$ = NULL; }
-               | '/' filterval oper NUMBER '/' { $$ = bf_new($3, $2, $4); }
-               | '/' NUMBER oper filterval '/' { $$ = bf_new($3, $4, $2); }
+               | '/' fval testop NUMBER '/'    { $$ = bf_new($3, $2, $4); }
+               | '/' NUMBER testop fval '/'    { $$ = bf_new($3, $4, $2); }
                | '/' condition '/'             { $$ = bc_new($2); }
                ;
 
@@ -180,12 +193,7 @@ expr               : CSTRING                       { $$ = ba_new($1, B_AT_STR); }
                ;
 
 term           : '(' term ')'                  { $$ = $2; }
-               | term '+' term                 { $$ = ba_op('+', $1, $3); }
-               | term '-' term                 { $$ = ba_op('-', $1, $3); }
-               | term '/' term                 { $$ = ba_op('/', $1, $3); }
-               | term '*' term                 { $$ = ba_op('*', $1, $3); }
-               | term '&' term                 { $$ = ba_op('&', $1, $3); }
-               | term '|' term                 { $$ = ba_op('|', $1, $3); }
+               | term binop term               { $$ = ba_op($2, $1, $3); }
                | NUMBER                        { $$ = ba_new($1, B_AT_LONG); }
                | builtin                       { $$ = ba_new(NULL, $1); }
                | gvar                          { $$ = bv_get($1); }
@@ -258,7 +266,7 @@ br_new(struct bt_probe *probe, struct bt_filter *filter, struct bt_stmt *head,
 
 /* Create a new event filter */
 struct bt_filter *
-bf_new(enum bt_operand op, enum bt_filtervar var, int val)
+bf_new(enum bt_argtype op, enum bt_filtervar var, int val)
 {
        struct bt_filter *bf;
 
@@ -349,33 +357,8 @@ ba_append(struct bt_arg *da0, struct bt_arg *da1)
 
 /* Create an operator argument */
 struct bt_arg *
-ba_op(const char op, struct bt_arg *da0, struct bt_arg *da1)
+ba_op(enum bt_argtype type, struct bt_arg *da0, struct bt_arg *da1)
 {
-       enum bt_argtype type;
-
-       switch (op) {
-       case '+':
-               type = B_AT_OP_ADD;
-               break;
-       case '-':
-               type = B_AT_OP_MINUS;
-               break;
-       case '*':
-               type = B_AT_OP_MULT;
-               break;
-       case '/':
-               type = B_AT_OP_DIVIDE;
-               break;
-       case '&':
-               type = B_AT_OP_AND;
-               break;
-       case '|':
-               type = B_AT_OP_OR;
-               break;
-       default:
-               assert(0);
-       }
-
        return ba_new(ba_append(da0, da1), type);
 }
 
@@ -581,8 +564,6 @@ struct keyword *
 lookup(char *s)
 {
        static const struct keyword kws[] = {
-               { "!=",         OP_NEQ,         0 },
-               { "==",         OP_EQ,          0 },
                { "BEGIN",      BEGIN,          0 },
                { "END",        END,            0 },
                { "arg0",       BUILTIN,        B_AT_BI_ARG0 },
@@ -699,9 +680,22 @@ again:
        }
 
        switch (c) {
+       case '!':
        case '=':
-               if (peek() == '=')
-                       break;
+               if (peek() == '=') {
+                       lgetc();
+                       return (c == '=') ? OP_EQ : OP_NE;
+               }
+       case '&':
+               if (peek() == '&') {
+                       lgetc();
+                       return OP_LAND;
+               }
+       case '|':
+               if (peek() == '|') {
+                       lgetc();
+                       return OP_LOR;
+               }
        case ',':
        case '(':
        case ')':
@@ -788,7 +782,7 @@ again:
                }
        }
 
-#define allowed_in_string(x) (isalnum(c) || c == '!' || c == '=' || c == '_')
+#define allowed_in_string(x) (isalnum(c) || c == '_')
 
        /* parsing next word */
        if (allowed_in_string(c)) {
index c873b8a..6cc84c3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bt_parser.h,v 1.12 2021/02/01 11:26:29 mpi Exp $      */
+/*     $OpenBSD: bt_parser.h,v 1.13 2021/02/08 09:46:45 mpi Exp $      */
 
 /*
  * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
@@ -46,11 +46,7 @@ struct bt_probe {
  * Event filters correspond to checks performed in-kernel.
  */
 struct bt_evtfilter {
-       enum bt_operand {
-               B_OP_NONE = 1,
-               B_OP_EQ,
-               B_OP_NE,
-       }                       bf_op;
+       int                     bf_op;
        enum bt_filtervar {
                B_FV_NONE = 1,
                B_FV_PID,
@@ -150,12 +146,18 @@ struct bt_arg {
                B_AT_MF_MIN,                    /* @map[key] = min(pid) */
                B_AT_MF_SUM,                    /* @map[key] = sum(@elapsed) */
 
-               B_AT_OP_ADD,
+               B_AT_OP_PLUS,
                B_AT_OP_MINUS,
                B_AT_OP_MULT,
                B_AT_OP_DIVIDE,
-               B_AT_OP_AND,
-               B_AT_OP_OR,
+               B_AT_OP_BAND,
+               B_AT_OP_BOR,
+               B_AT_OP_EQ,
+               B_AT_OP_NE,
+               B_AT_OP_LE,
+               B_AT_OP_GE,
+               B_AT_OP_LAND,
+               B_AT_OP_LOR,
        }                        ba_type;
 };
 
index 9be7bbd..992215f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: btrace.c,v 1.28 2021/02/01 11:26:29 mpi Exp $ */
+/*     $OpenBSD: btrace.c,v 1.29 2021/02/08 09:46:45 mpi Exp $ */
 
 /*
  * Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
@@ -104,7 +104,6 @@ void                         debug(const char *, ...);
 void                    debugx(const char *, ...);
 const char             *debug_rule_name(struct bt_rule *);
 void                    debug_dump_filter(struct bt_rule *);
-void                    debug_dump_rule(struct bt_rule *);
 
 struct dtioc_probe_info        *dt_dtpis;      /* array of available probes */
 size_t                  dt_ndtpi;      /* # of elements in the array */
@@ -375,12 +374,11 @@ rules_do(int fd, int tracepid)
 }
 
 static inline enum dt_operand
-dop2dt(enum bt_operand op)
+dop2dt(enum bt_argtype op)
 {
        switch (op) {
-       case B_OP_EQ:   return DT_OP_EQ;
-       case B_OP_NE:   return DT_OP_NE;
-       case B_OP_NONE: return DT_OP_NONE;
+       case B_AT_OP_EQ:        return DT_OP_EQ;
+       case B_AT_OP_NE:        return DT_OP_NE;
        default:        break;
        }
        xabort("unknown operand %d", op);
@@ -411,7 +409,8 @@ rules_setup(int fd, int tracepid)
        int dokstack = 0, on = 1;
 
        TAILQ_FOREACH(r, &g_rules, br_next) {
-               debug_dump_rule(r);
+               debug("parsed probe '%s'", debug_rule_name(r));
+               debug_dump_filter(r);
 
                if (r->br_type != B_RT_PROBE) {
                        if (r->br_type == B_RT_BEGIN)
@@ -524,6 +523,8 @@ rules_teardown(int fd)
        if (rend)
                rule_eval(rend, NULL);
        else {
+               debug("eval default 'end' rule\n");
+
                TAILQ_FOREACH(r, &g_rules, br_next)
                        rule_printmaps(r);
        }
@@ -534,7 +535,8 @@ rule_eval(struct bt_rule *r, struct dt_evt *dtev)
 {
        struct bt_stmt *bs;
 
-       debug("eval rule '%s'\n", debug_rule_name(r));
+       debug("eval rule '%s'", debug_rule_name(r));
+       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)
@@ -707,7 +709,7 @@ stmt_bucketize(struct bt_stmt *bs, struct dt_evt *dtev)
                    bv_name(bv), ba2long(bval, dtev));
                return;
        }
-       debug("hist=%p '%s' increment bucket=%s\n", bv->bv_value,
+       debug("hist=%p '%s' increment bucket '%s'\n", bv->bv_value,
            bv_name(bv), bucket);
 
        bv->bv_value = (struct bt_arg *)
@@ -833,7 +835,7 @@ stmt_store(struct bt_stmt *bs, struct dt_evt *dtev)
        case B_AT_BI_NSECS:
                bv->bv_value = ba_new(builtin_nsecs(dtev), B_AT_LONG);
                break;
-       case B_AT_OP_ADD ... B_AT_OP_OR:
+       case B_AT_OP_PLUS ... B_AT_OP_LOR:
                bv->bv_value = ba_new(ba2long(ba, dtev), B_AT_LONG);
                break;
        default:
@@ -1024,7 +1026,7 @@ baexpr2long(struct bt_arg *ba, struct dt_evt *dtev)
        second = ba2long(b, dtev);
 
        switch (ba->ba_type) {
-       case B_AT_OP_ADD:
+       case B_AT_OP_PLUS:
                result = first + second;
                break;
        case B_AT_OP_MINUS:
@@ -1036,23 +1038,81 @@ baexpr2long(struct bt_arg *ba, struct dt_evt *dtev)
        case B_AT_OP_DIVIDE:
                result = first / second;
                break;
-       case B_AT_OP_AND:
+       case B_AT_OP_BAND:
                result = first & second;
                break;
-       case B_AT_OP_OR:
+       case B_AT_OP_BOR:
                result = first | second;
                break;
+       case B_AT_OP_EQ:
+               result = (first == second);
+               break;
+       case B_AT_OP_NE:
+               result = (first != second);
+               break;
+       case B_AT_OP_LE:
+               result = (first <= second);
+               break;
+       case B_AT_OP_GE:
+               result = (first >= second);
+               break;
+       case B_AT_OP_LAND:
+               result = (first && second);
+               break;
+       case B_AT_OP_LOR:
+               result = (first || second);
+               break;
        default:
                xabort("unsuported operation %d", ba->ba_type);
        }
 
-       debug("ba=%p (%ld op %ld) = %ld\n", ba, first, second, result);
+       debug("ba=%p '%ld %s %ld = %ld'\n", ba, first, ba_name(ba), second,
+          result);
 
        --recursions;
 
        return result;
 }
 
+const char *
+ba_name(struct bt_arg *ba)
+{
+       switch (ba->ba_type) {
+       case B_AT_BI_PID:
+               return "pid";
+       case B_AT_BI_TID:
+               return "tid";
+       case B_AT_OP_PLUS:
+               return "+";
+       case B_AT_OP_MINUS:
+               return "-";
+       case B_AT_OP_MULT:
+               return "*";
+       case B_AT_OP_DIVIDE:
+               return "/";
+       case B_AT_OP_BAND:
+               return "&";
+       case B_AT_OP_BOR:
+               return "|";
+       case B_AT_OP_EQ:
+               return "==";
+       case B_AT_OP_NE:
+               return "!=";
+       case B_AT_OP_LE:
+               return "<=";
+       case B_AT_OP_GE:
+               return ">=";
+       case B_AT_OP_LAND:
+               return "&&";
+       case B_AT_OP_LOR:
+               return "||";
+       default:
+               break;
+       }
+
+       return ba2str(ba, NULL);
+}
+
 /*
  * Return the representation of `ba' as long.
  */
@@ -1072,6 +1132,9 @@ ba2long(struct bt_arg *ba, struct dt_evt *dtev)
                break;
        case B_AT_MAP:
                bv = ba->ba_value;
+               /* Unitialized map */
+               if (bv->bv_value == NULL)
+                       return 0;
                val = ba2long(map_get((struct map *)bv->bv_value,
                    ba2str(ba->ba_key, dtev)), dtev);
                break;
@@ -1081,7 +1144,7 @@ ba2long(struct bt_arg *ba, struct dt_evt *dtev)
        case B_AT_BI_RETVAL:
                val = dtev->dtev_sysretval[0];
                break;
-       case B_AT_OP_ADD ... B_AT_OP_OR:
+       case B_AT_OP_PLUS ... B_AT_OP_LOR:
                val = baexpr2long(ba, dtev);
                break;
        default:
@@ -1150,7 +1213,7 @@ ba2str(struct bt_arg *ba, struct dt_evt *dtev)
        case B_AT_VAR:
                str = ba2str(ba_read(ba), dtev);
                break;
-       case B_AT_OP_ADD ... B_AT_OP_OR:
+       case B_AT_OP_PLUS ... B_AT_OP_LOR:
                snprintf(buf, sizeof(buf), "%ld", ba2long(ba, dtev));
                str = buf;
                break;
@@ -1209,7 +1272,7 @@ ba2dtflags(struct bt_arg *ba)
                case B_AT_MF_MAX:
                case B_AT_MF_MIN:
                case B_AT_MF_SUM:
-               case B_AT_OP_ADD ... B_AT_OP_OR:
+               case B_AT_OP_PLUS ... B_AT_OP_LOR:
                        break;
                default:
                        xabort("invalid argument type %d", ba->ba_type);
@@ -1285,9 +1348,8 @@ static inline const char *
 debug_getfilterop(struct bt_evtfilter *df)
 {
        switch (df->bf_op) {
-       case B_OP_EQ:   return "==";
-       case B_OP_NE:   return "!=";
-       case B_OP_NONE: return "";
+       case B_AT_OP_EQ:        return "==";
+       case B_AT_OP_NE:        return "!=";
        default:
                xabort("invalid operand %d", df->bf_op);
        }
@@ -1296,11 +1358,21 @@ debug_getfilterop(struct bt_evtfilter *df)
 void
 debug_dump_filter(struct bt_rule *r)
 {
-       if (r->br_filter != NULL && r->br_filter->bf_condition == NULL) {
-               struct bt_evtfilter *df = &r->br_filter->bf_evtfilter;
+       if (r->br_filter != NULL) {
+               struct bt_stmt *bs = r->br_filter->bf_condition;
+
+               if (bs == NULL) {
+                       struct bt_evtfilter *df = &r->br_filter->bf_evtfilter;
 
-               debugx(" / %s %s %u /", debug_getfiltervar(df),
-                   debug_getfilterop(df), df->bf_val);
+                       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;
+
+                       debugx(" / %s[%s] != 0 /.", bv_name(bv),
+                           ba_name(ba->ba_key));
+               }
        }
        debugx("\n");
 }
@@ -1329,10 +1401,3 @@ debug_rule_name(struct bt_rule *r)
 
        return buf;
 }
-
-void
-debug_dump_rule(struct bt_rule *r)
-{
-       debug("parsed probe '%s'", debug_rule_name(r));
-       debug_dump_filter(r);
-}
index 6905b18..a45fa98 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: btrace.h,v 1.8 2020/08/13 11:29:39 mpi Exp $ */
+/*     $OpenBSD: btrace.h,v 1.9 2021/02/08 09:46:45 mpi Exp $ */
 
 /*
  * Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
@@ -29,6 +29,7 @@ struct bt_var;
 struct bt_stmt;
 
 /* btrace.c */
+const char *            ba_name(struct bt_arg *);
 long                    ba2long(struct bt_arg *, struct dt_evt *);
 const char             *ba2str(struct bt_arg *, struct dt_evt *);
 long                    bacmp(struct bt_arg *, struct bt_arg *);