Patchwork [RFC/CFT] Hookize TARGET_UNWIND_INFO and related macros

login
register
mail settings
Submitter Richard Henderson
Date Sept. 8, 2010, 8:22 p.m.
Message ID <4C87F095.3020007@redhat.com>
Download mbox | patch
Permalink /patch/64204/
State New
Headers show

Comments

Richard Henderson - Sept. 8, 2010, 8:22 p.m.
On 09/08/2010 01:18 PM, Richard Henderson wrote:
> I'll be away until next Tuesday (14 Sep), but I would greatly
> appreciate comments in the meantime.

Bah.  Of course it would help to attach the thing.


r~
Makefile.in              |    2 
 ada/gcc-interface/misc.c |    2 
 c-family/c-cppbuiltin.c  |    2 
 config/arm/arm.c         |   58 ++++++++++++++++++++------
 config/arm/arm.h         |   16 +------
 config/arm/bpabi.h       |    3 -
 config/ia64/ia64.c       |   61 +++++++++++++++++++++++++---
 config/ia64/ia64.h       |    8 ---
 config/pa/pa.c           |    2 
 cp/Make-lang.in          |    2 
 cp/cp-lang.c             |   22 +++++-----
 defaults.h               |   50 +----------------------
 doc/tm.texi              |   60 +++++++++++++++++++--------
 doc/tm.texi.in           |   60 +++++++++++++++++++--------
 dwarf2out.c              |  101 +++++++++++++++++++++--------------------------
 except.c                 |   18 +++++---
 final.c                  |   26 +-----------
 function.c               |    5 +-
 java/Make-lang.in        |    3 -
 java/lang.c              |    3 -
 objc/objc-act.c          |    2 
 objcp/Make-lang.in       |    2 
 objcp/objcp-lang.c       |    3 -
 opts.c                   |   39 ++++++++----------
 system.h                 |    2 
 target.def               |   14 ++++++
 target.h                 |   10 ++++
 targhooks.c              |   69 ++++++++++++++++++++++++++++++++
 targhooks.h              |    5 ++
 tree-tailcall.c          |    4 +
 tree.c                   |    4 -
 31 files changed, 404 insertions(+), 254 deletions(-)
Steve Ellcey - Sept. 17, 2010, 6:02 p.m.
Richard,

I finally has some time to test this patch on IA64 HP-UX and Linux and I
got build failures on both systems.  Using a preprocessed version of
libgcov.c I see:

 $ obj_gcc/gcc/cc1 -mlp64 -O2 -g -quiet x.i
x.i: In function 'gcov_exit':
x.i:3169:1: internal compiler error: in dwarf2out_frame_debug_expr, at
dwarf2out.c:2304
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

Looks like it is failing on this assert:

             /* Saving a register in a register.  */
              gcc_assert (!fixed_regs [REGNO (dest)]
                          /* For the SPARC and its register window.  */
                          || (DWARF_FRAME_REGNUM (REGNO (src))
                              == DWARF_FRAME_RETURN_COLUMN));

It looks like both src and dest are:

(reg/f:DI 12 r12)

and r12 is listed in FIXED_REGISTERS as the stack pointer.

Steve Ellcey
sje@cup.hp.com
Richard Henderson - Sept. 17, 2010, 6:20 p.m.
On 09/17/2010 11:02 AM, Steve Ellcey wrote:
> Richard,
> 
> I finally has some time to test this patch on IA64 HP-UX and Linux and I
> got build failures on both systems.  Using a preprocessed version of
> libgcov.c I see:
> 
>  $ obj_gcc/gcc/cc1 -mlp64 -O2 -g -quiet x.i
> x.i: In function 'gcov_exit':
> x.i:3169:1: internal compiler error: in dwarf2out_frame_debug_expr, at
> dwarf2out.c:2304
> Please submit a full bug report,
> with preprocessed source if appropriate.
> See <http://gcc.gnu.org/bugs.html> for instructions.
> 
> Looks like it is failing on this assert:
> 
>              /* Saving a register in a register.  */
>               gcc_assert (!fixed_regs [REGNO (dest)]
>                           /* For the SPARC and its register window.  */
>                           || (DWARF_FRAME_REGNUM (REGNO (src))
>                               == DWARF_FRAME_RETURN_COLUMN));

Hum.  So it looks like we'd be much better off if we could eliminate

  /* We want to emit correct CFA location expressions or lists, so we
     have to return true if we're going to output debug info, even if
     we're not going to output frame or unwind info.  */

Assuming we have dwarf3, and the use of DW_OP_call_frame_cfa, then
we don't need to generate those location lists.  What do you think
of forcing dwarf_version >= 3 for IA-64?  Would that cripple hpux?


r~
Steve Ellcey - Sept. 17, 2010, 6:30 p.m.
On Fri, 2010-09-17 at 11:20 -0700, Richard Henderson wrote:

> Hum.  So it looks like we'd be much better off if we could eliminate
> 
>   /* We want to emit correct CFA location expressions or lists, so we
>      have to return true if we're going to output debug info, even if
>      we're not going to output frame or unwind info.  */
> 
> Assuming we have dwarf3, and the use of DW_OP_call_frame_cfa, then
> we don't need to generate those location lists.  What do you think
> of forcing dwarf_version >= 3 for IA-64?  Would that cripple hpux?
> 
> 
> r~

It would cripple HP-UX.  The problem is that the open soure gdb was
never ported to IA64 HP-UX and we just use the HP provided version and
that doesn't support dwarf 3.

Steve Ellcey
sje@cup.hp.com
Tristan Gingold - Sept. 20, 2010, 7:23 a.m.
On Sep 17, 2010, at 8:30 PM, Steve Ellcey wrote:

> On Fri, 2010-09-17 at 11:20 -0700, Richard Henderson wrote:
> 
>> Hum.  So it looks like we'd be much better off if we could eliminate
>> 
>>  /* We want to emit correct CFA location expressions or lists, so we
>>     have to return true if we're going to output debug info, even if
>>     we're not going to output frame or unwind info.  */
>> 
>> Assuming we have dwarf3, and the use of DW_OP_call_frame_cfa, then
>> we don't need to generate those location lists.  What do you think
>> of forcing dwarf_version >= 3 for IA-64?  Would that cripple hpux?
>> 
>> 
>> r~
> 
> It would cripple HP-UX.  The problem is that the open soure gdb was
> never ported to IA64 HP-UX and we just use the HP provided version and
> that doesn't support dwarf 3.

We (= AdaCore) have ported gdb to ia64/hp-ux, and AFAIK Joel plan to submitted it around Xmas.
So this path is not completely closed.

Tristan.
Joel Brobecker - Sept. 20, 2010, 7:44 a.m.
> We (= AdaCore) have ported gdb to ia64/hp-ux, and AFAIK Joel plan to
> submitted it around Xmas.  So this path is not completely closed.

Small correction: We ported gdb-6.3, and never made the effort of
moving to more recent baselines. I am planning on using my Xmas break
to redo the porting effort, based on the work done on 6.3. There were
a couple of hacks back then that I wasn't very happy with, and I think
I know how it's supposed to work, now.

Patch

diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 17fcd4b..325af1a 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8738,7 +8738,8 @@  The default is that no label is emitted.
 
 @hook TARGET_ASM_UNWIND_EMIT
 This target hook emits assembly directives required to unwind the
-given instruction.  This is only used when TARGET_UNWIND_INFO is set.
+given instruction.  This is only used when @code{TARGET_EXCEPT_UNWIND_INFO}
+returns @code{UI_TARGET}.
 @end deftypefn
 
 @hook TARGET_ASM_UNWIND_EMIT_BEFORE_INSN
@@ -8787,23 +8788,32 @@  that it does not contain any extraneous set bits in it.
 Define this macro to 0 if your target supports DWARF 2 frame unwind
 information, but it does not yet work with exception handling.
 Otherwise, if your target supports this information (if it defines
-@samp{INCOMING_RETURN_ADDR_RTX} and either @samp{UNALIGNED_INT_ASM_OP}
-or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of 1.
+@code{INCOMING_RETURN_ADDR_RTX} and either @code{UNALIGNED_INT_ASM_OP}
+or @code{OBJECT_FORMAT_ELF}), GCC will provide a default definition of 1.
+@end defmac
 
