ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

能否追踪内联函数?BTF 扩展方案待时间检验

能否追踪内联函数?BTF 扩展方案待时间检验 1. 内联函数调试难题待解BPF 程序借助 BPF 类型格式BTF调试信息确定与内核中函数的交互方式。追踪内核函数时需在内核的 BTF 段中找其地址。然而内联函数无单一特定地址此方法对其不适用。Alan Maguire 希望在 BTF 中添加内联函数信息以实现追踪并在 2026 年的 Linux 存储、文件系统、内存管理和 BPF 峰会上主持相关会议。2. 内联函数现状如何Maguire 表示内核中有超 10 万个内联函数分布在多达 5 倍数量的位置。部分函数是部分内联的这可能导致看似函数被成功追踪实则有些调用未被监测到。不过用于追踪内联函数的其他基础设施已就位可支持 kprobes它能附着在任意位置。Maguire 指出只需将函数内联位置的数据转换为可用格式“整个流程实际上已经相当完善”。3. 信息存储在 BTF 需做什么DWARF 调试格式已有表示内联信息的方法但使用困难且无简单方式表示常见情况。Maguire 认为BTF 的解决方案应紧凑并允许去重以降低内存开销。理想情况下内联信息可存储在内核二进制文件的单独段中甚至作为单独的内核模块分发按需加载。4. Maguire 提议添加哪些信息Maguire 提议在 BTF 中添加三项新信息。第一项是内联位置特定信息即“位置段”包含每个调用点内联的函数及未内联时的调用方式。因数据特定于调用点不易去重应尽量由指向可去重数据的指针组成。第二项和第三项是被指向的数据“位置原型”和“位置参数”。位置原型指定内联函数参数在调用点的表示方式以指向位置参数的指针列表呈现每个位置参数存储访问单个函数参数的方式。当前内核中对位置原型去重后只有 57,141 个不同条目仅引用 17,535 个位置参数条目。总体而言Maguire 提议的扩展将增加约 11MB 数据即每个内联调用点约 21 字节若提取到单独内核模块并压缩数据总量降至 3.5MB。5. 特定函数信息如何存储以函数“int foo(int a, void *b, bool c);”为例若编译器以内联方式调用 foo()消除未使用的 a将 b 提升为寄存器传递确定 c 为常量BTF 表示为单独的位置段条目存储 foo() 的 BTF 类型 ID、调用点相对于内核内存基地址的偏移量以及指向位置原型条目的指针。该条目是带长度标签的数组引用位置参数条目。第一个条目为空表明 a 无法恢复第二个条目指向位置参数条目含标志表明值在寄存器中及具体寄存器编号最后一个位置参数条目有不同标志表明是常量及常量值。6. 位置段条目如何排序Alexei Starovoitov 询问位置段条目的存储顺序因为内核设置追踪时需遍历条目找正确的。起初Maguire 认为按调用点地址排序最好但考虑数据使用方式后决定按函数名排序以便追踪器通过二分查找快速找到所需信息。7. 添加内联信息有哪些先决问题Maguire 提到添加内联信息有两个先决问题。一方面位置段条目的数量需将包含结构的长度字段大小增加到 24 位。更严重的是一些现有处理 BTF 的工具无法很好处理不认识的新标签这也是 DWARF 脆弱的部分原因。为解决此问题Maguire 在内联信息中添加解析 BTF 的信息使能读取元信息的工具可正确跳过不理解的新标签。此外Maguire 还需更新 poke - a - hole (pahole) 实用工具以正确处理新型 BTF 标签的排序虽有点复杂但对正常内核构建可行。Andrii Nakryiko 询问如何处理外部模块Maguire 解释模块需弹性模块 BTF加载到运行内核中时可显式重定位其设计允许但会使构建过程稍复杂关于支持优雅处理外部模块的更改讨论未达成一致。8. 方案能否落地撰写本文时Maguire 的补丁集尚未合并。能够追踪内联和部分内联的函数显然有用但这样做是否值得付出复杂性和内存开销的代价还有待时间证明。9. 评论区观点如何有评论者认为BTF 扩展新类型信息时出现的问题类似内核开发者审视现有解决方案认为复杂后实现新方案随着用例增加又重新引入问题且所有人都需处理两种解决方案。也有评论者指出这在开源生态系统中是传统做法还有人认为这不是整个开源生态系统的传统除 Linux 内核外 DWARF 是通用的。另外关于 DWARF 是否支持描述内联函数返回值的位置表达式评论者也有不同看法。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进