LoGin 880720250e
doc: Add ai doc translate tool and add English doc. (#1168)
- add tools/doc_translator.py
- translated docs into English

Signed-off-by: longjin <longjin@DragonOS.org>
2025-05-20 10:44:28 +08:00

3.5 KiB
Raw Permalink Blame History

kprobe

作者: 陈林峰

Email: chenlinfeng25@outlook.com

概述

Linux kprobes调试技术是内核开发者们专门为了便于跟踪内核函数执行状态所设计的一种轻量级内核调试技术。利用kprobes技术内核开发人员可以在内核的绝大多数指定函数中动态的插入探测点来收集所需的调试状态信息而基本不影响内核原有的执行流程。

kprobes技术依赖硬件架构相关的支持主要包括CPU的异常处理和单步调试机制前者用于让程序的执行流程陷入到用户注册的回调函数中去而后者则用于单步执行被探测点指令。需要注意的是在一些架构上硬件并不支持单步调试机制这可以通过一些软件模拟的方法解决(比如riscv)。

kprobe工作流程

xxx
  1. 注册kprobe后注册的每一个kprobe对应一个kprobe结构体该结构中记录着探测点的位置以及该探测点本来对应的指令。
  2. 探测点的位置被替换成了一条异常的指令这样当CPU执行到探测点位置时会陷入到异常态在x86_64上指令是int3如果kprobe经过优化后指令是jmp
  3. 当执行到异常指令时系统换检查是否是kprobe 安装的异常如果是就执行kprobe的pre_handler,然后利用CPU提供的单步调试single-step功能设置好相应的寄存器将下一条指令设置为插入点处本来的指令从异常态返回
  4. 再次陷入异常态。上一步骤中设置了single-step相关的寄存器所以原指令刚一执行便会再次陷入异常态此时将single-step清除并且执行post_handler然后从异常态安全返回.
  5. 当卸载kprobe时探测点原来的指令会被恢复回去。

内核目前对x86和riscv64都进行了支持由于 riscv64 没有单步执行模式,因此我们使用 break 异常来进行模拟,在保存探测点指令时,我们会额外填充一条 break 指令这样就可以使得在riscv64架构上在执行完原指令后会再次触发break陷入异常。

kprobe的接口

pub fn register_kprobe(kprobe_info: KprobeInfo) -> Result<LockKprobe, SystemError>;
pub fn unregister_kprobe(kprobe: LockKprobe) -> Result<(), SystemError>;

impl KprobeBasic {
    pub fn call_pre_handler(&self, trap_frame: &dyn ProbeArgs) 
    pub fn call_post_handler(&self, trap_frame: &dyn ProbeArgs)
    pub fn call_fault_handler(&self, trap_frame: &dyn ProbeArgs)
    pub fn call_event_callback(&self, trap_frame: &dyn ProbeArgs) 
    pub fn update_event_callback(&mut self, callback: Box<dyn CallBackFunc>) 
    pub fn disable(&mut self) 
    pub fn enable(&mut self) 
    pub fn is_enabled(&self) -> bool
    pub fn symbol(&self) -> Option<&str>
}
  • call_pre_handler 在探测点指令被执行前调用用户定义的回调函数
  • call_post_handler 在单步执行完探测点指令后调用用户定义的回调函数
  • call_fault_handler 在调用前两种回调函数发生失败时调用
  • call_event_callback 用于调用eBPF相关的回调函数通常与call_post_handler 一样在单步执行探测点指令会调用
  • update_event_callback用于运行过程中更新回调函数
  • disableenable 用于动态关闭kprobedisable调用后kprobe被触发时不执行回调函数
  • symbol 返回探测点的函数名称