作者: 陈林峰
Email: chenlinfeng25@outlook.com
Linux kprobes调试技术是内核开发者们专门为了便于跟踪内核函数执行状态所设计的一种轻量级内核调试技术。利用kprobes技术,内核开发人员可以在内核的绝大多数指定函数中动态的插入探测点来收集所需的调试状态信息而基本不影响内核原有的执行流程。
kprobes技术依赖硬件架构相关的支持,主要包括CPU的异常处理和单步调试机制,前者用于让程序的执行流程陷入到用户注册的回调函数中去,而后者则用于单步执行被探测点指令。需要注意的是,在一些架构上硬件并不支持单步调试机制,这可以通过一些软件模拟的方法解决(比如riscv)。
内核目前对x86和riscv64都进行了支持,由于 riscv64 没有单步执行模式,因此我们使用 break 异常来进行模拟,在保存探测点指令时,我们会额外填充一条 break 指令,这样就可以使得在riscv64架构上,在执行完原指令后,会再次触发break陷入异常。
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
用于运行过程中更新回调函数disable
和 enable
用于动态关闭kprobe,在disable
调用后,kprobe被触发时不执行回调函数symbol
返回探测点的函数名称