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

Reply via email to