Message ID | 1456435447-23676-1-git-send-email-jose.marchesi@oracle.com |
---|---|
State | New |
Headers | show |
> 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). What's the problem exactly here? Simple non-DWARF unwinders usually work fine with the SPARC architecture thanks to the calling conventions.
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.)
> 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. How does that work for e.g. PowerPC or MIPS? Why not do the same for SPARC?
> 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. How does that work for e.g. PowerPC or MIPS? Why not do the same for SPARC? The glibc PowerPC port doesn't use the libgcc_s unwinder to implement backtrace(). It has a little ad-hoc unwinder. MIPS is like x86_64: it exclusively relies on libgcc_s _Unwind_Backtrace to unwind the stack. As far as I can tell, -fasynchronous-unwind-tables is disabled in MIPS by default. Therefore unless -fasynchronous-unwind-tables is used at build time backtrace() probably has the same problem than sparc (can't tell for sure, as I don't have access to any mips host where to test).
On 02/29/2016 07:50 AM, Jose E. Marchesi wrote: > 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. There's no reason that simple unwinder can't be put into MD_FALLBACK_FRAME_STATE_FOR. Currently we only use that for unwinding through signal stacks, but it could be used for anything that the dwarf2 unwinder doesn't have data for. Given sparc register windows, this seems particularly reliable. r~
> 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. There's no reason that simple unwinder can't be put into MD_FALLBACK_FRAME_STATE_FOR. Currently we only use that for unwinding through signal stacks, but it could be used for anything that the dwarf2 unwinder doesn't have data for. Given sparc register windows, this seems particularly reliable. Sounds like a good idea. Let me prepare a patch for that...
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3a13f5f..ba7befe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-02-25 Jose E. Marchesi <jose.marchesi@oracle.com> + + * common/config/sparc/sparc-common.c (sparc_option_init_struct): + New function. + (TARGET_OPTION_INIT_STRUCT): Defined. + 2016-02-25 Richard Biener <rguenther@suse.de> PR tree-optimization/48795 diff --git a/gcc/common/config/sparc/sparc-common.c b/gcc/common/config/sparc/sparc-common.c index 3958b7e..1c5bc06 100644 --- a/gcc/common/config/sparc/sparc-common.c +++ b/gcc/common/config/sparc/sparc-common.c @@ -24,6 +24,14 @@ along with GCC; see the file COPYING3. If not see #include "common/common-target.h" #include "common/common-target-def.h" +/* Implement TARGET_OPTION_INIT_STRUCT. */ + +static void +sparc_option_init_struct (struct gcc_options *opts) +{ + opts->x_flag_asynchronous_unwind_tables = 2; +} + /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ static const struct default_options sparc_option_optimization_table[] = { @@ -31,6 +39,8 @@ static const struct default_options sparc_option_optimization_table[] = { OPT_LEVELS_NONE, 0, NULL, 0 } }; +#undef TARGET_OPTION_INIT_STRUCT +#define TARGET_OPTION_INIT_STRUCT sparc_option_init_struct #undef TARGET_DEFAULT_TARGET_FLAGS #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT #undef TARGET_OPTION_OPTIMIZATION_TABLE