一种是kretprobe:用于完成指定函数返回值的探测功能,内核函数的退出点 其中最基本的就是kprobe机制,jprobe以及kretprobe的实现都依赖于kprobe,kprobe是linux内核的一个重要的特性,是其他内核调试工具(perf,systemtap)的基础设施,同时内核BPF也是依赖于kprobe,它是利用指令插桩原理,截获指令流,并在指令执行前后插入hook函数,...
kprobe hook的代码逻辑还是较为简单的,以上代码hook了do_exit,在函数调用的时候,打印出进程名和进程PID。 不仅可以通过写驱动程序的方式使用kprobe,还可以在用户层使用ftrace灵活的开启kprobe。下面以官网上的例子来讲解如何使用: 通过/sys/kernel/debug/tracing/kprobe_events添加探测点,以及/sys/kernel/debug/tracing/...
staticint__initdebug_traps_init(void){ hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,// 单步异常处理函数TRAP_TRACE,"single-step handler"); hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,// 断点异常处理函数TRAP_BRKPT,"ptrace BRK handler");return0; }...
通过前面有章调试方法概述的简单介绍,kprobe其实就是将某个要检测的指令备份,再替换成int3(x86)或者未定义指令(arm)来触发异常,再调用对应体系的异常处理函数来执行我们自定义的hook,执行完我们自定义的hook,再将备份的指令放回原来的位置继续往下执行,下面我们就来看下linux内核版本为5.17.5的arm64的kprobe代码架构,...
kprobe可以认为是一种kernel hook手段,它基于内核中断的方式实现,可以想象它是内核层的异常hook(参考SandHook),既然是异常hook,那么它所能hook的范围就没有限制了,可以针对函数、也可以针对单条指令。 简单理解就是把指定地址的指令替换成一个可以让cpu进入debug模式的指令(不同架构上指...
由于没有启用THUMB2模式,这里arm_probes_decode_init主要是获取PC和当前执行地址偏移值(ARM的流水线机制一般为8)以及设置相关寄存器值获取方式等代码;而register_undef_hook函数向全局undef_hook链表注册了一个未定义指令异常处理的钩子,相关的结构体如下:
kretprobe 的理论解法是将 return address 也固定,因此理论上可以截获 ret 指令,进入一个common stub hook 中判定该函数是不是需要被 hook,如果不需要这就返回,如果需要就先调用 hook 再返回,但依然会引入别的开销,那么可以缩小替换范围,只在 kretprobe function 附近搜索并替换 ret 指令。
hook_debug_fault_code替换了debug_fault_info的值,将原有的异常处理函数变成自定义的异常处理函数 arm64的异常处理都在arch/arm64/kernel/entry.S中 会调用到do_debug_exception函数,之所以是在el1这里处理,是因为BRK异常的产生是因为在内核态执行了BRR指令,内核态是执行在EL1的,所以异常等级是EL1...
从上图中可以看到,如果直接使用 eBPF kprobe hook 系统调用,得到的实际上是图中最右侧的压缩数据。此时除了可以借助静态字典解码一部分内容以外,大部分业务字段,特别是和追踪相关的 TraceID、SpanID、X-Request-ID 等都无法稳定获取。 因此,无论是 DeepFlow 还是 Pixie 等其他 eBPF 可观测性项目,通常都使用 uprobe...
kretprobe 的理论解法是将 return address 也固定,因此理论上可以截获 ret 指令,进入一个common stub hook 中判定该函数是不是需要被 hook,如果不需要这就返回,如果需要就先调用 hook 再返回,但依然会引入别的开销,那么可以缩小替换范围,只在 kretprobe function 附近搜索并替换 ret 指令。