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

查看:56
本文介绍了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).

如果我生成一个段错误,则回溯在 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?

[--编辑--]

我按照评论中的建议尝试了一些 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 函数(例如 abortgsignal)生成的堆栈帧,并且由于未构建该 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天全站免登陆