当前位置:   article > 正文

【内存踩踏分析】

【内存踩踏分析】

内存踩踏分析:

搞底层开发的人一定听过内存踩踏这个令人可怕的专业词语,轻则功能错乱,重则死机崩溃。关键是排查起来还费劲,尤其是在内核驱动中。因为当我们发现异常的时候,往往已经不是第一案发现场了,可能是第二、第三、第N现场了,作案人员可能早已逃离作案现场,在案发现场,可能不曾留下任何蛛丝马迹。有时可能有些蛛丝马迹,但也极为隐秘,很难找出来。当然你可以打开内核KASAN重新编译,再重新复现问题看能不能抓到一些有用的信息。但这样重新编译后,工作环境发生了变化,问题不一定能够复现。我最近遇到一个奇怪的问题,看上去很像内存踩踏。我一个结构体中的成员变量,在初始化之后,就再也没动过它了,可后面某次访问时,它的值突然就变成一个异常值了。种种迹象看起来很像是内存踩踏,于是我在这个变量前后加一些变量想看看踩踏的数据有没有啥规律,但是改了代码之后就复现不到了。由于我的变量是只读的,我就找找看有没有办法监控下这个变量的地址,当CPU往这个地址写数据的时候,自动把调用堆栈打印出来,那么就知道哪里在搞鬼了。我找到了以下方法验证可行,读和写都可以监控到,分享给C厂的小伙伴,希望大家以后遇到类似问题时,手上又多了一件破案的工具。对于那些非只读的场合,自己修改变量的值时,要先去掉监控,修改完了之后再打开监控。

解决方案:

#include <linux/kallsyms.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>

static struct perf_event * __percpu *sample_hbp;

static void sample_hbp_handler(struct perf_event *bp,
                               struct perf_sample_data *data,
                               struct pt_regs *regs) {
        printk(KERN_INFO "sample_hbp_handler!\n");
        dump_stack();
        printk(KERN_INFO "Dump stack from sample_hbp_handler!\n");
        BUG_ON(1); // 让系统停下来
}

static int my_hw_break_register(void *addr) {
        int ret;
        struct perf_event_attr attr;

        hw_breakpoint_init(&attr);
        attr.bp_addr = (__u64)addr; //64位系统
        attr.bp_len = HW_BREAKPOINT_LEN_8; //64位系统地址8字节,32位系统4字节
        attr.bp_type = HW_BREAKPOINT_W;// | HW_BREAKPOINT_R;
        sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL);
        if (IS_ERR((void __force *)sample_hbp)) {
                ret = PTR_ERR((void __force *)sample_hbp);
                goto fail;
        }

        printk(KERN_INFO "HW Breakpoint for write %p installed.\n", addr);

        return 0;

fail:
        printk(KERN_INFO "HW Breakpoint registration failed for %p!\n", addr);

        return ret;
}

static void my_hw_break_unregister(void) {
        unregister_wide_hw_breakpoint(sample_hbp);
        printk(KERN_INFO "HW Breakpoint for write uninstalled.\n");
}

//测试代码
void test(void) {
    int a = 0;

    my_hw_break_register(&a);
    a = 1; //这样就会触发监控
    my_hw_break_unregister(); //用完了释放
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/152470
推荐阅读
相关标签
  

闽ICP备14008679号