On Mon, 2023-03-27 at 12:06 +0100, Quentin Monnet wrote: > This set contains some improvements for bpftool's "visual" program dump > option, which produces the control flow graph in a DOT format. The main > objective is to add support for inline annotations on such graphs, so that > we can have the C source code for the program showing up alongside the > instructions, when available. The last commits also make it possible to > display the line numbers or the bare opcodes in the graph, as supported by > regular program dumps. > > v2: Replace fputc(..., stdout) with putchar(...) in dotlabel_puts(). Hi Quentin, It looks like currently there are no test cases for bpftool prog dump. Borrowing an idea to mix bpf program with comments parsed by awk from prog_tests/btf_dump.c it is possible to put together something like below (although, would be much simpler as a bash script). Is it worth the effort or dump format is too unstable? Thanks, Eduard --- diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_cfg.c b/tools/testing/selftests/bpf/prog_tests/bpftool_cfg.c new file mode 100644 index 000000000000..f582a93b5ee9 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/bpftool_cfg.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <test_progs.h> + +#include "bpf/libbpf.h" +#include "bpftool_cfg.skel.h" + +static int system_to_tmp(char *tmp_template, char *cmd) +{ + char buf[1024]; + int fd, err; + + fd = mkstemp(tmp_template); + if (!ASSERT_GE(fd, 0, "mkstemp")) + return fd; + + snprintf(buf, sizeof(buf), "%s > %s", cmd, tmp_template); + err = system(buf); + if (err) { + PRINT_FAIL("Command %s failed: err %d\n", cmd, err); + remove(tmp_template); + return err; + } + + return 0; +} + +void test_bpftool_cfg(void) +{ + const char *prog_pin_path = "/sys/fs/bpf/bpftool_cfg_test_pin"; + const char *bpftool = "./tools/build/bpftool/bpftool"; + char bpftool_tmp[256] = "/tmp/bpftool_test_cfg.XXXXXX"; + char awk_tmp[256] = "/tmp/bpftool_test_awk.XXXXXX"; + struct bpftool_cfg *skel; + const char *test_file; + char cmd_buf[1024]; + FILE *cmd; + int err; + + skel = bpftool_cfg__open_and_load(); + if (!skel) { + PRINT_FAIL("failed to load bpftool_cfg program: %d (%s)\n", + errno, strerror(errno)); + return; + } + + err = bpf_program__pin(skel->progs.bpftool_cfg_nanosleep, prog_pin_path); + if (err) { + PRINT_FAIL("failed to pin bpftool_cfg program: err %d, errno = %d (%s)\n", + err, errno, strerror(errno)); + goto out; + } + + /* When the test is run with O=, kselftest copies TEST_FILES + * without preserving the directory structure. + */ + if (access("progs/bpftool_cfg.c", R_OK) == 0) + test_file = "progs/bpftool_cfg.c"; + else if (access("bpftool_cfg.c", R_OK) == 0) + test_file = "bpftool_cfg.c"; + else { + PRINT_FAIL("Can't find bpftool_cfg.c\n"); + goto out_unpin; + } + + cmd = fmemopen(cmd_buf, sizeof(cmd_buf), "w"); + fprintf(cmd, "awk '"); + fprintf(cmd, " /END-BPFTOOL-CFG/ { out=0 } "); + fprintf(cmd, " out { print $0 } "); + fprintf(cmd, " /START-BPFTOOL-CFG/ { out=1 } "); + fprintf(cmd, "' '%s' > '%s'", test_file, awk_tmp); + fclose(cmd); + err = system_to_tmp(awk_tmp, cmd_buf); + if (!ASSERT_OK(err, "awk")) + goto out_unpin; + + cmd = fmemopen(cmd_buf, sizeof(cmd_buf), "w"); + fprintf(cmd, "%s prog dump xlated pinned %s visual", bpftool, prog_pin_path); + fclose(cmd); + err = system_to_tmp(bpftool_tmp, cmd_buf); + if (!ASSERT_OK(err, "bpftool")) + goto out_delete; + + cmd = fmemopen(cmd_buf, sizeof(cmd_buf), "w"); + fprintf(cmd, "diff -u %s %s", awk_tmp, bpftool_tmp); + fclose(cmd); + err = system(cmd_buf); + if (!ASSERT_OK(err, "diff")) + goto out_delete; + +out_delete: + if (awk_tmp[0]) + remove(awk_tmp); + if (bpftool_tmp[0]) + remove(bpftool_tmp); +out_unpin: + bpf_program__unpin(skel->progs.bpftool_cfg_nanosleep, prog_pin_path); +out: + bpftool_cfg__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/bpftool_cfg.c b/tools/testing/selftests/bpf/progs/bpftool_cfg.c new file mode 100644 index 000000000000..d10c4e2cecbd --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpftool_cfg.c @@ -0,0 +1,36 @@ +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> + +#include "bpf_misc.h" + +/* +START-BPFTOOL-CFG +digraph "DOT graph for eBPF program" { +subgraph "cluster_0" { + style="dashed"; + color="black"; + label="func_0 ()"; + fn_0_bb_0 [shape=Mdiamond,style=filled,label="ENTRY"]; + + fn_0_bb_2 [shape=record,style=filled,label="{\ +; int bpftool_cfg_nanosleep(void * ctx):\l\ +; return 0;\l\ +0: (b4) w0 = 0\l\ + | 1: (95) exit\l\ +}"]; + + fn_0_bb_1 [shape=Mdiamond,style=filled,label="EXIT"]; + + fn_0_bb_0:s -> fn_0_bb_2:n [style="solid,bold", color=black, weight=10, constraint=true]; + fn_0_bb_2:s -> fn_0_bb_1:n [style="solid,bold", color=black, weight=10, constraint=true]; + fn_0_bb_0:s -> fn_0_bb_1:n [style="invis", constraint=true]; +} +} +END-BPFTOOL-CFG +*/ + +SEC("tp/syscalls/sys_enter_getpid") +int bpftool_cfg_nanosleep(void *ctx) +{ + return 0; +}