Kprobes

【用途】【参考kernel/Documentation/kprobes.txt帮助文档】

Kprobes是一个轻量级内核调试工具,同时又是其他一些更高级的内核调试工具(如perf和systemtap)的基础,在Linux 4.0内核版本中,eBPF特性也寄生于kprobe之上。

【原理】

Kprobes的主要作用是在指定函数调用前后添加自定义函数,从而实现动态探测点的功能。

Kprobes有两种使用方法:1)模块加载;2)通过debugfs操作。

【接口说明】【参考kernel/sample/kprobes】

关键结构体

#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 */

};

注册kprobes探测点

int register_kprobe(struct kprobe *p);

注销kprobes探测点

void unregister_kprobe(struct kprobe *p);

【实例】

/*

* 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 will 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 you 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->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->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, regs->cp0_epc, regs->cp0_status);

#endif

/* A dump_stack() here will 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 an 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");

Linux内核调试方法总结之Kprobes的更多相关文章

  1. Linux内核调试方法总结

    Linux内核调试方法总结 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2   ...

  2. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

  3. 【转】Linux内核调试方法总结

    目录[-] 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2  dump_sta ...

  4. Linux内核调试方法【转】

    转自:http://www.cnblogs.com/shineshqw/articles/2359114.html kdb:只能在汇编代码级进行调试: 优点是不需要两台机器进行调试. gdb:在调试模 ...

  5. Linux内核调试方法总结之反汇编

    Linux反汇编调试方法 Linux内核模块或者应用程序经常因为各种各样的原因而崩溃,一般情况下都会打印函数调用栈信息,那么,这种情况下,我们怎么去定位问题呢?本文档介绍了一种反汇编的方法辅助定位此类 ...

  6. Linux内核调试方法总结之栈帧

    栈帧 栈帧和指针可以说是C语言的精髓.栈帧是一种特殊的数据结构,在C语言函数调用时,栈帧用来保存当前函数的父一级函数的栈底指针,当前函数的局部变量以及被调用函数返回后下一条汇编指令的地址.如下图所示: ...

  7. Linux内核调试方法总结之序言

    本系列主要介绍Linux内核死机.异常重启类稳定性问题的调试方法. 在Linux系统中,一切皆为文件,而系统运行的载体,是一类特殊的文件,即进程.因此,我尝试从进程的角度分析Linux内核的死机.异常 ...

  8. Linux内核调试方法总结之ddebug

    [用途] Linux内核动态调试特性,适用于驱动和内核各子系统调试.动态调试的主要功能就是允许你动态的打开或者关闭内核代码中的各种提示信息.适用于驱动和内核线程功能调试. [使用方法] 依赖于CONF ...

  9. Linux内核调试方法总结之调试宏

    本文介绍的内核调试宏属于静态调试方法,通过调试宏主动触发oops从而打印出函数调用栈信息. 1) BUG_ON 查看bug处堆栈内容,主动制造oops Linux中BUG_ON,WARN_ON用于调试 ...

随机推荐

  1. Luogu P1084 [NOIP2012]疫情控制

    题目 首先我们二分一下答案. 然后我们用倍增让军队往上跳,最多先跳到根的子节点. 如果当前军队可以到达根节点,那么记录一下它的编号和它到达根节点后还可以走的时间. 并且我们记录根节点的叶子节点上到根节 ...

  2. 请写出一段Python代码实现删除一个list里面的重复元素?

    方法1:使用set函数  s=set(list),然后再list(s) 方法2:append    def delList(L): L1 = [] for i in L: if i not in L1 ...

  3. django字段类型(Field types)介绍

    字段类型(Field types) AutoField 它是一个根据 ID 自增长的 IntegerField 字段.通常,你不必直接使用该字段.如果你没在别的字段上指定主 键,Django 就会自动 ...

  4. 05-Django-session-admin

    # session- 为了应对HTTP协议的无状态性- 用来保存用户比较敏感的信息- 属于request的一个属性- 常用操作: - request.session.get(key, defaultV ...

  5. mac 命令行终端 设置代理

    环境: macOS Mojave 10.14.3 iTrem 2 3.2.8 酸酸乳1.1.4.4-R8 查看自己命令行的状态 curl ip.gs 正式开始 一.首先检查自己的酸酸乳是否正常,并在高 ...

  6. Spring基础04——ApplicationContext

    1.ApplicationContext简述 ApplicationContext代表IOC容器,在SpringIOC容器中读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后 ...

  7. python函数带不带括号的问题

    Python带括号返回的是该函数的返回值 不带括号返回的是该函数的位置信息等

  8. test dword ptr [eax],eax ; probe page.局部数组变量定义所分配的最大空间为1M

    问题的出现 使用VS2017编写程序时,程序编译可以通过,但运行时就会弹出错误 经过查证发现: 这跟局部数组变量定义所分配的最大空间设置大小有关. 局部变量的申请空间是存放于栈中,windows里默认 ...

  9. CF547E Mike and Friends

    子串看起来就很SuffixStructures 于是上SAM 本来想着直接LCT 后来发现没法串定位(暴力匹配复杂度不对) 然后就离线吧,先建出来然后链加子树和,树剖就odk. 其实更直接的套路是线段 ...

  10. redis数据库的set去重操作

    一:业务需求  用户名存储之前进行去重判断 方法一:使用redis的set集合进行去重判断 keys * 查看所有的键 type 键名 查看对应的数据类型 sadd set a b c 往set集合里 ...