Skip to content

Commit 6ff0a99

Browse files
alan-maguireKernel Patches Daemon
authored andcommitted
kbuild, module, bpf: Support CONFIG_DEBUG_INFO_BTF_EXTRA=m
Allow module-based delivery of potentially large vmlinux .BTF.extra section; section; also support visibility of BTF data in kernel, modules in /sys/kernel/btf_extra. Signed-off-by: Alan Maguire <[email protected]>
1 parent 74f9928 commit 6ff0a99

File tree

12 files changed

+154
-34
lines changed

12 files changed

+154
-34
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ struct inode;
6363
extern struct idr btf_idr;
6464
extern spinlock_t btf_idr_lock;
6565
extern struct kobject *btf_kobj;
66+
extern struct kobject *btf_extra_kobj;
6667
extern struct bpf_mem_alloc bpf_global_ma, bpf_global_percpu_ma;
6768
extern bool bpf_global_ma_set;
6869

include/linux/btf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,8 @@ int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_ty
621621
bool btf_types_are_same(const struct btf *btf1, u32 id1,
622622
const struct btf *btf2, u32 id2);
623623
int btf_check_iter_arg(struct btf *btf, const struct btf_type *func, int arg_idx);
624+
struct bin_attribute *sysfs_btf_add(struct kobject *kobj, const char *name,
625+
void *data, size_t data_size);
624626

