在ARM平台上没有SIGABRT信号的回溯吗? [英] No backtrace from SIGABRT signal on ARM platform?

查看:197
本文介绍了在ARM平台上没有SIGABRT信号的回溯吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在信号处理程序中使用' backtrce()'和' backtrace_symbols_fd()'函数来生成用于调试的回溯(GDB不可用).

I'm using 'backtrce()' and 'backtrace_symbols_fd()' functions in a signal handler to generate a backtrace for debugging (GDB not available).

它们在x86桌面版(Ubuntu)上可以正常工作,但是在目标设备(基于ARM)上,Abort信号的回溯(由于双重释放错误)仅显示三个帧:信号处理程序还有两个来自libc,这对调试我们的代码没有用!SEGV上的回溯(例如使用错误的指针)确实会产生良好的回溯.

They work fine on x86 desktop (Ubuntu), but on the target device (ARM based) the backtrace on Abort signal (due to double-free error) shows only three frames: the signal handler and two from within libc, which is not useful for debugging our code! Backtrace on SEGV (e.g. using a bad pointer) DOES produce a good backtrace.

为什么在ARM上无法获得关于ABRT信号的有用回溯?

Why can't I get a useful backtrace on ABRT signal on ARM?

[为清楚起见,问题已编辑]

[Question edited for clarity]

这是一个演示问题的简单测试程序:

Here's a simple test program which demonstrates the problem:

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// Signal hangler to catch seg fault:
void handler_segv(int sig) {
    // get void*'s for all entries on the stack
    void *array[10];
    size_t size;
    size = backtrace(array, 10);
    fprintf(stderr, "Error: Signal %d; %d frames found:\n", sig, size);
    // print out all the frames to stderr
    backtrace_symbols_fd(array, size, STDERR_FILENO);
    exit(1);
}


void crashme()
{
  // Deliberate Error: Abort (double free):
  char *test_ptr = malloc(1);
  free(test_ptr);
  free(test_ptr);
  // Deliberate Error #2: Seg fault:
  //char * p = NULL;
  //*p = 0;
}

void foo()
{
    fprintf(stdout, "---->About to crash...\n");
    crashme();
    fprintf(stdout, "---->Crashed (shouldn't get to here)...\n");
}



// Main entry point:
int main(int argc, char *argv[])
{
    fprintf(stdout, "Application start...\n");

    // Install signal handlers:
    fprintf(stdout, "-->Adding handler for SIGSEGV and SIGABRT\n");
    signal(SIGSEGV, handler_segv);
    signal(SIGABRT, handler_segv);

    fprintf(stdout, "-->OK. Causing Error...\n");
    foo();
    fprintf(stdout, "-->Test finished (shouldn't get to here!)\n");
    return 0;
}

这是为x86编译的,如下所示:

This was compiled for x86 as follows:

gcc -o test test-backtrace-simple.c -g -rdynamic

对于ARM:

arm-none-linux-gnueabi-gcc -o test-arm test-backtrace-simple.c -g -rdynamic -O0 -mapcs-frame -funwind-tables -fasynchronous-unwind-tables

我已经为ARM使用了各种编译器选项,如与在ARM上生成回溯相关的其他文章中所述.

I've used various compiler options for ARM as described in other posts related to generating backtraces on ARM.

在x86桌面上运行时,它会产生带有大量调试的预期输出,结尾为:

When run on the x86 desktop, it generates the expected output with plenty of debug, ending in:

Error: Signal 6; 10 frames found: 
./test(handler_segv+0x19)[0x80487dd]
[0xb7745404] 
[0xb7745428]
/lib/i386-linux-gnu/libc.so.6(gsignal+0x4f)[0xb75b0e0f]
/lib/i386-linux-gnu/libc.so.6(abort+0x175)[0xb75b4455]
/lib/i386-linux-gnu/libc.so.6(+0x6a43a)[0xb75ed43a]
/lib/i386-linux-gnu/libc.so.6(+0x74f82)[0xb75f7f82]
./test(crashme+0x2b)[0x8048855] 
./test(foo+0x33)[0x804888a]
./test(main+0xae)[0x8048962]

(即,由我的处理程序生成的后向跟踪,我的函数调用位于底部).

(i.e. the back trace generated by my handler, with my function calls at the bottom).

但是,在ARM平台上运行时,我得到:

However, when run on the ARM platform, I get:

