From: Alan Maguire <alan.maguire@xxxxxxxxxx> This patch implements a proof-of-concept of the kernel side of global variable support discussed in [1]. Add new tristate CONFIG_DEBUG_INFO_BTF_VARS; when it is 'y' both per-CPU and global variables are added to vmlinux BTF. When set to 'm', variable BTF is added to module kernel/bpf/vmlinux_btf_extra.ko; as a result, global variables will be available in /sys/kernel/btf/vmlinux_btf_extra using split BTF to store variables. To achieve this, we add a "target" option to scripts/pahole-flags.sh which - if set to "extra" - gives us the flags to be used for extra vmlinux BTF generation. Module building and BTF generation are skipped if CONFIG_DEBUG_INFO_BTF_VARS is 'y' or 'n'. Depends on having a v1.24 of dwarves which provides support for encoding all variables as per patch 1-7 of [1]. To put the pieces together, apply those patches to pahole. Eventually, like other functionality it would likely require dependending on a newer version of pahole like v1.25. CMakeLists.txt before building so that the pahole version can be a proxy for detecting the "encode all variables" feature. Prior to fixes [2] and [3] dedup failed and was highly redundant, but with those fixes in pahole and libbpf we see that in the module case, vmlinux_btf_extra.ko only defines two non-VAR kinds; one for the percpu DATASEC and one for the 'double' type: $ bpftool btf dump -B ~/src/bpf/vmlinux file ~/src/bpf/kernel/bpf/vmlinux_btf_extra.ko|egrep -v VAR [115981] INT 'double' size=8 bits_offset=0 nr_bits=64 encoding=(none) [159904] DATASEC '.data..percpu' size=209156 vlen=378 Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> [1] TBD (requires resyncing patches with dwarves) [2] https://lore.kernel.org/bpf/1666364523-9648-1-git-send-email-alan.maguire@xxxxxxxxxx/ [3] https://lore.kernel.org/bpf/1666622309-22289-1-git-send-email-alan.maguire@xxxxxxxxxx/ --- Makefile | 3 ++- kernel/bpf/Makefile | 4 ++++ kernel/bpf/vmlinux_btf_extra.c | 22 ++++++++++++++++++++ lib/Kconfig.debug | 9 ++++++++ scripts/Makefile.modfinal | 6 ++++++ scripts/pahole-flags.sh | 38 ++++++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 kernel/bpf/vmlinux_btf_extra.c diff --git a/Makefile b/Makefile index f659d3085121..7cc99a424a85 100644 --- a/Makefile +++ b/Makefile @@ -527,6 +527,7 @@ XZ = xz ZSTD = zstd PAHOLE_FLAGS = $(shell PAHOLE=$(PAHOLE) $(srctree)/scripts/pahole-flags.sh) +EXTRA_PAHOLE_FLAGS = $(shell PAHOLE=$(PAHOLE) $(srctree)/scripts/pahole-flags.sh extra) CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) @@ -614,7 +615,7 @@ export KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL -export PAHOLE_FLAGS +export PAHOLE_FLAGS EXTRA_PAHOLE_FLAGS # Files to ignore in find ... statements diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile index 341c94f208f4..8e3ee5c98f23 100644 --- a/kernel/bpf/Makefile +++ b/kernel/bpf/Makefile @@ -43,3 +43,7 @@ obj-$(CONFIG_BPF_PRELOAD) += preload/ obj-$(CONFIG_BPF_SYSCALL) += relo_core.o $(obj)/relo_core.o: $(srctree)/tools/lib/bpf/relo_core.c FORCE $(call if_changed_rule,cc_o_c) + +ifeq ($(CONFIG_DEBUG_INFO_BTF_VARS),m) +obj-m = vmlinux_btf_extra.o +endif diff --git a/kernel/bpf/vmlinux_btf_extra.c b/kernel/bpf/vmlinux_btf_extra.c new file mode 100644 index 000000000000..9aa682287a1e --- /dev/null +++ b/kernel/bpf/vmlinux_btf_extra.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022, Oracle and/or its affiliates. */ + +#include <linux/kernel.h> +#include <linux/module.h> + +/* Dummy module used as a container for extra vmlinux BTF information; + * to be used if vmlinux BTF size is a concern. + */ +static int __init vmlinux_btf_extra_init(void) +{ + return 0; +} +module_init(vmlinux_btf_extra_init); + +static void __exit vmlinux_btf_extra_exit(void) +{ + return; +} +module_exit(vmlinux_btf_extra_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f473f7d8a0a2..3c7df82a37db 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -364,6 +364,15 @@ config DEBUG_INFO_BTF_MODULES help Generate compact split BTF type information for kernel modules. +config DEBUG_INFO_BTF_VARS + tristate "Encode kernel variables in BTF" + depends on DEBUG_INFO_BTF && PAHOLE_VERSION >= 124 + help + Decide whether pahole emits variable definitions for all + variables. If 'm', variables are stored in vmlinux-btf-extra + module, which has BTF for variables only (it is deduplicated + with vmlinux BTF). + config MODULE_ALLOW_BTF_MISMATCH bool "Allow loading modules with non-matching BTF type info" depends on DEBUG_INFO_BTF_MODULES diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 9a1fa6aa30fe..210d7869c14f 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -43,6 +43,12 @@ quiet_cmd_btf_ko = BTF [M] $@ printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ elif [ -n "$(CONFIG_RUST)" ] && $(srctree)/scripts/is_rust_module.sh $@; then \ printf "Skipping BTF generation for %s because it's a Rust module\n" $@ 1>&2; \ + elif [ $@ == "kernel/bpf/vmlinux_btf_extra.ko" ]; then \ + LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J \ + --btf_encode_detached=$@.btf --btf_base vmlinux \ + $(EXTRA_PAHOLE_FLAGS) vmlinux; \ + $(OBJCOPY) --add-section .BTF=$(@).btf \ + --set-section-flags .BTF=alloc,readonly $(@); \ else \ LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \ $(RESOLVE_BTFIDS) -b vmlinux $@; \ diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh index 0d99ef17e4a5..44bc714fe926 100755 --- a/scripts/pahole-flags.sh +++ b/scripts/pahole-flags.sh @@ -1,6 +1,16 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 +config_value() { + awk -v name=$1 -F '=' '$1 == name { print $2 }' include/config/auto.conf +} + +# target is set to "extra" for vmlinux_btf_extra module encoding flags. +# If CONFIG_DEBUG_INFO_BTF_VARS is 'm', we encode variables in +# the module, otherwise if 'y' encode them in vmlinux BTF directly. + +target=$1 + extra_paholeopt= if ! [ -x "$(command -v ${PAHOLE})" ]; then @@ -20,4 +30,32 @@ if [ "${pahole_ver}" -ge "122" ]; then extra_paholeopt="${extra_paholeopt} -j" fi +case $(config_value CONFIG_DEBUG_INFO_BTF_VARS) in +y) + # variables are encoded in core vmlinux BTF; nothing is encoded + # in vmlinux_btf_extra module BTF. + if [[ $target == "extra" ]]; then + extra_paholeopt="" + else + extra_paholeopt="${extra_paholeopt} --encode_all_btf_vars" + fi + ;; +m) + # global variables are encoded in vmlinux_btf_extra; per-CPU + # variables are still found in vmlinux BTF. + if [[ $target == "extra" ]]; then + extra_paholeopt="--encode_all_btf_vars" + else + extra_paholeopt="${extra_paholeopt}" + fi + ;; +*) + # nothing is encoded in vmlinux_btf_extra; no global variables + # are encoded in core vmlinux BTF. + if [[ $target == "extra" ]]; then + extra_paholeopt="" + fi + ;; +esac + echo ${extra_paholeopt} -- 2.31.1