-If @code{TARGET_UNWIND_INFO} is defined, the target specific unwinder
-will be used in all cases.  Defining this macro will enable the generation
-of DWARF 2 frame debugging information.
+@hook TARGET_EXCEPT_UNWIND_INFO
+This hook defines the mechanism that will be used for exception handling
+by the target.  If the target has ABI specified unwind tables, the hook
+should return @code{UI_TARGET}.  If the target is to use the
+@code{setjmp}/@code{longjmp}-based exception handling scheme, the hook
+should return @code{UI_SJLJ}.  If the target supports DWARF 2 frame unwind
+information, the hook should return @code{UI_DWARF2}.
 
-If @code{TARGET_UNWIND_INFO} is not defined, and this macro is defined to 1,
-the DWARF 2 unwinder will be the default exception handling mechanism;
-otherwise, the @code{setjmp}/@code{longjmp}-based scheme will be used by
-default.
-@end defmac
+A target may, if exceptions are disabled, choose to return @code{UI_NONE}.
+This may end up simplifying other parts of target-specific code.  The
+default implementation of this hook never returns @code{UI_NONE}.
 
-@defmac TARGET_UNWIND_INFO
-Define this macro if your target has ABI specified unwind tables.  Usually
-these will be output by @code{TARGET_ASM_UNWIND_EMIT}.
-@end defmac
+Note that the value returned by this hook should be constant.  It should
+not depend on anything except command-line switches.  In particular, the
+setting @code{UI_SJLJ} must be fixed at compiler start-up as C pre-processor
+macros and builtin functions related to exception handling are set up
+depending on this setting.
+
+The default implementation of the hook first honors the
+@option{--enable-sjlj-exceptions} configure option, then
+@code{DWARF2_UNWIND_INFO}, and finally defaults to @code{UI_SJLJ}.
+@end deftypefn
 
 @hook TARGET_UNWIND_TABLES_DEFAULT
 This variable should be set to @code{true} if the target ABI requires unwinding
@@ -9312,11 +9322,25 @@  as appropriate from @code{TARGET_ASM_FUNCTION_PROLOGUE} if you don't.
 
 @defmac DWARF2_FRAME_INFO
 Define this macro to a nonzero value if GCC should always output
