zoukankan      html  css  js  c++  java
  • Linux内核调试方法总结之Kprobes

    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 ",         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 ",         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 ",         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 ",         p->addr, regs->flags);

    #endif

    #ifdef CONFIG_PPC

        printk(KERN_INFO "post_handler: p->addr = 0x%p, msr = 0x%lx ",         p->addr, regs->msr);

    #endif

    #ifdef CONFIG_MIPS

        printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx ",         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 ", ret);

            return ret;

        }

        printk(KERN_INFO "Planted kprobe at %p ", kp.addr);

        return 0;

    }

    static void __exit kprobe_exit(void) {

        unregister_kprobe(&kp);

        printk(KERN_INFO "kprobe at %p unregistered ", kp.addr);

    }

    module_init(kprobe_init) module_exit(kprobe_exit) MODULE_LICENSE("GPL");

  • 相关阅读:
    一行代码搞定Dubbo接口调用
    测试周期内测试进度报告规范
    jq 一个强悍的json格式化查看工具
    浅析Docker容器的应用场景
    HDU 4432 Sum of divisors (水题,进制转换)
    HDU 4431 Mahjong (DFS,暴力枚举,剪枝)
    CodeForces 589B Layer Cake (暴力)
    CodeForces 589J Cleaner Robot (DFS,或BFS)
    CodeForces 589I Lottery (暴力,水题)
    CodeForces 589D Boulevard (数学,相遇)
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/5424582.html
Copyright © 2011-2022 走看看