• 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");

  • 相关阅读:
    焦虑:都说程序员是青春饭,那么程序员老了何去何从呢?
    数据库查询语句优化,mysql优化,join语句优化附带YYC松鼠短视频系统详细demo效果
    IT行业:为什么大部分人都不认可php语言呢?
    拇指赚点赞无加密源码发布分享仅供学习
    区块鼠区块养殖系统源码无加密源码发布分享仅供学习
    3月1日晚突遭大量攻击,网站/APP突然遭遇黑客攻击时该如何应对?
    ThinkPHP内核全行业小程序运营管理系统源码免费分享下载
    2020年不管打工还是创业,居然还有人相信读书无用论?
    在IT界,应聘企业去上班如果老板一点不懂技术那绝对是作茧自缚
    看了这篇文章你还不懂傅里叶变换,那我就真没办法呢!
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/5424582.html
Copyright © 2020-2023  润新知