-Dwarf 2 frame information.  If @code{DWARF2_UNWIND_INFO}
-(@pxref{Exception Region Output} is nonzero, GCC will output this
-information not matter how you define @code{DWARF2_FRAME_INFO}.
+Dwarf 2 frame information.  If @code{TARGET_EXCEPT_UNWIND_INFO}
+(@pxref{Exception Region Output}) returns @code{UI_DWARF2}, and
+exceptions are enabled, GCC will output this information not matter
+how you define @code{DWARF2_FRAME_INFO}.
 @end defmac
 
+@hook TARGET_DEBUG_UNWIND_INFO
+This hook defines the mechanism that will be used for describing frame
+unwind information to the debugger.  Normally the hook will return
+@code{UI_DWARF2} if DWARF 2 debug information is enabled, and
+return @code{UI_NONE} otherwise.
+
+A target may return @code{UI_DWARF2} even when DWARF 2 debug information
+is disabled in order to always output DWARF 2 frame information.
+
+A target may return @code{UI_TARGET} if it has ABI specified unwind tables.
+This will suppress generation of the normal debug frame unwind information.
+@end deftypefn
+
 @defmac DWARF2_ASM_LINE_DEBUG_INFO
 Define this macro to be a nonzero value if the assembler can generate Dwarf 2
 line debug info sections.  This will result in much more compact line number
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 736963c..6a41938 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2503,7 +2503,7 @@  tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
 tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(TREE_H) $(TM_P_H) $(FUNCTION_H) $(TM_H) coretypes.h \
    $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(EXCEPT_H) $(TREE_PASS_H) $(FLAGS_H) langhooks.h \
-   $(BASIC_BLOCK_H) $(DBGCNT_H) gimple-pretty-print.h
+   $(BASIC_BLOCK_H) $(DBGCNT_H) gimple-pretty-print.h $(TARGET_H)
 tree-ssa-sink.o : tree-ssa-sink.c $(TREE_FLOW_H) $(CONFIG_H) \
    $(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
    $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(FLAGS_H) alloc-pool.h \
diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 080e988..d4030eb 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -751,7 +751,7 @@  gnat_eh_personality (void)
 {
   if (!gnat_eh_personality_decl)
     gnat_eh_personality_decl
-      = build_personality_function (USING_SJLJ_EXCEPTIONS
+      = build_personality_function (targetm.except_unwind_info () == UI_SJLJ
 				    ? "__gnat_eh_personality_sj"
 				    : "__gnat_eh_personality");
 
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index fbace22..86e4520 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -601,7 +601,7 @@  c_cpp_builtins (cpp_reader *pfile)
 				   1000 + flag_abi_version);
 
   /* libgcc needs to know this.  */
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__");
 
   /* limits.h and stdint.h need to know these.  */
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 1d547b0..cc48bb5 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -193,12 +193,13 @@  static bool arm_align_anon_bitfield (void);
 static bool arm_return_in_msb (const_tree);
 static bool arm_must_pass_in_stack (enum machine_mode, const_tree);
 static bool arm_return_in_memory (const_tree, const_tree);
-#ifdef TARGET_UNWIND_INFO
+#if ARM_UNWIND_INFO
 static void arm_unwind_emit (FILE *, rtx);
 static bool arm_output_ttype (rtx);
 static void arm_asm_emit_except_personality (rtx);
 static void arm_asm_init_sections (void);
 #endif
+static enum unwind_info_type arm_except_unwind_info (void);
 static void arm_dwarf_handle_frame_unspec (const char *, rtx, int);
 static rtx arm_dwarf_register_span (rtx);
 
@@ -447,7 +448,7 @@  static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
 
-#ifdef TARGET_UNWIND_INFO
+#if ARM_UNWIND_INFO
 #undef TARGET_ASM_UNWIND_EMIT
 #define TARGET_ASM_UNWIND_EMIT arm_unwind_emit
 
@@ -463,7 +464,10 @@  static const struct attribute_spec arm_attribute_table[] =
 
 #undef TARGET_ASM_INIT_SECTIONS
 #define TARGET_ASM_INIT_SECTIONS arm_asm_init_sections
-#endif /* TARGET_UNWIND_INFO */
+#endif /* ARM_UNWIND_INFO */
+
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO  arm_except_unwind_info
 
 #undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
 #define TARGET_DWARF_HANDLE_FRAME_UNSPEC arm_dwarf_handle_frame_unspec
@@ -2012,7 +2016,7 @@  arm_compute_func_type (void)
   if (optimize > 0
       && (TREE_NOTHROW (current_function_decl)
           || !(flag_unwind_tables
-               || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
+               || (flag_exceptions && arm_except_unwind_info () != UI_SJLJ)))
       && TREE_THIS_VOLATILE (current_function_decl))
     type |= ARM_FT_VOLATILE;
 
@@ -15670,7 +15674,8 @@  arm_expand_prologue (void)
      using the EABI unwinder, to prevent faulting instructions from being
      swapped with a stack adjustment.  */
   if (crtl->profile || !TARGET_SCHED_PROLOG
-      || (ARM_EABI_UNWIND_TABLES && cfun->can_throw_non_call_exceptions))
+      || (arm_except_unwind_info () == UI_TARGET
+	  && cfun->can_throw_non_call_exceptions))
     emit_insn (gen_blockage ());
 
   /* If the link register is being kept alive, with the return address in it,
@@ -19526,7 +19531,7 @@  thumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
       return;
     }
 
-  if (ARM_EABI_UNWIND_TABLES && push)
+  if (push && arm_except_unwind_info () == UI_TARGET)
     {
       fprintf (f, "\t.save\t{");
       for (regno = 0; regno < 15; regno++)
@@ -20466,7 +20471,8 @@  thumb1_expand_prologue (void)
      using the EABI unwinder, to prevent faulting instructions from being
      swapped with a stack adjustment.  */
   if (crtl->profile || !TARGET_SCHED_PROLOG
-      || (ARM_EABI_UNWIND_TABLES && cfun->can_throw_non_call_exceptions))
+      || (arm_except_unwind_info () == UI_TARGET
+	  && cfun->can_throw_non_call_exceptions))
     emit_insn (gen_blockage ());
 
   cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
@@ -20579,7 +20585,7 @@  thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
   if (crtl->args.pretend_args_size)
     {
       /* Output unwind directive for the stack adjustment.  */
-      if (ARM_EABI_UNWIND_TABLES)
+      if (arm_except_unwind_info () == UI_TARGET)
 	fprintf (f, "\t.pad #%d\n",
 		 crtl->args.pretend_args_size);
 
@@ -20649,7 +20655,7 @@  thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
       work_register = thumb_find_work_register (live_regs_mask);
 
-      if (ARM_EABI_UNWIND_TABLES)
+      if (arm_except_unwind_info () == UI_TARGET)
 	asm_fprintf (f, "\t.pad #16\n");
 
       asm_fprintf
@@ -21953,7 +21959,7 @@  arm_dwarf_register_span (rtx rtl)
   return p;
 }
 
-#ifdef TARGET_UNWIND_INFO
+#if ARM_UNWIND_INFO
 /* Emit unwind directives for a store-multiple instruction or stack pointer
    push during alignment.
    These should only ever be generated by the function prologue code, so
@@ -22167,7 +22173,7 @@  arm_unwind_emit (FILE * asm_out_file, rtx insn)
 {
   rtx pat;
 
-  if (!ARM_EABI_UNWIND_TABLES)
+  if (arm_except_unwind_info != UI_TARGET)
     return;
 
   if (!(flag_unwind_tables || crtl->uses_eh_lsda)
@@ -22236,7 +22242,33 @@  arm_asm_init_sections (void)
   exception_section = get_unnamed_section (0, output_section_asm_op,
 					   "\t.handlerdata");
 }
-#endif /* TARGET_UNWIND_INFO */
+#endif /* ARM_UNWIND_INFO */
+
+/* Implement TARGET_EXCEPT_UNWIND_INFO.  */
+
+static enum unwind_info_type
+arm_except_unwind_info (void)
+{
+  /* Honor the --enable-sjlj-exceptions configure switch.  */
+#ifdef CONFIG_SJLJ_EXCEPTIONS
+  if (CONFIG_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* If not using ARM EABI unwind tables... */
+  if (ARM_UNWIND_INFO)
+    {
+      /* For simplicity elsewhere in this file, indicate that all unwind
+	 info is disabled if we're not emitting unwind tables.  */
+      if (!flag_exceptions && !flag_unwind_tables)
+	return UI_NONE;
+      else
+	return UI_TARGET;
+    }
+
+  /* ... we use sjlj exceptions for backwards compatibility.  */
+  return UI_SJLJ;
+}
 
 
 /* Handle UNSPEC DWARF call frame instructions.  These are needed for dynamic
@@ -22268,7 +22300,7 @@  arm_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
 void
 arm_output_fn_unwind (FILE * f, bool prologue)
 {
-  if (!ARM_EABI_UNWIND_TABLES)
+  if (arm_except_unwind_info () != UI_TARGET)
     return;
 
   if (prologue)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 5b66510..089aced 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -959,14 +959,11 @@  extern int arm_structure_size_boundary;
 #define FIRST_HI_REGNUM		8
 #define LAST_HI_REGNUM		11
 
-#ifndef TARGET_UNWIND_INFO
-/* We use sjlj exceptions for backwards compatibility.  */
-#define MUST_USE_SJLJ_EXCEPTIONS 1
+/* Overridden by config/arm/bpabi.h.  */
+#ifndef ARM_UNWIND_INFO
+#define ARM_UNWIND_INFO  0
 #endif
 
-/* We can generate DWARF2 Unwind info, even though we don't use it.  */
-#define DWARF2_UNWIND_INFO 1
-
 /* Use r0 and r1 to pass exception handling information.  */
 #define EH_RETURN_DATA_REGNO(N) (((N) < 2) ? N : INVALID_REGNUM)
 
@@ -2051,13 +2048,6 @@  typedef struct
 
 #define ARM_OUTPUT_FN_UNWIND(F, PROLOGUE) arm_output_fn_unwind (F, PROLOGUE)
 
-#ifdef TARGET_UNWIND_INFO
-#define ARM_EABI_UNWIND_TABLES \
-  ((!USING_SJLJ_EXCEPTIONS && flag_exceptions) || flag_unwind_tables)
-#else
-#define ARM_EABI_UNWIND_TABLES 0
-#endif
-
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
    We have two alternate definitions for each of them.
diff --git a/gcc/config/arm/bpabi.h b/gcc/config/arm/bpabi.h
index 8ab9346..cadf232 100644
--- a/gcc/config/arm/bpabi.h
+++ b/gcc/config/arm/bpabi.h
@@ -26,7 +26,8 @@ 
 #define TARGET_BPABI (TARGET_AAPCS_BASED)
 
 /* BPABI targets use EABI frame unwinding tables.  */
-#define TARGET_UNWIND_INFO 1
+#undef ARM_UNWIND_INFO
+#define ARM_UNWIND_INFO 1
 
 /* Section 4.1 of the AAPCS requires the use of VFP format.  */
 #undef  FPUTYPE_DEFAULT
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 17b6a47..4265e5a 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -251,6 +251,9 @@  static void ia64_asm_unwind_emit (FILE *, rtx);
 static void ia64_asm_emit_except_personality (rtx);
 static void ia64_asm_init_sections (void);
 
+static enum unwind_info_type ia64_debug_unwind_info (void);
+static enum unwind_info_type ia64_except_unwind_info (void);
+
 static struct bundle_state *get_free_bundle_state (void);
 static void free_bundle_state (struct bundle_state *);
 static void initiate_bundle_states (void);
@@ -317,6 +320,8 @@  static enum machine_mode ia64_promote_function_mode (const_tree,
 						     int);
 static void ia64_trampoline_init (rtx, tree, rtx);
 static void ia64_override_options_after_change (void);
+
+static void ia64_dwarf_handle_frame_unspec (const char *, rtx, int);
 
 /* Table of valid machine attributes.  */
 static const struct attribute_spec ia64_attribute_table[] =
@@ -524,6 +529,8 @@  static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg
 
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC  ia64_dwarf_handle_frame_unspec
 #undef TARGET_ASM_UNWIND_EMIT
 #define TARGET_ASM_UNWIND_EMIT ia64_asm_unwind_emit
 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
@@ -531,6 +538,11 @@  static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_ASM_INIT_SECTIONS
 #define TARGET_ASM_INIT_SECTIONS  ia64_asm_init_sections
 
+#undef TARGET_DEBUG_UNWIND_INFO
+#define TARGET_DEBUG_UNWIND_INFO  ia64_debug_unwind_info
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO  ia64_except_unwind_info
+
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P ia64_scalar_mode_supported_p
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
@@ -3888,7 +3900,7 @@  ia64_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 	     current_frame_info.n_output_regs,
 	     current_frame_info.n_rotate_regs);
 
-  if (!flag_unwind_tables && (!flag_exceptions || USING_SJLJ_EXCEPTIONS))
+  if (ia64_except_unwind_info () != UI_TARGET)
     return;
 
   /* Emit the .prologue directive.  */
@@ -3946,7 +3958,7 @@  ia64_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 static void
 ia64_output_function_end_prologue (FILE *file)
 {
-  if (!flag_unwind_tables && (!flag_exceptions || USING_SJLJ_EXCEPTIONS))
+  if (ia64_except_unwind_info () != UI_TARGET)
     return;
 
   fputs ("\t.body\n", file);
@@ -8543,7 +8555,7 @@  ia64_add_bundle_selector_before (int template0, rtx insn)
   ia64_emit_insn_before (b, insn);
 #if NR_BUNDLES == 10
   if ((template0 == 4 || template0 == 5)
-      && (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
+      && ia64_except_unwind_info () == UI_TARGET)
     {
       int i;
       rtx note = NULL_RTX;
@@ -9384,7 +9396,7 @@  ia64_reorg (void)
   /* A call must not be the last instruction in a function, so that the
      return address is still within the function, so that unwinding works
      properly.  Note that IA-64 differs from dwarf2 on this point.  */
-  if (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS))
+  if (ia64_except_unwind_info () == UI_TARGET)
     {
       rtx insn;
       int saw_stop = 0;
@@ -9587,6 +9599,17 @@  ia64_dwarf2out_def_steady_cfa (rtx insn, bool frame)
      + ARG_POINTER_CFA_OFFSET (current_function_decl));
 }
 
+/* All we need to do here is avoid a crash in the generic dwarf2
+   processing.  The real CFA definition is set up above.  */
+
+static void
+ia64_dwarf_handle_frame_unspec (const char * ARG_UNUSED (label),
+				rtx ARG_UNUSED (pattern),
+				int index)
+{
+  gcc_assert (index == UNSPECV_ALLOC);
+}
+
 /* The generic dwarf2 frame debug info generator does not define a
    separate region for the very end of the epilogue, so refrain from
    doing so in the IA64-specific code as well.  */
@@ -9856,8 +9879,7 @@  process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
 static void
 ia64_asm_unwind_emit (FILE *asm_out_file, rtx insn)
 {
-  bool unwind = (flag_unwind_tables
-		 || (flag_exceptions && !USING_SJLJ_EXCEPTIONS));
+  bool unwind = ia64_except_unwind_info () == UI_TARGET;
   bool frame = dwarf2out_do_frame ();
 
   if (unwind || frame)
@@ -9935,6 +9957,33 @@  ia64_asm_init_sections (void)
   exception_section = get_unnamed_section (0, output_section_asm_op,
 					   "\t.handlerdata");
 }
+
+/* Implement TARGET_DEBUG_UNWIND_INFO.  */
+
+static enum unwind_info_type
+ia64_debug_unwind_info (void)
+{
+  return UI_TARGET;
+}
+
+/* Implement TARGET_EXCEPT_UNWIND_INFO.  */
+
+static enum unwind_info_type
+ia64_except_unwind_info (void)
+{
+  /* Honor the --enable-sjlj-exceptions configure switch.  */
+#ifdef CONFIG_UNWIND_EXCEPTIONS
+  if (CONFIG_UNWIND_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* For simplicity elsewhere in this file, indicate that all unwind
+     info is disabled if we're not emitting unwind tables.  */
+  if (!flag_exceptions && !flag_unwind_tables)
+    return UI_NONE;
+
+  return UI_TARGET;
+}
 
 enum ia64_builtins
 {
diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h
index 13aa2cd..f1b0cd4 100644
--- a/gcc/config/ia64/ia64.h
+++ b/gcc/config/ia64/ia64.h
@@ -1739,12 +1739,6 @@  do {									\
 
 #define DWARF2_DEBUGGING_INFO 1
 
-/* We do not want call-frame info to be output, since debuggers are
-   supposed to use the target unwind info.  Leave this undefined it
-   TARGET_UNWIND_INFO might ever be false.  */
-
-#define DWARF2_FRAME_INFO 0
-
 #define DWARF2_ASM_LINE_DEBUG_INFO (TARGET_DWARF2_ASM)
 
 /* Use tags for debug info labels, so that they don't break instruction
@@ -1857,8 +1851,6 @@  do {									\
 
 extern int ia64_final_schedule;
 
-#define TARGET_UNWIND_INFO	1
-
 #define TARGET_UNWIND_TABLES_DEFAULT true
 
 #define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 15 : INVALID_REGNUM)
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 9c24f01..a2ca050 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -514,7 +514,7 @@  pa_option_override (void)
      call frame information.  There is no benefit in using this optimization
      on PA8000 and later processors.  */
   if (pa_cpu >= PROCESSOR_8000
-      || (! USING_SJLJ_EXCEPTIONS && flag_exceptions)
+      || (targetm.except_unwind_info () == UI_DWARF2 && flag_exceptions)
       || flag_unwind_tables)
     target_flags &= ~MASK_JUMP_IN_DELAY;
 
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index a2d34e3..35736ca 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -250,7 +250,7 @@  cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \
   $(C_PRAGMA_H) toplev.h output.h input.h cp/operators.def $(TM_P_H)
 cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) toplev.h debug.h langhooks.h \
   $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-cp.h gt-cp-cp-lang.h \
-  cp/cp-objcp-common.h $(EXPR_H)
+  cp/cp-objcp-common.h $(EXPR_H) $(TARGET_H)
 cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \
   output.h toplev.h $(HASHTAB_H) $(RTL_H) \
   cp/operators.def $(TM_P_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(C_PRAGMA_H) \
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index fb687b8..0b70444 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -32,6 +32,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "cp-objcp-common.h"
 #include "hashtab.h"
+#include "target.h"
 
 enum c_language_kind c_language = clk_cxx;
 static void cp_init_ts (void);
@@ -165,16 +166,17 @@  cp_eh_personality (void)
 {
   if (!cp_eh_personality_decl)
     {
-      if (!pragma_java_exceptions)
-	cp_eh_personality_decl
-	  = build_personality_function (USING_SJLJ_EXCEPTIONS
-					? "__gxx_personality_sj0"
-					: "__gxx_personality_v0");
-      else
-	cp_eh_personality_decl
-	  = build_personality_function (USING_SJLJ_EXCEPTIONS
-					? "__gcj_personality_sj0"
-					: "__gcj_personality_v0");
+      const char *name;
+
+      name = (targetm.except_unwind_info () == UI_SJLJ
+	      ? (pragma_java_exceptions
+		 ? "__gcj_personality_sj0"
+		 : "__gxx_personality_sj0")
+	      : (pragma_java_exceptions
+		 ? "__gcj_personality_v0"
+		 : "__gxx_personality_v0"));
+
+      cp_eh_personality_decl = build_personality_function (name);
     }
 
   return cp_eh_personality_decl;
diff --git a/gcc/defaults.h b/gcc/defaults.h
index e30ec17..2eb0bcd 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -372,8 +372,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 /* If we have a definition of INCOMING_RETURN_ADDR_RTX, assume that
    the rest of the DWARF 2 frame unwind support is also provided.  */
-#if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX) \
-    && !defined (TARGET_UNWIND_INFO)
+#if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX)
 #define DWARF2_UNWIND_INFO 1
 #endif
 
@@ -1240,49 +1239,6 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    functions.
 */
 
-/* Just because the user configured --with-sjlj-exceptions=no doesn't
-   mean that we can use call frame exceptions.  Detect that the target
-   has appropriate support.  */
-
-#ifndef MUST_USE_SJLJ_EXCEPTIONS
-# if defined (EH_RETURN_DATA_REGNO)			\
-       && (defined (TARGET_UNWIND_INFO)			\
-	   || (DWARF2_UNWIND_INFO			\
-	       && (defined (EH_RETURN_HANDLER_RTX)	\
-		   || defined (HAVE_eh_return))))
-#  define MUST_USE_SJLJ_EXCEPTIONS	0
-# else
-#  define MUST_USE_SJLJ_EXCEPTIONS	1
-# endif
-#endif
-
-#ifdef CONFIG_SJLJ_EXCEPTIONS
-# if CONFIG_SJLJ_EXCEPTIONS == 1
-#  define USING_SJLJ_EXCEPTIONS		1
-# endif
-# if CONFIG_SJLJ_EXCEPTIONS == 0
-#  define USING_SJLJ_EXCEPTIONS		0
-#  if !defined(EH_RETURN_DATA_REGNO)
-    #error "EH_RETURN_DATA_REGNO required"
-#  endif
-#  if ! (defined(TARGET_UNWIND_INFO) || DWARF2_UNWIND_INFO)
-    #error "{DWARF2,TARGET}_UNWIND_INFO required"
-#  endif
-#  if !defined(TARGET_UNWIND_INFO) \
-	&& !(defined(EH_RETURN_HANDLER_RTX) || defined(HAVE_eh_return))
-    #error "EH_RETURN_HANDLER_RTX or eh_return required"
-#  endif
-/* Usually the above error checks will have already triggered an
-   error, but backends may set MUST_USE_SJLJ_EXCEPTIONS for their own
-   reasons.  */
-#  if MUST_USE_SJLJ_EXCEPTIONS
-    #error "Must use SJLJ exceptions but configured not to"
-#  endif
-# endif
-#else
-# define USING_SJLJ_EXCEPTIONS		MUST_USE_SJLJ_EXCEPTIONS
-#endif
-
 /* The default branch cost is 1.  */
 #ifndef BRANCH_COST
 #define BRANCH_COST(speed_p, predictable_p) 1
@@ -1390,7 +1346,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define STACK_OLD_CHECK_PROTECT STACK_CHECK_PROTECT
 #else
 #define STACK_OLD_CHECK_PROTECT \
- (USING_SJLJ_EXCEPTIONS ? 75 * UNITS_PER_WORD : 8 * 1024)
+ (targetm.except_unwind_info () == UI_SJLJ ? 75 * UNITS_PER_WORD : 8 * 1024)
 #endif
 
 /* Minimum amount of stack required to recover from an anticipated stack
@@ -1398,7 +1354,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    of stack required to propagate an exception.  */
 #ifndef STACK_CHECK_PROTECT
 #define STACK_CHECK_PROTECT \
- (USING_SJLJ_EXCEPTIONS ? 75 * UNITS_PER_WORD : 12 * 1024)
+ (targetm.except_unwind_info () == UI_SJLJ ? 75 * UNITS_PER_WORD : 12 * 1024)
 #endif
 
 /* Make the maximum frame size be the largest we can and still only need
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index e60392f..8cad220 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -8750,7 +8750,8 @@  If the target implements @code{TARGET_ASM_UNWIND_EMIT}, this hook may be used to
 
 @deftypefn {Target Hook} void TARGET_ASM_UNWIND_EMIT (FILE *@var{stream}, rtx @var{insn})
 This target hook emits assembly directives required to unwind the
-given instruction.  This is only used when TARGET_UNWIND_INFO is set.
+given instruction.  This is only used when @code{TARGET_EXCEPT_UNWIND_INFO}
+returns @code{UI_TARGET}.
 @end deftypefn
 
 @deftypevr {Target Hook} bool TARGET_ASM_UNWIND_EMIT_BEFORE_INSN
@@ -8801,23 +8802,32 @@  that it does not contain any extraneous set bits in it.
 Define this macro to 0 if your target supports DWARF 2 frame unwind
 information, but it does not yet work with exception handling.
 Otherwise, if your target supports this information (if it defines
-@samp{INCOMING_RETURN_ADDR_RTX} and either @samp{UNALIGNED_INT_ASM_OP}
-or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of 1.
+@code{INCOMING_RETURN_ADDR_RTX} and either @code{UNALIGNED_INT_ASM_OP}
+or @code{OBJECT_FORMAT_ELF}), GCC will provide a default definition of 1.
+@end defmac
 
-If @code{TARGET_UNWIND_INFO} is defined, the target specific unwinder
-will be used in all cases.  Defining this macro will enable the generation
-of DWARF 2 frame debugging information.
+@deftypefn {Target Hook} {enum unwind_info_type} TARGET_EXCEPT_UNWIND_INFO (void)
+This hook defines the mechanism that will be used for exception handling
+by the target.  If the target has ABI specified unwind tables, the hook
+should return @code{UI_TARGET}.  If the target is to use the
+@code{setjmp}/@code{longjmp}-based exception handling scheme, the hook
+should return @code{UI_SJLJ}.  If the target supports DWARF 2 frame unwind
+information, the hook should return @code{UI_DWARF2}.
 
-If @code{TARGET_UNWIND_INFO} is not defined, and this macro is defined to 1,
-the DWARF 2 unwinder will be the default exception handling mechanism;
-otherwise, the @code{setjmp}/@code{longjmp}-based scheme will be used by
-default.
-@end defmac
+A target may, if exceptions are disabled, choose to return @code{UI_NONE}.
+This may end up simplifying other parts of target-specific code.  The
+default implementation of this hook never returns @code{UI_NONE}.
 
-@defmac TARGET_UNWIND_INFO
-Define this macro if your target has ABI specified unwind tables.  Usually
-these will be output by @code{TARGET_ASM_UNWIND_EMIT}.
-@end defmac
+Note that the value returned by this hook should be constant.  It should
+not depend on anything except command-line switches.  In particular, the
+setting @code{UI_SJLJ} must be fixed at compiler start-up as C pre-processor
+macros and builtin functions related to exception handling are set up
+depending on this setting.
+
+The default implementation of the hook first honors the
+@option{--enable-sjlj-exceptions} configure option, then
+@code{DWARF2_UNWIND_INFO}, and finally defaults to @code{UI_SJLJ}.
+@end deftypefn
 
 @deftypevr {Target Hook} bool TARGET_UNWIND_TABLES_DEFAULT
 This variable should be set to @code{true} if the target ABI requires unwinding
@@ -9326,11 +9336,25 @@  as appropriate from @code{TARGET_ASM_FUNCTION_PROLOGUE} if you don't.
 
 @defmac DWARF2_FRAME_INFO
 Define this macro to a nonzero value if GCC should always output
-Dwarf 2 frame information.  If @code{DWARF2_UNWIND_INFO}
-(@pxref{Exception Region Output} is nonzero, GCC will output this
-information not matter how you define @code{DWARF2_FRAME_INFO}.
+Dwarf 2 frame information.  If @code{TARGET_EXCEPT_UNWIND_INFO}
+(@pxref{Exception Region Output}) returns @code{UI_DWARF2}, and
+exceptions are enabled, GCC will output this information not matter
+how you define @code{DWARF2_FRAME_INFO}.
 @end defmac
 
+@deftypefn {Target Hook} {enum unwind_info_type} TARGET_DEBUG_UNWIND_INFO (void)
+This hook defines the mechanism that will be used for describing frame
+unwind information to the debugger.  Normally the hook will return
+@code{UI_DWARF2} if DWARF 2 debug information is enabled, and
+return @code{UI_NONE} otherwise.
+
+A target may return @code{UI_DWARF2} even when DWARF 2 debug information
+is disabled in order to always output DWARF 2 frame information.
+
+A target may return @code{UI_TARGET} if it has ABI specified unwind tables.
+This will suppress generation of the normal debug frame unwind information.
+@end deftypefn
+
 @defmac DWARF2_ASM_LINE_DEBUG_INFO
 Define this macro to be a nonzero value if the assembler can generate Dwarf 2
 line debug info sections.  This will result in much more compact line number
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 237d089..b23b79f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -112,23 +112,18 @@  int vms_file_stats_name (const char *, long long *, long *, char *, int *);
 #define DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET 0
 #endif
 
-#ifndef DWARF2_UNWIND_INFO
-#define DWARF2_UNWIND_INFO 0
+/* ??? Poison these here until it can be done generically.  They've been
+   totally replaced in this file; make sure it stays that way.  */
+#undef DWARF2_UNWIND_INFO
+#undef DWARF2_FRAME_INFO
+#if (GCC_VERSION >= 3000)
+ #pragma GCC poison DWARF2_UNWIND_INFO DWARF2_FRAME_INFO
 #endif
 
 #ifndef INCOMING_RETURN_ADDR_RTX
 #define INCOMING_RETURN_ADDR_RTX  (gcc_unreachable (), NULL_RTX)
 #endif
 
-#ifndef DWARF2_FRAME_INFO
-# ifdef DWARF2_DEBUGGING_INFO
-#  define DWARF2_FRAME_INFO \
-  (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
-# else
-#  define DWARF2_FRAME_INFO 0
-# endif
-#endif
-
 /* Map register numbers held in the call frame info that gcc has
    collected using DWARF_FRAME_REGNUM to those that should be output in
    .debug_frame and .eh_frame.  */
@@ -148,13 +143,20 @@  dwarf2out_do_frame (void)
   /* We want to emit correct CFA location expressions or lists, so we
      have to return true if we're going to output debug info, even if
      we're not going to output frame or unwind info.  */
-  return (write_symbols == DWARF2_DEBUG
-	  || write_symbols == VMS_AND_DWARF2_DEBUG
-	  || DWARF2_FRAME_INFO || saved_do_cfi_asm
-	  || (DWARF2_UNWIND_INFO
-	      && (flag_unwind_tables
-		  || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
-	  );
+  if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+    return true;
+
+  if (saved_do_cfi_asm)
+    return true;
+
+  if (targetm.debug_unwind_info () == UI_DWARF2)
+    return true;
+
+  if ((flag_unwind_tables || flag_exceptions)
+      && targetm.except_unwind_info () == UI_DWARF2)
+    return true;
+
+  return false;
 }
 
 /* Decide whether to emit frame unwind via assembler directives.  */
@@ -167,10 +169,10 @@  dwarf2out_do_cfi_asm (void)
 #ifdef MIPS_DEBUGGING_INFO
   return false;
 #endif
-  if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
-    return false;
   if (saved_do_cfi_asm)
     return true;
+  if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
+    return false;
   if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
     return false;
 
@@ -183,15 +185,12 @@  dwarf2out_do_cfi_asm (void)
   if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel)
     return false;
 
-  if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE)
-    {
-#ifdef TARGET_UNWIND_INFO
-      return false;
-#else
-      if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions))
-	return false;
-#endif
-    }
+  /* If we can't get the assembler to emit only .debug_frame, and we don't need
+     dwarf2 unwind info for exceptions, then emit .debug_frame by hand.  */
+  if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE
+      && !flag_unwind_tables && !flag_exceptions
+      && targetm.except_unwind_info () != UI_DWARF2)
+    return false;
 
   saved_do_cfi_asm = true;
   return true;
@@ -3965,20 +3964,18 @@  dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   char * dup_label;
   dw_fde_ref fde;
   section *fnsec;
+  bool do_frame;
 
   current_function_func_begin_label = NULL;
 
-#ifdef TARGET_UNWIND_INFO
-  /* ??? current_function_func_begin_label is also used by except.c
-     for call-site information.  We must emit this label if it might
-     be used.  */
-  if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
-      && ! dwarf2out_do_frame ())
-    return;
-#else
-  if (! dwarf2out_do_frame ())
+  do_frame = dwarf2out_do_frame ();
+
+  /* ??? current_function_func_begin_label is also used by except.c for
+     call-site information.  We must emit this label if it might be used.  */
+  if (!do_frame
+      && (!flag_exceptions
+	  || targetm.except_unwind_info () != UI_TARGET))
     return;
-#endif
 
   fnsec = function_section (current_function_decl);
   switch_to_section (fnsec);
@@ -3989,11 +3986,9 @@  dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   dup_label = xstrdup (label);
   current_function_func_begin_label = dup_label;
 
-#ifdef TARGET_UNWIND_INFO
   /* We can elide the fde allocation if we're not emitting debug info.  */
-  if (! dwarf2out_do_frame ())
+  if (!do_frame)
     return;
-#endif
 
   /* Expand the fde table if necessary.  */
   if (fde_table_in_use == fde_table_allocated)
@@ -4162,7 +4157,8 @@  dwarf2out_frame_init (void)
   /* On entry, the Canonical Frame Address is at SP.  */
   dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
 
-  if (DWARF2_UNWIND_INFO || DWARF2_FRAME_INFO)
+  if (targetm.debug_unwind_info () == UI_DWARF2
+      || targetm.except_unwind_info () == UI_DWARF2)
     initial_return_save (INCOMING_RETURN_ADDR_RTX);
 }
 
@@ -4170,14 +4166,13 @@  void
 dwarf2out_frame_finish (void)
 {
   /* Output call frame information.  */
-  if (DWARF2_FRAME_INFO)
+  if (targetm.debug_unwind_info () == UI_DWARF2)
     output_call_frame_info (0);
 
-#ifndef TARGET_UNWIND_INFO
   /* Output another copy for the unwinder.  */
-  if (! USING_SJLJ_EXCEPTIONS && (flag_unwind_tables || flag_exceptions))
+  if ((flag_unwind_tables || flag_exceptions)
+      && targetm.except_unwind_info () == UI_DWARF2)
     output_call_frame_info (1);
-#endif
 }
 
 /* Note that the current function section is being used for code.  */
@@ -21649,13 +21644,11 @@  dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 static void
 dwarf2out_assembly_start (void)
 {
-  if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE && dwarf2out_do_cfi_asm ())
-    {
-#ifndef TARGET_UNWIND_INFO
-      if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions))
-#endif
-	fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n");
-    }
+  if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE
+      && dwarf2out_do_cfi_asm ()
+      && (!(flag_unwind_tables || flag_exceptions)
+	  || targetm.except_unwind_info () != UI_DWARF2))
+    fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n");
 }
 
 /* A helper function for dwarf2out_finish called through
diff --git a/gcc/except.c b/gcc/except.c
index bfffa44..5ee9ba3 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -209,7 +209,7 @@  init_eh (void)
 
   /* Create the SjLj_Function_Context structure.  This should match
      the definition in unwind-sjlj.c.  */
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     {
       tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
 
@@ -1375,13 +1375,13 @@  finish_eh_generation (void)
   basic_block bb;
 
   /* Construct the landing pads.  */
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     sjlj_build_landing_pads ();
   else
     dw2_build_landing_pads ();
   break_superblocks ();
 
-  if (USING_SJLJ_EXCEPTIONS
+  if (targetm.except_unwind_info () == UI_SJLJ
       /* Kludge for Alpha/Tru64 (see alpha_gp_save_rtx).  */
       || single_succ_edge (ENTRY_BLOCK_PTR)->insns.r)
     commit_edge_insertions ();
@@ -2620,7 +2620,11 @@  static bool
 gate_convert_to_eh_region_ranges (void)
 {
   /* Nothing to do for SJLJ exceptions or if no regions created.  */
-  return !(USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL);
+  if (cfun->eh->region_tree == NULL)
+    return false;
+  if (targetm.except_unwind_info () == UI_SJLJ)
+    return false;
+  return true;
 }
 
 struct rtl_opt_pass pass_convert_to_eh_region_ranges =
@@ -2957,7 +2961,7 @@  output_one_function_exception_table (int section)
 		       eh_data_format_name (tt_format));
 
 #ifndef HAVE_AS_LEB128
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     call_site_len = sjlj_size_of_call_site_table ();
   else
     call_site_len = dw2_size_of_call_site_table (section);
@@ -3024,14 +3028,14 @@  output_one_function_exception_table (int section)
   dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
 				"Call-site table length");
   ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     sjlj_output_call_site_table ();
   else
     dw2_output_call_site_table (cs_format, section);
   ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
 #else
   dw2_asm_output_data_uleb128 (call_site_len, "Call-site table length");
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     sjlj_output_call_site_table ();
   else
     dw2_output_call_site_table (cs_format, section);
