Chinaunix首页 | 论坛 | 博客
  • 博客访问: 210995
  • 博文数量: 55
  • 博客积分: 1305
  • 博客等级: 中尉
  • 技术积分: 350
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-11 15:18
文章分类

全部博文(55)

文章存档

2012年(1)

2011年(54)

分类: LINUX

2011-08-20 19:29:48

不使用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:
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6.   
  7. #define SIZE 1000  
  8. void *buffer[SIZE];  
  9.   
  10. void todo1(char *buf);  
  11. void todo2(char *buf);  
  12.   
  13. void test(int n,struct siginfo *siginfo,void *myact)  
  14. {  
  15.         int i, num;  
  16.         char **calls;  
  17.         printf("Fault address:%X\n",siginfo->si_addr);     
  18.         num = backtrace(buffer, SIZE);  
  19.         calls = backtrace_symbols(buffer, num);  
  20.         for (i = 0; i < num; i++)  
  21.                 printf("%s\n", calls[i]);  
  22.         exit(1);  
  23. }    
  24. void todo2(char *buf)  
  25. {  
  26.         memcpy(buf, "aaaa", 4); //引发段错误  
  27. }  
  28. void todo1(char *buf)  
  29. {  
  30.         todo2(buf);  
  31. }  
  32. int main(int argc, char **argv)  
  33. {  
  34.         char *no_alloc = (char *)0x1234; //未分配的内存  
  35.         struct sigaction act;  
  36.         sigemptyset(&act.sa_mask);     
  37.         act.sa_flags=SA_SIGINFO;      
  38.         act.sa_sigaction=test;  
  39.         sigaction(SIGSEGV,&act,NULL);  
  40.         todo1(no_alloc);  
  41. }  


编译:
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即可在第一时间得到段错误的详细信息,包括引发段错误的地址,以及函数调用堆栈。
  1. #include   
  2. #include   
  3. #define SIZE 1000  
  4. void *buffer[SIZE];  
  5. void fault_trap(int n,struct siginfo *siginfo,void *myact)  
  6. {  
  7.         int i, num;  
  8.         char **calls;  
  9.         printf("Fault address:%X\n",siginfo->si_addr);     
  10.         num = backtrace(buffer, SIZE);  
  11.         calls = backtrace_symbols(buffer, num);  
  12.         for (i = 0; i < num; i++)  
  13.                 printf("%s\n", calls[i]);  
  14.         exit(1);  
  15. }  
  16. void setuptrap()  
  17. {  
  18.     struct sigaction act;  
  19.         sigemptyset(&act.sa_mask);     
  20.         act.sa_flags=SA_SIGINFO;      
  21.         act.sa_sigaction=fault_trap;  
  22.         sigaction(SIGSEGV,&act,NULL);  
  23. }  
阅读(1845) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~