Hi Eric. > In sparc systems glibc uses libgcc's unwinder to implement the > backtrace(3) function, defaulting to a simple non-dwarf unwinder if > libgcc_s doesn't provide a working _Unwind_Backtrace. > > However, libgcc's unwinder uses .eh_frame instead of .frame_debug, and > .eh_frame is fully populated only if applications are built with > -fexceptions or -fasynchronous-unwind-tables. > > This patch changes GCC to assume -fasynchronous-unwind-tables by default > in sparcv9 and sparc64, like other ports (notably x86) do. eric@polaris:~/svn/gcc/gcc/common/config> grep -r x_flag_asynchronous_unwind_tables . ./tilegx/tilegx-common.c: opts->x_flag_asynchronous_unwind_tables = 1; ./tilepro/tilepro-common.c: opts->x_flag_asynchronous_unwind_tables = 1; ./i386/i386-common.c: opts->x_flag_asynchronous_unwind_tables = 2; ./s390/s390-common.c: opts->x_flag_asynchronous_unwind_tables = 1; In particular, the 2 means that it's overridden by USE_IX86_FRAME_POINTER, i.e. the frame pointer is always enabled instead (e.g on Solaris).
Ah, so I guess the right value to set in sparc-*-* is 1. What's the problem exactly here? Simple non-DWARF unwinders usually work fine with the SPARC architecture thanks to the calling conventions. Consider the attached test program. When built with -g in sparc64-*-* the resulting binary contains: - A .eh_frame segment containing CFA information for __libc_csu_init and __libc_csu_fini. - A .debug_frame segment containing CFA information for func2, func1 and main. The backtrace(3) implementation for sparc contains a simple unwinder that works well in most cases, but that unwinder is not used if libgcc_s.so can be dlopened and it provides _Unwind_Backtrace. Now, _Unwind_Backtrace uses .eh_frame but not .debug_frame. Thus, backtrace(3) is only useful in programs built with -fasynchronous-unwind-tables even if -g provides CFA info in .debug_frame. I see three solutions to this: - To change glibc in order to not use libgcc's DWARF unwinder. - To expand the libgcc unwinder to use the CFA in .frame_debug. - To change GCC in sparc-*-* to generate fully populated .eh_frame sections by default. (The patch I attempted.)
#include <stdio.h> #include <execinfo.h> int func2() { const int MAXFRAME = 10; void *buffer[MAXFRAME]; int nframes = backtrace(buffer, MAXFRAME); printf("backtrace returned %d frames\n", nframes); return nframes; } void func1() { int num = func2(); printf("func2 returned %d\n", num); return; } int main() { func1(); return 0; }