xref: /linux/scripts/gen-btf.sh (revision 1a8fa7faf4890d201aad4f5d4943f74d840cd0ba)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
4#
5# This script generates BTF data for the provided ELF file.
6#
7# Kernel BTF generation involves these conceptual steps:
8#   1. pahole generates BTF from DWARF data
9#   2. resolve_btfids applies kernel-specific btf2btf
10#      transformations and computes data for .BTF_ids section
11#   3. the result gets linked/objcopied into the target binary
12#
13# How step (3) should be done differs between vmlinux, and
14# kernel modules, which is the primary reason for the existence
15# of this script.
16#
17# For modules the script expects vmlinux passed in as --btf_base.
18# Generated .BTF, .BTF.base and .BTF_ids sections become embedded
19# into the input ELF file with objcopy.
20#
21# For vmlinux the input file remains unchanged and two files are produced:
22#   - ${1}.btf.o ready for linking into vmlinux
23#   - ${1}.BTF_ids with .BTF_ids data blob
24# This output is consumed by scripts/link-vmlinux.sh
25
26set -e
27
28usage()
29{
30	echo "Usage: $0 [--btf_base <file>] <target ELF file>"
31	exit 1
32}
33
34BTF_BASE=""
35
36while [ $# -gt 0 ]; do
37	case "$1" in
38	--btf_base)
39		BTF_BASE="$2"
40		shift 2
41		;;
42	-*)
43		echo "Unknown option: $1" >&2
44		usage
45		;;
46	*)
47		break
48		;;
49	esac
50done
51
52if [ $# -ne 1 ]; then
53	usage
54fi
55
56ELF_FILE="$1"
57shift
58
59is_enabled() {
60	grep -q "^$1=y" ${objtree}/include/config/auto.conf
61}
62
63info()
64{
65	printf "  %-7s %s\n" "${1}" "${2}"
66}
67
68case "${KBUILD_VERBOSE}" in
69*1*)
70	set -x
71	;;
72esac
73
74
75gen_btf_data()
76{
77	info BTF "${ELF_FILE}"
78	btf1="${ELF_FILE}.BTF.1"
79	${PAHOLE} -J ${PAHOLE_FLAGS}			\
80		${BTF_BASE:+--btf_base ${BTF_BASE}}	\
81		--btf_encode_detached=${btf1}		\
82		"${ELF_FILE}"
83
84	info BTFIDS "${ELF_FILE}"
85	${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_FLAGS}	\
86		${BTF_BASE:+--btf_base ${BTF_BASE}}	\
87		--btf ${btf1} "${ELF_FILE}"
88}
89
90gen_btf_o()
91{
92	local btf_data=${ELF_FILE}.btf.o
93
94	# Create ${btf_data} which contains just .BTF section but no symbols. Add
95	# SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
96	# deletes all symbols including __start_BTF and __stop_BTF, which will
97	# be redefined in the linker script.
98	info OBJCOPY "${btf_data}"
99	echo "" | ${CC} ${CLANG_FLAGS} ${KBUILD_CFLAGS} -c -x c -o ${btf_data} -
100	${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF \
101		--set-section-flags .BTF=alloc,readonly ${btf_data}
102	${OBJCOPY} --only-section=.BTF --strip-all ${btf_data}
103
104	# Change e_type to ET_REL so that it can be used to link final vmlinux.
105	# GNU ld 2.35+ and lld do not allow an ET_EXEC input.
106	if is_enabled CONFIG_CPU_BIG_ENDIAN; then
107		et_rel='\0\1'
108	else
109		et_rel='\1\0'
110	fi
111	printf "${et_rel}" | dd of="${btf_data}" conv=notrunc bs=1 seek=16 status=none
112}
113
114embed_btf_data()
115{
116	info OBJCOPY "${ELF_FILE}.BTF"
117	${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF ${ELF_FILE}
118
119	# a module might not have a .BTF_ids or .BTF.base section
120	local btf_base="${ELF_FILE}.BTF.base"
121	if [ -f "${btf_base}" ]; then
122		${OBJCOPY} --add-section .BTF.base=${btf_base} ${ELF_FILE}
123	fi
124	local btf_ids="${ELF_FILE}.BTF_ids"
125	if [ -f "${btf_ids}" ]; then
126		${RESOLVE_BTFIDS} --patch_btfids ${btf_ids} ${ELF_FILE}
127	fi
128}
129
130cleanup()
131{
132	rm -f "${ELF_FILE}.BTF.1"
133	rm -f "${ELF_FILE}.BTF"
134	if [ "${BTFGEN_MODE}" = "module" ]; then
135		rm -f "${ELF_FILE}.BTF.base"
136		rm -f "${ELF_FILE}.BTF_ids"
137	fi
138}
139trap cleanup EXIT
140
141BTFGEN_MODE="vmlinux"
142if [ -n "${BTF_BASE}" ]; then
143	BTFGEN_MODE="module"
144fi
145
146gen_btf_data
147
148case "${BTFGEN_MODE}" in
149vmlinux)
150	gen_btf_o
151	;;
152module)
153	embed_btf_data
154	;;
155esac
156
157exit 0
158