summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2021-09-09 09:53:12 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2021-09-09 09:53:12 +0000
commit2f3358f86858bf931beccf16d07cebd0fd1c25fa (patch)
treeb357b1008e9d16b25392c1757bd9cfe97a86d275
parent2b0ddd4013a90152d58bd092bd1d971c5ac944ab (diff)
Make it possible to associate multiple probes to a single rule.
The following syntax, reducing duplication, is now allowed: END, interval:hz:2 { ... } Rule descriptors are now linked to a list of probe descriptors instead of a single one. Enabled kernel probes are now linked to btrace(8) probe descriptors. While here stop parsing filter and probe if debug is not enabled.
-rw-r--r--usr.sbin/btrace/bt_parse.y73
-rw-r--r--usr.sbin/btrace/bt_parser.h23
-rw-r--r--usr.sbin/btrace/btrace.c138
3 files changed, 145 insertions, 89 deletions
diff --git a/usr.sbin/btrace/bt_parse.y b/usr.sbin/btrace/bt_parse.y
index 99ad7d0cf30..196edc4e28a 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.41 2021/09/08 15:34:01 mpi Exp $ */
+/* $OpenBSD: bt_parse.y,v 1.42 2021/09/09 09:53:11 mpi Exp $ */
/*
* Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
@@ -59,8 +59,8 @@ SLIST_HEAD(, bt_var) l_variables;
struct bt_arg g_nullba = BA_INITIALIZER(0, B_AT_LONG);
struct bt_arg g_maxba = BA_INITIALIZER(LONG_MAX, B_AT_LONG);
-struct bt_rule *br_new(struct bt_probe *, struct bt_filter *, struct bt_stmt *,
- enum bt_rtype);
+struct bt_rule *br_new(struct bt_probe *, struct bt_filter *,
+ struct bt_stmt *);
struct bt_probe *bp_new(const char *, const char *, const char *, int32_t);
struct bt_arg *ba_append(struct bt_arg *, struct bt_arg *);
struct bt_arg *ba_op(enum bt_argtype, struct bt_arg *, struct bt_arg *);
@@ -124,7 +124,7 @@ static int pflag;
%type <v.string> gvar lvar
%type <v.i> beginend
-%type <v.probe> probe pname
+%type <v.probe> plist probe pname
%type <v.filter> filter
%type <v.stmt> action stmt stmtblck stmtlist block
%type <v.arg> pat vargs mentry mpat pargs staticv
@@ -137,13 +137,18 @@ grammar : /* empty */
| grammar error
;
-rule : beginend action { br_new(NULL, NULL, $2, $1); }
- | probe filter action { br_new($1, $2, $3, B_RT_PROBE); }
+rule : plist filter action { br_new($1, $2, $3); }
;
beginend: BEGIN | END ;
+plist : plist ',' probe { $$ = bp_append($1, $3); }
+ | probe
+ ;
+
probe : { pflag = 1; } pname { $$ = $2; pflag = 0; }
+ | beginend { $$ = bp_new(NULL, NULL, NULL, $1); }
+ ;
pname : STRING ':' STRING ':' STRING { $$ = bp_new($1, $3, $5, 0); }
| STRING ':' HZ ':' NUMBER { $$ = bp_new($1, "hz", NULL, $5); }
@@ -227,8 +232,9 @@ pargs : expr
| gvar ',' pat { $$ = ba_append(bg_find($1), $3); }
;
-NL : /* empty */ | '\n'
- ;
+NL : /* empty */
+ | '\n'
+ ;
stmt : ';' NL { $$ = NULL; }
| gvar '=' pat { $$ = bg_store($1, $3); }
@@ -291,29 +297,29 @@ get_nargs(void)
/* Create a new rule, representing "probe / filter / { action }" */
struct bt_rule *
-br_new(struct bt_probe *probe, struct bt_filter *filter, struct bt_stmt *head,
- enum bt_rtype rtype)
+br_new(struct bt_probe *probe, struct bt_filter *filter, struct bt_stmt *head)
{
struct bt_rule *br;
br = calloc(1, sizeof(*br));
if (br == NULL)
err(1, "bt_rule: calloc");
- br->br_probe = probe;
+ /* SLIST_INSERT_HEAD() nullify the next pointer. */
+ SLIST_FIRST(&br->br_probes) = probe;
br->br_filter = filter;
/* SLIST_INSERT_HEAD() nullify the next pointer. */
SLIST_FIRST(&br->br_action) = head;
- br->br_type = rtype;
SLIST_FIRST(&br->br_variables) = SLIST_FIRST(&l_variables);
SLIST_INIT(&l_variables);
- if (rtype == B_RT_PROBE) {
+ do {
+ if (probe->bp_type != B_PT_PROBE)
+ continue;
g_nprobes++;
- TAILQ_INSERT_TAIL(&g_rules, br, br_next);
- } else {
- TAILQ_INSERT_HEAD(&g_rules, br, br_next);
- }
+ } while ((probe = SLIST_NEXT(probe, bp_next)) != NULL);
+
+ TAILQ_INSERT_TAIL(&g_rules, br, br_next);
return br;
}
@@ -349,10 +355,16 @@ struct bt_probe *
bp_new(const char *prov, const char *func, const char *name, int32_t rate)
{
struct bt_probe *bp;
+ enum bt_ptype ptype;
if (rate < 0 || rate > INT32_MAX)
errx(1, "only positive values permitted");
+ if (prov == NULL && func == NULL && name == NULL)
+ ptype = rate; /* BEGIN or END */
+ else
+ ptype = B_PT_PROBE;
+
bp = calloc(1, sizeof(*bp));
if (bp == NULL)
err(1, "bt_probe: calloc");
@@ -360,10 +372,33 @@ bp_new(const char *prov, const char *func, const char *name, int32_t rate)
bp->bp_func = func;
bp->bp_name = name;
bp->bp_rate = rate;
+ bp->bp_type = ptype;
return bp;
}
+/*
+ * Link two probes together, to build a probe list attached to
+ * a single action.
+ */
+struct bt_probe *
+bp_append(struct bt_probe *bp0, struct bt_probe *bp1)
+{
+ struct bt_probe *bp = bp0;
+
+ assert(bp1 != NULL);
+
+ if (bp0 == NULL)
+ return bp1;
+
+ while (SLIST_NEXT(bp, bp_next) != NULL)
+ bp = SLIST_NEXT(bp, bp_next);
+
+ SLIST_INSERT_AFTER(bp, bp1, bp_next);
+
+ return bp0;
+}
+
/* Create a new argument */
struct bt_arg *
ba_new0(void *val, enum bt_argtype type)
@@ -660,8 +695,8 @@ struct keyword *
lookup(char *s)
{
static const struct keyword kws[] = {
- { "BEGIN", BEGIN, B_RT_BEGIN },
- { "END", END, B_RT_END },
+ { "BEGIN", BEGIN, B_PT_BEGIN },
+ { "END", END, B_PT_END },
{ "arg0", BUILTIN, B_AT_BI_ARG0 },
{ "arg1", BUILTIN, B_AT_BI_ARG1 },
{ "arg2", BUILTIN, B_AT_BI_ARG2 },
diff --git a/usr.sbin/btrace/bt_parser.h b/usr.sbin/btrace/bt_parser.h
index b7288e73675..20fde72791e 100644
--- a/usr.sbin/btrace/bt_parser.h
+++ b/usr.sbin/btrace/bt_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bt_parser.h,v 1.19 2021/09/08 13:29:51 dv Exp $ */
+/* $OpenBSD: bt_parser.h,v 1.20 2021/09/09 09:53:11 mpi Exp $ */
/*
* Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
@@ -32,13 +32,23 @@
* "provider:function:name"
* or
* "provider:time_unit:rate"
+ *
+ * Multiple probes can be associated to the same action.
*/
struct bt_probe {
+ SLIST_ENTRY(bt_probe) bp_next; /* next probe for this rule */
const char *bp_prov; /* provider */
const char *bp_func; /* function or time unit */
const char *bp_name;
uint32_t bp_rate;
#define bp_unit bp_func
+ enum bt_ptype {
+ B_PT_BEGIN = 1,
+ B_PT_END,
+ B_PT_PROBE,
+ } bp_type; /* BEGIN, END or 'probe' */
+ void *bp_cookie; /* ioctl request */
+ uint32_t bp_pbn; /* ID assigned by the kernel */
};
@@ -77,19 +87,10 @@ TAILQ_HEAD(bt_ruleq, bt_rule);
*/
struct bt_rule {
TAILQ_ENTRY(bt_rule) br_next; /* linkage in global list */
- struct bt_probe *br_probe;
+ SLIST_HEAD(, bt_probe) br_probes; /* list of probes */
struct bt_filter *br_filter;
SLIST_HEAD(, bt_stmt) br_action;
SLIST_HEAD(, bt_var) br_variables; /* local variables */
-
- enum bt_rtype {
- B_RT_BEGIN = 1,
- B_RT_END,
- B_RT_PROBE,
- } br_type; /* BEGIN, END or 'probe' */
-
- uint32_t br_pbn; /* ID assigned by the kernel */
- void *br_cookie;
};
/*
diff --git a/usr.sbin/btrace/btrace.c b/usr.sbin/btrace/btrace.c
index 65e2a5257c0..a84ab5c40ca 100644
--- a/usr.sbin/btrace/btrace.c
+++ b/usr.sbin/btrace/btrace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: btrace.c,v 1.53 2021/09/09 09:43:49 mpi Exp $ */
+/* $OpenBSD: btrace.c,v 1.54 2021/09/09 09:53:11 mpi Exp $ */
/*
* Copyright (c) 2019 - 2021 Martin Pieuchot <mpi@openbsd.org>
@@ -105,7 +105,7 @@ int ba2dtflags(struct bt_arg *);
__dead void xabort(const char *, ...);
void debug(const char *, ...);
void debugx(const char *, ...);
-const char *debug_rule_name(struct bt_rule *);
+const char *debug_probe_name(struct bt_probe *);
void debug_dump_term(struct bt_arg *);
void debug_dump_expr(struct bt_arg *);
void debug_dump_filter(struct bt_rule *);
@@ -398,54 +398,58 @@ rules_setup(int fd)
struct bt_probe *bp;
struct bt_stmt *bs;
int dokstack = 0, on = 1;
+ uint64_t evtflags;
TAILQ_FOREACH(r, &g_rules, br_next) {
- debug("parsed probe '%s'", debug_rule_name(r));
- debug_dump_filter(r);
-
- if (r->br_type != B_RT_PROBE) {
- if (r->br_type == B_RT_BEGIN)
- rbegin = r;
- continue;
- }
-
- bp = r->br_probe;
- dtpi_cache(fd);
- dtpi = dtpi_get_by_value(bp->bp_prov, bp->bp_func, bp->bp_name);
- if (dtpi == NULL) {
- errx(1, "probe '%s:%s:%s' not found", bp->bp_prov,
- bp->bp_func, bp->bp_name);
- }
-
- dtrq = calloc(1, sizeof(*dtrq));
- if (dtrq == NULL)
- err(1, "dtrq: 1alloc");
-
- r->br_pbn = dtpi->dtpi_pbn;
- dtrq->dtrq_pbn = dtpi->dtpi_pbn;
- dtrq->dtrq_rate = r->br_probe->bp_rate;
-
+ evtflags = 0;
SLIST_FOREACH(bs, &r->br_action, bs_next) {
struct bt_arg *ba;
SLIST_FOREACH(ba, &bs->bs_args, ba_next)
- dtrq->dtrq_evtflags |= ba2dtflags(ba);
+ evtflags |= ba2dtflags(ba);
/* Also check the value for map/hist insertion */
switch (bs->bs_act) {
case B_AC_BUCKETIZE:
case B_AC_INSERT:
ba = (struct bt_arg *)bs->bs_var;
- dtrq->dtrq_evtflags |= ba2dtflags(ba);
+ evtflags |= ba2dtflags(ba);
break;
default:
break;
}
}
- if (dtrq->dtrq_evtflags & DTEVT_KSTACK)
- dokstack = 1;
- r->br_cookie = dtrq;
+ SLIST_FOREACH(bp, &r->br_probes, bp_next) {
+ debug("parsed probe '%s'", debug_probe_name(bp));
+ debug_dump_filter(r);
+
+ if (bp->bp_type != B_PT_PROBE) {
+ if (bp->bp_type == B_PT_BEGIN)
+ rbegin = r;
+ continue;
+ }
+
+ dtpi_cache(fd);
+ dtpi = dtpi_get_by_value(bp->bp_prov, bp->bp_func,
+ bp->bp_name);
+ if (dtpi == NULL) {
+ errx(1, "probe '%s:%s:%s' not found",
+ bp->bp_prov, bp->bp_func, bp->bp_name);
+ }
+
+ dtrq = calloc(1, sizeof(*dtrq));
+ if (dtrq == NULL)
+ err(1, "dtrq: 1alloc");
+
+ bp->bp_pbn = dtpi->dtpi_pbn;
+ dtrq->dtrq_pbn = dtpi->dtpi_pbn;
+ dtrq->dtrq_rate = bp->bp_rate;
+ dtrq->dtrq_evtflags = evtflags;
+ if (dtrq->dtrq_evtflags & DTEVT_KSTACK)
+ dokstack = 1;
+ bp->bp_cookie = dtrq;
+ }
}
if (dokstack)
@@ -463,12 +467,14 @@ rules_setup(int fd)
/* Enable all probes */
TAILQ_FOREACH(r, &g_rules, br_next) {
- if (r->br_type != B_RT_PROBE)
- continue;
+ SLIST_FOREACH(bp, &r->br_probes, bp_next) {
+ if (bp->bp_type != B_PT_PROBE)
+ continue;
- dtrq = r->br_cookie;
- if (ioctl(fd, DTIOCPRBENABLE, dtrq))
- err(1, "DTIOCPRBENABLE");
+ dtrq = bp->bp_cookie;
+ if (ioctl(fd, DTIOCPRBENABLE, dtrq))
+ err(1, "DTIOCPRBENABLE");
+ }
}
if (g_nprobes > 0) {
@@ -481,12 +487,16 @@ void
rules_apply(struct dt_evt *dtev)
{
struct bt_rule *r;
+ struct bt_probe *bp;
TAILQ_FOREACH(r, &g_rules, br_next) {
- if (r->br_type != B_RT_PROBE || r->br_pbn != dtev->dtev_pbn)
- continue;
+ SLIST_FOREACH(bp, &r->br_probes, bp_next) {
+ if (bp->bp_type != B_PT_PROBE ||
+ bp->bp_pbn != dtev->dtev_pbn)
+ continue;
- rule_eval(r, dtev);
+ rule_eval(r, dtev);
+ }
}
}
@@ -494,6 +504,7 @@ void
rules_teardown(int fd)
{
struct dtioc_req *dtrq;
+ struct bt_probe *bp;
struct bt_rule *r, *rend = NULL;
int dokstack = 0, off = 0;
@@ -503,18 +514,19 @@ rules_teardown(int fd)
}
TAILQ_FOREACH(r, &g_rules, br_next) {
- dtrq = r->br_cookie;
- if (r->br_type != B_RT_PROBE) {
- if (r->br_type == B_RT_END)
- rend = r;
- continue;
- } else {
- if (ioctl(fd, DTIOCPRBDISABLE, dtrq))
- err(1, "DTIOCPRBDISABLE");
- }
+ SLIST_FOREACH(bp, &r->br_probes, bp_next) {
+ if (bp->bp_type != B_PT_PROBE) {
+ if (bp->bp_type == B_PT_END)
+ rend = r;
+ continue;
+ }
- if (dtrq->dtrq_evtflags & DTEVT_KSTACK)
- dokstack = 1;
+ dtrq = bp->bp_cookie;
+ if (ioctl(fd, DTIOCPRBDISABLE, dtrq))
+ err(1, "DTIOCPRBDISABLE");
+ if (dtrq->dtrq_evtflags & DTEVT_KSTACK)
+ dokstack = 1;
+ }
}
if (dokstack)
@@ -535,9 +547,12 @@ void
rule_eval(struct bt_rule *r, struct dt_evt *dtev)
{
struct bt_stmt *bs;
+ struct bt_probe *bp;
- debug("eval rule '%s'", debug_rule_name(r));
- debug_dump_filter(r);
+ SLIST_FOREACH(bp, &r->br_probes, bp_next) {
+ debug("eval rule '%s'", debug_probe_name(bp));
+ debug_dump_filter(r);
+ }
if (r->br_filter != NULL && r->br_filter->bf_condition != NULL) {
if (stmt_test(r->br_filter->bf_condition, dtev) == false) {
@@ -1542,6 +1557,9 @@ debug_dump_filter(struct bt_rule *r)
{
struct bt_stmt *bs;
+ if (verbose < 2)
+ return;
+
if (r->br_filter == NULL) {
debugx("\n");
return;
@@ -1555,20 +1573,22 @@ debug_dump_filter(struct bt_rule *r)
}
const char *
-debug_rule_name(struct bt_rule *r)
+debug_probe_name(struct bt_probe *bp)
{
- struct bt_probe *bp = r->br_probe;
static char buf[64];
- if (r->br_type == B_RT_BEGIN)
+ if (verbose < 2)
+ return "";
+
+ if (bp->bp_type == B_PT_BEGIN)
return "BEGIN";
- if (r->br_type == B_RT_END)
+ if (bp->bp_type == B_PT_END)
return "END";
- assert(r->br_type == B_RT_PROBE);
+ assert(bp->bp_type == B_PT_PROBE);
- if (r->br_probe->bp_rate) {
+ if (bp->bp_rate) {
snprintf(buf, sizeof(buf), "%s:%s:%u", bp->bp_prov,
bp->bp_unit, bp->bp_rate);
} else {