内联函数的调试信息
摘要
Alan Maguire 在 Linux 存储、文件系统、内存管理和 BPF 峰会上主持了一场会议,提议对 BTF 进行扩展,以存储有关内联函数的信息,从而通过 kprobes 实现对这类函数的内核跟踪。
暂无内容
查看缓存全文
缓存时间: 2026/08/12 23:23
# 内联函数的调试信息
来源:https://lwn.net/Articles/1083985/
> **您知道吗……?**LWN.net 是一家由订阅者支持的出版物;我们依靠订阅者来维持整个运营。请通过购买订阅(https://lwn.net/Promo/nst-nag4/subscribe)来帮助 LWN 继续运行。
BPF 程序使用 BPF 类型格式 (https://docs.kernel.org/bpf/btf.html)(BTF) 调试信息来确定如何与内核中的函数交互。具体来说,跟踪一个内核函数需要在内核的 BTF 段中找到其地址——但对于已被内联、因此没有单一特定地址的函数,这并不奏效。Alan Maguire 希望向 BTF 添加内联函数的相关信息,以便能够跟踪它们,并在 2026 Linux Storage, Filesystem, Memory-Management, and BPF Summit (https://events.linuxfoundation.org/lsfmmbpf/) 上主持了一场关于该主题的会议。
Maguire 表示,内核中有超过 100,000 个内联函数,分布在五倍于该数量的调用点上。更糟糕的是,其中一些是部分内联:在某些地方被正常调用,在其他地方被内联。这可能导致当前出现这样的情况:某个函数看似跟踪成功,但实际上有些调用并未被观察到。
好消息是,跟踪内联函数的其余基础设施已经就绪,可用于 kprobes (https://docs.kernel.org/trace/kprobes.html),kprobes 可以附加到任意位置。Maguire 表示,问题仅在于将有关函数在何处被内联的数据转换成可用格式。“故事实际上已经相当完整了。”
那么,将这一信息存储在 BTF 中需要什么呢?DWARF 调试格式 (https://dwarfstd.org/) 已有办法表示内联信息,但 DWARF 使用起来也比较困难,并且没有一种简单方式来表示常见情况。Maguire 说,BTF 的解决方案应当紧凑,并允许去重,以保持较低的内存开销。理想情况下,内联信息可以存储在内核二进制文件的一个单独段中,甚至可以作为独立的内核模块分发,这样在需要之前不会被加载。
具体而言,Maguire 提议向 BTF 添加三类新信息。第一类是内联点特有的(inline-site-specific)信息,说明每个调用点内联了哪个函数,以及如果该函数未被内联将如何被调用,这部分称为“位置段”(location section)。这些数据不容易去重,因为它特定于某个调用点,因此信息应尽可能由指向可去重数据的指针组成。
他想添加的第二和第三类信息是指向的数据:“位置原型”(location prototype)和“位置参数”(location parameter)。位置原型指定内联函数的参数在调用点如何表示,表现为一个指向位置参数的指针列表,每个位置参数存储如何访问单个函数参数。理论上,编译器可能会为每个内联调用点(共 538,090 个)将给定的函数参数存储在不同位置;实际上,编译器转换参数的方式是有限的,许多函数拥有兼容的函数签名,导致编译器做出相同的选择。在当前内核中,对位置原型进行去重后,仅剩 57,141 个不同的条目,总共只引用了 17,535 个位置参数条目。
这意味着位置段占据了新增数据的大部分。总体而言,Maguire 提议的 BTF 新增内容大约会增加 11MB 数据,或者说每个内联调用点约 21 字节。如果提取到独立的内核模块中并压缩,总数据量将降至 3.5MB。
然后 Maguire 以一个示例说明了关于某个特定函数的信息将如何存储。考虑以下函数:
```
int foo(int a, void *b, bool c);
```
如果编译器选择内联 `foo()` 的方式是:省略未使用的 `a`,将 `b` 提升为通过寄存器传递,并确定 `c` 是一个常量,那么 BTF 表示将是一个单独的位置段条目,存储 `foo()` 的 B
相似文章
调试BPF中基于类型的别名分析优化
文章描述了如何将BPF程序切换到使用BTF生成的vmlinux.h,由于Clang的基于类型的别名分析优化,导致IP校验和不正确,并通过汇编检查详细说明了调试过程。
Linux/x86-64上使用内存间接调用(徒劳?)的系统调用检测,第一部分
一篇技术博文,讨论在Linux/x86-64上检测系统调用的技术,包括指令双关、E9Patch、zpoline以及短指令修补的挑战。
字节码虚拟机在意外场景中的应用 (2024)
本文探讨了字节码虚拟机的出人意料的应用,特别是Linux内核中的eBPF以及编译后二进制文件中用于调试信息的DWARF表达式。
GCC 16及以后版本中的BPF支持
何塞·马奇西(José Marchesi)和GCC-BPF团队提供了GCC 16中BPF支持的更新,突出了在与LLVM功能对等方面取得的进展,以及内核BPF自测通过率的提升。
如何对eBPF代码进行性能分析?
本文演示了如何通过创建一个简单的C测试框架来衡量文件打开延迟,从而对eBPF代码性能进行分析,使开发者能够比较附加eBPF钩子前后的开销。