diff --git a/gcc/final.c b/gcc/final.c
index 79cd85e..82844f0 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -87,9 +87,7 @@  along with GCC; see the file COPYING3.  If not see
 				   declarations for e.g. AIX 4.x.  */
 #endif
 
-#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
-#endif
 
 #ifdef DBX_DEBUGGING_INFO
 #include "dbxout.h"
@@ -1534,10 +1532,8 @@  final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
   if (!DECL_IGNORED_P (current_function_decl))
     debug_hooks->begin_prologue (last_linenum, last_filename);
 
-#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO)
   if (!dwarf2_debug_info_emitted_p (current_function_decl))
     dwarf2out_begin_prologue (0, NULL);
-#endif
 
 #ifdef LEAF_REG_REMAP
   if (current_function_uses_only_leaf_regs)
@@ -1549,7 +1545,7 @@  final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
   if (targetm.profile_before_prologue () && crtl->profile)
     profile_function (file);
 
-#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
+#if defined (HAVE_prologue)
   if (dwarf2out_do_frame ())
     dwarf2out_frame_debug (NULL_RTX, false);
 #endif
@@ -1657,11 +1653,9 @@  final_end_function (void)
   if (!DECL_IGNORED_P (current_function_decl))
     debug_hooks->end_epilogue (last_linenum, last_filename);
 
