Skip to content

Commit 341dfcf

Browse files
anakryikoborkmann
authored andcommitted
btf: expose BTF info through sysfs
Make .BTF section allocated and expose its contents through sysfs. /sys/kernel/btf directory is created to contain all the BTFs present inside kernel. Currently there is only kernel's main BTF, represented as /sys/kernel/btf/kernel file. Once kernel modules' BTFs are supported, each module will expose its BTF as /sys/kernel/btf/<module-name> file. Current approach relies on a few pieces coming together: 1. pahole is used to take almost final vmlinux image (modulo .BTF and kallsyms) and generate .BTF section by converting DWARF info into BTF. This section is not allocated and not mapped to any segment, though, so is not yet accessible from inside kernel at runtime. 2. objcopy dumps .BTF contents into binary file and subsequently convert binary file into linkable object file with automatically generated symbols _binary__btf_kernel_bin_start and _binary__btf_kernel_bin_end, pointing to start and end, respectively, of BTF raw data. 3. final vmlinux image is generated by linking this object file (and kallsyms, if necessary). sysfs_btf.c then creates /sys/kernel/btf/kernel file and exposes embedded BTF contents through it. This allows, e.g., libbpf and bpftool access BTF info at well-known location, without resorting to searching for vmlinux image on disk (location of which is not standardized and vmlinux image might not be even available in some scenarios, e.g., inside qemu during testing). Alternative approach using .incbin assembler directive to embed BTF contents directly was attempted but didn't work, because sysfs_proc.o is not re-compiled during link-vmlinux.sh stage. This is required, though, to update embedded BTF data (initially empty data is embedded, then pahole generates BTF info and we need to regenerate sysfs_btf.o with updated contents, but it's too late at that point). If BTF couldn't be generated due to missing or too old pahole, sysfs_btf.c handles that gracefully by detecting that _binary__btf_kernel_bin_start (weak symbol) is 0 and not creating /sys/kernel/btf at all. v2->v3: - added Documentation/ABI/testing/sysfs-kernel-btf (Greg K-H); - created proper kobject (btf_kobj) for btf directory (Greg K-H); - undo v2 change of reusing vmlinux, as it causes extra kallsyms pass due to initially missing __binary__btf_kernel_bin_{start/end} symbols; v1->v2: - allow kallsyms stage to re-use vmlinux generated by gen_btf(); Reviewed-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent a664a83 commit 341dfcf

File tree

4 files changed

+104
-19
lines changed

4 files changed

+104
-19
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
What: /sys/kernel/btf
2+
Date: Aug 2019
3+
KernelVersion: 5.5
4+
5+
Description:
6+
Contains BTF type information and related data for kernel and
7+
kernel modules.
8+
9+
What: /sys/kernel/btf/kernel
10+
Date: Aug 2019
11+
KernelVersion: 5.5
12+
13+
Description:
14+
Read-only binary attribute exposing kernel's own BTF type
15+
information with description of all internal kernel types. See
16+
Documentation/bpf/btf.rst for detailed description of format
17+
itself.

kernel/bpf/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ obj-$(CONFIG_CGROUP_BPF) += cgroup.o
2222
ifeq ($(CONFIG_INET),y)
2323
obj-$(CONFIG_BPF_SYSCALL) += reuseport_array.o
2424
endif
25+
ifeq ($(CONFIG_SYSFS),y)
26+
obj-$(CONFIG_DEBUG_INFO_BTF) += sysfs_btf.o
27+
endif

kernel/bpf/sysfs_btf.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Provide kernel BTF information for introspection and use by eBPF tools.
4+
*/
5+
#include <linux/kernel.h>
6+
#include <linux/module.h>
7+
#include <linux/kobject.h>
8+
#include <linux/init.h>
9+
#include <linux/sysfs.h>
10+
11+
/* See scripts/link-vmlinux.sh, gen_btf() func for details */
12+
extern char __weak _binary__btf_kernel_bin_start[];
13+
extern char __weak _binary__btf_kernel_bin_end[];
14+
15+
static ssize_t
16+
btf_kernel_read(struct file *file, struct kobject *kobj,
17+
struct bin_attribute *bin_attr,
18+
char *buf, loff_t off, size_t len)
19+
{
20+
memcpy(buf, _binary__btf_kernel_bin_start + off, len);
21+
return len;
22+
}
23+
24+
static struct bin_attribute bin_attr_btf_kernel __ro_after_init = {
25+
.attr = { .name = "kernel", .mode = 0444, },
26+
.read = btf_kernel_read,
27+
};
28+
29+
static struct kobject *btf_kobj;
30+
31+
static int __init btf_kernel_init(void)
32+
{
33+
int err;
34+
35+
if (!_binary__btf_kernel_bin_start)
36+
return 0;
37+
38+
btf_kobj = kobject_create_and_add("btf", kernel_kobj);
39+
if (IS_ERR(btf_kobj)) {
40+
err = PTR_ERR(btf_kobj);
41+
btf_kobj = NULL;
42+
return err;
43+
}
44+
45+
bin_attr_btf_kernel.size = _binary__btf_kernel_bin_end -
46+
_binary__btf_kernel_bin_start;
47+
48+
return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_kernel);
49+
}
50+
51+
subsys_initcall(btf_kernel_init);

