赞
踩
搞底层开发的人一定听过内存踩踏这个令人可怕的专业词语,轻则功能错乱,重则死机崩溃。关键是排查起来还费劲,尤其是在内核驱动中。因为当我们发现异常的时候,往往已经不是第一案发现场了,可能是第二、第三、第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(); //用完了释放 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。