前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux内核调试技术——kprobe使用与实现(三)

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

作者头像
用户5807183
发布2019-07-15 16:59:09
1.8K0
发布2019-07-15 16:59:09
举报
文章被收录于专栏:Linux知识积累

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的初始化过程。

图 kprobes初始化流程

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

首先初始化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段信息:

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

例如其中的get_kprobe函数:

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

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

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

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

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux知识积累 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Linux内核调试技术——kprobe使用与实现(一)
  • Linux内核调试技术——kprobe使用与实现(二)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档