From 6f84e5f76992f4a42af5fb8fd918abf5b12f73a8 Mon Sep 17 00:00:00 2001 From: mpi Date: Sat, 12 Nov 2022 14:19:08 +0000 Subject: [PATCH] Add support for string comparison in filters. It is now possible to filter by process name, like: syscall:mmap:entry /comm == "ld"/ { ... } Currently the parser treats C-string like any other expression member even if arithmetic operations do no apply to strings. --- regress/usr.sbin/btrace/Makefile | 4 +- regress/usr.sbin/btrace/filters.bt | 22 ++++++++++ regress/usr.sbin/btrace/filters.ok | 0 usr.sbin/btrace/bt_parse.y | 3 +- usr.sbin/btrace/btrace.c | 64 +++++++++++++++++++++++++++--- 5 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 regress/usr.sbin/btrace/filters.bt create mode 100644 regress/usr.sbin/btrace/filters.ok diff --git a/regress/usr.sbin/btrace/Makefile b/regress/usr.sbin/btrace/Makefile index 08654e32a3c..04c322f9e6a 100644 --- a/regress/usr.sbin/btrace/Makefile +++ b/regress/usr.sbin/btrace/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.25 2021/12/19 01:07:50 guenther Exp $ +# $OpenBSD: Makefile,v 1.26 2022/11/12 14:19:08 mpi Exp $ BTRACE?= /usr/sbin/btrace ALLOWDT!= sysctl -n kern.allowdt 2>/dev/null @@ -14,7 +14,7 @@ BT_LANG_SCRIPTS= arithm beginend boolean comments delete exit \ BT_ARG_LANG_SCRIPTS= staticv str # scripts that use kernel probes -BT_KERN_SCRIPTS= multiprobe +BT_KERN_SCRIPTS= filters multiprobe REGRESS_EXPECTED_FAILURES= run-maxoperand diff --git a/regress/usr.sbin/btrace/filters.bt b/regress/usr.sbin/btrace/filters.bt new file mode 100644 index 00000000000..4ea6ebd4e4b --- /dev/null +++ b/regress/usr.sbin/btrace/filters.bt @@ -0,0 +1,22 @@ +syscall:open:entry +/"ksh" != comm/ +{ + exit(); +} + +syscall:close:entry +/comm == "ksh" && tid >= 45/ +{ + exit(); +} + +syscall:open:return +/pid != 99/ +{ + exit(); +} + +interval:hz:1 +{ + exit(); +} diff --git a/regress/usr.sbin/btrace/filters.ok b/regress/usr.sbin/btrace/filters.ok new file mode 100644 index 00000000000..e69de29bb2d diff --git a/usr.sbin/btrace/bt_parse.y b/usr.sbin/btrace/bt_parse.y index acd12538bff..1beedf8c543 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.47 2022/11/11 22:40:41 mpi Exp $ */ +/* $OpenBSD: bt_parse.y,v 1.48 2022/11/12 14:19:08 mpi Exp $ */ /* * Copyright (c) 2019-2021 Martin Pieuchot @@ -218,6 +218,7 @@ variable: lvar { $$ = bl_find($1); } factor : '(' expr ')' { $$ = $2; } | NUMBER { $$ = ba_new($1, B_AT_LONG); } | BUILTIN { $$ = ba_new(NULL, $1); } + | CSTRING { $$ = ba_new($1, B_AT_STR); } | staticv | variable | mentry diff --git a/usr.sbin/btrace/btrace.c b/usr.sbin/btrace/btrace.c index e6bcd932130..0db10681ed8 100644 --- a/usr.sbin/btrace/btrace.c +++ b/usr.sbin/btrace/btrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: btrace.c,v 1.66 2022/11/11 22:43:09 mpi Exp $ */ +/* $OpenBSD: btrace.c,v 1.67 2022/11/12 14:19:08 mpi Exp $ */ /* * Copyright (c) 2019 - 2021 Martin Pieuchot @@ -434,14 +434,23 @@ rules_setup(int fd) struct bt_rule *r, *rbegin = NULL; struct bt_probe *bp; struct bt_stmt *bs; + struct bt_arg *ba; int dokstack = 0, on = 1; uint64_t evtflags; TAILQ_FOREACH(r, &g_rules, br_next) { evtflags = 0; - SLIST_FOREACH(bs, &r->br_action, bs_next) { - struct bt_arg *ba; + if (r->br_filter != NULL && + r->br_filter->bf_condition != NULL) { + + bs = r->br_filter->bf_condition; + ba = SLIST_FIRST(&bs->bs_args); + + evtflags |= ba2dtflags(ba); + } + + SLIST_FOREACH(bs, &r->br_action, bs_next) { SLIST_FOREACH(ba, &bs->bs_args, ba_next) evtflags |= ba2dtflags(ba); @@ -1185,6 +1194,36 @@ baexpr2long(struct bt_arg *ba, struct dt_evt *dtev) lhs = ba->ba_value; rhs = SLIST_NEXT(lhs, ba_next); + /* + * String comparison also use '==' and '!='. + */ + if (lhs->ba_type == B_AT_STR || + (rhs != NULL && rhs->ba_type == B_AT_STR)) { + char lstr[STRLEN], rstr[STRLEN]; + + strlcpy(lstr, ba2str(lhs, dtev), sizeof(lstr)); + strlcpy(rstr, ba2str(rhs, dtev), sizeof(rstr)); + + result = strncmp(lstr, rstr, STRLEN) == 0; + + switch (ba->ba_type) { + case B_AT_OP_EQ: + break; + case B_AT_OP_NE: + result = !result; + break; + default: + warnx("operation '%d' unsupported on strings", + ba->ba_type); + result = 1; + } + + debug("ba=%p eval '(%s %s %s) = %d'\n", ba, lstr, ba_name(ba), + rstr, result); + + goto out; + } + lval = ba2long(lhs, dtev); if (rhs == NULL) { rval = 0; @@ -1243,9 +1282,10 @@ baexpr2long(struct bt_arg *ba, struct dt_evt *dtev) xabort("unsupported operation %d", ba->ba_type); } - debug("ba=%p eval '%ld %s %ld = %d'\n", ba, lval, ba_name(ba), + debug("ba=%p eval '(%ld %s %ld) = %d'\n", ba, lval, ba_name(ba), rval, result); +out: --recursions; return result; @@ -1255,10 +1295,15 @@ const char * ba_name(struct bt_arg *ba) { switch (ba->ba_type) { + case B_AT_STR: + return (const char *)ba->ba_value; + case B_AT_LONG: + return ba2str(ba, NULL); case B_AT_NIL: return "0"; case B_AT_VAR: case B_AT_MAP: + case B_AT_HIST: break; case B_AT_BI_PID: return "pid"; @@ -1336,7 +1381,8 @@ ba_name(struct bt_arg *ba) xabort("unsupported type %d", ba->ba_type); } - assert(ba->ba_type == B_AT_VAR || ba->ba_type == B_AT_MAP); + assert(ba->ba_type == B_AT_VAR || ba->ba_type == B_AT_MAP || + ba->ba_type == B_AT_HIST); static char buf[64]; size_t sz; @@ -1526,9 +1572,13 @@ ba2str(struct bt_arg *ba, struct dt_evt *dtev) int ba2dtflags(struct bt_arg *ba) { + static long recursions; struct bt_arg *bval; int flags = 0; + if (++recursions >= __MAXOPERANDS) + errx(1, "too many operands (>%d) in expression", __MAXOPERANDS); + do { if (ba->ba_type == B_AT_MAP) bval = ba->ba_key; @@ -1567,13 +1617,17 @@ ba2dtflags(struct bt_arg *ba) case B_AT_MF_MIN: case B_AT_MF_SUM: case B_AT_FN_STR: + break; case B_AT_OP_PLUS ... B_AT_OP_LOR: + flags |= ba2dtflags(bval->ba_value); break; default: xabort("invalid argument type %d", bval->ba_type); } } while ((ba = SLIST_NEXT(ba, ba_next)) != NULL); + --recursions; + return flags; } -- 2.20.1