Application start...
-->Adding handler for SIGSEGV and SIGABRT
-->OK. Causing Error...
---->About to crash...
*** Error in `/opt/bin/test-arm': double free or corruption (fasttop): 0x015b6008 ***
Error: Signal 6; 3 frames found:
/opt/bin/test-arm(handler_segv+0x24)[0x8868]
/lib/libc.so.6(__default_sa_restorer_v2+0x0)[0xb6e6c150]
/lib/libc.so.6(gsignal+0x34)[0xb6e6af48]

backtrace()仅找到3帧,它们只是信号处理程序和libc中的内容(无用)!

The backtrace() finds only 3 frames, and they are only the signal handler and something in libc (not useful)!

我找到了一个邮件列表帖子,上面写着:

I found a mailing list post which said:

如果与调试C库-lc_g链接,则将进行调试信息返回过去abort().

If you link with the debugging C library, -lc_g, you'll get debugging info back past abort().

这可能是相关的,但是-lc_g在我的编译器上不起作用(ld:找不到-lg_c).

This might be relevant, but -lc_g doesn't work on my compiler (ld: cannot find -lg_c).

如果我生成段错误,则backtrace在ARM上工作正常(例如,将crashme()函数更改为使用"char * p = NULL; * p = 0;"而不是double free.

The backtrace works fine on ARM if I generate a seg fault instead (e.g. change crashme() function to use "char *p = NULL; *p = 0;" instead of the double free.

是否有其他回溯方式的想法或建议?

Any ideas or suggestions for other ways to get a back trace?

[-EDIT-]

我按照注释中的建议尝试了一些MALLOC_CHECK_选项,但唯一的效果是更改了是否生成异常终止.这是ARM上的三个运行的输出:

I tried some MALLOC_CHECK_ options as suggested in the comments, but the only effect was to change whether the abort was generated. Here is the output from three runs on the ARM:

 # MALLOC_CHECK_=0 /opt/bin/test-arm
Application start...
-->Adding handler for SIGSEGV and SIGABRT
-->OK. Causing Error...
---->About to crash...
---->Crashed (shouldn't get to here)...
-->Test finished (shouldn't get to here!)


# MALLOC_CHECK_=1 /opt/bin/test-arm
Application start...
-->Adding handler for SIGSEGV and SIGABRT
-->OK. Causing Error...
---->About to crash...
*** Error in `/opt/bin/test-arm': free(): invalid pointer: 0x015b2008 ***
---->Crashed (shouldn't get to here)...
-->Test finished (shouldn't get to here!)


# MALLOC_CHECK_=2 /opt/bin/test-arm
Application start...
-->Adding handler for SIGSEGV and SIGABRT
-->OK. Causing Error...
---->About to crash...
Error: Signal 6; 3 frames found:
/opt/bin/test-arm(handler_segv+0x24)[0x8868]
/lib/libc.so.6(__default_sa_restorer_v2+0x0)[0xb6e24150]
/lib/libc.so.6(gsignal+0x34)[0xb6e22f48]
#

MALLOC_CHECK_ = 0:无错误消息(双倍空闲将被忽略!)

MALLOC_CHECK_=0: No error message (double free is ignored!)

MALLOC_CHECK_ = 1:错误消息,但是程序继续

MALLOC_CHECK_=1: Error message, but program continues

MALLOC_CHECK_ = 2:错误消息和ABRT信号;产生了无用的回溯(这是默认行为!)

MALLOC_CHECK_=2: Error message and ABRT signal; useless backtrace generated (this is the default behaviour!)

我的交叉编译器报告:gcc版本4.6.1(Sourcery CodeBench Lite 2011.09-70)目标设备具有Linux内核版本3.8.8

My cross compiler reports: gcc version 4.6.1 (Sourcery CodeBench Lite 2011.09-70) Target device has linux kernel version 3.8.8

推荐答案

看来您已经做了大量研究,知道您需要开关 -funwind-tables -fasynchronous-unwind-tables 在编译器命令行中.实际上,它们中的任何一个似乎都足够,但是如果没有它们的回溯,显然是行不通的.现在,诸如SIGABRT之类的问题是回溯必须遍历由libc函数(如 abort gsignal )生成的堆栈帧,并且由于未构建lib而失败这些开关中的任何一个(我所知道的任何分布).

It appears you have done sufficient research to know that you need the switches -funwind-tables and -fasynchronous-unwind-tables in your compiler command line. In practice either one of them seems sufficient but clearly without them backtracing doesn't work at all. Now, the trouble with things like SIGABRT is that the backtrace must traverse stack frames that were generated by libc functions such as abort and gsignal, and fails because that lib is not built with either of those switches (in any distribution that I know of).

虽然恳求Sourcery CodeBench的维护者使用该选项构建他们的发行版是很好的,但是唯一的直接解决方案是自己构建libc,同时设置这两个标志中的一个或两个(根据我的经验,-funwind-tables 就足够了).如果还需要堆栈跟踪以捕获未处理的异常(通过 std :: set_terminate ),则还需要重建libstdc ++.

While it would be nice to petition the maintainers of Sourcery CodeBench to build their distribution with that option, the only immediate solution is to build libc yourself, with either or both of those flags set (in my experience just -funwind-tables is enough). If you also need a stack trace in case of catching an unhandled exception (via std::set_terminate) then you will also need to rebuild libstdc++.

在我的工作场所中,我们都需要回溯这两种情况(SIGABRT和未处理的异常),并且由于libstdc ++是工具链的一部分,因此我们自己重新构建了工具链.工具 crosstool-NG 使此操作相对容易.在配置实用程序 ./ct-ng menuconfig 中,我们输入了 Target Options 部分,并编辑了 Target CFLAGS (将构建变量TARGET_CFLAGS设置为 -funwind-tables .生成的工具链(更具体地说,使用生成的工具链中的libc和libstdc ++)为我们提供了几乎所有情况下的完整回溯.

At my workplace we needed backtraces for both cases (SIGABRT and unhandled exceptions), and since libstdc++ is part of the toolchain we rebuilt the toolchain ourselves. The tool crosstool-NG makes this relatively easy to do. In the configuration utility ./ct-ng menuconfig we entered section Target Options and edited Target CFLAGS (which sets the build variable TARGET_CFLAGS) to -funwind-tables. The resulting toolchain (more specifically, using the libc and libstdc++ from the resulting toolchain build) provides us with a full backtrace in nearly all cases.

我发现了一种情况,我们仍然没有得到完整的追溯:如果崩溃发生在最初用汇编语言编写的函数中,例如 memcpy (不幸的是,这不是罕见的情况).也许需要将一些选项传递给汇编器,但是我没有时间进一步研究.

I've found one case where we still don't get a full backtrace: if the crash occurred within a function that originally is written in assembly, such as memcpy (unfortunately this is not an uncommon occurrence). Perhaps some option needs to be passed to the assembler, but I didn't have the time to investigate this further.

这篇关于在ARM平台上没有SIGABRT信号的回溯吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