自定义kfunc加载BPF程序失败:找不到foo_bar的BTF符号
问题分析与修复方案
报错原因
libbpf: failed to find BTF for extern 'foo_bar': -3 报错源于两个核心问题:
- BPF程序未标记kfunc引用:默认情况下libbpf会将
extern符号视为普通内核符号,仅在vmlinux的BTF中查找,不会识别为自定义kfunc。 - kfunc注册的程序类型不匹配:你的BPF程序是
uretprobe(属于BPF_PROG_TYPE_UPROBE类型),但内核模块中却将kfunc注册给了BPF_PROG_TYPE_KPROBE类型,导致UPROBE程序无法访问该kfunc。
修复步骤
1. 修改BPF程序(foo_bpf.c)
在extern声明中添加__attribute__((btf_decl_tag("bpf_kfunc"))),明确标记这是一个kfunc,让libbpf知道要从kfunc集合中查找:
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> #include <asm/ptrace.h> // 添加btf_decl_tag标记,指定为kfunc extern int foo_bar(struct pt_regs *regs) __attribute__((btf_decl_tag("bpf_kfunc"))); SEC("uretprobe//tmp/app:foo") int foo_bar_call(struct pt_regs *ctx) { foo_bar(ctx); return 0; } char _license[] SEC("license") = "GPL";
2. 修改内核模块(kfoo.c)
将register_btf_kfunc_id_set的第一个参数改为BPF_PROG_TYPE_UPROBE,与你的uretprobe程序类型匹配:
static int __init kfoo_init(void) { int ret; // 替换为BPF_PROG_TYPE_UPROBE,对应uretprobe程序类型 ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UPROBE, &foo_bar_set); pr_err("%s: %d\n", __func__, ret); return ret; }
3. 重新编译加载
执行以下命令完成重新编译与加载:
# 清理并重新编译内核模块 make clean && make # 卸载旧模块(若已加载) sudo rmmod kfoo # 加载新模块 sudo insmod kfoo.ko # 重新编译BPF程序 clang -Wall -Werror -O2 -target bpf -c foo_bpf.c -o foo_bpf.o # 加载BPF程序 sudo bpftool prog load foo_bpf.o /sys/fs/bpf/foo_bpf autoattach
验证
加载成功后,运行/tmp/app触发uretprobe,通过dmesg或journalctl -k查看内核日志,应该能看到foo_bar的打印信息。
内容的提问来源于stack exchange,提问作者Sławek
相关产品推荐
相关产品推荐

