1. Tracepoints 与 Kprobes 的区别
tracepoints
和 kprobes
都是 Linux 内核提供的动态追踪机制,用于性能分析和调试。但它们有不同的设计理念和使用场景:
1.1 Tracepoints
适用场景:稳定性高,适用于长期维护的分析工具,如 eBPF、perf
采样、bpftrace
等。
✅ 官方提供的接口
-
tracepoints
由内核 显式 添加,代码中通常带有TRACE_EVENT()
宏。 -
这些点是 稳定 API,不会随内核版本轻易更改。
✅ 性能较优
-
由于是 静态探测点,在编译时已经优化,性能损耗低。
-
适用于高频事件(如
syscalls
、scheduler
调度等)。
✅ 使用方式
-
tracepoint
可以直接通过/sys/kernel/debug/tracing/events/
查询:ls /sys/kernel/debug/tracing/events/syscalls/
-
bpftrace
追踪rename
:sudo bpftrace -e 'tracepoint:syscalls:sys_enter_rename { printf("rename detected\n"); }'
✅ 示例代码(使用 ``):
TRACEPOINT_PROBE(syscalls, sys_enter_rename) {
bpf_trace_printk("File rename detected: %s -> %s\n", args->oldpath, args->newpath);
return 0;
}
💡 适用场景:
-
系统调用跟踪(
syscalls
、block
、net
、sched
等)。 -
稳定的 API,适用于生产环境。
-
性能影响较低,适合长期运行。
1.2 Kprobes
适用场景:适用于深入分析和调试,灵活性强,但可能影响系统稳定性。
✅ 动态挂载
-
kprobes
可以挂载到任意内核函数,不需要提前定义探测点。 -
适用于 调试私有/未公开的内核函数,如
do_renameat2
。
✅ 不稳定
-
kprobes
依赖 内核符号表,如果 内核更新,可能导致探测点失效或变化。 -
生产环境慎用,可能影响系统稳定性。
✅ 使用方式
-
列出可用
kprobes
:cat /sys/kernel/debug/tracing/available_filter_functions | grep rename
-
bpftrace
追踪rename
:sudo bpftrace -e 'kprobe:sys_rename { printf("rename called\n"); }'
✅ 示例代码(使用 ``):
int trace_rename(struct pt_regs *ctx) {
bpf_trace_printk("sys_rename called!\n");
return 0;
}
💡 适用场景:
-
深入分析 内核函数(
do_renameat2
等)。 -
调试私有/不公开的内核函数。
-
用于开发调试,不建议长期运行,可能影响稳定性。
2. 主要区别总结
特性 |
Tracepoints |
Kprobes |
---|---|---|
接口类型 |
静态(官方提供) |
动态(用户自定义) |
稳定性 |
高(不会随内核版本变化) |
低(内核升级后可能失效) |
性能 |
低开销(优化过的探测点) |
可能较高(影响稳定性) |
使用场景 |
系统调用、网络、调度、I/O |
深入分析、调试私有内核函数 |
生产环境 |
可以长期使用 |
慎用,可能影响系统 |
示例 |
|
|
3. 解决 错误
如果遇到错误:
Exception: Failed to attach BPF program b'trace_rename' to kprobe b'sys_rename'
说明 sys_rename
不存在或不可用,可能是被 sys_renameat
或 sys_renameat2
取代。
3.1 检查可用相关函数
执行:
cat /sys/kernel/debug/tracing/available_filter_functions | grep rename
如果 sys_rename
不存在,请改用 sys_renameat
或 sys_renameat2
。
3.2 自动适配可用系统调用
from bcc import BPF
bpf_text = """
int trace_rename(struct pt_regs *ctx) {
bpf_trace_printk("rename syscall triggered!\n");
return 0;
}
"""
bpf = BPF(text=bpf_text)
#
适配不同的
`rename`
相关系统调用
for syscall in ["sys_rename", "sys_renameat", "sys_renameat2"]:
fnname = bpf.get_syscall_fnname(syscall)
if fnname:
print(f"Attaching to {fnname}...")
bpf.attach_kprobe(event=fnname, fn_name="trace_rename")
bpf.trace_print()
3.3 使用
from bcc import BPF
bpf_text = """
TRACEPOINT_PROBE(syscalls, sys_enter_rename) {
bpf_trace_printk("File rename detected!\n");
return 0;
}
"""
bpf = BPF(text=bpf_text)
bpf.trace_print()
4. 结论
-
优先使用 tracepoints(如果可用)。
-
如果 tracepoints 不存在,使用Kprobes
自动匹配
。 -
长期监控用 tracepoints,调试用 kprobes。