-/* $OpenBSD: bt_parse.y,v 1.21 2021/01/10 11:06:08 jmatthew Exp $ */
+/* $OpenBSD: bt_parse.y,v 1.22 2021/02/01 11:26:28 mpi Exp $ */
/*
- * Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
* Copyright (c) 2019 Tobias Heider <tobhe@openbsd.org>
* Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
*
%type <v.probe> probe probeval
%type <v.filter> predicate
%type <v.stmt> action stmt stmtlist
-%type <v.arg> expr vargs map mexpr printargs term
+%type <v.arg> expr vargs map mexpr printargs term condition
%type <v.rtype> beginend
%left '|'
predicate : /* empty */ { $$ = NULL; }
| '/' filterval oper NUMBER '/' { $$ = bf_new($3, $2, $4); }
| '/' NUMBER oper filterval '/' { $$ = bf_new($3, $4, $2); }
+ | '/' condition '/' { $$ = bc_new($2); }
+ ;
+
+condition : gvar { $$ = bv_get($1); }
+ | map { $$ = $1; }
;
builtin : PID { $$ = B_AT_BI_PID; }
{
struct bt_rule *br;
- br = calloc(1, sizeof(struct bt_rule));
+ br = calloc(1, sizeof(*br));
if (br == NULL)
err(1, "bt_rule: calloc");
br->br_probe = probe;
return br;
}
-/* Create a new filter */
+/* Create a new event filter */
struct bt_filter *
bf_new(enum bt_operand op, enum bt_filtervar var, int val)
{
- struct bt_filter *df;
+ struct bt_filter *bf;
if (val < 0 || val > INT_MAX)
errx(1, "invalid pid '%d'", val);
- df = calloc(1, sizeof(struct bt_filter));
- if (df == NULL)
+ bf = calloc(1, sizeof(*bf));
+ if (bf == NULL)
err(1, "bt_filter: calloc");
- df->bf_op = op;
- df->bf_var = var;
- df->bf_val = val;
+ bf->bf_evtfilter.bf_op = op;
+ bf->bf_evtfilter.bf_var = var;
+ bf->bf_evtfilter.bf_val = val;
+
+ return bf;
+}
+
+/* Create a new condition */
+struct bt_filter *
+bc_new(struct bt_arg *ba)
+{
+ struct bt_filter *bf;
+
+ bf = calloc(1, sizeof(*bf));
+ if (bf == NULL)
+ err(1, "bt_filter: calloc");
+
+ bf->bf_condition = bs_new(B_AC_TEST, ba, NULL);
- return df;
+ return bf;
}
/* Create a new probe */
if (rate < 0 || rate > INT32_MAX)
errx(1, "only positive values permitted");
- bp = calloc(1, sizeof(struct bt_probe));
+ bp = calloc(1, sizeof(*bp));
if (bp == NULL)
err(1, "bt_probe: calloc");
bp->bp_prov = prov;
{
struct bt_arg *ba;
- ba = calloc(1, sizeof(struct bt_arg));
+ ba = calloc(1, sizeof(*ba));
if (ba == NULL)
err(1, "bt_arg: calloc");
ba->ba_value = val;
{
struct bt_stmt *bs;
- bs = calloc(1, sizeof(struct bt_stmt));
+ bs = calloc(1, sizeof(*bs));
if (bs == NULL)
err(1, "bt_stmt: calloc");
bs->bs_act = act;
{
struct bt_var *bv;
- bv = calloc(1, sizeof(struct bt_var));
+ bv = calloc(1, sizeof(*bv));
if (bv == NULL)
err(1, "bt_var: calloc");
bv->bv_name = vname;
-/* $OpenBSD: bt_parser.h,v 1.11 2021/01/27 07:19:54 deraadt Exp $ */
+/* $OpenBSD: bt_parser.h,v 1.12 2021/02/01 11:26:29 mpi Exp $ */
/*
- * Copyright (c) 2019-2020 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#define bp_unit bp_func
};
+
/*
- * Filters correspond to predicates performed in kernel.
- *
- * When a probe fires the check is performed, if it isn't true no event
- * is recorded.
+ * Event filters correspond to checks performed in-kernel.
*/
-struct bt_filter {
+struct bt_evtfilter {
enum bt_operand {
B_OP_NONE = 1,
B_OP_EQ,
B_OP_NE,
- } bf_op;
- enum bt_filtervar {
+ } bf_op;
+ enum bt_filtervar {
B_FV_NONE = 1,
B_FV_PID,
B_FV_TID
uint32_t bf_val;
};
+/*
+ * Filters, also known as predicates, describe under which set of
+ * conditions a rule is executed.
+ *
+ * Depending on their type they are performed in-kernel or when a rule
+ * is evaluated. In the first case they might prevent the recording of
+ * events, in the second case events might be discarded at runtime.
+ */
+struct bt_filter {
+ struct bt_evtfilter bf_evtfilter; /* in-kernel event filter */
+ struct bt_stmt *bf_condition; /* per event condition */
+};
+
TAILQ_HEAD(bt_ruleq, bt_rule);
/*
B_AC_PRINT, /* print(@map, 10) */
B_AC_PRINTF, /* printf("hello!\n") */
B_AC_STORE, /* @a = 3 */
+ B_AC_TEST, /* if (@a) */
B_AC_TIME, /* time("%H:%M:%S ") */
B_AC_ZERO, /* zero(@map) */
} bs_act;
-/* $OpenBSD: btrace.c,v 1.27 2021/01/21 13:19:25 mpi Exp $ */
+/* $OpenBSD: btrace.c,v 1.28 2021/02/01 11:26:29 mpi Exp $ */
/*
* Copyright (c) 2019 - 2020 Martin Pieuchot <mpi@openbsd.org>
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stmt_insert(struct bt_stmt *, struct dt_evt *);
void stmt_print(struct bt_stmt *, struct dt_evt *);
void stmt_store(struct bt_stmt *, struct dt_evt *);
+bool stmt_test(struct bt_stmt *, struct dt_evt *);
void stmt_time(struct bt_stmt *, struct dt_evt *);
void stmt_zero(struct bt_stmt *);
struct bt_arg *ba_read(struct bt_arg *);
r->br_pbn = dtpi->dtpi_pbn;
dtrq->dtrq_pbn = dtpi->dtpi_pbn;
- if (r->br_filter) {
- struct bt_filter *df = r->br_filter;
+ if (r->br_filter != NULL &&
+ r->br_filter->bf_condition == NULL) {
+ struct bt_evtfilter *df = &r->br_filter->bf_evtfilter;
dtrq->dtrq_filter.dtf_operand = dop2dt(df->bf_op);
dtrq->dtrq_filter.dtf_variable = dvar2dt(df->bf_var);
debug("eval rule '%s'\n", debug_rule_name(r));
+ if (r->br_filter != NULL && r->br_filter->bf_condition != NULL) {
+ if (stmt_test(r->br_filter->bf_condition, dtev) == false)
+ return;
+ }
+
SLIST_FOREACH(bs, &r->br_action, bs_next) {
switch (bs->bs_act) {
case B_AC_BUCKETIZE:
}
/*
- * Variable store: { var = 3; }
+ * Variable store: { @var = 3; }
*
* In this case '3' is represented by `ba', the argument of a STORE
* action.
debug("bv=%p var '%s' store (%p) \n", bv, bv_name(bv), bv->bv_value);
}
+/*
+ * Expression test: { if (expr) stmt; }
+ */
+bool
+stmt_test(struct bt_stmt *bs, struct dt_evt *dtev)
+{
+ struct bt_arg *ba;
+ long val;
+
+ if (bs == NULL)
+ return true;
+
+ assert(bs->bs_var == NULL);
+ ba = SLIST_FIRST(&bs->bs_args);
+ val = ba2long(ba, dtev);
+
+ debug("ba=%p test (%ld != 0)\n", ba, val);
+
+ return val != 0;
+}
+
/*
* Print time: { time("%H:%M:%S"); }
*/
}
static inline const char *
-debug_getfiltervar(struct bt_filter *df)
+debug_getfiltervar(struct bt_evtfilter *df)
{
switch (df->bf_var) {
case B_FV_PID: return "pid";
default:
xabort("invalid filtervar %d", df->bf_var);
}
-
-
}
static inline const char *
-debug_getfilterop(struct bt_filter *df)
+debug_getfilterop(struct bt_evtfilter *df)
{
switch (df->bf_op) {
case B_OP_EQ: return "==";
void
debug_dump_filter(struct bt_rule *r)
{
- if (r->br_filter) {
- debugx(" / %s %s %u /", debug_getfiltervar(r->br_filter),
- debug_getfilterop(r->br_filter), r->br_filter->bf_val);
+ if (r->br_filter != NULL && r->br_filter->bf_condition == NULL) {
+ struct bt_evtfilter *df = &r->br_filter->bf_evtfilter;
+
+ debugx(" / %s %s %u /", debug_getfiltervar(df),
+ debug_getfilterop(df), df->bf_val);
}
debugx("\n");
}