diff mbox

[SPARC] sparc: switch -fasynchronous-unwind-tables on by default.

Message ID 1456435447-23676-1-git-send-email-jose.marchesi@oracle.com
State New
Headers show

Commit Message

Jose E. Marchesi Feb. 25, 2016, 9:24 p.m. UTC
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.

Tested in both sparcv9-*-* and sparc64-*-* targets.

       * common/config/sparc/sparc-common.c (sparc_option_init_struct):
         New function.
         (TARGET_OPTION_INIT_STRUCT): Defined.
---
 gcc/ChangeLog                          |  6 ++++++
 gcc/common/config/sparc/sparc-common.c | 10 ++++++++++
 2 files changed, 16 insertions(+)

Comments

Eric Botcazou Feb. 28, 2016, 6:35 p.m. UTC | #1
> 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.
Jose E. Marchesi Feb. 29, 2016, 3:50 p.m. UTC | #2
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.)
Eric Botcazou March 9, 2016, 10:02 a.m. UTC | #3
> 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?
Jose E. Marchesi March 15, 2016, 4:46 p.m. UTC | #4
> 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).
Richard Henderson March 17, 2016, 9:14 p.m. UTC | #5
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~
Jose E. Marchesi March 18, 2016, 12:41 a.m. UTC | #6
> 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 mbox

Patch

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