Linux内核调试技术——kprobe使用与实现(三)

Linux内核调试技术——kprobe使用与实现(一)

Linux内核调试技术——kprobe使用与实现(二)

对于kprobe功能的实现主要利用了内核中的两个功能特性:异常(尤其是int 3),单步执行(EFLAGS中的TF标志)。

大概的流程:

1)在注册探测点的时候,对被探测函数的指令码进行替换,替换为int 3的指令码;

2)在执行int 3的异常执行中,通过通知链的方式调用kprobe的异常处理函数;

3)在kprobe的异常出来函数中,判断是否存在pre_handler钩子,存在则执行;

4)执行完后,准备进入单步调试,通过设置EFLAGS中的TF标志位,并且把异常返回的地址修改为保存的原指令码;

5)代码返回,执行原有指令,执行结束后触发单步异常;

6)在单步异常的处理中,清除单步标志,执行post_handler流程,并最终返回;

在了解了kprobe的基本原理和使用后,现在从源码的角度来详细分析它是如何实现的。主要包括kprobes的初始化、注册kprobe和触发kprobe(包括arm结构和x86_64架构的回调函数和single-step单步执行)


本篇文章首先介绍kprobe的初始化过程。



640?wx_fmt=png

图  kprobes初始化流程 

kprobes作为一个模块,其初始化函数为init_kprobes,代码路径kernel/kprobes.c

640?wx_fmt=png

640?wx_fmt=png

首先初始化hash表的各个链表头,用来保存后面调用kprobe_register函数注册的struct kprobes实例(会使用探测地址作为索引),同时初始化kretprobe用到的自旋锁。


接下来调用populate_kprobe_blacklist函数将kprobe实现相关的代码函数保存到kprobe_blacklist这个链表中去,用于后面注册探测点时判断使用,注意这里的__start_kprobe_blacklist和__stop_kprobe_blacklist定义在include/asm-generic/vmlinux.lds.h中的.init.rodata段中,其中保存了_kprobe_blacklist段信息:

640?wx_fmt=png

_kprobe_blacklist段中保存了实现kprobes的关键代码路径,这些代码是不可以被kprobe自己所探测的,在源码定义相关函数时使用NOKPROBE_SYMBOL宏将函数放到这个段中:

640?wx_fmt=png

例如其中的get_kprobe函数:

640?wx_fmt=png

回到init_kprobes函数中继续分析,接下来的片段是kretprobe相关的代码,用来核对kretprobe_blacklist中定义的函数是否存在,这里kretprobe_blacklist_size变量默认为0;接下来初始化3个全局变量,kprobes_all_disarmed用于表示是否启用kprobe机制,这里默认设置为启用;随后调用arch_init_kprobes进行架构相关的初始化,x86架构的实现为空,arm架构的实现如下:

640?wx_fmt=png

由于没有启用THUMB2模式,这里arm_probes_decode_init主要是获取PC和当前执行地址偏移值(ARM的流水线机制一般为8)以及设置相关寄存器值获取方式等代码;而register_undef_hook函数向全局undef_hook链表注册了一个未定义指令异常处理的钩子,相关的结构体如下:

640?wx_fmt=png

这样在触发未定义指令KPROBE_ARM_BREAKPOINT_INSTRUCTION(机器码0x07f001f8)时将会调用到这里的kprobe_trap_handler函数。

再次回到init_kprobes函数,接下来分别注册die和module的内核通知链kprobe_exceptions_nb和kprobe_module_nb:

640?wx_fmt=png

640?wx_fmt=png

其中kprobe_exceptions_nb的优先级很高,如此在执行回调函数和单步执行被探测指令期间若发生了内存异常,将优先调用kprobe_exceptions_notify函数处理(架构相关,x86会调用kprobe的fault回调函数,而arm则为空);注册module notify回调kprobes_module_callback函数的作用是若当某个内核模块发生卸载操作时有必要检测并移除注册到该模块函数的探测点。

最后init_kprobes函数置位kprobes_initialized标识,初始化完成。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值