首页
社区
课程
招聘
systemtap追踪自己开发的内核模块
发表于: 2023-12-29 17:13 11806

systemtap追踪自己开发的内核模块

2023-12-29 17:13
11806

    看了动态追踪技术漫谈这篇文章之后,就想着拿systemtap追踪一下自己开发的内核模块,然而,systemtap官方文档,对如何追踪内核模块的描述中,只是拿内核源码树中的驱动举例,比如:probe module("ext3").function("*") { },实际验证确实也很顺利(我的系统使用的是xfs文件驱动,stap命令执行后,随便vi一个文件,就能看到xfs_iread()函数被调用了,并列出了参数信息)

    

    然后,我写了一个最简单的驱动,test.c:

    Makefile:

    以及x.stap:

    接下来,编译test.c->加载test.ko->执行x.stap(此刻,我还在一个思维陷阱里,以为加载驱动,是stap追踪该驱动的前提)

    

    我一开始认为,驱动都已经加载了,stap却还不认识,那问题应该出在test.ko的编译上,为了解决这个问题,兜兜绕绕了一大圈。

    首先是百度、google了一遍,看了前几页的回答,都是说要安装内核debuginfo,不过我的系统,正好之前已经安装过内核debuginfo,而且我要追踪的是自己开发的驱动,按道理也不需要依赖内核debuginfo。

     

    然后到一些微信群里询问也无果,可能大佬都很忙,没空理我。

    最后只能自己再翻翻官方文档,开始各种推测与尝试。

    记忆中,之前看过一款动态追踪工具的原理,提到在编译被追踪程序时,gcc必须添加-pg编译选项,这会使gcc在每个函数入口,添加5条nop指令,从而预留5个字节,可以在动态追踪时,替换成"call mcount"的机器码,才能使在追踪点注入的代码有机会执行。想到这,就在Makefile里加了一行:

    结果,问题仍然存在,再回过头搜一下资料,得知ftrace才依赖-pg编译选项,systemtap底层依赖的是kprobe,它可以追踪任何地址处的指令,原理是将追踪地址的第一个字节,替换成0xCC(即"int 3"指令),利用中断机制实现的。

    那么,和xfs驱动相比,除了是否已加载和编译选项之外,还有什么区别?

    官方文档中的这么一句话,虽然只是阐述了一个客观情况,并没有表达,.ko文件一定要放在/lib/modules/$(uname -r)/目录,才能被追踪的意思,但是test.ko和xfs驱动相比,目前能想的的区别,也就这个了,所以就侥幸的试了一下,竟然成功了:

    

    并且,额外的惊喜是,"stat x.stp"的执行,并不依赖先"insmod test.ko",也就是说,test_init()函数,也可以被追踪。不过想想也是,如果连内核模块加载函数都追踪不了,那systemtap还号称什么"利器"。

    本来以为,接下来就可以尽情的畅游了。

    然而,通过"insmod test.ko"和"rmmod test"分别触发test_init()和test_exit()执行,发现stap的打印内容是这样:

    

    其中,0xffffffffc037f000是test_init()函数的加载地址,0xffffffffc0876000是test_exit()函数的加载地址,这可以在test.ko卸载之前,通过以下3种方式证实:

    ① 查看test.ko节区的加载地址

        

    ② 查看内核符号表中,属于test驱动的符号及其加载地址(不清楚为什么没看到"test_init")

        

    ③ 查看这两个内存地址的内容,与test_init()/test_exit()函数反汇编的机器码对比(这种方式要求系统安装了内核debuginfo)

        test_exit()函数机器码:

        

        内存查看:

        

    确认打印内容中,"->"之后是被追踪函数的地址之后,还存在另外3个疑问:

    1. stap打印的为什么是函数地址,而不是函数名称?

        这个可以通过将x.stp脚本中的probefunc(),替换成ppfunc()解决,同时也能避免以下问题3中的现象:

        

    2. test_init()和test_exit()函数都可以追踪了,test()函数为什么没被追踪到?

        第4节专门介绍。

    3. "<-"与"->"后面的地址不同,又代表什么地址?

        解决问题2后,让函数多调用几层,就能看出,"->"后面是callee函数地址,"<-"后面是caller函数地址。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 6
支持
分享
最新回复 (3)
雪    币: 3573
活跃值: (31026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-1-2 10:12
1
雪    币: 2445
活跃值: (5519)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2024-1-3 11:59
0
雪    币: 8401
活跃值: (4976)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
systemtap能否支持追踪andorid内核调试呢
2024-1-10 00:27
0
游客
登录 | 注册 方可回帖
返回
//