Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Documentation/process/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bash 4.2 bash --version
binutils 2.30 ld -v
flex 2.5.35 flex --version
bison 2.0 bison --version
pahole 1.16 pahole --version
pahole 1.22 pahole --version
util-linux 2.10o mount --version
kmod 13 depmod -V
e2fsprogs 1.41.4 e2fsck -V
Expand Down Expand Up @@ -143,7 +143,7 @@ pahole

Since Linux 5.2, if CONFIG_DEBUG_INFO_BTF is selected, the build system
generates BTF (BPF Type Format) from DWARF in vmlinux, a bit later from kernel
modules as well. This requires pahole v1.16 or later.
modules as well. This requires pahole v1.22 or later.

It is found in the 'dwarves' or 'pahole' distro packages or from
https://fedorapeople.org/~acme/dwarves/.
Expand Down
1 change: 0 additions & 1 deletion Documentation/scheduler/sched-ext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ options should be enabled to use sched_ext:
CONFIG_DEBUG_INFO_BTF=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
CONFIG_PAHOLE_HAS_BTF_TAG=y

sched_ext is used only when the BPF scheduler is loaded and running.
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4766,6 +4766,7 @@ F: net/sched/act_bpf.c
F: net/sched/cls_bpf.c
F: samples/bpf/
F: scripts/bpf_doc.py
F: scripts/gen-btf.sh
F: scripts/Makefile.btf
F: scripts/pahole-version.sh
F: tools/bpf/
Expand Down
15 changes: 11 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -708,11 +708,12 @@ endif

# The expansion should be delayed until arch/$(SRCARCH)/Makefile is included.
# Some architectures define CROSS_COMPILE in arch/$(SRCARCH)/Makefile.
# CC_VERSION_TEXT and RUSTC_VERSION_TEXT are referenced from Kconfig (so they
# need export), and from include/config/auto.conf.cmd to detect the compiler
# upgrade.
# CC_VERSION_TEXT, RUSTC_VERSION_TEXT and PAHOLE_VERSION are referenced from
# Kconfig (so they need export), and from include/config/auto.conf.cmd to
# detect the version changes between builds.
CC_VERSION_TEXT = $(subst $(pound),,$(shell LC_ALL=C $(CC) --version 2>/dev/null | head -n 1))
RUSTC_VERSION_TEXT = $(subst $(pound),,$(shell $(RUSTC) --version 2>/dev/null))
PAHOLE_VERSION = $(shell $(srctree)/scripts/pahole-version.sh $(PAHOLE))

ifneq ($(findstring clang,$(CC_VERSION_TEXT)),)
include $(srctree)/scripts/Makefile.clang
Expand All @@ -733,7 +734,7 @@ ifdef config-build
# KBUILD_DEFCONFIG may point out an alternative default configuration
# used for 'make defconfig'
include $(srctree)/arch/$(SRCARCH)/Makefile
export KBUILD_DEFCONFIG KBUILD_KCONFIG CC_VERSION_TEXT RUSTC_VERSION_TEXT
export KBUILD_DEFCONFIG KBUILD_KCONFIG CC_VERSION_TEXT RUSTC_VERSION_TEXT PAHOLE_VERSION

config: outputmakefile scripts_basic FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
Expand Down Expand Up @@ -1921,12 +1922,18 @@ clean: private rm-files := Module.symvers modules.nsdeps compile_commands.json
PHONY += prepare
# now expand this into a simple variable to reduce the cost of shell evaluations
prepare: CC_VERSION_TEXT := $(CC_VERSION_TEXT)
prepare: PAHOLE_VERSION := $(PAHOLE_VERSION)
prepare:
@if [ "$(CC_VERSION_TEXT)" != "$(CONFIG_CC_VERSION_TEXT)" ]; then \
echo >&2 "warning: the compiler differs from the one used to build the kernel"; \
echo >&2 " The kernel was built by: $(CONFIG_CC_VERSION_TEXT)"; \
echo >&2 " You are using: $(CC_VERSION_TEXT)"; \
fi
@if [ "$(PAHOLE_VERSION)" != "$(CONFIG_PAHOLE_VERSION)" ]; then \
echo >&2 "warning: pahole version differs from the one used to build the kernel"; \
echo >&2 " The kernel was built with: $(CONFIG_PAHOLE_VERSION)"; \
echo >&2 " You are using: $(PAHOLE_VERSION)"; \
fi

PHONY += help
help:
Expand Down
2 changes: 1 addition & 1 deletion init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ config RUSTC_HAS_FILE_AS_C_STR

config PAHOLE_VERSION
int
default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE))
default "$(PAHOLE_VERSION)"