625627
static inline bool btf_type_is_struct_ptr(struct btf *btf, const struct btf_type *t)
626628
{

include/linux/module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,10 @@ struct module {
512512
unsigned int btf_base_data_size;
513513
void *btf_data;
514514
void *btf_base_data;
515+
#if IS_ENABLED(CONFIG_DEBUG_INFO_BTF_EXTRA)
516+
unsigned int btf_extra_data_size;
517+
void *btf_extra_data;
518+
#endif
515519
#endif
516520
#ifdef CONFIG_JUMP_LABEL
517521
struct jump_entry *jump_entries;

kernel/bpf/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ obj-$(CONFIG_BPF_SYSCALL) += reuseport_array.o
3838
endif
3939
ifeq ($(CONFIG_SYSFS),y)
4040
obj-$(CONFIG_DEBUG_INFO_BTF) += sysfs_btf.o
41+
obj-$(CONFIG_DEBUG_INFO_BTF_EXTRA) += btf_extra.o
4142
endif
4243
ifeq ($(CONFIG_BPF_JIT),y)
4344
obj-$(CONFIG_BPF_SYSCALL) += bpf_struct_ops.o

kernel/bpf/btf.c

Lines changed: 83 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8323,12 +8323,42 @@ enum {
83238323
BTF_MODULE_F_LIVE = (1 << 0),
83248324
};
83258325

8326+
#if IS_ENABLED(CONFIG_SYSFS)
8327+
struct bin_attribute *sysfs_btf_add(struct kobject *kobj, const char *name,
8328+
void *data, size_t data_size)
8329+
{
8330+
struct bin_attribute *attr = kzalloc(sizeof(*attr), GFP_KERNEL);
8331+
int err;
8332+
8333+
if (!attr)
8334+
return ERR_PTR(-ENOMEM);
8335+
8336+
sysfs_bin_attr_init(attr);
8337+
attr->attr.name = name;
8338+
attr->attr.mode = 0444;
8339+
attr->size = data_size;
8340+
attr->private = data;
8341+
attr->read = sysfs_bin_attr_simple_read;
8342+
8343+
err = sysfs_create_bin_file(kobj, attr);
8344+
if (err) {
8345+
pr_warn("failed to register module [%s] BTF in sysfs : %d\n", name, err);
8346+
kfree(attr);
8347+
return ERR_PTR(err);
8348+
}
8349+
return attr;
8350+
}
8351+
8352+
#endif
8353+
83268354
#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
83278355
struct btf_module {
83288356
struct list_head list;
83298357
struct module *module;
83308358
struct btf *btf;
83318359
struct bin_attribute *sysfs_attr;
8360+
void *btf_extra_data;
8361+
struct bin_attribute *sysfs_extra_attr;
83328362
int flags;
83338363
};
83348364

@@ -8342,12 +8372,12 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
83428372
{
83438373
struct btf_module *btf_mod, *tmp;
83448374
struct module *mod = module;
8345-
struct btf *btf;
8375+
struct bin_attribute *attr;
8376+
struct btf *btf = NULL;
83468377
int err = 0;
83478378

8348-
if (mod->btf_data_size == 0 ||
8349-
(op != MODULE_STATE_COMING && op != MODULE_STATE_LIVE &&
8350-
op != MODULE_STATE_GOING))
8379+
if (op != MODULE_STATE_COMING && op != MODULE_STATE_LIVE &&
8380+
op != MODULE_STATE_GOING)
83518381
goto out;
83528382

83538383
switch (op) {
@@ -8357,8 +8387,10 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
83578387
err = -ENOMEM;
83588388
goto out;
83598389
}
8360-
btf = btf_parse_module(mod->name, mod->btf_data, mod->btf_data_size,
8361-
mod->btf_base_data, mod->btf_base_data_size);
8390+
if (mod->btf_data_size > 0) {
8391+
btf = btf_parse_module(mod->name, mod->btf_data, mod->btf_data_size,
8392+
mod->btf_base_data, mod->btf_base_data_size);
8393+
}
83628394
if (IS_ERR(btf)) {
83638395
kfree(btf_mod);
83648396
if (!IS_ENABLED(CONFIG_MODULE_ALLOW_BTF_MISMATCH)) {
@@ -8370,7 +8402,8 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
83708402
}
83718403
goto out;
83728404
}
8373-
err = btf_alloc_id(btf);
8405+
if (btf)
8406+
err = btf_alloc_id(btf);
83748407
if (err) {
83758408
btf_free(btf);
83768409
kfree(btf_mod);
@@ -8384,32 +8417,45 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
83848417
list_add(&btf_mod->list, &btf_modules);
83858418
mutex_unlock(&btf_module_mutex);
83868419

8387-
if (IS_ENABLED(CONFIG_SYSFS)) {
8388-
struct bin_attribute *attr;
8389-
8390-
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
8391-
if (!attr)
8392-
goto out;
8393-
8394-
sysfs_bin_attr_init(attr);
8395-
attr->attr.name = btf->name;
8396-
attr->attr.mode = 0444;
8397-
attr->size = btf->data_size;
8398-
attr->private = btf->data;
8399-
attr->read = sysfs_bin_attr_simple_read;
8400-
8401-
err = sysfs_create_bin_file(btf_kobj, attr);
8402-
if (err) {
8403-
pr_warn("failed to register module [%s] BTF in sysfs: %d\n",
8404-
mod->name, err);
8405-
kfree(attr);
8406-
err = 0;
8420+
if (IS_ENABLED(CONFIG_SYSFS) && btf) {
8421+
attr = sysfs_btf_add(btf_kobj, btf->name, btf->data, btf->data_size);
8422+
if (IS_ERR(attr)) {
8423+
err = PTR_ERR(attr);
84078424
goto out;
84088425
}
8409-
84108426
btf_mod->sysfs_attr = attr;
84118427
}
8428+
#if IS_ENABLED(CONFIG_DEBUG_INFO_BTF_EXTRA)
8429+
if (mod->btf_extra_data_size > 0) {
8430+
const char *name = mod->name;
8431+
void *data;
84128432

8433+
/* vmlinux .BTF.extra is SHF_ALLOC; other modules
8434+
* are not, so for them we need to kvmemdup() the data.
8435+
*/
8436+
if (strcmp(mod->name, "btf_extra") == 0) {
8437+
name = "vmlinux";
8438+
data = mod->btf_extra_data;
8439+
} else {
8440+
data = kvmemdup(mod->btf_extra_data, mod->btf_extra_data_size,
8441+
GFP_KERNEL | __GFP_NOWARN);
8442+
if (!data) {
8443+
err = -ENOMEM;
8444+
goto out;
8445+
}
8446+
btf_mod->btf_extra_data = data;
8447+
}
8448+
attr = sysfs_btf_add(btf_extra_kobj, name, data,
8449+
mod->btf_extra_data_size);
8450+
if (IS_ERR(attr)) {
8451+
err = PTR_ERR(attr);
8452+
kfree(btf_mod->sysfs_attr);
8453+
kvfree(btf_mod->btf_extra_data);
8454+
goto out;
8455+
}
8456+
btf_mod->sysfs_extra_attr = attr;
8457+
}
8458+
#endif
84138459
break;
84148460
case MODULE_STATE_LIVE:
84158461
mutex_lock(&btf_module_mutex);
@@ -8431,9 +8477,15 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
84318477
list_del(&btf_mod->list);
84328478
if (btf_mod->sysfs_attr)
84338479
sysfs_remove_bin_file(btf_kobj, btf_mod->sysfs_attr);
8434-
purge_cand_cache(btf_mod->btf);
8435-
btf_put(btf_mod->btf);
8436-
kfree(btf_mod->sysfs_attr);
8480+
if (btf_mod->btf_extra_data)
8481+
kvfree(btf_mod->btf_extra_data);
8482+
if (btf_mod->sysfs_extra_attr)
8483+
sysfs_remove_bin_file(btf_extra_kobj, btf_mod->sysfs_extra_attr);
8484+
if (btf_mod->btf) {
8485+
purge_cand_cache(btf_mod->btf);
8486+
btf_put(btf_mod->btf);
8487+
kfree(btf_mod->sysfs_attr);
8488+
}
84378489
kfree(btf_mod);
84388490
break;
84398491
}

kernel/bpf/btf_extra.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025, Oracle and/or its affiliates. */
3+
/*
4+
* Provide extra kernel BTF information for use by BPF tools.
5+
*
6+
* Can be built as a module to support cases where vmlinux .BTF.extra
7+
* section size in the vmlinux image is too much.
8+
*/
9+
#include <linux/kernel.h>
10+
#include <linux/module.h>
11+
#include <linux/init.h>
12+
13+
static int __init btf_extra_init(void)
14+
{
15+
return 0;
16+
}
17+
subsys_initcall(btf_extra_init);
18+
19+
static void __exit btf_extra_exit(void)
20+
{
21+
}
22+
module_exit(btf_extra_exit);
23+
24+
MODULE_DESCRIPTION("Extra BTF information");
25+
MODULE_LICENSE("GPL v2");

kernel/bpf/sysfs_btf.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,15 @@ static struct bin_attribute bin_attr_btf_vmlinux __ro_after_init = {
4949
.mmap = btf_sysfs_vmlinux_mmap,
5050
};
5151

52-
struct kobject *btf_kobj;
52+
struct kobject *btf_kobj, *btf_extra_kobj;
53+
54+
#if IS_BUILTIN(CONFIG_DEBUG_INFO_BTF_EXTRA)
55+
/* See scripts/link-vmlinux.sh, gen_btf() func for details */
56+
extern char __start_BTF_extra[];
57+
extern char __stop_BTF_extra[];
58+
59+
struct bin_attribute *extra_attr;
60+
#endif
5361

5462
static int __init btf_vmlinux_init(void)
5563
{
@@ -62,6 +70,17 @@ static int __init btf_vmlinux_init(void)
6270
btf_kobj = kobject_create_and_add("btf", kernel_kobj);
6371
if (!btf_kobj)
6472
return -ENOMEM;
73+
if (IS_ENABLED(CONFIG_DEBUG_INFO_BTF_EXTRA)) {
74+
btf_extra_kobj = kobject_create_and_add("btf_extra", kernel_kobj);
75+
if (!btf_extra_kobj)
76+
return -ENOMEM;
77+
#if IS_BUILTIN(CONFIG_DEBUG_INFO_BTF_EXTRA)
78+
extra_attr = sysfs_btf_add(btf_extra_kobj, "vmlinux", __start_BTF_extra,
79+
__stop_BTF_extra - __start_BTF_extra);
80+
if (IS_ERR(extra_attr))
81+
return PTR_ERR(extra_attr);
82+
#endif
83+
}
6584

6685
return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_vmlinux);
6786
}

kernel/module/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
26482648
mod->btf_base_data = any_section_objs(info, ".BTF.base", 1,
26492649
&mod->btf_base_data_size);
26502650
#endif
2651+
#if IS_ENABLED(CONFIG_DEBUG_INFO_BTF_EXTRA)
2652+
mod->btf_extra_data = any_section_objs(info, ".BTF.extra", 1,
2653+
&mod->btf_extra_data_size);
2654+
#endif
26512655
#ifdef CONFIG_JUMP_LABEL
26522656
mod->jump_entries = section_objs(info, "__jump_table",
26532657
sizeof(*mod->jump_entries),

lib/Kconfig.debug

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ config MODULE_ALLOW_BTF_MISMATCH
434434
it when a mismatch is found.
435435

436436
config DEBUG_INFO_BTF_EXTRA
437-
bool "Provide extra information about inline sites in BTF"
437+
tristate "Provide extra information about inline sites in BTF"
438438
default n
439439
depends on DEBUG_INFO_BTF && PAHOLE_HAS_INLINE
440440
help

scripts/Makefile.btf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module-pahole-flags-$(call test-ge, $(pahole-ver), 128) += --btf_features=distil
3232
else
3333
ifneq ($(CONFIG_DEBUG_INFO_BTF_EXTRA),)
3434
pahole-flags-$(call test-ge, $(pahole-ver), 130) += --btf_features=inline.extra
35-
btf-extra := y
35+
btf-extra := $(CONFIG_DEBUG_INFO_BTF_EXTRA)
3636
endif
3737
endif
3838

@@ -43,3 +43,4 @@ pahole-flags-$(CONFIG_PAHOLE_HAS_LANG_EXCLUDE) += --lang_exclude=rust
4343
export PAHOLE_FLAGS := $(pahole-flags-y)
4444
export MODULE_PAHOLE_FLAGS := $(module-pahole-flags-y)
4545
export BTF_EXTRA := $(btf-extra)
46+
export VMLINUX_BTF_EXTRA := .tmp_vmlinux_btf_extra

0 commit comments

Comments
 (0)