-#if defined (DWARF2_UNWIND_INFO)
   if (!dwarf2_debug_info_emitted_p (current_function_decl)
       && dwarf2out_do_frame ())
     dwarf2out_end_epilogue (last_linenum, last_filename);
-#endif
 }
 
 /* Output assembler code for some insns: all or part of a function.
@@ -1834,12 +1828,10 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
 	case NOTE_INSN_SWITCH_TEXT_SECTIONS:
 	  in_cold_section_p = !in_cold_section_p;
-#ifdef DWARF2_UNWIND_INFO
+
 	  if (dwarf2out_do_frame ())
 	    dwarf2out_switch_text_section ();
-	  else
-#endif
-	  if (!DECL_IGNORED_P (current_function_decl))
+	  else if (!DECL_IGNORED_P (current_function_decl))
 	    debug_hooks->switch_text_section ();
 
 	  switch_to_section (current_function_section ());
@@ -1890,7 +1882,7 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_EPILOGUE_BEG:
-#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_epilogue)
+#if defined (HAVE_epilogue)
 	  if (dwarf2out_do_frame ())
 	    dwarf2out_cfi_begin_epilogue (insn);
 #endif
@@ -1899,9 +1891,7 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 	  break;
 
 	case NOTE_INSN_CFA_RESTORE_STATE:
-#if defined (DWARF2_UNWIND_INFO)
 	  dwarf2out_frame_debug_restore_state ();
-#endif
 	  break;
 
 	case NOTE_INSN_FUNCTION_BEG:
@@ -2010,10 +2000,8 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
       break;
 
     case BARRIER:
-#if defined (DWARF2_UNWIND_INFO)
       if (dwarf2out_do_frame ())
 	dwarf2out_frame_debug (insn, false);
-#endif
       break;
 
     case CODE_LABEL:
@@ -2281,11 +2269,9 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
 	    /* Record the delay slots' frame information before the branch.
 	       This is needed for delayed calls: see execute_cfa_program().  */