config CONSTRUCTORS
bool
Expand Down
13 changes: 4 additions & 9 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -388,18 +388,13 @@ config DEBUG_INFO_BTF
depends on !DEBUG_INFO_SPLIT && !DEBUG_INFO_REDUCED
depends on !GCC_PLUGIN_RANDSTRUCT || COMPILE_TEST
depends on BPF_SYSCALL
depends on PAHOLE_VERSION >= 116
depends on DEBUG_INFO_DWARF4 || PAHOLE_VERSION >= 121
depends on PAHOLE_VERSION >= 122
# pahole uses elfutils, which does not have support for Hexagon relocations
depends on !HEXAGON
help
Generate deduplicated BTF type information from DWARF debug info.
Turning this on requires pahole v1.16 or later (v1.21 or later to
support DWARF 5), which will convert DWARF type info into equivalent
deduplicated BTF type info.

config PAHOLE_HAS_SPLIT_BTF
def_bool PAHOLE_VERSION >= 119
Turning this on requires pahole v1.22 or later, which will convert
DWARF type info into equivalent deduplicated BTF type info.

config PAHOLE_HAS_BTF_TAG
def_bool PAHOLE_VERSION >= 123
Expand All @@ -421,7 +416,7 @@ config PAHOLE_HAS_LANG_EXCLUDE
config DEBUG_INFO_BTF_MODULES
bool "Generate BTF type information for kernel modules"
default y
depends on DEBUG_INFO_BTF && MODULES && PAHOLE_HAS_SPLIT_BTF
depends on DEBUG_INFO_BTF && MODULES
help
Generate compact split BTF type information for kernel modules.

Expand Down
21 changes: 8 additions & 13 deletions scripts/Makefile.btf
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,7 @@ JOBS := $(patsubst -j%,%,$(filter -j%,$(MAKEFLAGS)))

ifeq ($(call test-le, $(pahole-ver), 125),y)

# pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars
ifeq ($(call test-le, $(pahole-ver), 121),y)
pahole-flags-$(call test-ge, $(pahole-ver), 118) += --skip_encoding_btf_vars
endif

pahole-flags-$(call test-ge, $(pahole-ver), 121) += --btf_gen_floats

pahole-flags-$(call test-ge, $(pahole-ver), 122) += -j$(JOBS)
pahole-flags-y += --btf_gen_floats -j$(JOBS)

pahole-flags-$(call test-ge, $(pahole-ver), 125) += --skip_encoding_btf_inconsistent_proto --btf_gen_optimized

Expand All @@ -25,13 +18,15 @@ pahole-flags-$(call test-ge, $(pahole-ver), 126) = -j$(JOBS) --btf_features=enc

pahole-flags-$(call test-ge, $(pahole-ver), 130) += --btf_features=attributes

ifneq ($(KBUILD_EXTMOD),)
module-pahole-flags-$(call test-ge, $(pahole-ver), 128) += --btf_features=distilled_base
endif

endif

pahole-flags-$(CONFIG_PAHOLE_HAS_LANG_EXCLUDE) += --lang_exclude=rust

export PAHOLE_FLAGS := $(pahole-flags-y)
export MODULE_PAHOLE_FLAGS := $(module-pahole-flags-y)

resolve-btfids-flags-y :=
resolve-btfids-flags-$(CONFIG_WERROR) += --fatal_warnings
resolve-btfids-flags-$(if $(KBUILD_EXTMOD),y) += --distill_base
resolve-btfids-flags-$(if $(KBUILD_VERBOSE),y) += --verbose

export RESOLVE_BTFIDS_FLAGS := $(resolve-btfids-flags-y)
5 changes: 2 additions & 3 deletions scripts/Makefile.modfinal
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ quiet_cmd_btf_ko = BTF [M] $@
cmd_btf_ko = \
if [ ! -f $(objtree)/vmlinux ]; then \
printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \
else \
LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base $(objtree)/vmlinux $@; \
$(RESOLVE_BTFIDS) -b $(objtree)/vmlinux $@; \
else \
$(srctree)/scripts/gen-btf.sh --btf_base $(objtree)/vmlinux $@; \
fi;

# Same as newer-prereqs, but allows to exclude specified extra dependencies
Expand Down
2 changes: 1 addition & 1 deletion scripts/Makefile.vmlinux
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ targets += vmlinux.unstripped .vmlinux.export.o
vmlinux.unstripped: scripts/link-vmlinux.sh vmlinux.o .vmlinux.export.o $(KBUILD_LDS) FORCE
+$(call if_changed_dep,link_vmlinux)
ifdef CONFIG_DEBUG_INFO_BTF
vmlinux.unstripped: $(RESOLVE_BTFIDS)
vmlinux.unstripped: $(RESOLVE_BTFIDS) $(srctree)/scripts/gen-btf.sh
endif

