[DTrace-devel] [PATCH v2] Introduce 'bpflog' runtime option to request BPF verifier log
Kris Van Hees
kris.van.hees at oracle.com
Thu Jul 29 20:38:49 PDT 2021
The default behaviour is to only print the BPF verifier log when a BPF
program fails to load. It is sometimes desirable to obtain the BPF
verifier log for successful prgoram loads to assist in debugging other
issues with BPF programs. Specifying -xbpflog on the command line or
setting this option using a pragma will force printing of the BPF
verifier log for all program loads.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
include/dtrace/options_defines.h | 3 +-
libdtrace/dt_bpf.c | 64 +++++++++++++-----------
libdtrace/dt_options.c | 1 +
test/unittest/misc/tst.bpflog-cmdline.sh | 13 +++++
test/unittest/misc/tst.bpflog-pragma.sh | 20 ++++++++
5 files changed, 71 insertions(+), 30 deletions(-)
create mode 100755 test/unittest/misc/tst.bpflog-cmdline.sh
create mode 100755 test/unittest/misc/tst.bpflog-pragma.sh
diff --git a/include/dtrace/options_defines.h b/include/dtrace/options_defines.h
index bda4f739..5385f2f2 100644
--- a/include/dtrace/options_defines.h
+++ b/include/dtrace/options_defines.h
@@ -59,7 +59,8 @@
#define DTRACEOPT_PCAPSIZE 29 /* number of bytes to be captured */
#define DTRACEOPT_BPFLOGSIZE 30 /* BPF verifier log, max # bytes */
#define DTRACEOPT_MAXFRAMES 31 /* maximum number of stack frames */
-#define DTRACEOPT_MAX 32 /* number of options */
+#define DTRACEOPT_BPFLOG 32 /* always output BPF verifier log */
+#define DTRACEOPT_MAX 33 /* number of options */
#define DTRACEOPT_UNSET (dtrace_optval_t)-2 /* unset option */
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 17fc2428..101413e3 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -384,7 +384,7 @@ dt_bpf_load_prog(dtrace_hdl_t *dtp, const dt_probe_t *prp,
struct bpf_load_program_attr attr;
size_t logsz;
char *log;
- int rc;
+ int rc, origerrno = 0;
const dtrace_probedesc_t *pdp = prp->desc;
char *p, *q;
@@ -406,14 +406,14 @@ dt_bpf_load_prog(dtrace_hdl_t *dtp, const dt_probe_t *prp,
attr.insns_cnt = dp->dtdo_len;
attr.license = BPF_CG_LICENSE;
- rc = bpf_load_program_xattr(&attr, NULL, 0);
- if (rc >= 0)
- return rc;
+ if (dtp->dt_options[DTRACEOPT_BPFLOG] == DTRACEOPT_UNSET) {
+ rc = bpf_load_program_xattr(&attr, NULL, 0);
+ if (rc >= 0)
+ return rc;
+
+ origerrno = errno;
+ }
- /* if failure, note error and rerun with logging */
- dt_bpf_error(dtp, "BPF program load for '%s:%s:%s:%s' failed: %s\n",
- pdp->prv, pdp->mod, pdp->fun, pdp->prb,
- strerror(errno));
if (dtp->dt_options[DTRACEOPT_BPFLOGSIZE] != DTRACEOPT_UNSET)
logsz = dtp->dt_options[DTRACEOPT_BPFLOGSIZE];
else
@@ -422,34 +422,40 @@ dt_bpf_load_prog(dtrace_hdl_t *dtp, const dt_probe_t *prp,
log = dt_zalloc(dtp, logsz);
assert(log != NULL);
rc = bpf_load_program_xattr(&attr, log, logsz);
+ if (rc < 0) {
+ dt_bpf_error(dtp, "BPF program load for '%s:%s:%s:%s' failed: "
+ "%s\n",
+ pdp->prv, pdp->mod, pdp->fun, pdp->prb,
+ strerror(origerrno ? origerrno : errno));
+
+ /* check whether we have an incomplete BPF log */
+ if (errno == ENOSPC) {
+ fprintf(stderr,
+ "BPF verifier log is incomplete and is not reported.\n"
+ "Set DTrace option 'bpflogsize' to some greater size for more output.\n"
+ "(Current size is %ld.)\n", logsz);
+ goto out;
+ }
+ } else if (dtp->dt_options[DTRACEOPT_BPFLOGSIZE] == DTRACEOPT_UNSET)
+ goto out;
- /* since it failed once, it should fail again */
- assert(rc < 0);
-
- /* check whether we have an incomplete BPF log */
- if (errno == ENOSPC) {
- fprintf(stderr,
- "BPF verifier log is incomplete and is not reported.\n"
- "Set DTrace option 'bpflogsize' to some greater size for more output.\n"
- "(Current size is %ld.)\n", logsz);
- } else {
- /*
- * If there is BPF verifier output, print it with a "BPF: "
- * prefix so it is easier to distinguish.
- */
- for (p = log; p && *p; p = q) {
- q = strchr(p, '\n');
+ /*
+ * If there is BPF verifier output, print it with a "BPF: "
+ * prefix so it is easier to distinguish.
+ */
+ for (p = log; p && *p; p = q) {
+ q = strchr(p, '\n');
- if (q)
- *q++ = '\0';
+ if (q)
+ *q++ = '\0';
- fprintf(stderr, "BPF: %s\n", p);
- }
+ fprintf(stderr, "BPF: %s\n", p);
}
+out:
dt_free(dtp, log);
- return -1;
+ return rc >= 0 ? rc : -1;
}
/*
diff --git a/libdtrace/dt_options.c b/libdtrace/dt_options.c
index a8dd5829..62f356fa 100644
--- a/libdtrace/dt_options.c
+++ b/libdtrace/dt_options.c
@@ -1093,6 +1093,7 @@ static const dt_option_t _dtrace_ctoptions[] = {
*/
static const dt_option_t _dtrace_rtoptions[] = {
{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
+ { "bpflog", dt_opt_runtime, DTRACEOPT_BPFLOG},
{ "bpflogsize", dt_opt_size, DTRACEOPT_BPFLOGSIZE },
{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
diff --git a/test/unittest/misc/tst.bpflog-cmdline.sh b/test/unittest/misc/tst.bpflog-cmdline.sh
new file mode 100755
index 00000000..6a1ee1e2
--- /dev/null
+++ b/test/unittest/misc/tst.bpflog-cmdline.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+
+dtrace=$1
+
+$dtrace -xbpflog -qn 'BEGIN { exit(0); }' |& grep '^BPF: ' > /dev/null
+
+exit $?
diff --git a/test/unittest/misc/tst.bpflog-pragma.sh b/test/unittest/misc/tst.bpflog-pragma.sh
new file mode 100755
index 00000000..7e959184
--- /dev/null
+++ b/test/unittest/misc/tst.bpflog-pragma.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+
+dtrace=$1
+
+$dtrace -qs /dev/stdin << EOT |& grep '^BPF: ' > /dev/null
+#pragma D option bpflog
+
+BEGIN
+{
+ exit(0);
+}
+EOT
+
+exit $?
--
2.32.0
More information about the DTrace-devel
mailing list