-/* $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>
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 *);
%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
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); }
/* 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;
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;
}
/* 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. */
-/* $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>
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 *);
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;
printf("%llu events read\n", dtst.dtst_readevt);
printf("%llu events dropped\n", dtst.dtst_dropevt);
+ printf("%llu events filtered\n", bt_filtered);
}
}
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) {
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;
}
/*
}
/*
- * 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;
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:
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:
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;
}
/*
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;
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");