Diff below adds support for the common following idiom: syscall:open:entry /comm == "ksh"/ { ... }
String comparison is tricky as it can be combined with any other expression in filters, like: syscall:mmap:entry /comm == "cc" && pid != 4589/ { ... } I don't have the energy to change the parser so I went for the easy solution to treat any "stupid" string comparisons as 'true' albeit printing a warning. I'd love if somebody with some yacc knowledge could come up with a better solution. ok? Index: usr.sbin/btrace/bt_parse.y =================================================================== RCS file: /cvs/src/usr.sbin/btrace/bt_parse.y,v retrieving revision 1.46 diff -u -p -r1.46 bt_parse.y --- usr.sbin/btrace/bt_parse.y 28 Apr 2022 21:04:24 -0000 1.46 +++ usr.sbin/btrace/bt_parse.y 11 Nov 2022 14:34:37 -0000 @@ -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 Index: usr.sbin/btrace/btrace.c =================================================================== RCS file: /cvs/src/usr.sbin/btrace/btrace.c,v retrieving revision 1.64 diff -u -p -r1.64 btrace.c --- usr.sbin/btrace/btrace.c 11 Nov 2022 10:51:39 -0000 1.64 +++ usr.sbin/btrace/btrace.c 11 Nov 2022 14:44:15 -0000 @@ -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); @@ -1175,6 +1184,36 @@ baexpr2long(struct bt_arg *ba, struct dt 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; @@ -1233,9 +1272,10 @@ baexpr2long(struct bt_arg *ba, struct dt 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; @@ -1245,10 +1285,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"; @@ -1326,7 +1371,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; @@ -1516,9 +1562,13 @@ ba2str(struct bt_arg *ba, struct dt_evt 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; @@ -1557,12 +1607,16 @@ 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; } Index: regress/usr.sbin/btrace/Makefile =================================================================== RCS file: /cvs/src/regress/usr.sbin/btrace/Makefile,v retrieving revision 1.25 diff -u -p -r1.25 Makefile --- regress/usr.sbin/btrace/Makefile 19 Dec 2021 01:07:50 -0000 1.25 +++ regress/usr.sbin/btrace/Makefile 11 Nov 2022 14:31:54 -0000 @@ -14,7 +14,7 @@ BT_LANG_SCRIPTS= arithm beginend boolean 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 Index: regress/usr.sbin/btrace/filters.bt =================================================================== RCS file: regress/usr.sbin/btrace/filters.bt diff -N regress/usr.sbin/btrace/filters.bt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/usr.sbin/btrace/filters.bt 11 Nov 2022 14:35:07 -0000 @@ -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(); +} Index: regress/usr.sbin/btrace/filters.ok =================================================================== RCS file: regress/usr.sbin/btrace/filters.ok diff -N regress/usr.sbin/btrace/filters.ok