scripts/link-vmlinux.sh

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ modpost_link()
5656
}
5757

5858
# Link of vmlinux
59-
# ${1} - optional extra .o files
60-
# ${2} - output file
59+
# ${1} - output file
60+
# ${@:2} - optional extra .o files
6161
vmlinux_link()
6262
{
6363
local lds="${objtree}/${KBUILD_LDS}"
@@ -70,9 +70,9 @@ vmlinux_link()
7070
--start-group \
7171
${KBUILD_VMLINUX_LIBS} \
7272
--end-group \
73-
${1}"
73+
${@:2}"
7474

75-
${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
75+
${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} -o ${1} \
7676
-T ${lds} ${objects}
7777
else
7878
objects="-Wl,--whole-archive \
@@ -81,9 +81,9 @@ vmlinux_link()
8181
-Wl,--start-group \
8282
${KBUILD_VMLINUX_LIBS} \
8383
-Wl,--end-group \
84-
${1}"
84+
${@:2}"
8585

86-
${CC} ${CFLAGS_vmlinux} -o ${2} \
86+
${CC} ${CFLAGS_vmlinux} -o ${1} \
8787
-Wl,-T,${lds} \
8888
${objects} \
8989
-lutil -lrt -lpthread
@@ -92,23 +92,34 @@ vmlinux_link()
9292
}
9393

9494
# generate .BTF typeinfo from DWARF debuginfo
95+
# ${1} - vmlinux image
96+
# ${2} - file to dump raw BTF data into
9597
gen_btf()
9698
{
97-
local pahole_ver;
99+
local pahole_ver
100+
local bin_arch
98101

99102
if ! [ -x "$(command -v ${PAHOLE})" ]; then
100103
info "BTF" "${1}: pahole (${PAHOLE}) is not available"
101-
return 0
104+
return 1
102105
fi
103106

104107
pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
105108
if [ "${pahole_ver}" -lt "113" ]; then
106109
info "BTF" "${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.13"
107-
return 0
110+
return 1
108111
fi
109112

110-
info "BTF" ${1}
113+
info "BTF" ${2}
114+
vmlinux_link ${1}
111115
LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1}
116+
117+
# dump .BTF section into raw binary file to link with final vmlinux
118+
bin_arch=$(${OBJDUMP} -f ${1} | grep architecture | \
119+
cut -d, -f1 | cut -d' ' -f2)
120+
${OBJCOPY} --dump-section .BTF=.btf.kernel.bin ${1} 2>/dev/null
121+
${OBJCOPY} -I binary -O ${CONFIG_OUTPUT_FORMAT} -B ${bin_arch} \
122+
--rename-section .data=.BTF .btf.kernel.bin ${2}
112123
}
113124

114125
# Create ${2} .o file with all symbols from the ${1} object file
@@ -153,6 +164,7 @@ sortextable()
153164
# Delete output files in case of error
154165
cleanup()
155166
{
167+
rm -f .btf.*
156168
rm -f .tmp_System.map
157169
rm -f .tmp_kallsyms*
158170
rm -f .tmp_vmlinux*
@@ -215,6 +227,13 @@ ${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o
215227
info MODINFO modules.builtin.modinfo
216228
${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo
217229

230+
btf_kernel_bin_o=""
231+
if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then
232+
if gen_btf .tmp_vmlinux.btf .btf.kernel.bin.o ; then
233+
btf_kernel_bin_o=.btf.kernel.bin.o
234+
fi
235+
fi
236+
218237
kallsymso=""
219238
kallsyms_vmlinux=""
220239
if [ -n "${CONFIG_KALLSYMS}" ]; then
@@ -246,11 +265,11 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
246265
kallsyms_vmlinux=.tmp_vmlinux2
247266

248267
# step 1
249-
vmlinux_link "" .tmp_vmlinux1
268+
vmlinux_link .tmp_vmlinux1 ${btf_kernel_bin_o}
250269
kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o
251270

252271
# step 2
253-
vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2
272+
vmlinux_link .tmp_vmlinux2 .tmp_kallsyms1.o ${btf_kernel_bin_o}
254273
kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o
255274

256275
# step 3
@@ -261,18 +280,13 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
261280
kallsymso=.tmp_kallsyms3.o
262281
kallsyms_vmlinux=.tmp_vmlinux3
263282

264-
vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3
265-
283+
vmlinux_link .tmp_vmlinux3 .tmp_kallsyms2.o ${btf_kernel_bin_o}
266284
kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o
267285
fi
268286
fi
269287

270288
info LD vmlinux
271-
vmlinux_link "${kallsymso}" vmlinux
272-
273-
if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then
274-
gen_btf vmlinux
275-
fi
289+
vmlinux_link vmlinux "${kallsymso}" "${btf_kernel_bin_o}"
276290

277291
if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then
278292
info SORTEX vmlinux

0 commit comments

Comments
 (0)