• [fw]用Kprobes调试(debug)内核


    Kprobes是一种运行时动态调试内核的机制, 你可以用它设置断点并收集调试信息, 甚至改变内核行为.

    Kprobes分三种, 普通kprobes以及基于普通kprobes的jprobes和kretprobes. kprobes可以注入某个地址, jprobes用来注入某个函数入口, 而kretprobes则用来注入某个函数返回.

    实现原理

    Kprobes的实现主要利用了处理器的异常和单步执行特性. 以普通kprobes举例, 注册时它会复制一份被注入的指令, 并加入断点(例如x86的int 3), 当CPU执行到被注入的指令时就会陷入到Kprobes中, 此时Kprobes先运行钩子函数”pre_handler”, 然后单步执行被复制的指令, 并且由于是单步执行模式, 指令执行完毕后会再次触发异常而陷入到Kprobes中, 此时Kprobes会运行钩子函数”post_handler”并最终返回.

    使用方法

    通常情况下, Kprobes以内核模块的形式工作, 模块的init函数用来注册Kprobes, exit函数相应得用来注销, pre_handler和post_handler分别在单步执行被复制的指令前后运行, fault_handler则在单步执行发生异常时运行.

    Kprobes模块写起来很简单, 下面是一个内核源码中的例子, 演示如何在每次do_fork()的时候打印选定寄存器中的内容.

     1 #include <linux/kernel.h>
     2 #include <linux/module.h>
     3 #include <linux/kprobes.h>
     4 
     5 /* For each probe you need to allocate a kprobe structure */
     6 static struct kprobe kp = {
     7     .symbol_name    = "do_fork",
     8 };
     9 
    10 /* kprobe pre_handler: called just before the probed instruction is executed */
    11 static int handler_pre(struct kprobe *p, struct pt_regs *regs)
    12 {
    13     printk(KERN_INFO "pre_handler: p->addr = 0x%p, ip = %lx,"
    14             " flags = 0x%lx
    ",
    15         p->addr, regs->ip, regs->flags);
    16 
    17     /* A dump_stack() here will give a stack backtrace */
    18     return 0;
    19 }
    20 
    21 /* kprobe post_handler: called after the probed instruction is executed */
    22 static void handler_post(struct kprobe *p, struct pt_regs *regs,
    23                 unsigned long flags)
    24 {
    25     printk(KERN_INFO "post_handler: p->addr = 0x%p, flags = 0x%lx
    ",
    26         p->addr, regs->flags);
    27 }
    28 
    29 /*
    30  * fault_handler: this is called if an exception is generated for any
    31  * instruction within the pre- or post-handler, or when Kprobes
    32  * single-steps the probed instruction.
    33  */
    34 static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
    35 {
    36     printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
    37         p->addr, trapnr);
    38     /* Return 0 because we don't handle the fault. */
    39     return 0;
    40 }
    41 
    42 static int __init kprobe_init(void)
    43 {
    44     int ret;
    45     kp.pre_handler = handler_pre;
    46     kp.post_handler = handler_post;
    47     kp.fault_handler = handler_fault;
    48 
    49     ret = register_kprobe(&kp);
    50     if (ret < 0) {
    51         printk(KERN_INFO "register_kprobe failed, returned %d
    ", ret);
    52         return ret;
    53     }
    54     printk(KERN_INFO "Planted kprobe at %p
    ", kp.addr);
    55     return 0;
    56 }
    57 
    58 static void __exit kprobe_exit(void)
    59 {
    60     unregister_kprobe(&kp);
    61     printk(KERN_INFO "kprobe at %p unregistered
    ", kp.addr);
    62 }
    63 
    64 module_init(kprobe_init)
    65 module_exit(kprobe_exit)
    66 MODULE_LICENSE("GPL");

    这只是一个简单的打印示例, Kprobes还可以修改被注入函数的上下文, 如内核数据结构和寄存器, 并且都是在运行时动态修改, 多么美好!

    ref:

    1, https://lwn.net/Articles/132196/
    2, https://www.kernel.org/doc/Documentation/kprobes.txt
    3, http://www.ibm.com/developerworks/library/l-kprobes/index.html

  • 相关阅读:
    How Many Tables 并查集(求有几个集合)
    Spell checker 字典树&&普通查找(加计数)
    昂贵的聘礼 dijstra算法(要枚举源点)
    All in All 找子串 水题
    Ultra-QuickSort 求逆序对 归并排序
    Snowflake Snow Snowflakes 根据相似度排序,有点暴力
    Gold Balanced Lineup hash函数,第一次接触,借鉴了大神的博客思想,看了很久才看懂,弱菜啦
    Stockbroker Grapevine 裸的floyd算法,求最大中的最小
    Check the difficulty of problems 概率dp,概率知识很重要
    [leetcode] Valid Anagram 、 Find All Anagrams in a String
  • 原文地址:https://www.cnblogs.com/bittorrent/p/3496507.html
Copyright © 2020-2023  润新知