上一章我们学习了,kprobe 可以实现动态内核的注入,基于中断的方法在任意指令中插入追踪代码,并且通过 pre_handler/post_handler去接收回调。另一个 kprobe 的同族是 kretprobe,只不过是针对函数级别的内核监控,根据用户注册时提供的 entry_handler 和 ret_handler 来分别在函数进入时和返回前进行回调。
本章的我们来学习uprobe ,顾名思义,相对于内核函数/地址的监控,主要用于用户态函数/地址的监控。听起来是不是有点神奇,内核怎么监控用户态函数的调用呢?本章的内容包括:
- 如何使用uprobe
- 内核是如何通过uprobe监控用户态的调用,其原理是如何的
1 如何使用uprobe
站在用户视角,我们先看个简单的例子,假设有这么个一个用户程序:
// test.c
#include <stdio.h>
void foo() {
printf("hello, uprobe!\n");
}
int main() {
foo();
return 0;
}
编译好之后,查看某个符号的地址,然后告诉内核我要监控这个地址的调用:
#gcc test.c -o test
#readelf -s test | grep foo
56: 000000000000115a 19 FUNC GLOBAL DEFAULT 14 foo
#echo 1 > /sys/kernel/debug/tracing/events/uprobes/p_test_0x115a/enable
#echo 1 > /sys/kernel/debug/tracing/events/uprobes/p_test_0x115a/enable
#echo 1 > /sys/kernel/debug/tracing/tracing_on
然后运行用户程序并检查内核的监控返回:
$ ./test && ./test
hello, uprobe!
hello, uprobe!

对于内核如何使用uprobe,请参考内核文档uprobetracer.html,其使用基本跟kprobe类似

2 实现原理
上面的接口是基于 tracefs,即读写文件的方式去与内核交互实现 uprobe 监控。

其中写入 uprobe_events 时会经过一系列内核调用,最终会调用到create_or_delete_trace_uprobe

对于__trace_uprobe_create跟使用kprobe类似,也是大家使用的三板斧
- **alloc_trace_uprobe:**分配 uprobe 结构体

-
**register_trace_uprobe:**注册 uprobe:
-
regiseter_uprobe_event: 将 probe 添加到全局列表中,并创建对应的 uprobe debugfs 目录,即上文示例中的 p_tes

本文详细介绍了Linux内核监控技术,从kprobe的动态内核注入到kretprobe的函数级别监控,然后重点讲解了uprobe如何监控用户态函数调用。通过示例展示了如何使用uprobe监控用户程序,并探讨了其实现原理,包括内核如何通过修改指令触发软中断并在内核中执行回调。此外,还提到了uprobe_event和perf_event_open作为无需内核模块的uprobe使用方法。最后,给出了一个使用bpftrace附加到uretprobe的示例。

1655

被折叠的 条评论
为什么被折叠?



