diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2021-02-08 09:46:46 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2021-02-08 09:46:46 +0000 |
commit | 16d10f648535cbd97acb7e1da8caae9c6734c691 (patch) | |
tree | 383cf77bd3a1579e642782cd0608e105d068c860 /usr.sbin/btrace | |
parent | 7e93d4f7aa216178b18a473cf34da5448d4dcc98 (diff) |
Extend binary operators support, required for more filter features.
Improve debugging of filters and print operator names in debug output.
Diffstat (limited to 'usr.sbin/btrace')
-rw-r--r-- | usr.sbin/btrace/bt_parse.y | 88 | ||||
-rw-r--r-- | usr.sbin/btrace/bt_parser.h | 20 | ||||
-rw-r--r-- | usr.sbin/btrace/btrace.c | 127 | ||||
-rw-r--r-- | usr.sbin/btrace/btrace.h | 3 |
4 files changed, 150 insertions, 88 deletions
diff --git a/usr.sbin/btrace/bt_parse.y b/usr.sbin/btrace/bt_parse.y index 607d6dc5241..64a6cc9fc43 100644 --- a/usr.sbin/btrace/bt_parse.y +++ b/usr.sbin/btrace/bt_parse.y @@ -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)) { diff --git a/usr.sbin/btrace/bt_parser.h b/usr.sbin/btrace/bt_parser.h index c873b8a6c25..6cc84c32f34 100644 --- a/usr.sbin/btrace/bt_parser.h +++ b/usr.sbin/btrace/bt_parser.h @@ -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; }; diff --git a/usr.sbin/btrace/btrace.c b/usr.sbin/btrace/btrace.c index 9be7bbd849f..992215f172c 100644 --- a/usr.sbin/btrace/btrace.c +++ b/usr.sbin/btrace/btrace.c @@ -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); -} diff --git a/usr.sbin/btrace/btrace.h b/usr.sbin/btrace/btrace.h index 6905b187112..a45fa98cfc2 100644 --- a/usr.sbin/btrace/btrace.h +++ b/usr.sbin/btrace/btrace.h @@ -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 *); |