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

在处理应用程序中的信号时,我可以正确地看到调试器中的回溯.但是回溯系统调用没有正确显示堆栈帧.gdb存储堆栈帧的方式和回溯系统调用如何转储它们有区别吗?

解决方法:

您无法在C99C11中移植迭代堆栈帧.

首先是因为不能保证C标准中有任何call stack. (可以想象一些C编译器进行整个程序分析并避免堆栈,如果它没用,例如,如果不能进行递归;我不知道这样的C编译器).参见例如this C FAQ question用于奇怪的C实现.

然后,因为编译器有时可能会做一些optimizations,例如inline一些调用(甚至是未标记为内联的函数,特别是在请求link-time optimizations并将-flto传递给gcc时),或者有时发出tail-calls(和GCC可以同时执行).您可以禁用优化,但随后会失去很多性能.优化编译器会将一些变量仅放在寄存器中,并为多个变量重用一些堆栈槽.

最后,在一些体系结构(例如32位x86)上,一些代码(特别是一些库代码,例如在libc内)可能用-fomit-frame-pointer编译,然后没有它就无法得到帧信息.

您可以在Ian Taylor Ian Taylor内使用libbacktrace;你也可以使用backtrace(3)backtrace(3)功能;您甚至可以在使用GCC进行编译时使用return address builtins.但是所有这些工具可能无法在优化代码上运行.

实际上,如果你真的需要一些回溯,要么自己实现(我在我过时的MELT系统中做到了,通过在一些本地结构中打包本地,生成了C代码),或者避免优化太多,例如:通过仅使用gcc -g -O1进行编译.

请注意,回溯不是system call(在0​​70019中列出),而是glibc特定的库函数.

还要非常仔细地阅读signal(7)sigreturn(2).很少(异步信号安全)功能可以直接或间接地从信号处理程序调用,并且回溯(或printf)不在其中.在实践中,便携式信号处理程序通常应该只设置一些你应该在别处测试的易失性sigatomic_t标志 – 或者调用siglongjmp(3).

上一篇:TensorFlow入门


下一篇:有没有比使用backtrace()更便宜的方法来查找调用堆栈的深度?