首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何获取调用堆栈回溯?(深度嵌入,无库支持)

如何获取调用堆栈回溯?(深度嵌入,无库支持)
EN

Stack Overflow用户
提问于 2010-08-04 00:38:10
回答 6查看 16.9K关注 0票数 20

我希望我的异常处理程序和调试函数能够打印调用堆栈回溯,基本上就像glibc中的backtrace()库函数一样。不幸的是,我的C库(Newlib)没有提供这样的调用。

我得到了类似这样的东西:

代码语言:javascript
复制
#include <unwind.h> // GCC's internal unwinder, part of libgcc
_Unwind_Reason_Code trace_fcn(_Unwind_Context *ctx, void *d)
{
    int *depth = (int*)d;
    printf("\t#%d: program counter at %08x\n", *depth, _Unwind_GetIP(ctx));
    (*depth)++;
    return _URC_NO_REASON;
}

void print_backtrace_here()
{
    int depth = 0;
    _Unwind_Backtrace(&trace_fcn, &depth);
}

这基本上是有效的,但产生的跟踪并不总是完整的。例如,如果我这样做了

代码语言:javascript
复制
int func3() { print_backtrace_here(); return 0; }
int func2() { return func3(); }
int func1() { return func2(); }
int main()  { return func1(); }

回溯只显示func3()和main()。(这是obv。一个玩具示例,但我检查了反汇编,并确认这些函数在这里都是完整的,没有优化或内联。)

更新:我在旧的ARM7系统上尝试了这个回溯代码,但是使用了相同的(或者至少是尽可能等效的)编译器选项和链接器脚本,它输出了一个正确的、完整的回溯(即func1和func2没有丢失),实际上它甚至回溯到引导初始化代码中。因此,问题大概不在于链接器脚本或编译器选项。(此外,通过反汇编确认在此ARM7测试中也未使用帧指针)。

代码是使用-fomit- frame -pointer编译的,但是我的平台(裸机ARM Cortex M3)定义了一个不使用帧指针的ABI。(这个系统的前一个版本在ARM7上使用了旧的APCS ABI,带有强制堆栈帧和帧指针,以及一个像here这样的回溯,它工作得很好)。

整个系统是用-fexception编译的,这确保了_Unwind使用的必要元数据包含在ELF文件中。(我认为_Unwind是为异常处理而设计的)。

所以,我的问题是:在使用GCC的嵌入式系统中,是否有一种“标准”的、公认的方法来获得可靠的回溯?

如果有必要,我不介意摆弄链接器脚本和crt0代码,但我不想给工具链本身带来任何机会。

谢谢!

EN

回答 6

Stack Overflow用户

发布于 2011-08-05 03:07:27

为此,您需要在某些目标中使用-funwind-tables-fasynchronous-unwind-tables,这是_Unwind_Backtrace正常工作所必需的!

票数 10
EN

Stack Overflow用户

发布于 2010-08-04 00:57:58

由于ARM平台不使用帧指针,因此您永远不会确切地知道栈帧有多大,并且不能简单地将栈转出到R14中的单个返回值之外。

在调查没有调试符号的崩溃时,我们只需转储整个堆栈,并查找与指令范围内的每一项最接近的符号。它确实会产生大量的误报,但对于调查崩溃仍然非常有用。

如果您运行的是纯ELF可执行文件,则可以将调试符号从发布的可执行文件中分离出来。然后,gdb可以帮助您找出标准unix核心转储中发生的事情。

票数 8
EN

Stack Overflow用户

发布于 2010-08-04 00:40:25

gcc确实做了返回优化。在func1()和func2()中,它不调用func2()/func3(),而是跳转到func2()/func3(),因此func3()可以立即返回到main()。

在您的示例中,func1()和func2()不需要设置堆栈帧,但是如果它们需要设置堆栈帧(例如,对于局部变量),如果函数调用是最后一条指令,则gcc仍然可以进行优化-它然后在跳转到func3()之前清理堆栈。

请看一下生成的汇编代码以了解它。

编辑/更新:

要验证这就是原因,请在函数调用后执行一些无法由编译器重新排序的操作(例如,使用返回值)。或者尝试使用-O0进行编译。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3398664

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档