Add support for string comparison in filters.
authormpi <mpi@openbsd.org>
Sat, 12 Nov 2022 14:19:08 +0000 (14:19 +0000)
committermpi <mpi@openbsd.org>
Sat, 12 Nov 2022 14:19:08 +0000 (14:19 +0000)
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
regress/usr.sbin/btrace/filters.bt [new file with mode: 0644]
regress/usr.sbin/btrace/filters.ok [new file with mode: 0644]
usr.sbin/btrace/bt_parse.y
usr.sbin/btrace/btrace.c

index 08654e3..04c322f 100644 (file)
@@ -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 (file)
index 0000000..4ea6ebd
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
index acd1253..1beedf8 100644 (file)
@@ -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 <mpi@openbsd.org>
@@ -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 e6bcd93..0db1068 100644 (file)
@@ -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 <mpi@openbsd.org>
@@ -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;
 }