summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2021-04-21 10:53:18 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2021-04-21 10:53:18 +0000
commit35ab9c5b3b74373793665e6e576f6722046c83cd (patch)
treec3fc882288853b86ab970b995df5850010ca73df /usr.sbin
parent06107cad10033b73935ac7d3e337796f1ecfb420 (diff)
Extend filters to support any conditionnal test including global variables.
Stop using in-kernel filtering for the moment except for not tracing the tracer. Keep track of the number of filtered events.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/btrace/bt_parse.y21
-rw-r--r--usr.sbin/btrace/btrace.c84
2 files changed, 74 insertions, 31 deletions
diff --git a/usr.sbin/btrace/bt_parse.y b/usr.sbin/btrace/bt_parse.y
index 3fcb212108f..44f4204051f 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.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. */
diff --git a/usr.sbin/btrace/btrace.c b/usr.sbin/btrace/btrace.c
index 17bb7b187bf..296f2e254d5 100644
--- a/usr.sbin/btrace/btrace.c
+++ b/usr.sbin/btrace/btrace.c
@@ -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");