Add special BPF CO-RE mode to `btf dump` sub-command, which emits C dump of provided BTF data, but with additional provisions for use with BPF CO-RE. The first special BPF CO-RE specific feature added is applying preserve_access_index attribute to all structs/unions to make them automatically relocatable. This is especially useful for tp_btf/fentry/fexit BPF program types. They allow direct memory access, so BPF C code just uses straightfoward a->b->c access pattern to read data from kernel. But without kernel structs marked as CO-RE relocatable through preserve_access_index attribute, one has to enclose all the data reads into a special __builtin_preserve_access_index code block, like so: __builtin_preserve_access_index(({ x = p->pid; /* where p is struct task_struct *, for example */ })); This is very inconvenient and obscures the logic quite a bit. By marking all auto-generated types with preserve_access_index attribute the above code is reduced to just clean and natural `x = p->pid;`. Having a special `format core`, as opposed to extending existing `format c` mode, allows us to do more improvements like above, knowing that intended use case is for BPF CO-RE. And still have a clean and unassuming plain C mode for any other generic use case. Signed-off-by: Andrii Nakryiko <andriin@xxxxxx> --- .../bpf/bpftool/Documentation/bpftool-btf.rst | 7 ++++-- tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/btf.c | 24 +++++++++++++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-btf.rst b/tools/bpf/bpftool/Documentation/bpftool-btf.rst index 39615f8e145b..101a91280f3d 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-btf.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-btf.rst @@ -24,7 +24,7 @@ BTF COMMANDS | **bpftool** **btf help** | | *BTF_SRC* := { **id** *BTF_ID* | **prog** *PROG* | **map** *MAP* [{**key** | **value** | **kv** | **all**}] | **file** *FILE* } -| *FORMAT* := { **raw** | **c** } +| *FORMAT* := { **raw** | **c** | **core** } | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } @@ -59,7 +59,10 @@ DESCRIPTION **format** option can be used to override default (raw) output format. Raw (**raw**) or C-syntax (**c**) output - formats are supported. + formats are supported. There is also a special BPF CO-RE + mode (**core**), which emits types in valid C syntax, but + with additional provisions for more seamless use with BPF + CO-RE. **bpftool btf help** Print short help message. diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index 754d8395e451..8308ae5f5679 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -800,7 +800,7 @@ _bpftool() return 0 ;; format) - COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "c core raw" -- "$cur" ) ) ;; *) # emit extra options diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c index e5bc97b71ceb..a57494493fec 100644 --- a/tools/bpf/bpftool/btf.c +++ b/tools/bpf/bpftool/btf.c @@ -361,7 +361,7 @@ static void __printf(2, 0) btf_dump_printf(void *ctx, } static int dump_btf_c(const struct btf *btf, - __u32 *root_type_ids, int root_type_cnt) + __u32 *root_type_ids, int root_type_cnt, bool core_mode) { struct btf_dump *d; int err = 0, i; @@ -370,6 +370,13 @@ static int dump_btf_c(const struct btf *btf, if (IS_ERR(d)) return PTR_ERR(d); + if (core_mode) { + printf("#if defined(__has_attribute) && __has_attribute(preserve_access_index)\n"); + printf("#define __CLANG_BPF_CORE_SUPPORTED\n"); + printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n"); + printf("#endif\n\n"); + } + if (root_type_cnt) { for (i = 0; i < root_type_cnt; i++) { err = btf_dump__dump_type(d, root_type_ids[i]); @@ -386,6 +393,12 @@ static int dump_btf_c(const struct btf *btf, } } + if (core_mode) { + printf("#ifdef __CLANG_BPF_CORE_SUPPORTED\n"); + printf("#pragma clang attribute pop\n"); + printf("#endif\n"); + } + done: btf_dump__free(d); return err; @@ -441,10 +454,10 @@ static bool is_btf_raw(const char *file) static int do_dump(int argc, char **argv) { + bool dump_c = false, core_mode = false; struct btf *btf = NULL; __u32 root_type_ids[2]; int root_type_cnt = 0; - bool dump_c = false; __u32 btf_id = -1; const char *src; int fd = -1; @@ -544,6 +557,9 @@ static int do_dump(int argc, char **argv) } if (strcmp(*argv, "c") == 0) { dump_c = true; + } else if (strcmp(*argv, "core") == 0) { + dump_c = true; + core_mode = true; } else if (strcmp(*argv, "raw") == 0) { dump_c = false; } else { @@ -577,7 +593,7 @@ static int do_dump(int argc, char **argv) err = -ENOTSUP; goto done; } - err = dump_btf_c(btf, root_type_ids, root_type_cnt); + err = dump_btf_c(btf, root_type_ids, root_type_cnt, core_mode); } else { err = dump_btf_raw(btf, root_type_ids, root_type_cnt); } @@ -925,7 +941,7 @@ static int do_help(int argc, char **argv) " %s btf help\n" "\n" " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n" - " FORMAT := { raw | c }\n" + " FORMAT := { raw | c | core }\n" " " HELP_SPEC_MAP "\n" " " HELP_SPEC_PROGRAM "\n" " " HELP_SPEC_OPTIONS "\n" -- 2.17.1