最近学习bcc-tools工具的使用,发现单单会使用还是不行,必须了解到其深层次的原理,所以使用该工具的时候,加了-v指令,分析了下bcc的调用流程,大致如下:
^CTraceback (most recent call last):
File "./funclatency", line 211, in <module>
b.attach_kretprobe(event_re=pattern, fn_name="trace_func_return")
File "/usr/lib/python2.7/site-packages/bcc/__init__.py", line 645, in attach_kretprobe
for line in BPF.get_kprobe_functions(event_re):
File "/usr/lib/python2.7/site-packages/bcc/__init__.py", line 525, in get_kprobe_functions
(t, fn) = line.rstrip().split()[1:3]
从内容来看,采用的kprobe探测功能实现,下面就简短介绍下kprobe的实现原理,后面到bcc熟悉的差不多后再结合bcc相关代码讲其是怎么通过kprobe实现的。
kprobe作为轻量级内核调试工具,在诊断内核bug时有着先天独厚的优势,相关其他工具,kprobe有如下优点:
1、不用更新内核
2、可以以模块的形式加载进内核,用完后直接卸载即可,不会对内核造成污染
3、动态跟踪,自由构造,灵巧轻便。
kprobe实现原理:
原汁原味可以查看kernel doc:Documentation/kprobes.txt建议在分析其原理时,一定要看下,此外还可以参考 samples/kprobes编写kprobe探测驱动。
kprobe实现原理还是容易理解的,在调用跟踪函数前,插入kprobe指令至此执行pre_handler,例如通过软中断方式,进入单步调试,此时执行原先代码本该执行的指令,执行完成后返回会再次进入kprobe状态,执行post_handler,执行完成后再次从异常状态返回到代码顺序执行。从上面描述可知kprobe的实现机制其实就是在被探测的函数前后打点,执行到该点时,进入异常状态,使的程序暂停执行,去执行kprobe相关处理函数,执行完成后又再次从异常状态恢复到正常执行,此过程执行主要涉及到对EIP/SIP等相关寄存器的操作。
kprobe实现步骤:
- 注册kprobe:register_kprobe,此处关键是需要实现如下三个函数:pre_handler、post_handler和fault_handler
- 初始化kprobe:init_kprobe,和驱动的编写一样,实例化结构体,调用内核函数初始化
- 实现中断处理函数:跟踪一个函数的目的是什么。
如何让内核支持kprobe
- CONFIG_KPROBES
- CONFIG_MODULES:kprobe是按照驱动的形式加入进入内核的,所以支持驱动加载和卸载时最基本的
- CONFIG_MODULE_UNLOAD
- CONFIG_KALLSYMS:设置CONFIG_KALLSYMS_ALL为y将更好,此处主要让kprobe可以跟踪的内核函数kprobe。