Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 163267)
+++ gcc/dwarf2out.c	(working copy)
@@ -268,12 +272,20 @@ typedef union GTY(()) dw_cfi_oprnd_struct {
 }
 dw_cfi_oprnd;
 
+/* Use the first out-of-band opcode number as a marker for the start of 
+   epilogues.  */
+#define DW_CFA_INTERNAL_start_epilogue 0x100
+#define CFI_T enum dwarf_call_frame_info
+
+static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc (unsigned int cfi);
+static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc (unsigned int cfi);
+
 typedef struct GTY(()) dw_cfi_struct {
   dw_cfi_ref dw_cfi_next;
-  enum dwarf_call_frame_info dw_cfi_opc;
-  dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)")))
+  unsigned int dw_cfi_opc;
+  dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc ((unsigned int)%1.dw_cfi_opc)")))
     dw_cfi_oprnd1;
-  dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)")))
+  dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc ((unsigned int)%1.dw_cfi_opc)")))
     dw_cfi_oprnd2;
 }
 dw_cfi_node;
@@ -821,9 +833,15 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
     }
 
   list_head = &cie_cfi_head;
-
-  if (dwarf2out_do_cfi_asm ())
+  
+  if (cfi->dw_cfi_opc == DW_CFA_INTERNAL_start_epilogue)
     {
+      dw_fde_ref fde = current_fde ();
+      gcc_assert (fde != NULL);
+      list_head = &fde->dw_fde_cfi;
+    }
+  else if (dwarf2out_do_cfi_asm ())
+    {
       if (label)
 	{
 	  dw_fde_ref fde = current_fde ();
@@ -850,6 +868,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
 		case DW_CFA_def_cfa_sf:
 		case DW_CFA_def_cfa_expression:
 		case DW_CFA_restore_state:
+		case DW_CFA_INTERNAL_start_epilogue:
 		  if (*label == 0 || strcmp (label, "<do not output>") == 0)
 		    label = dwarf2out_cfi_label (true);
 
@@ -2894,12 +2913,22 @@ dwarf2out_cfi_begin_epilogue (rtx insn)
     return;
 
   /* Otherwise, search forward to see if the return insn was the last
-     basic block of the function.  If so, we don't need save/restore.  */
+     basic block of the function.  If so, we don't need save/restore.  
+     However, we do mark the position so that we can skip the epilogue
+     in _eh frames where required.  */
   gcc_assert (i != NULL);
   i = next_real_insn (i);
   if (i == NULL)
-    return;
+    {
+      dw_cfi_ref cfi_epi_start;
 
+      /* Emit a marker for the epilogue start. */
+      cfi_epi_start = new_cfi ();
+      cfi_epi_start->dw_cfi_opc = DW_CFA_INTERNAL_start_epilogue;
+      add_fde_cfi ("", cfi_epi_start);   
+      return;
+    }
+
   /* Insert the restore before that next real insn in the stream, and before
      a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be
      properly nested.  This should be after any label or alignment.  This
@@ -2941,11 +2970,9 @@ dwarf2out_frame_debug_restore_state (void)
 }
 
 /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used.  */
-static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc
- (enum dwarf_call_frame_info cfi);
 
 static enum dw_cfi_oprnd_type
-dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
+dw_cfi_oprnd1_desc (unsigned int cfi)
 {
   switch (cfi)
     {
@@ -2953,6 +2980,7 @@ static enum dw_cfi_oprnd_type
     case DW_CFA_GNU_window_save:
     case DW_CFA_remember_state:
     case DW_CFA_restore_state:
+    case DW_CFA_INTERNAL_start_epilogue:
       return dw_cfi_oprnd_unused;
 
     case DW_CFA_set_loc:
@@ -2990,11 +3018,9 @@ static enum dw_cfi_oprnd_type
 }
 
 /* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used.  */
-static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc
- (enum dwarf_call_frame_info cfi);
 
 static enum dw_cfi_oprnd_type
-dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
+dw_cfi_oprnd2_desc (unsigned int cfi)
 {
   switch (cfi)
     {
@@ -3121,6 +3148,13 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int fo
       dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
 			   "DW_CFA_restore, column %#lx", r);
     }
+  else if (cfi->dw_cfi_opc == DW_CFA_INTERNAL_start_epilogue)
+    {
+      /* This is a nop unless we want a debug message.  */
+      if (flag_debug_asm)
+	fputs (ASM_COMMENT_START"\t\t\t" ASM_COMMENT_START
+			" DW_CFA_INTERNAL_start_epilogue\n",asm_out_file);
+    }
   else
     {
       dw2_asm_output_data (1, cfi->dw_cfi_opc,
@@ -3303,6 +3337,13 @@ output_cfi_directive (dw_cfi_ref cfi)
 	       cfi->dw_cfi_oprnd1.dw_cfi_offset);
       break;
 
+    case DW_CFA_INTERNAL_start_epilogue:
+      /* no-op apart from an informational message.  */
+      if (flag_debug_asm)
+	fputs (ASM_COMMENT_START"\t\t\t" ASM_COMMENT_START
+			" DW_CFA_INTERNAL_start_epilogue\n",asm_out_file);
+      break;
+      
     case DW_CFA_remember_state:
       fprintf (asm_out_file, "\t.cfi_remember_state\n");
       break;
@@ -3498,6 +3539,46 @@ output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_f
     }
 }
 
+/* Output cfi skipping save/restore and epilogues in _eh frames
+   for targets that do not want them.  */
+
+static dw_cfi_ref
+emit_cfi_or_skip_epilogue (dw_cfi_ref cfi, dw_fde_ref fde, bool for_eh)
+{
+  if (for_eh 
+      && !flag_asynchronous_unwind_tables)
+    {
+      if (cfi->dw_cfi_opc == DW_CFA_remember_state)
+	{
+	  if (flag_debug_asm)
+	    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+	      " DW_CFA_remember/restore_state pair skipped\n",asm_out_file);
+	  /* Skip to the restore, unless there's an error and we fall off
+	     the end.  */
+	  while (cfi->dw_cfi_next 
+		 && cfi->dw_cfi_opc != DW_CFA_restore_state) 
+	    cfi = cfi->dw_cfi_next;
+	  return cfi;
+        }
+      if (cfi->dw_cfi_opc == DW_CFA_INTERNAL_start_epilogue)
+        {
+	  if (flag_debug_asm)
+	    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+			" DW_CFA_INTERNAL_start_epilogue\n",asm_out_file);
+	  while (cfi->dw_cfi_next) 
+	    /* Skip to the end.  */
+	    cfi = cfi->dw_cfi_next;
+          return cfi;
+        }
+    }
+
+  /* If it's not a special case, then just carry on.  
+     This will also cause the no-op 'DW_CFA_INTERNAL_start_epilogue' to be
+     listed when flag_debug_asm is set.  */
+  output_cfi (cfi, fde, for_eh);
+  return cfi;
+}
+
 /* Output one FDE.  */
 
 static void
