第一时间捕获段错误 segment fault 的详细信息

不使用gdb也能捕获段错误的详细信息,事实上,使用gdb是一件很麻烦的事情!第一,gdb功能太过强大,诊断个段错误真是大材小用,如果不会用还要学...其次,很多系统并没有安装这个工具。因此最好的办法就是“自报死因”。在Linux中,这是很容易做到的,本文给出一种方式。

1.理解“自报死因”这个机制的前提

1.1.SIGSEGV信号是可以捕获的
1.2.siginfo中对于SIGSEGV而言其si_addr字段(由宏定义)保存段错误地址
1.3.backtrace_symbols/backtrace是很好的调试函数
1.4.rdynamic编译参数加载所有的符号
1.5.Linux的信号处理函数在用户栈上堆叠执行(详情参阅Linux源码setup_frame函数)。

2.测试的例子

以下为测试程序源码segftest.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>

#define SIZE 1000
void *buffer[SIZE];

void todo1(char *buf);
void todo2(char *buf);

void test(int n,struct siginfo *siginfo,void *myact)
{
        int i, num;
        char **calls;
        printf("Fault address:%X\n",siginfo->si_addr);   
        num = backtrace(buffer, SIZE);
        calls = backtrace_symbols(buffer, num);
        for (i = 0; i < num; i++)
                printf("%s\n", calls[i]);
        exit(1);
}  
void todo2(char *buf)
{
        memcpy(buf, "aaaa", 4); //引发段错误
}
void todo1(char *buf)
{
        todo2(buf);
}
int main(int argc, char **argv)
{
        char *no_alloc = (char *)0x1234; //未分配的内存
        struct sigaction act;
        sigemptyset(&act.sa_mask);   
        act.sa_flags=SA_SIGINFO;    
        act.sa_sigaction=test;
        sigaction(SIGSEGV,&act,NULL);
        todo1(no_alloc);
}


编译:
gcc segftest.c -o segftest -rdynamic
执行segftest的输出:
./segftest(test+0x3f) [0x400a63]
/lib/libc.so.6(+0x321e0) [0x7fe7ec9441e0]
/lib/libc.so.6(memcpy+0x37) [0x7fe7ec991787]
./segftest(todo2+0x22) [0x400ad2]
./segftest(todo1+0x18) [0x400aec]
./segftest(main+0x6a) [0x400b58]
/lib/libc.so.6(__libc_start_main+0xfd) [0x7fe7ec930c4d]
./segftest() [0x400969]
很是一目了然!因此在任意程序中调用下列的setuptrap即可在第一时间得到段错误的详细信息,包括引发段错误的地址,以及函数调用堆栈。
#include <signal.h>
#include <execinfo.h>
#define SIZE 1000
void *buffer[SIZE];
void fault_trap(int n,struct siginfo *siginfo,void *myact)
{
        int i, num;
        char **calls;
        printf("Fault address:%X\n",siginfo->si_addr);   
        num = backtrace(buffer, SIZE);
        calls = backtrace_symbols(buffer, num);
        for (i = 0; i < num; i++)
                printf("%s\n", calls[i]);
        exit(1);
}
void setuptrap()
{
    struct sigaction act;
        sigemptyset(&act.sa_mask);   
        act.sa_flags=SA_SIGINFO;    
        act.sa_sigaction=fault_trap;
        sigaction(SIGSEGV,&act,NULL);
}



再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

上一篇:scala当中的Actor并发编程


下一篇:解决微信自动清除缓存,每天都需要重新登录