void dump(int __signal)
{
const int __max_stack_flow = 20;
void* __array[__max_stack_flow];
char** __strings;
size_t __size = backtrace(__array,__max_stack_flow);
printf("backtrace() returned %d addresses\n", (int)__size);
__strings = backtrace_symbols(__array,__size);
if(NULL == __strings)
{
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
fprintf (stderr,"obtained %zd stack frames.nm", __size);
for (size_t __i = 0; __i < __size; ++__i)
{
printf("%s\n", __strings[__i]);
}
// This __strings is malloc(3)ed by backtrace_symbols(), and must be freed here
free (__strings);
exit(0);
}void segv_fun()
{
unsigned char* __ptr = 0x00;
*__ptr = 0x00;
}
void register_signal(int __signal)
{
signal(__signal, dump);
}
void TestDump::test_signal_segv()
{
printf("TestDump::test_signal SIGSEGV\n");
register_signal(SIGSEGV);
segv_fun();
}
运行输出:
从运行结果可以看到,程序SIGSEGV中断触发了dump函数,dump打印出了6帧,第一帧:/easy_main(_Z4dumpi+0x26) [0x402896] 是在执行dump;第二帧:/lib64/libc.so.6() [0x332ae329a0] 是调用libc的库函数;第三帧:./easy_main(_ZN8TestDump5myRunEPKcb+0x5f) [0x402d2f],这个看起来有点奇怪,这一串貌似可以看出来一些信息,TestDump?不能很快定位。不用急,如果出现这个请看看,我们可以借助addr2line,通过地址转换到对应文件的行数。
再看看源代码文件,void segv_fun() { unsigned char* __ptr = 0x00; *__ptr = 0x00; }
这下就知道问题所在之处了吧!第N帧......
void dump_for_gdb(int __signal)
{
const int __max_buf_size = 512;
char __buf[__max_buf_size] = {};
char __cmd[__max_buf_size] = {};
FILE* __file;
snprintf(__buf, sizeof(__buf), "/proc/%d/cmdline", getpid());
if(!(__file = fopen(__buf, "r")))
{
exit(0);
}
fclose(__file);
if(__buf[strlen(__buf) - 1] == '\n') // warning: multi-character character constant [-Wmultichar]
{
__buf[strlen(__buf) - 1] = '\0'; // warning: multi-character character constant [-Wmultichar]
}
snprintf(__cmd, sizeof(__cmd), "gdb %s %d",__buf, getpid());
system(__cmd);
exit(0);
}void register_signal_for_gdb(int __signal)
{
signal(__signal, dump_for_gdb);
}void TestDump::test_dump_for_gdb()
{
printf("TestDump::test_dump_for_gdb SIGSEGV\n");
register_signal_for_gdb(SIGSEGV);
segv_fun2();
}
输出结果
当然,我们可以把这些东西整合起来,比如在项目最终上线后,我们希望这个操作更加简单,因为到了运营阶段,操作者可能不是开发者,而是运维人员,我们希望用更简单,直接的方式,把这些信息提取出来,那就需要更进一步的工作了。我们之前采用的方法是:把dump的堆栈信息写的文件中,然后使用shell读取这些堆栈信息,病使用addr2line转化到具体的文件行数或者函数并保存最终文件。这样运维人员只需要把最终的文件给开发人员,便可分析定位问题了。目前所常用的就这些了,如果有更好的方式,欢迎补充。
引用代码:
Linux 信号signal处理机制
原文:http://blog.csdn.net/yuyunliuhen/article/details/41673599