ARM平台backtrace抓取回溯栈信息

工作遇到了一个段错误的异常,本来想在程序里使用backtrace等接口抓取一下异常现场的信息,结果并没有抓到,所以记录一下这个问题。

一开始我是在程序里设置了如下的代码

void logTrace(int signal)
{
    void* array[300];
    size_t size;
    char** strings;
    int i;

    size = backtrace(array, 300);
    strings = backtrace_symbols(array, size);
    if (NULL == strings) {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }
    LOG(LOG_LEVEL_ERROR, "Obtained %zd stack frames.", size);
    for(i = 0 ; i < size; i++){
        LOG(LOG_LEVEL_ERROR, "[%d] %s", i, strings[i]);
    }
    free(strings);
    strings = NULL;
    exit(EXIT_SUCCESS);
}

并在main函数中对几个信号都进行了捕捉

    signal(SIGSEGV, logTrace);
    signal(SIGTERM, logTrace);
    signal(SIGKILL, logTrace);
    signal(SIGINT, logTrace);

本以为在程序异常退出的时候,可以记录出程序退出的回溯栈信息,方便定位问题,但结果并不是我想象的那样,只输出了一句话!!!

Obtained 1 stack frames.
[0] app(logTrace+0x1c) [0x405410]

我就奇怪了?为啥?百思不得其解。于是我写了一个简单的c程序,打算验证一下这个事情。

#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdlib.h>
#include<string.h>

void logTrace(int signal)
{
    void* array[300];
    size_t size;
    char** strings;
    int i;

    size = backtrace(array, 300);
    strings = backtrace_symbols(array, size);
    if (NULL == strings) {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }
    printf("Obtained %zd stack frames.\n", size);
    for(i = 0 ; i < size; i++){
        printf("[%d] %s\n", i, strings[i]);
    }
    free(strings);
    strings = NULL;
    exit(EXIT_SUCCESS);
}

void Fun1()
{
    char *p=NULL;
    *p = 'A';
}

void Fun()
{
    Fun1();
}

int main(void)
{
    signal(SIGHUP, logTrace);
    signal(SIGINT, logTrace);
    signal(SIGQUIT, logTrace);
    signal(SIGILL, logTrace);
    signal(SIGTRAP, logTrace);
    signal(SIGKILL, logTrace);
    signal(SIGSEGV, logTrace);
    signal(SIGTERM, logTrace);

    Fun();
    return 0;
}

我把常见的几个信号都绑定了logTrace函数,当信号发生时,会先触发这个函数。然后故意搞了个Fun函数访问空指针,触发段错误,看能不能打印回溯信息。

gcc -g -rdynamic trace.c -o trace

事实证明,确实会打印出回溯信息。

Obtained 7 stack frames.
[0] ./trace(logTrace+0x34) [0x55df6c534a6e]
[1] /lib/x86_64-linux-gnu/libc.so.6(+0x3ef10) [0x7f196e15df10]
[2] ./trace(Fun1+0x10) [0x55df6c534b61]
[3] ./trace(Fun+0xe) [0x55df6c534b75]
[4] ./trace(main+0x96) [0x55df6c534c0e]
[5] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f196e140c87]
[6] ./trace(_start+0x2a) [0x55df6c53495a]

从这个信息上看基本能看出来问题出现的大概位置,这样的效果我也是能接受的,但是,为啥我的业务程序加了同样的代码却没有这样的回溯信息呢?于是我把这个程序使用交叉工具编译,上传到arm平台上验证了一下,不验不知道,一验才知道,是!真!的!不!可!以!

代码原封不动,我只是换了交叉工具编译而已。

aarch64-linux-gnu-gcc -g -rdynamic trace.c -o trace

也不知道是什么妖孽在做妖,偏偏为难我这个程序员,它只输出了一句话,和我业务程序的现象一毛一样。

Obtained 1 stack frames.
[0] ./trace(logTrace+0x1c) [0x400ad0]

查了半天才试出来,原来和编译选项有关。在arm平台编译的时候需要加上-funwind-tables -ffunction-sections选项。

aarch64-linux-gnu-gcc -g -rdynamic -funwind-tables -ffunction-sections trace.c -o trace

这样编译出来的程序,才香!

Obtained 7 stack frames.
[0] ./trace(logTrace+0x1c) [0x400ad0]
[1] linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7fb666c66c]
[2] ./trace(Fun1+0x10) [0x400b8c]
[3] ./trace(Fun+0xc) [0x400ba8]
[4] ./trace(main+0xac) [0x400c60]
[5] /lib/libc.so.6(__libc_start_main+0xe4) [0x7fb64f3ce4]
[6] ./trace() [0x4009fc]

这样的效果至少能给点崩溃的信息,有点作用。这两个选项啥意思?附上GCC的说明

-funwind-tables
Similar to -fexceptions, except that it will just generate any needed static data, but will not affect the generated code in any other way. You will normally not enable this option; instead, a language processor that needs this handling would enable it on your behalf.

简单的说,这个选项是会生成一些静态数据,也不会影响正式代码。

-ffunction-sections 
instructs gcc to place each function(including static ones) in its own section named .text.function_name instead of placing all functions in one big .text section.

这个的意思应该是将每个函数或符号创建为一个单独的.text.function_name,而不是放在一个大的.text里。

通常在资源不是特别紧张的时候开启这两个选项没太大问题,但对于资源紧张的情况,可能需要注意以下程序的大小,必要时可以优化以下其他的选项。

这里只是记录一下这个问题,在其他的一些平台我没有试过。结束。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mr_xiaogui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值