How can iterate the stack frames manually in C?

1.9k views Asked by At

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?

3

There are 3 answers

0
Basile Starynkevitch On BEST ANSWER

You cannot portably iterate through the stack frames in C99 or C11.

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.

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.

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.

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.

In practical terms, if you really need some backtrace, either implement that yourself (I did that in my obsolete 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.

Notice that backtrace is not a system call (listed in syscalls(2)) but a glibc-specific library function.

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).

0
Vality On

The debugger uses an additional set of extra data placed into the binary by the compiler by gcc when you use the -g option. This data is not used by the backtrace call and only the basic linker information is used. This means for example any static data is not viewable by the backtrace but is by gdb, this also results in various optimizations breaking backtrace which gdb works around through explicit knowledge.

Remember, gdb is specific to a certain language and compiler while backtrace is much more portable.

See the man page of backtrace http://linux.die.net/man/3/backtrace:

Omission of the frame pointers (as implied by any of gcc(1)'s nonzero optimization levels) may cause these assumptions to be violated.

If the backtrace call wanted to use this information it would have to force you to always compile with debug symbols and would have much greater overhead and many other issues.

0
Santhosh Kumar On

The problem might be, by the time backtrace is exectued you stack might have been bady corrupted.

Just take a address of local variable in the function. Calculate the stack size . add it from the the local variable address and print those inbetween the addition and location variable address;.

you got your stack printed :)