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