-#if defined (DWARF2_UNWIND_INFO)
 	    if (dwarf2out_do_frame ())
 	      for (i = 1; i < XVECLEN (body, 0); i++)
 		dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
-#endif
 
 	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
 	       force the restoration of a comparison that was previously
@@ -2600,10 +2586,8 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
 	current_output_insn = debug_insn = insn;
 
-#if defined (DWARF2_UNWIND_INFO)
 	if (CALL_P (insn) && dwarf2out_do_frame ())
 	  dwarf2out_frame_debug (insn, false);
-#endif
 
 	/* Find the proper template for this insn.  */
 	templ = get_insn_template (insn_code_number, insn);
@@ -2705,14 +2689,12 @@  final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 	/* If necessary, report the effect that the instruction has on
 	   the unwind info.   We've already done this for delay slots
 	   and call instructions.  */
-#if defined (DWARF2_UNWIND_INFO)
 	if (final_sequence == 0
 #if !defined (HAVE_prologue)
 	    && !ACCUMULATE_OUTGOING_ARGS
 #endif
 	    && dwarf2out_do_frame ())
 	  dwarf2out_frame_debug (insn, true);
-#endif
 
 	if (!targetm.asm_out.unwind_emit_before_insn
 	    && targetm.asm_out.unwind_emit)
