Kprobes
"Use" "Reference Kernel/documentation/kprobes.txt Help Document"
Kprobes is a lightweight kernel debugging tool and is the foundation of some of the more advanced kernel debugging tools such as Perf and Systemtap, and in the Linux 4.0 kernel version, the EBPF feature is also parasitic on the kprobe.
Principle
The main function of Kprobes is to add a custom function before and after the specified function call, thus realizing the function of the dynamic probe point.
There are two ways to use Kprobes: 1) module loading, 2) operation via Debugfs.
"Interface description""Reference Kernel/sample/kprobes"
Key structural bodies
#include <linux/kprobes.h>
struct Kprobe {
kprobe_opcode_t *addr; /* location of the probe point */
const char *symbol_name; /* Allow user to indicate symbol name of the probe point */
kprobe_pre_handler_t Pre_handler; /* Called before addr is executed */
kprobe_pre_handler_t Post_handler; /* Called after addr is executed */
kprobe_pre_handler_t Fault_handler; /* called if executing addr caused a fault * *
};
Registering Kprobes probe points
int register_kprobe (struct kprobe *p);
Unregister Kprobes probe points
void Unregister_kprobe (struct kprobe *p);
Instance
/*
* Note:this example is works on x86 and PowerPC.
* Here's a sample kernel module showing the use of kprobes to dump a
* Stack trace and selected registers when Do_fork () is called.
* For more information on theory of operation of Kprobes, see
* Documentation/kprobes.txt
* You'll see the trace data in/var/log/messages and on the console
* Whenever Do_fork () is invoked to create a new process.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
/* For each probe-need to allocate a KPROBE structure */
static struct Kprobe KP = {
. symbol_name = "Do_fork",
};
/* Kprobe pre_handler:called just before the probed instruction is executed */
static int handler_pre (struct kprobe *p, struct Pt_regs *regs) {
#ifdef config_x86
PRINTK (kern_info "pre_handler:p->addr = 0x%p, IP =%LX," "Flags = 0x%lx\r\n", P->addr, REGS-&G T;ip, Regs->flags);
#endif
#ifdef CONFIG_PPC
PRINTK (kern_info "pre_handler:p->addr = 0x%p, Nip = 0x%lx," "MSR = 0x%lx\r\n", P->addr, regs-& Gt;nip, REGS->MSR);
#endif
#ifdef config_mips
PRINTK (kern_info "pre_handler:p->addr = 0x%p, EPC = 0X%LX," "Status = 0x%lx\r\n", P->addr, Reg S->CP0_EPC, Regs->cp0_status);
#endif
/* a dump_stack () here'll give a stack backtrace */
return 0;
}
/* Kprobe post_handler:called after the probed instruction is executed */
static void Handler_post (struct kprobe *p, struct pt_regs *regs, unsigned long flags) {
#ifdef config_x86
PRINTK (kern_info "post_handler:p->addr = 0x%p, flags = 0x%lx\r\n", p->addr, Regs->flags);
#endif
#ifdef CONFIG_PPC
PRINTK (kern_info "post_handler:p->addr = 0x%p, msr = 0x%lx\r\n", p->addr, REGS->MSR);
#endif
#ifdef config_mips
PRINTK (kern_info "post_handler:p->addr = 0x%p, status = 0x%lx\r\n", p->addr, Regs->cp0_status);
#endif
}
/*
* Fault_handler:this is called if a exception is generated for any
* Instruction within the pre-or Post-handler, or when Kprobes
* Single-steps the probed instruction.
*/
static int Handler_fault (struct kprobe *p, struct pt_regs *regs, int trapnr) {
PRINTK (kern_info "fault_handler:p->addr = 0x%p, Trap #%dn", p->addr, TRAPNR);
/* Return 0 because we don ' t handle the fault. */
return 0;
}
static int __init kprobe_init (void) {
int ret;
Kp.pre_handler = Handler_pre;
Kp.post_handler = Handler_post;
Kp.fault_handler = Handler_fault;
ret = Register_kprobe (&KP);
if (Ret < 0) {
PRINTK (kern_info "Register_kprobe failed, returned%d\r\n", ret);
return ret;
}
PRINTK (kern_info "planted kprobe at%p\r\n", kp.addr);
return 0;
}
static void __exit kprobe_exit (void) {
Unregister_kprobe (&KP);
PRINTK (kern_info "Kprobe at%p unregistered\r\n", kp.addr);
}
Module_init (Kprobe_init) module_exit (kprobe_exit) module_license ("GPL");
Summary of Linux kernel debugging methods Kprobes