Index: include/dwarf2.h
===================================================================
--- include/dwarf2.h	(revision 163221)
+++ include/dwarf2.h	(working copy)
@@ -854,7 +854,8 @@ enum dwarf_call_frame_info
     /* GNU extensions.  */
     DW_CFA_GNU_window_save = 0x2d,
     DW_CFA_GNU_args_size = 0x2e,
-    DW_CFA_GNU_negative_offset_extended = 0x2f
+    DW_CFA_GNU_negative_offset_extended = 0x2f,
+    DW_CFA_GNU_start_epilogue = 0x30
   };
 
 #define DW_CIE_ID	  0xffffffff
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 163221)
+++ gcc/dwarf2out.c	(working copy)
@@ -720,7 +724,9 @@ dwarf_cfi_name (unsigned int cfi_opc)
       return "DW_CFA_GNU_args_size";
     case DW_CFA_GNU_negative_offset_extended:
       return "DW_CFA_GNU_negative_offset_extended";
-
+    case DW_CFA_GNU_start_epilogue:
+      return "DW_CFA_GNU_start_epilogue";
+      
     default:
       return "DW_CFA_<unknown>";
     }
@@ -801,6 +807,9 @@ dwarf2out_cfi_label (bool force)
 /* True if remember_state should be emitted before following CFI directive.  */
 static bool emit_cfa_remember;
 
+/* True if start_epilogue should be emitted before following CFI directive.  */
+static bool emit_cfa_start_epilogue;
+
 /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
    or to the CIE if LABEL is NULL.  */
 
