From 2e14aa1dba324e11fde754a5b8e3f77172ed613c Mon Sep 17 00:00:00 2001 From: Mykyta Yatsenko Date: Mon, 28 Jul 2025 01:02:53 +0100 Subject: [PATCH] selftests/bpf: add BPF program dump in veristat This patch adds support for dumping BPF program instructions directly from veristat. While it is already possible to inspect BPF program dump using bpftool, it requires multiple commands. During active development, it's common for developers to use veristat for testing verification. Integrating instruction dumping into veristat reduces the need to switch tools and simplifies the workflow. By making this information more readily accessible, this change aims to streamline the BPF development cycle and improve usability for developers. Signed-off-by: Mykyta Yatsenko --- tools/testing/selftests/bpf/veristat.c | 44 +++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index d532dd82a3a83..c59f3104c4c33 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -181,6 +181,12 @@ struct var_preset { bool applied; }; +enum dump_mode { + NO_DUMP = 0, + XLATED, + JITED, +}; + static struct env { char **filenames; int filename_cnt; @@ -227,6 +233,7 @@ static struct env { char orig_cgroup[PATH_MAX]; char stat_cgroup[PATH_MAX]; int memory_peak_fd; + enum dump_mode dump_mode; } env; static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) @@ -295,6 +302,7 @@ static const struct argp_option opts[] = { "Force BPF verifier failure on register invariant violation (BPF_F_TEST_REG_INVARIANTS program flag)" }, { "top-src-lines", 'S', "N", 0, "Emit N most frequent source code lines" }, { "set-global-vars", 'G', "GLOBAL", 0, "Set global variables provided in the expression, for example \"var1 = 1\"" }, + { "dump", 'p', "DUMP", 0, "Print BPF program dump" }, {}, }; @@ -427,6 +435,16 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) return err; } break; + case 'p': + if (strcmp(arg, "jited") == 0) { + env.dump_mode = JITED; + } else if (strcmp(arg, "xlated") == 0) { + env.dump_mode = XLATED; + } else { + fprintf(stderr, "Unrecognized dump mode '%s'\n", arg); + return -EINVAL; + } + break; default: return ARGP_ERR_UNKNOWN; } @@ -1554,6 +1572,27 @@ static int parse_rvalue(const char *val, struct rvalue *rvalue) return 0; } +static void dump(int prog_fd) +{ + char command[512]; + char buf[1024]; + FILE *fp; + + snprintf(command, sizeof(command), "bpftool prog dump %s id %d", + env.dump_mode == JITED ? "jited" : "xlated", prog_fd); + fp = popen(command, "r"); + if (!fp) { + fprintf(stderr, "Can't run bpftool\n"); + return; + } + + while (fgets(buf, sizeof(buf), fp)) { + printf("%s", buf); + } + + pclose(fp); +} + static int process_prog(const char *filename, struct bpf_object *obj, struct bpf_program *prog) { const char *base_filename = basename(strdupa(filename)); @@ -1630,8 +1669,11 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf memset(&info, 0, info_len); fd = bpf_program__fd(prog); - if (fd > 0 && bpf_prog_get_info_by_fd(fd, &info, &info_len) == 0) + if (fd > 0 && bpf_prog_get_info_by_fd(fd, &info, &info_len) == 0) { stats->stats[JITED_SIZE] = info.jited_prog_len; + if (env.dump_mode != NO_DUMP) + dump(info.id); + } parse_verif_log(buf, buf_sz, stats);