Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can iterate the stack frames manually in C?

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?

like image 863
karan Avatar asked Oct 15 '25 14:10

karan


1 Answers

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

like image 148
Basile Starynkevitch Avatar answered Oct 17 '25 04:10

Basile Starynkevitch