@@ -3613,13 +3694,13 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco
   fde->dw_fde_current_label = begin;
   if (!fde->dw_fde_switched_sections)
     for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-      output_cfi (cfi, fde, for_eh);
+      cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
   else if (!second)
     {
       if (fde->dw_fde_switch_cfi)
 	for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
 	  {
-	    output_cfi (cfi, fde, for_eh);
+	    cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
 	    if (cfi == fde->dw_fde_switch_cfi)
 	      break;
 	  }
@@ -3627,7 +3708,6 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco
   else
     {
       dw_cfi_ref cfi_next = fde->dw_fde_cfi;
-
       if (fde->dw_fde_switch_cfi)
 	{
 	  cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next;
@@ -3636,7 +3716,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco
 	  fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
 	}
       for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
-	output_cfi (cfi, fde, for_eh);
+	cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
     }
 
   /* If we are to emit a ref/link from function bodies to their frame tables,
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 163267)
+++ gcc/toplev.c	(working copy)
@@ -1798,9 +1801,9 @@ process_options (void)
   if (flag_rename_registers == AUTODETECT_VALUE)
     flag_rename_registers = flag_unroll_loops || flag_peel_loops;
 
-  if (flag_non_call_exceptions)
+  if (flag_non_call_exceptions && flag_asynchronous_unwind_tables == 2)
     flag_asynchronous_unwind_tables = 1;
-  if (flag_asynchronous_unwind_tables)
+  if (flag_asynchronous_unwind_tables || flag_non_call_exceptions)
     flag_unwind_tables = 1;
 
   if (flag_value_profile_transformations)
Index: gcc/config/darwin.c
===================================================================
--- gcc/config/darwin.c	(revision 163267)
+++ gcc/config/darwin.c	(working copy)
@@ -1884,7 +1915,22 @@ darwin_override_options (void)
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
+    
+  if (flag_asynchronous_unwind_tables)
+    {
+      if (flag_asynchronous_unwind_tables == 2)
+	flag_asynchronous_unwind_tables = 0;
+      else
+	/* Issue a warning */
+	warning (OPT_Wall,
+	  "this architecture does not fully support"
+	  " -fasynchronous-unwind-tables");
+    }
 
+  if ((flag_exceptions || flag_non_call_exceptions)
+       && strverscmp (darwin_macosx_version_min, "10.4") >= 0)
+    flag_unwind_tables = 1;
+
   if (flag_mkernel || flag_apple_kext)
     {
       /* -mkernel implies -fapple-kext for C++ */
@@ -1897,6 +1943,9 @@ darwin_override_options (void)
       flag_exceptions = 0;
       /* No -fnon-call-exceptions data in kexts.  */
       flag_non_call_exceptions = 0;
+      /* so no tables either.. */
+      flag_unwind_tables = 0;
+      flag_asynchronous_unwind_tables = 0;
       /* We still need to emit branch islands for kernel context.  */
       darwin_emit_branch_islands = true;
     }