ifdef CONFIG_BUILDTIME_TABLE_SORT
Expand Down
157 changes: 157 additions & 0 deletions scripts/gen-btf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
#
# This script generates BTF data for the provided ELF file.
#
# Kernel BTF generation involves these conceptual steps:
# 1. pahole generates BTF from DWARF data
# 2. resolve_btfids applies kernel-specific btf2btf
# transformations and computes data for .BTF_ids section
# 3. the result gets linked/objcopied into the target binary
#
# How step (3) should be done differs between vmlinux, and
# kernel modules, which is the primary reason for the existence
# of this script.
#
# For modules the script expects vmlinux passed in as --btf_base.
# Generated .BTF, .BTF.base and .BTF_ids sections become embedded
# into the input ELF file with objcopy.
#
# For vmlinux the input file remains unchanged and two files are produced:
# - ${1}.btf.o ready for linking into vmlinux
# - ${1}.BTF_ids with .BTF_ids data blob
# This output is consumed by scripts/link-vmlinux.sh

set -e

usage()
{
echo "Usage: $0 [--btf_base <file>] <target ELF file>"
exit 1
}

BTF_BASE=""

while [ $# -gt 0 ]; do
case "$1" in
--btf_base)
BTF_BASE="$2"
shift 2
;;
-*)
echo "Unknown option: $1" >&2
usage
;;
*)
break
;;
esac
done

if [ $# -ne 1 ]; then
usage
fi

ELF_FILE="$1"
shift

is_enabled() {
grep -q "^$1=y" ${objtree}/include/config/auto.conf
}

info()
{
printf " %-7s %s\n" "${1}" "${2}"
}

case "${KBUILD_VERBOSE}" in
*1*)
set -x
;;
esac


gen_btf_data()
{
info BTF "${ELF_FILE}"
btf1="${ELF_FILE}.BTF.1"
${PAHOLE} -J ${PAHOLE_FLAGS} \
${BTF_BASE:+--btf_base ${BTF_BASE}} \
--btf_encode_detached=${btf1} \
"${ELF_FILE}"

info BTFIDS "${ELF_FILE}"
${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_FLAGS} \
${BTF_BASE:+--btf_base ${BTF_BASE}} \
--btf ${btf1} "${ELF_FILE}"
}

gen_btf_o()
{
local btf_data=${ELF_FILE}.btf.o

# Create ${btf_data} which contains just .BTF section but no symbols. Add
# SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
# deletes all symbols including __start_BTF and __stop_BTF, which will
# be redefined in the linker script.
info OBJCOPY "${btf_data}"
echo "" | ${CC} ${CLANG_FLAGS} -c -x c -o ${btf_data} -
${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF \
--set-section-flags .BTF=alloc,readonly ${btf_data}
${OBJCOPY} --only-section=.BTF --strip-all ${btf_data}

# Change e_type to ET_REL so that it can be used to link final vmlinux.
# GNU ld 2.35+ and lld do not allow an ET_EXEC input.
if is_enabled CONFIG_CPU_BIG_ENDIAN; then
et_rel='\0\1'
else
et_rel='\1\0'
fi
printf "${et_rel}" | dd of="${btf_data}" conv=notrunc bs=1 seek=16 status=none
}

embed_btf_data()
{
info OBJCOPY "${ELF_FILE}.BTF"
${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF ${ELF_FILE}

# a module might not have a .BTF_ids or .BTF.base section
local btf_base="${ELF_FILE}.BTF.base"
if [ -f "${btf_base}" ]; then
${OBJCOPY} --add-section .BTF.base=${btf_base} ${ELF_FILE}
fi
local btf_ids="${ELF_FILE}.BTF_ids"
if [ -f "${btf_ids}" ]; then
${OBJCOPY} --update-section .BTF_ids=${btf_ids} ${ELF_FILE}
fi
}

cleanup()
{
rm -f "${ELF_FILE}.BTF.1"
rm -f "${ELF_FILE}.BTF"
if [ "${BTFGEN_MODE}" = "module" ]; then
rm -f "${ELF_FILE}.BTF.base"
rm -f "${ELF_FILE}.BTF_ids"
fi
}
trap cleanup EXIT

BTFGEN_MODE="vmlinux"
if [ -n "${BTF_BASE}" ]; then
BTFGEN_MODE="module"
fi

gen_btf_data

case "${BTFGEN_MODE}" in
vmlinux)
gen_btf_o
;;
module)
embed_btf_data
;;
esac

exit 0
Loading
Loading