diff --git a/gcc/function.c b/gcc/function.c
index 670ff80..882d832 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4892,7 +4892,7 @@  expand_function_end (void)
   /* Output the label for the actual return from the function.  */
   emit_label (return_label);
 
-  if (USING_SJLJ_EXCEPTIONS)
+  if (targetm.except_unwind_info () == UI_SJLJ)
     {
       /* Let except.c know where it should emit the call to unregister
 	 the function context for sjlj exceptions.  */
@@ -5050,7 +5050,8 @@  expand_function_end (void)
   /* @@@ This is a kludge.  We want to ensure that instructions that
      may trap are not moved into the epilogue by scheduling, because
      we don't always emit unwind information for the epilogue.  */
-  if (!USING_SJLJ_EXCEPTIONS && cfun->can_throw_non_call_exceptions)
+  if (cfun->can_throw_non_call_exceptions
+      && targetm.except_unwind_info () != UI_SJLJ)
     emit_insn (gen_blockage ());
 
   /* If stack protection is enabled for this function, check the guard.  */
diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in
index 7d2a6a3..0c91c37 100644
--- a/gcc/java/Make-lang.in
+++ b/gcc/java/Make-lang.in
@@ -302,7 +302,8 @@  java/jvgenmain.o: java/jvgenmain.c $(CONFIG_H) $(JAVA_TREE_H) $(SYSTEM_H) \
   coretypes.h $(TM_H) intl.h
 java/lang.o: java/lang.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h input.h \
   toplev.h $(SYSTEM_H) coretypes.h $(TM_H) $(DIAGNOSTIC_H) \
-  langhooks.h $(LANGHOOKS_DEF_H) gt-java-lang.h opts.h options.h
+  langhooks.h $(LANGHOOKS_DEF_H) gt-java-lang.h opts.h options.h \
+  $(TARGET_H)
 java/mangle.o: java/mangle.c $(CONFIG_H) java/jcf.h $(JAVA_TREE_H) $(SYSTEM_H) \
   coretypes.h $(TM_H) toplev.h $(GGC_H) gt-java-mangle.h $(LANGHOOKS_DEF_H)
 java/mangle_name.o: java/mangle_name.c $(CONFIG_H) java/jcf.h $(JAVA_TREE_H) \
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 1633c02..78f9715 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -43,6 +43,7 @@  The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "tree-dump.h"
 #include "opts.h"
 #include "options.h"
+#include "target.h"
 
 static bool java_init (void);
 static void java_finish (void);
@@ -902,7 +903,7 @@  java_eh_personality (void)
 {
   if (!java_eh_personality_decl)
     java_eh_personality_decl
-      = build_personality_function (USING_SJLJ_EXCEPTIONS
+      = build_personality_function (targetm.except_unwind_info () == UI_SJLJ
 				    ? "__gcj_personality_sj0"
 				    : "__gcj_personality_v0");
 
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 81aba84..8f811c6 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -3513,7 +3513,7 @@  objc_eh_personality (void)
   if (!flag_objc_sjlj_exceptions
       && !objc_eh_personality_decl)
     objc_eh_personality_decl
-      = build_personality_function (USING_SJLJ_EXCEPTIONS
+      = build_personality_function (targetm.except_unwind_info () == UI_SJLJ
 				    ? "__gnu_objc_personality_sj0"
 				    : "__gnu_objc_personality_v0");
 
diff --git a/gcc/objcp/Make-lang.in b/gcc/objcp/Make-lang.in
index 22dc30f..0849a89 100644
--- a/gcc/objcp/Make-lang.in
+++ b/gcc/objcp/Make-lang.in
@@ -73,7 +73,7 @@  cc1objplus$(exeext): $(OBJCXX_OBJS) cc1objplus-checksum.o $(BACKEND) $(LIBDEPS)
 objcp/objcp-lang.o : objcp/objcp-lang.c \
   $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) \
   $(C_COMMON_H) $(LANGHOOKS_DEF_H) objc/objc-act.h cp/cp-objcp-common.h \
-  gtype-objcp.h
+  $(TARGET_H) gtype-objcp.h
 
 objcp/objcp-decl.o : objcp/objcp-decl.c \
    $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) \
diff --git a/gcc/objcp/objcp-lang.c b/gcc/objcp/objcp-lang.c
index 70a605b..fdb2976 100644
--- a/gcc/objcp/objcp-lang.c
+++ b/gcc/objcp/objcp-lang.c
@@ -29,6 +29,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "objc-act.h"
 #include "langhooks.h"
 #include "langhooks-def.h"
+#include "target.h"
 #include "cp-objcp-common.h"
 
 enum c_language_kind c_language = clk_objcxx;
@@ -147,7 +148,7 @@  objcxx_eh_personality (void)
 {
   if (!objcp_eh_personality_decl)
     objcp_eh_personality_decl
-	= build_personality_function (USING_SJLJ_EXCEPTIONS
+	= build_personality_function (targetm.except_unwind_info () == UI_SJLJ
 				      ? "__gxx_personality_sj0"
 				      : "__gxx_personality_v0");
 
diff --git a/gcc/opts.c b/gcc/opts.c
index e59332f..bdb086e 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -665,6 +665,7 @@  decode_options (unsigned int argc, const char **argv,
   int opt3;
   int opt1_max;
   int ofast = 0;
+  enum unwind_info_type ui_except;
 
   if (first_time_p)
     {
@@ -994,15 +995,15 @@  decode_options (unsigned int argc, const char **argv,
      generating unwind info.  If flag_exceptions is turned on we need to
      turn off the partitioning optimization.  */
 
-  if (flag_exceptions && flag_reorder_blocks_and_partition
-      && (USING_SJLJ_EXCEPTIONS
-#ifdef TARGET_UNWIND_INFO
-	  || 1
-#endif
-	 ))
+  ui_except = targetm.except_unwind_info ();
+
+  if (flag_exceptions
+      && flag_reorder_blocks_and_partition
+      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))
     {
       inform (input_location,
-	      "-freorder-blocks-and-partition does not work with exceptions on this architecture");
+	      "-freorder-blocks-and-partition does not work "
+	      "with exceptions on this architecture");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -1010,16 +1011,14 @@  decode_options (unsigned int argc, const char **argv,
   /* If user requested unwind info, then turn off the partitioning
      optimization.  */
 
-  if (flag_unwind_tables && ! targetm.unwind_tables_default
+  if (flag_unwind_tables
+      && !targetm.unwind_tables_default
       && flag_reorder_blocks_and_partition
-      && (USING_SJLJ_EXCEPTIONS
-#ifdef TARGET_UNWIND_INFO
-	  || 1
-#endif
-	 ))
+      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))
     {
       inform (input_location,
-	      "-freorder-blocks-and-partition does not support unwind info on this architecture");
+	      "-freorder-blocks-and-partition does not support "
+	      "unwind info on this architecture");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -1030,15 +1029,13 @@  decode_options (unsigned int argc, const char **argv,
 
   if (flag_reorder_blocks_and_partition
       && (!targetm.have_named_sections
-	  || (flag_unwind_tables && targetm.unwind_tables_default
-	      && (USING_SJLJ_EXCEPTIONS
-#ifdef TARGET_UNWIND_INFO
-		  || 1
-#endif
-		 ))))
+	  || (flag_unwind_tables
+	      && targetm.unwind_tables_default
+	      && (ui_except == UI_SJLJ || ui_except == UI_TARGET))))
     {
       inform (input_location,
-	      "-freorder-blocks-and-partition does not work on this architecture");
+	      "-freorder-blocks-and-partition does not work "
+	      "on this architecture");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
diff --git a/gcc/system.h b/gcc/system.h
index a5cfaba..30313ae 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -715,7 +715,7 @@  extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 	ALLOCATE_INITIAL_VALUE LEGITIMIZE_ADDRESS FRAME_POINTER_REQUIRED \
 	CAN_ELIMINATE TRAMPOLINE_TEMPLATE INITIALIZE_TRAMPOLINE		\
 	TRAMPOLINE_ADJUST_ADDRESS STATIC_CHAIN STATIC_CHAIN_INCOMING	\
-	RETURN_POPS_ARGS
+	RETURN_POPS_ARGS USING_SJLJ_EXCEPTIONS TARGET_UNWIND_INFO
 
 /* Other obsolete target macros, or macros that used to be in target
    headers and were not used, and may be obsolete or may never have
diff --git a/gcc/target.def b/gcc/target.def
index 6910ce9..fc6f901 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2307,6 +2307,20 @@  DEFHOOK
  void, (bitmap regs),
  hook_void_bitmap)
 
+/* Determine the type of unwind info to emit for debugging.  */
+DEFHOOK
+(debug_unwind_info,
+ "",
+ enum unwind_info_type, (void),
+ default_debug_unwind_info)
+
+/* Determine the type of unwind info to emit for exceptions.  */
+DEFHOOK
+(except_unwind_info,
+ "",
+ enum unwind_info_type, (void),
+ default_except_unwind_info)
+
 /* Leave the boolean fields at the end.  */
 
 /* True if unwinding tables should be generated by default.  */
diff --git a/gcc/target.h b/gcc/target.h
index 99dd1ee..f160e97 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -128,6 +128,16 @@  enum vect_cost_for_stmt
   vec_perm
 };
 
+/* Types of unwind/exception handling info that can be generated.  */
+
+enum unwind_info_type
+{
+  UI_NONE,
+  UI_SJLJ,
+  UI_DWARF2,
+  UI_TARGET
+};
+
 /* The target structure.  This holds all the backend hooks.  */
 #define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
 #define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS;
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index a0e24c0..50b022a 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1232,4 +1232,73 @@  default_class_likely_spilled_p (reg_class_t rclass)
 #endif
 }
 
+/* Determine the debugging unwind mechanism for the target.  */
+
+enum unwind_info_type
+default_debug_unwind_info (void)
+{
+  /* If the target wants to force the use of dwarf2 unwind info, let it.  */
+  /* ??? Change all users to the hook, then poison this.  */
+#ifdef DWARF2_FRAME_INFO
+  if (DWARF2_FRAME_INFO)
+    return UI_DWARF2;
+#endif
+
+  /* Otherwise, only turn it on if dwarf2 debugging is enabled.  */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+    return UI_DWARF2;
+#endif
+
+  return UI_NONE;
+}
+
+/* Determine the exception handling mechanism for the target.  */
+
+enum unwind_info_type
+default_except_unwind_info (void)
+{
+  /* ??? Change the one user to the hook, then poison this.  */
+#ifdef MUST_USE_SJLJ_EXCEPTIONS
+  if (MUST_USE_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* Obey the configure switch to turn on sjlj exceptions.  */
+#ifdef CONFIG_SJLJ_EXCEPTIONS
+  if (CONFIG_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* ??? Change all users to the hook, then poison this.  */
+#ifdef DWARF2_UNWIND_INFO
+  if (DWARF2_UNWIND_INFO)
+    return UI_DWARF2;
+#endif
+
+  return UI_SJLJ;
+}
+
+/* To be used by targets that force dwarf2 unwind enabled.  */
+
+enum unwind_info_type
+dwarf2_except_unwind_info (void)
+{
+  /* Obey the configure switch to turn on sjlj exceptions.  */
+#ifdef CONFIG_SJLJ_EXCEPTIONS
+  if (CONFIG_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  return UI_DWARF2;
+}
+
+/* To be used by targets that force sjlj unwind enabled.  */
+
+enum unwind_info_type
+sjlj_except_unwind_info (void)
+{
+  return UI_SJLJ;
+}
+
 #include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 4073cbe..19b70c4 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -153,3 +153,8 @@  extern int default_register_move_cost (enum machine_mode, reg_class_t,
 
 extern bool default_profile_before_prologue (void);
 extern bool default_class_likely_spilled_p (reg_class_t);
+
+extern enum unwind_info_type default_debug_unwind_info (void);
+extern enum unwind_info_type default_except_unwind_info (void);
+extern enum unwind_info_type dwarf2_except_unwind_info (void);
+extern enum unwind_info_type sjlj_except_unwind_info (void);
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index 71a273f..38daed9 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -34,6 +34,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "langhooks.h"
 #include "dbgcnt.h"
+#include "target.h"
 
 /* The file implements the tail recursion elimination.  It is also used to
    analyze the tail calls in general, passing the results to the rtl level
@@ -151,7 +152,8 @@  suitable_for_tail_call_opt_p (void)
   /* If we are using sjlj exceptions, we may need to add a call to
      _Unwind_SjLj_Unregister at exit of the function.  Which means
      that we cannot do any sibcall transformations.  */
-  if (USING_SJLJ_EXCEPTIONS && current_function_has_exception_handlers ())
+  if (targetm.except_unwind_info () == UI_SJLJ
+      && current_function_has_exception_handlers ())
     return false;
 
   /* Any function that calls setjmp might have longjmp called from
diff --git a/gcc/tree.c b/gcc/tree.c
index d696e96..d709ebd 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9310,7 +9310,7 @@  build_common_builtin_nodes (void)
   ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
   local_define_builtin ("__builtin_unwind_resume", ftype,
 			BUILT_IN_UNWIND_RESUME,
-			(USING_SJLJ_EXCEPTIONS
+			(targetm.except_unwind_info () == UI_SJLJ
 			 ? "_Unwind_SjLj_Resume" : "_Unwind_Resume"),
 			ECF_NORETURN);
 
@@ -10894,7 +10894,7 @@  lhd_gcc_personality (void)
 {
   if (!gcc_eh_personality_decl)
     gcc_eh_personality_decl
-      = build_personality_function (USING_SJLJ_EXCEPTIONS
+      = build_personality_function (targetm.except_unwind_info () == UI_SJLJ
 				    ? "__gcc_personality_sj0"
 				    : "__gcc_personality_v0");