kprobe(二)

上一篇文章介绍了kprobe的使用方法,这么这一篇进一步介绍kprobe的实现机制。

概要

Kprobes可以让你动态的中断任何函数并且在此处收集debug信息和性能信息。基本大多数的内核代码地址都可以设置为断点,并且触发运行我们想要的handler。

kprobe由两部分组成,core部分需要编译到内核中,另一部分是可以以module形式存在的。之所以这么设计,就是为了动态的调试内核,可以动态insmode和rmmod来插入断点和删除断点,而不用重复编译内核并引导来增加调试信息。

如何运行的?

当一个kprobe被注册时,kprobes会先复制断点处的指令,然后用一个breakpoint指令来替换此处的指令(比如i386和x86_64平台上的int3指令)。当CPU运行到断点地址处时,会去运行被替换为breakpoint的指令,并由此引发CPU进入trap(陷阱)。

这里写图片描述

上图在网上google到的一张比较形象的图片,以X86平台为例,整个流程如下:

准备阶段

(1)copy断点处的指令

(2)插入特殊breakpoint指令

运行阶段

(1)运行到断点,会执行breakpoint指令

(2)运行到breakpoint指令后触发breakpoint exception,陷入trap,执行对应ISR,CPU的寄存器会被在此时保存下来

(3)利用notifier机制执行pre_handler,并把前面保存下来的CPU寄存器传递给pre handler

(4)set TF=1,CPU进入singlestep单步运行模式,执行copy的指令

(5)单步执行完copy的指令后,会触发singlestep exception,并依然发出notifier

(6)post notifier处理中清除TF标志位,退出单步运行模式,并执行post handler

(7)跳转回断点后面的一条指令继续正常执行下去

规则和限制

(1)允许在同一个address上使用多个kprobe

(2)kprobe不能在在本身代码指令中做断点,因为这可能是引起double fault或者recursive trap

(3)kprobe利用blacklist来禁止不允许设置断点的地址

breakpoint断点

kprobe利用到了断点机制,那么断点到底是怎么实现的呢?其实断点分为两种类型,一种为硬件断点,另一种为软件断点。

硬件断点

从字面意义上很好理解,由硬件直接监控,一般的处理器中都会有对应的硬件断点监控单元,它应该属于一种硬件资源,那么既然是资源肯定就是有限的,我们不可能无限制的去使用硬件在代码中设置断点,因为资源总有被用尽的一刻。硬件断点需要我们配置对应的硬件断点监控单元来设置断点。比如使用ARM调试器时会直接操作硬件断点寄存器来控制断点和清除断点,这时候不需要修改原本的代码,只需要配置对应的断点监控单元即可实现断点。

软件断点

这种类型的断点虽然叫软件断点,但是也需要硬件断点的支持,实现的原理是:利用一个硬件断点单元来监控某一个特定的指令,在使用时需要我们在代码中插入此种指令,这样当CPU运行到此指令时就会触发断点,进入trap。这种方式需要软件配合才能实现一个断点,也就是说,我们需要提前在代码中埋下一个断点才有可能实现此功能。它的好处就是不受数量的限制,因为每次都是相同的指令被监控,所以我们不用担心资源不够用。一般各个平台会实现设置软件断点的指令码,比如X86平台上的int3指令,ARM平台上的BKPT指令。

猜你喜欢

转载自blog.csdn.net/rikeyone/article/details/80196565
今日推荐