如何可以在C手动遍历堆栈帧? [英] How can iterate the stack frames manually in C?
问题描述
虽然在处理信号的应用,我可以正确地看到debugger.But回溯回溯系统调用没有显示的堆栈帧correctly.Is那里的回溯系统调用如何存储gdb的栈帧以及如何转储它们有区别吗?
While handling signals in applications I can correctly see the backtrace in the debugger.But the backtrace system call is not showing the stack frames correctly.Is there a difference in how gdb stores stack frames and how the backtrace system call dumps them?
推荐答案
You cannot portably iterate thru the stack frames in C99 or C11.
首先,因为没有任何调用堆栈的保证。 (人们可以想象一些C编译器做整个程序分析和避免堆栈,如果它是无用的,例如如果不能发生递归;我不知道有这样的C编译器)。例如参见这款C FAQ问题以怪异的C实现。
First because there is no guarantee of any call stack in the C standard. (one could imagine some C compiler doing whole program analysis and avoiding the stack if it is useless, e.g. if recursion cannot occur; I know no such C compiler). See e.g. this C FAQ question for weird C implementations.
然后,因为编译器有时会做一些优化,例如直列一些电话(甚至没有标明功能在线
,特别是当要求链接时优化,提供 -flto
传递给 GCC
),或有时发出的尾通话(和 GCC 都可以做)。你可以禁用优化,但你失去了很多的性能。一个优化的编译器会把一些变量只在登记和重用某些堆栈插槽几个变量。
Then, because the compiler might sometimes do some optimizations, e.g. inline some calls (even to functions not marked inline
, in particular when asking for link-time optimizations with -flto
passed to gcc
), or sometimes emit tail-calls (and GCC can do both). You could disable the optimizations, but then you lose a lot of performance. An optimizing compiler would put some variables only in registers and reuse some stack slots for several variables.
最后,在一些系统上(如32位的x86),一些code(尤其是某些库code,如的 libc中)可能与 -fomit-frame-pointer的
进行编译,然后就没有办法让帧信息离不开它。
At last, on some architectures (e.g. 32 bits x86), some code (in particular some library code, e.g. inside libc) might be compiled with -fomit-frame-pointer
and then there is no way to get frame information without it.
您可以使用 libbacktrace
通过伊恩·泰勒的里面的 GCC ;你也可以使用回溯(3)从功能<一个HREF =http://www.gnu.org/software/libc/libc.html相对=nofollow> GNU的glibc ;你甚至可以使用与返回的 =http://gcc.gnu.org/相对=nofollow> GCC 。但是,所有这些工具可能无法在优化code工作。
You could use the libbacktrace
by Ian Taylor inside GCC; you could also use the backtrace(3) function from GNU glibc; you might even use the return address builtins available when compiling with GCC. But all these tools might not work on optimized code.
在实践中,如果你真的需要一些回溯,可以实施自己(我做的,在我的 MELT 一>系统,它的C ++ code产生,在一些地方结构
),或避免包装当地人优化太多,如通过 GCC编译-g -O1
仅
In practical terms, if you really need some backtrace, either implement that yourself (I am doing that in my MELT system, whose C++ code is generated, by packing locals in some local struct
), or avoid optimizing too much, e.g. by compiling with gcc -g -O1
only.
注意回溯
是的不的一个的系统调用(在系统调用上市(2) ),但的glibc
特异性的库函数。
Notice that backtrace
is not a system call (listed in syscalls(2)) but a glibc
-specific library function.
阅读也很仔细信号(7)和< A HREF =http://man7.org/linux/man-pages/man2/sigreturn.2.html相对=nofollow> sigreturn(2)。有能可靠地从信号处理(直接或间接)称为极少数(异步信号安全)功能,以及回溯
(或的printf
)是的不的在他们之中。在实践中,便携式信号处理程序应往往只是设置一些你应该在别处测试挥发性sigatomic_t
标志 - 或致电的 siglongjmp(3)。
Read also very carefully signal(7) and sigreturn(2). There are very few (async-signal-safe) functions which can reliably be called (directly or indirectly) from signal handlers, and backtrace
(or printf
) is not amongst them. In practice a portable signal handler should often just set some volatile sigatomic_t
flag which you should test elsewhere - or call siglongjmp(3).
这篇关于如何可以在C手动遍历堆栈帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!