Skip to content
Open
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
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4672,6 +4672,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
5 changes: 2 additions & 3 deletions scripts/Makefile.modfinal
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,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 \
$(objtree)/scripts/gen-btf.sh --btf_base $(objtree)/vmlinux $@; \
fi;

# Same as newer-prereqs, but allows to exclude specified extra dependencies
Expand Down
166 changes: 166 additions & 0 deletions scripts/gen-btf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#!/bin/sh
# 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

if ! is_enabled CONFIG_DEBUG_INFO_BTF; then
exit 0
fi

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_OPTS=""
if is_enabled CONFIG_WERROR; then
RESOLVE_BTFIDS_OPTS+=" --fatal_warnings "
fi
if [ -n "${KBUILD_VERBOSE}" ]; then
RESOLVE_BTFIDS_OPTS+=" -v "
fi
${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_OPTS} \
${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} -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}"

${OBJCOPY} \
--add-section .BTF=${ELF_FILE}.btf \
--add-section .BTF.base=${ELF_FILE}.distilled_base.btf \
${ELF_FILE}

# a module might not have a .BTF_ids section
if [ -f "${ELF_FILE}.btf_ids" ]; then
${OBJCOPY} --update-section .BTF_ids=${ELF_FILE}.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}.distilled_base.btf"
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
42 changes: 6 additions & 36 deletions scripts/link-vmlinux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,34 +105,6 @@ vmlinux_link()
${kallsymso} ${btf_vmlinux_bin_o} ${arch_vmlinux_o} ${ldlibs}
}

# generate .BTF typeinfo from DWARF debuginfo
# ${1} - vmlinux image
gen_btf()
{
local btf_data=${1}.btf.o

info BTF "${btf_data}"
LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}

# 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. Add 2>/dev/null to suppress GNU
# objcopy warnings: "empty loadable segment detected at ..."
${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \
--strip-all ${1} "${btf_data}" 2>/dev/null
# 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

btf_vmlinux_bin_o=${btf_data}
}

# Create ${2}.o file with all symbols from the ${1} object file
kallsyms()
{
Expand Down Expand Up @@ -204,6 +176,7 @@ if is_enabled CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX; then
fi

btf_vmlinux_bin_o=
btfids_vmlinux=
kallsymso=
strip_debug=
generate_map=
Expand All @@ -224,11 +197,13 @@ if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then
fi

if is_enabled CONFIG_DEBUG_INFO_BTF; then
if ! gen_btf .tmp_vmlinux1; then
if ! scripts/gen-btf.sh .tmp_vmlinux1; then
echo >&2 "Failed to generate BTF for vmlinux"
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
exit 1
fi
btf_vmlinux_bin_o=.tmp_vmlinux1.btf.o
btfids_vmlinux=.tmp_vmlinux1.btf_ids
fi

if is_enabled CONFIG_KALLSYMS; then
Expand Down Expand Up @@ -281,14 +256,9 @@ fi

vmlinux_link "${VMLINUX}"

# fill in BTF IDs
if is_enabled CONFIG_DEBUG_INFO_BTF; then
info BTFIDS "${VMLINUX}"
RESOLVE_BTFIDS_ARGS=""
if is_enabled CONFIG_WERROR; then
RESOLVE_BTFIDS_ARGS=" --fatal_warnings "
fi
${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_ARGS} "${VMLINUX}"
info OBJCOPY ${btfids_vmlinux}
${OBJCOPY} --update-section .BTF_ids=${btfids_vmlinux} ${VMLINUX}
fi

mksysmap "${VMLINUX}" System.map
Expand Down
Loading
Loading