1. 背景与适用场景
在 openEuler 22.03 LTS SP4(基于 Linux 5.10 内核)环境中,系统默认开启了 CONFIG_DEBUG_INFO_BTF,因此 /sys/kernel/btf/vmlinux 是存在的。然而,该版本内核并未开启模块级 BTF 支持(即缺少 CONFIG_DEBUG_INFO_BTF_MODULES),导致部分独立的内核模块(如 ceph.ko)内部不包含 .BTF ELF 段。
在使用 eBPF 工具(如 gala-gopher 等)时,如果底层依赖的 libbpf 库强制要求从模块中提取 BTF 信息,就会抛出 failed to find '.BTF' ELF section 错误。本文档介绍如何在不重新编译内核的前提下,利用现有的调试符号提取全内核 BTF 信息,生成独立的 .btf 文件供外部工具使用。
2. 前置准备
生成和解析 BTF 文件强依赖于 dwarves(包含 pahole)、llvm 以及当前运行内核对应的 debuginfo 包。
2.1 安装基础工具链
bash
sudo yum install -y dwarves llvm elfutils-libelf-devel bpftool
2.2 下载并安装 Debuginfo 包
完整的 BTF 转换需要读取未压缩的内核调试符号(vmlinux)。通过 debuginfo-install 自动匹配并安装当前内核版本的调试包:
bash
# 获取当前内核版本并安装对应的 debuginfo
sudo debuginfo-install kernel-$(uname -r)
注:安装完成后,vmlinux 文件通常位于 /usr/lib/debug/lib/modules/$(uname -r)/vmlinux。
3. 提取并生成独立 .btf 文件
此步骤将从带有 DWARF 调试信息的 vmlinux 中生成 BTF 数据,并将其剥离为纯 BTF 格式的 ELF 文件。
bash
# 1. 定义环境变量
VMLINUX_PATH="/usr/lib/debug/lib/modules/$(uname -r)/vmlinux"
OUTPUT_BTF="/tmp/$(uname -r).btf"
# 2. 检查 vmlinux 是否存在
if [ ! -f "$VMLINUX_PATH" ]; then
echo " 错误: 未找到 $VMLINUX_PATH,请确认 debuginfo 已正确安装"; exit 1;
fi
# 3. 使用 pahole 将 DWARF 转换为 BTF 格式并注入到 vmlinux 中
pahole -J $VMLINUX_PATH
# 4. 使用 llvm-objcopy 仅保留 .BTF 段,清理其他冗余符号
llvm-objcopy --only-section=.BTF --set-section-flags .BTF=alloc,readonly --strip-all $VMLINUX_PATH $OUTPUT_BTF
# 5. 进一步去除多余的字符串表等信息,精简文件体积
strip -x $OUTPUT_BTF
echo " 成功生成独立 BTF 文件: $OUTPUT_BTF"
4. 验证生成的 BTF 文件完整性
为确保生成的 .btf 文件能够被 libbpf 正常加载,需进行以下三个层级的验证:
4.1 基础文件格式检查
确认文件非空且符合 ELF 规范:
bash
ls -lh $OUTPUT_BTF
file $OUTPUT_BTF
预期输出 :文件大小通常在数 MB 级别;file 命令应返回 ELF 64-bit LSB relocatable...。
4.2 内容解析验证(最重要)
使用官方 BPF 工具 bpftool 尝试将二进制 BTF 反序列化为 C 语言结构体定义。这是判断 BTF 是否损坏或有效最直接的标准:
bash
sudo bpftool btf dump file $OUTPUT_BTF format c | head -n 20
预期输出 :终端正常打印出类似 struct task_struct { ... } 或 struct inode { ... } 的内核数据结构代码。只要无报错且能输出结构体,即代表文件完全可用。
4.3 与系统原生 BTF 交叉比对(可选)
将生成的独立文件与运行时内核暴露的原生 BTF 进行特征对比,确保两者高度一致:
bash
# 查看原生 BTF 大小作为基准参考
ls -lh /sys/kernel/btf/vmlinux
# 验证原生 BTF 同样可被正确解析
sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c | head -n 20
5. 集成与应用
验证无误后,可将生成的 .btf 文件部署至 libbpf 默认搜索路径,或通过环境变量传递给目标应用:
方式 A:部署至全局目录
bash
sudo mkdir -p /etc/btf
sudo cp $OUTPUT_BTF /etc/btf/$(uname -r).btf
方式 B:运行时指定路径
在执行 eBPF 编译或运行脚本前,声明环境变量:
bash
export VMLINUX_BTF=/tmp/$(uname -r).btf
make clean && make