其中最基本的就是kprobe机制,jprobe以及kretprobe的实现都依赖于kprobe,kprobe是linux内核的一个重要的特性,是其他内核调试工具(perf,systemtap)的基础设施,同时内核BPF也是依赖于kprobe,它是利用指令插桩原理,截获指令流,并在指令执行前后插入hook函数,其如下: 所以kprobe的实现原理是把制定地址(探测点)的指令替换成一个...
unsigned long nmissed; /*count the number of times this probe was temporarily disarmed. 代表CPU正在执行其他kprobe过程中, hit到了该kprobe指令, 从到导致该kprobe指令仅被执行探测指令本身, 但未执行pre_handler和post_handler. 即: 该kprobe点被hit到,但pre_handler和post_handler未被执行的次数. */ kprob...
回到register_kprobe函数中,下面调用check_kprobe_rereg函数防止同一个kprobe实例被重复注册,其中check_kprobe_rereg->__get_valid_kprobe调用流程将根据addr地址值搜索全局hash表并查看是否有同样的kprobe实例已经在表中了。 随后register_kprobe函数继续初始化kprobe的flags、nmissed字段和list链表(flag只允许用户传递KPRO...
首先kprobe是最基本的探测方式,是实现后两种的基础,它可以在任意的位置放置探测点(就连函数内部的某条指令处也可以),它提供了探测点的调用前、调用后和内存访问出错3种回调方式,分别是pre_handler、post_handler和fault_handler,其中pre_handler函数将在被探测指令被执行前回调,post_handler会在被探测指令执行完毕后回...
kprobe 是一种动态调试机制,用于debugging,动态跟踪,性能分析,动态修改内核行为等,2004年由IBM发布,是名为Dprobes工具集的底层实现机制[1][2],2005年合入Linux kernel。probe的含义是像一个探针,可以不修改分析对象源码的情况下,获取Kernel的运行时信息。
通过前面有章调试方法概述的简单介绍,kprobe其实就是将某个要检测的指令备份,再替换成int3(x86)或者未定义指令(arm)来触发异常,再调用对应体系的异常处理函数来执行我们自定义的hook,执行完我们自定义的hook,再将备份的指令放回原来的位置继续往下执行,下面我们就来看下linux内核版本为5.17.5的arm64的kprobe代码架构...
首先我们从kprobe的起始点init_kprobe函数切入,由于各个架构的实现不同,下面以arm64为例 init_kprobes的第一步是初始化哈希表,这里的哈希表指代的就是管理kprobe实例 KPROBE_TABLE_SIZE是64,对于每个槽初始化一个头结点kprobe table的形式参考下图以hook的address为key,将kprobe保存到哈希表中,后续在查找时可以通过addr...
要编写一个 kprobe 内核模块,可以按照以下步骤完成: 第一步:根据需要来编写探测函数,如 pre_handler 和 post_handler 回调函数。 第二步:定义 struct kprobe 结构并且填充其各个字段,如要探测的内核函数名和各个探测回调函数。 第三步:通过调用 register_kprobe 函数注册一个探测点。
不仅如此 x2,除了 eBPF kprobe 以外,对于通过cBPF采集到的流量数据,DeepFlow 6.4 也支持了对压缩头的解码,因此即使你的内核版本更低,同样也能享用到此项特性。 这里我们也说明一下此项特性的两点限制: 对于deepflow-agent 启动之前就已经存在的 HTTP2 长连接,已存在的动态字典表项无法解码(但新增的动态字典表项无...
kprobe的工作过程大致如下: 1)注册kprobe。注册的每个kprobe对应一个kprobe结构体,该结构中记录着插入点(位置),以及该插入点本来对应的指令original_opcode; 2)替换原有指令。使能kprobe的时候,将插入点位置的指令替换为一条异常(BRK)指令,这样当CPU执行到插入点位置时会陷入到异常态; ...