#!/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 ] " 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 } case "${KBUILD_VERBOSE}" in *1*) set -x ;; esac gen_btf_data() { btf1="${ELF_FILE}.BTF.1" ${PAHOLE} -J ${PAHOLE_FLAGS} \ ${BTF_BASE:+--btf_base ${BTF_BASE}} \ --btf_encode_detached=${btf1} \ "${ELF_FILE}" ${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_FLAGS} \ ${BTF_BASE:+--btf_base ${BTF_BASE}} \ --btf ${btf1} "${ELF_FILE}" } gen_btf_o() { 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. echo "" | ${CC} ${CLANG_FLAGS} ${KBUILD_CPPFLAGS} ${KBUILD_CFLAGS} -fno-lto -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() { ${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF ${ELF_FILE} # a module might not have a .BTF_ids or .BTF.base section btf_base="${ELF_FILE}.BTF.base" if [ -f "${btf_base}" ]; then ${OBJCOPY} --add-section .BTF.base=${btf_base} ${ELF_FILE} fi btf_ids="${ELF_FILE}.BTF_ids" if [ -f "${btf_ids}" ]; then ${RESOLVE_BTFIDS} --patch_btfids ${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