summaryrefslogtreecommitdiff
path: root/usr.sbin/btrace
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2021-02-08 09:46:46 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2021-02-08 09:46:46 +0000
commit16d10f648535cbd97acb7e1da8caae9c6734c691 (patch)
tree383cf77bd3a1579e642782cd0608e105d068c860 /usr.sbin/btrace
parent7e93d4f7aa216178b18a473cf34da5448d4dcc98 (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.y88
-rw-r--r--usr.sbin/btrace/bt_parser.h20
-rw-r--r--usr.sbin/btrace/btrace.c127
-rw-r--r--usr.sbin/btrace/btrace.h3
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 *);