@@ -809,6 +818,17 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
 {
   dw_cfi_ref *list_head;
 
+  if (emit_cfa_start_epilogue)
+    {
+      dw_cfi_ref cfi_epi_start;
+
+      /* Emit the state save.  */
+      emit_cfa_start_epilogue = false;
+      cfi_epi_start = new_cfi ();
+      cfi_epi_start->dw_cfi_opc = DW_CFA_GNU_start_epilogue;
+      add_fde_cfi (label, cfi_epi_start);   
+    }
+    
   if (emit_cfa_remember)
     {
       dw_cfi_ref cfi_remember;
@@ -2898,7 +2918,12 @@ dwarf2out_cfi_begin_epilogue (rtx insn)
   gcc_assert (i != NULL);
   i = next_real_insn (i);
   if (i == NULL)
-    return;
+    {
+      /* But we do mark the start of the epilogue to allow it to be skipped
+         in _eh frames.  */
+      emit_cfa_start_epilogue = true; 
+      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
@@ -2953,6 +2978,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi
     case DW_CFA_GNU_window_save:
     case DW_CFA_remember_state:
     case DW_CFA_restore_state:
+    case DW_CFA_GNU_start_epilogue:
       return dw_cfi_oprnd_unused;
 
     case DW_CFA_set_loc:
@@ -3121,6 +3148,10 @@ 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_GNU_start_epilogue)
+/* DEBUG */
+    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
   else
     {
       dw2_asm_output_data (1, cfi->dw_cfi_opc,
@@ -3303,6 +3334,12 @@ output_cfi_directive (dw_cfi_ref cfi)
 	       cfi->dw_cfi_oprnd1.dw_cfi_offset);
       break;
 
+    case DW_CFA_GNU_start_epilogue:
+/*DEBUG */
+    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
+      break;
+      
     case DW_CFA_remember_state:
       fprintf (asm_out_file, "\t.cfi_remember_state\n");
       break;
@@ -3498,6 +3535,41 @@ 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 
+      && targetm.asm_out.suppress_eh_epilogue_p())
+    {
+      if (cfi->dw_cfi_opc == DW_CFA_remember_state)
+	{
+	  /* 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_GNU_start_epilogue)
+        {
+/*DEBUG */
+    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+    		" DW_CFA_GNU_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 emit it.  */
+  output_cfi (cfi, fde, for_eh);
+  return cfi;
+}
+
 /* Output one FDE.  */
 
 static void
@@ -3613,13 +3685,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;
 	  }
@@ -3636,7 +3707,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/target.def
===================================================================
--- gcc/target.def	(revision 163221)
+++ gcc/target.def	(working copy)
@@ -390,6 +406,15 @@ DEFHOOK
  void, (FILE *file, int size, rtx x),
  NULL)
 
+/* Targets might not need epilogue information in dwarf2 _eh frames.  This
+   hook should return true if the epilogue should be suppressed in such frames.
+   Epilogues will still be emitted in _debug_frames.  */
+DEFHOOK_UNDOC
+(suppress_eh_epilogue_p,
+ "",
+ bool, (void),
+ hook_bool_void_false)
+
 /* Some target machines need to postscan each insn after it is output.  */
 DEFHOOK
 (final_postscan_insn,
Index: gcc/config/darwin-protos.h
===================================================================
--- gcc/config/darwin-protos.h	(revision 163221)
+++ gcc/config/darwin-protos.h	(working copy)
@@ -83,10 +84,15 @@ extern tree darwin_handle_weak_import_attribute (t
 extern void machopic_output_stub (FILE *, const char *, const char *);
 extern void darwin_globalize_label (FILE *, const char *);
 extern void darwin_assemble_visibility (tree, int);
+
+extern bool darwin_asm_suppress_eh_epilogue_p (void);
+extern void darwin_asm_output_dwarf_section_start_label (FILE *file, 
+							section *sect);
 extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
 					   const char *);
 extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
 					    section *);
+
 extern void darwin_asm_declare_constant_name (FILE *, const char *,
 					      const_tree, HOST_WIDE_INT);
 extern bool darwin_binds_local_p (const_tree);
Index: gcc/config/darwin.h
===================================================================
--- gcc/config/darwin.h	(revision 163221)
+++ gcc/config/darwin.h	(working copy)
@@ -669,7 +675,6 @@ extern GTY(()) int darwin_ms_struct;
    Make Objective-C internal symbols local and in doing this, we need 
    to accommodate the name mangling done by c++ on file scope locals.  */
 
-
 int darwin_label_is_anonymous_local_objc_name (const char *name);
 
 #undef	ASM_OUTPUT_LABELREF
@@ -927,6 +932,16 @@ enum machopic_addr_class {
    ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \
      ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
 
+/* Mark the start of each dwarf debug section to allow us to compute local
+   offsets within the sections.  We do this in darwin, rather than emitting
+   relocs.  */
+#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \
+	darwin_asm_output_dwarf_section_start_label
+
+/* For OSX compatibility we do not want to emit epilogues in _eh frames.  */
+#define TARGET_ASM_SUPPRESS_EH_EPILOGUE_P \
+	darwin_asm_suppress_eh_epilogue_p
+
 #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2)  \
   darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2)
 
Index: gcc/config/darwin.c
===================================================================
--- gcc/config/darwin.c	(revision 163221)
+++ gcc/config/darwin.c	(working copy)
@@ -1666,6 +1666,36 @@ darwin_assemble_visibility (tree decl, int vis)
 	     "not supported in this configuration; ignored");
 }
 
+/* For compatibility with OSX versions that do not emit epilogues in _eh
+   frames we suppress them.  This is made a predicate function to permit 
+   us to add an OSX/FSF compatibility switch should that be required.  */
+
+bool
+darwin_asm_suppress_eh_epilogue_p (void)
+{
+  return true;
+}
+
+/* So that we can compute dwarf offsets within sections, we emit a known
+   section marker at the begining of the section.  This is distinct from
+   the ones emitted by dwarf2out.  The label is constructed by extracting
+   sectname from __DWARF,__sectname,etc,etc.  The hook should be invoked
+   once, after the first switch to the section.  */
+   
+void
+darwin_asm_output_dwarf_section_start_label (FILE *file, section *sect)
+{
+  const char *dnam;
+  int namelen;
+  gcc_assert (sect && (sect->common.flags & (SECTION_NAMED|SECTION_DEBUG)));
+  dnam = ((struct named_section *)sect)->name;
+  gcc_assert (strncmp (dnam, "__DWARF,", 8) == 0);
+  gcc_assert (strchr (dnam + 8, ','));
+
+  namelen = strchr (dnam + 8, ',') - (dnam + 8);
+  fprintf (file, "Lsection%.*s:\n", namelen, dnam + 8);
+}
+
 /* Output a difference of two labels that will be an assembly time
    constant if the two labels are local.  (.long lab1-lab2 will be
    very different if lab1 is at the boundary between two sections; it
