1:探测schedule()函数,在探测点执行前后分别输出当前正在运行的进程、所在的CPU以及preempt_count(),当卸载该模块时将输出该模块运行时间以及发生的调度次数
/* kprobe-exam.c */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <linux/sched.h>
#include <linux/time.h>
static struct kprobe kp;
static struct timeval start, end;
static int schedule_counter = 0;
int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
printk("current task on CPU#%d: %s (before scheduling), preempt_count = %d\n", smp_processor_id(), current->comm, preempt_count());
schedule_counter++;
return 0;
}
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
printk("current task on CPU#%d: %s (after scheduling), preempt_count = %d\n", smp_processor_id(), current->comm, preempt_count());
}
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
printk("A fault happened during probing.\n");
return 0;
}
int init_module(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("schedule");
if (!kp.addr) {
printk("Couldn't get the address of schedule.\n");
return -1;
}
if ((ret = register_kprobe(&kp) < 0)) {
printk("register_kprobe failed, returned %d\n", ret);
return -1;
}
do_gettimeofday(&start);
printk("kprobe registered\n");
return 0;
}
void cleanup_module(void)
{
unregister_kprobe(&kp);
do_gettimeofday(&end);
printk("Scheduling times is %d during of %ld milliseconds.\n", schedule_counter, ((end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec))/1000);
printk("kprobe unregistered\n");
}
MODULE_LICENSE("GPL");
2:,它示例了获取系统调用open的参数,但读者不要试图在实际的应用中这么使用,因为copy_from_user可能导致睡眠,而kprobe并不允许在探测点处理函数中这么做
/* jprobe-exam.c */
/* jprobe-exam.c */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
static struct jprobe jp;
asmlinkage long jprobe_sys_open(const char __user *filename, int flags, int mode)
{
int len = PATH_MAX;
char * tmpfilename = NULL;
if (TASK_SIZE - (unsigned long) filename < PATH_MAX) {
len = TASK_SIZE - (unsigned long) filename;
}
tmpfilename = kmalloc(len, GFP_ATOMIC);
if (tmpfilename == NULL) return 0;
if (copy_from_user(tmpfilename, filename, len)) return 0;
printk("process '%s' call open('%s', %d, %d)\n", current->comm, tmpfilename, flags, mode);
jprobe_return();
return 0;
}
int init_module(void)
{
int ret;
jp.entry = (kprobe_opcode_t *) jprobe_sys_open;
jp.kp.addr = (kprobe_opcode_t *)kallsyms_lookup_name("sys_open");
if (!jp.kp.addr) {
printk("Couldn't find the address of sys_open\n");
return -1;
}
if ((ret = register_jprobe(&jp)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return -1;
}
printk("Registered a jprobe.\n");
return 0;
}
void cleanup_module(void)
{
unregister_jprobe(&jp);
printk("jprobe unregistered\n");
}
MODULE_LICENSE("GPL");
3:kretprobe-exam.c是一个返回探测例子,它探测系统调用open并输出返回值小于0的情况。它也有意设置maxactive为1,以便示例丢失探测运行的情况,当然,只有系统并发运行多个sys_open才可能导致这种情况,因此,读者需要有SMP的系统或者有超线程支持才能看到这种情况。
/*kretprobe-exam.c*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
static struct kretprobe kretp;
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
// Substitute the appropriate register name for your architecture --
// e.g., regs->rax for x86_64, regs->gpr[3] for ppc64.
int retval = (int) regs->eax;
if (retval < 0) {
printk("sys_open returns %d\n", retval);
}
return 0;
}
int init_module(void)
{
int ret;
kretp.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("sys_open");
if (!kretp.kp.addr) {
printk("Couldn't find sys_open.\n");
return -1;
}
kretp.handler = ret_handler,
kretp.maxactive = 1;
if ((ret = register_kretprobe(&kretp)) < 0) {
printk("register_kretprobe failed, returned %d\n", ret);
return -1;
}
printk("Registered a return probe.\n");
return 0;
}
void cleanup_module(void)
{
unregister_kretprobe(&kretp);
printk("kretprobe unregistered\n");
printk("Missed %d sys_open probe instances.\n", kretp.nmissed);
}
MODULE_LICENSE("GPL");