eBPF Talk: bpfsnoop v0.4.0 发布
文章目录
bpfsnoop 是一款 bpf 时代的现代化内核函数、内核跟踪点和 bpf 程序的动态追踪工具。
bpfsnoop 发布 v0.4.0 版本,主要更新如下:
- 使用
kprobe动态追踪内核函数的所有指令。 - 实现了一个基于 BTF 的 C 表达式编译器。
- 为
--output-arg新增指针内容、buf()内置函数和str()内置函数。 - 复用
ringbuf传递函数参数、函数返回值和所有匹配的--output-arg。
bpfsnoop 官网:bpfsnoop.com
使用 kprobe 动态追踪内核函数的所有指令
bpfsnoop 使用 capstone-engine 来反汇编内核函数的所有指令,然后使用 kprobe 来动态追踪内核函数的所有指令。
效果如下:
|
|
P.S. BPF 程序不允许使用 kprobe 来动态追踪程序的所有指令。
实现了一个基于 BTF 的 C 表达式编译器
bpfsnoop 实现了一个基于 BTF 的 C 表达式编译器,支持使用复杂的 C 表达式来过滤和获取函数参数的属性。
效果如下:
|
|
支持以下操作符:
- Limited support for memory access via ‘.’, ‘->’, ‘array[idx]’, ‘& (get addr)’ and ‘* (access data of pointer)’.
- Bitwise and ‘&’.
- Bool and ‘&&’.
- Ternary condition ‘?:’.
- Math div ‘/’.
- Bool equal ‘==’.
- Bool greater than ‘>’.
- Bool greater than or equal ‘>=’.
- Bitwise left shift ‘«’.
- Bool less than ‘<’.
- Bool less than or equal ‘<=’.
- Unary minus ‘-’.
- Math mod ‘%’.
- Math multi ‘*’.
- Internal constants ’true’, ‘false’ and ‘NULL’.
- Variable from function’s arguments.
- Unary bool not ‘!’.
- Bool not equal ‘!=’.
- Constant number, including hex, oct, bin, decimal and char.
- Bitwise or ‘|’.
- Bool or ‘||’.
- Parentheses ‘()’.
- Unary plus ‘+’.
- Pre-decrement ‘–’.
- Pre-increment ‘++’.
- Bitwise right shift ‘»’.
- Math sub ‘-’.
- Bitwise twid ‘~’.
- Bitwise xor ‘^’.
而且,它们的优先级遵循 C 语言的优先级规则。
为 --output-arg 新增指针内容、buf() 内置函数和 str() 内置函数
使用 ringbuf 传递 --output-arg 的数据后,--output-arg 数据的大小不再有限制(理论上最大为 64MiB),因此可以输出指针内容,比如完整的结构体。
效果如下:
|
|
结构体内容的输出,复用了 eBPF Talk: 谁动了我的 bpf map? 里 mad 的功能。
与此同时,给 --output-arg 新增了 buf() 内置函数和 str() 内置函数。
buf() 内置函数
buf() 内置函数有 2 种用法:
buf(ptr, size):输出指针ptr指向的内存区域的内容,大小为size字节。buf(ptr, offset, size):输出指针ptr指向的内存区域的内容,偏移量为offset,大小为size字节。
效果如下:
|
|
str() 内置函数
str() 内置函数有 2 种用法:
str(array):输出字符串数组array的字符串。str(ptr, size):输出指针ptr指向的内存区域的字符串,大小为size字节。
效果如下:
|
|
复用 ringbuf 传递函数参数、函数返回值和所有匹配的 --output-arg
这是一次受益巨大的重构,既提升了可扩展性,又简化了代码,还少用了 5 个 bpf map。
因为 bpfsnoop 会为每个被动态追踪的对象都使用独立的 bpf prog,因而可以通过 volatile const struct config {...} 来传递函数参数、函数返回值和所有匹配的 --output-arg 等数据的字节数量;然后,根据 [event | args and retval | output args] 的格式来输出数据。
|
|
在 Go 里,按需解析事件数据:
|
|
总结
bpfsnoop v0.4.0 版本的发布,主要是为了提升可扩展性和简化代码,同时也增加了对内核函数所有指令的动态追踪、基于 BTF 的 C 表达式编译器、指针内容输出、buf() 和 str() 内置函数等功能。
bpfsnoop 是一款 bpf 时代的现代化内核函数、内核跟踪点和 bpf 程序的动态追踪工具:
- 支持输出 LBR 记录。
- 支持反汇编内核函数和 bpf prog。
- 支持输出函数调用栈。
- 支持输出带类型信息的参数和带类型的返回值。
- 支持使用复杂的 C 表达式来过滤函数参数的属性。
- 支持根据函数参数来过滤需要动态追踪的内核函数列表。
- 支持使用 pcap-filter(7) 语法来过滤网络包。
- 支持
--output-pkt输出网络包里的五元组信息。 - 支持动态追踪多达 12 个参数的内核函数。
- 支持
--output-arg来输出函数参数的属性,类似于--filter-arg。 - 支持
--output-flamegraph来输出火焰图的折叠后的数据。 - 支持
-t来动态追踪内核跟踪点。 - 在
-k里支持 ‘(i)’ 前缀来动态追踪内核函数的所有指令。 - 支持
--output-arg来输出指针内容、buf()内置函数和str()内置函数。
未来将支持更多高级功能,敬请期待!
bpfsnoop 项目地址:bpfsnoop。
文章作者 Leon Hwang
上次更新 2025-05-26