如何在C中手动迭代堆栈帧?

在处理应用程序中的信号时,我可以在debugging器中正确地看到回溯。但是回溯系统调用不能正确显示堆栈帧。gdb如何存储堆栈帧以及回溯系统调用如何转储它们?

Solutions Collecting From Web of "如何在C中手动迭代堆栈帧?"

您不能在C99或C11中轻易地迭代堆栈帧。

首先是因为在C标准中没有任何调用堆栈的保证。 (可以想象一些C编译器在做整个程序分析,并且避免了堆栈的使用,例如,如果递归不能发生;我不知道这样的C编译器)。 看看例如这个C常见问题奇怪的C实现。

然后,因为编译器有时可能会做一些优化 ,例如内联某些调用(即使是没有inline标记的函数,特别是在使用-flto传递给gcc时要求链接时优化 ),或者有时会发出tail call (和GCC can做两个)。 您可以禁用优化,但是那样会失去很多性能。 一个优化的编译器会把一些变量放在寄存器中,并为一些变量重用一些栈槽。

最后,在某些体系结构(例如32位x86)上,某些代码(特别是某些库代码,例如libc内部)可能会使用-fomit-frame-pointer进行编译,如果没有它,则无法获取帧信息。

你可以在GCC里面使用Ian Taylor的libbacktrace ; 你也可以使用GNU glibc的backtrace(3)函数; 你甚至可以用GCC编译时使用的内置返回地址 。 但所有这些工具可能无法在优化的代码上工作。

实际上,如果你真的需要一些回溯,或者自己实现(我在我的MELT系统中,通过在本地struct包装本地代码来生成C ++代码),或者避免优化太多,例如通过编译gcc -g -O1只。

请注意, backtrace 不是 系统调用 (在syscalls(2)中列出),而是glibc特定的库函数。

请仔细阅读信号(7)和信号(2) 。 信号处理程序可以可靠地(直接或间接)调用(异步信号安全)功能,而且backtrace (或printf不在其中。 在实践中,一个便携式信号处理器通常应该设置一些你应该在别处测试的volatile sigatomic_t标志,或者调用siglongjmp(3) 。

当您使用-g选项时,调试器会使用由gcc编译器放置在二进制文件中的额外数据集。 该数据不被回溯调用使用,只使用基本链接器信息。 这意味着例如任何静态数据都不能通过回溯查看,而是通过gdb,这也导致各种优化打破回溯,gdb通过显式知识工作。

请记住,gdb是特定于某种语言和编译器的,而backtrace则更具可移植性。

请参阅http :// tradetrace http://linux.die.net/man/3/backtrace的手册页:

忽略帧指针(如gcc(1)的非零优化级别所暗示的)可能会导致这些假设被违反。

如果回溯调用想要使用这个信息,它将不得不强制你总是用调试符号进行编译,并会有更多的开销和许多其他问题。

问题可能是,在回溯执行的时候,堆栈可能已经坏了。

只要在函数中取一个局部变量的地址即可。 计算堆栈大小。 从本地变量地址添加它并将其添加到位置变量地址之间。

你有你的堆栈打印:)