OSDN Git Service

* Makefile.in (c-cppbuiltin.o): Depend on debug.h.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 5 Aug 2008 17:24:37 +0000 (17:24 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 5 Aug 2008 17:24:37 +0000 (17:24 +0000)
        * c-cppbuiltin.c (c_cpp_builtins): Define __GCC_HAVE_DWARF2_CFI_ASM.
        * doc/cpp.texi (__GCC_HAVE_DWARF2_CFI_ASM): Document it.
        * common.opt (fdwarf2-cfi-asm): New.
        * configure.ac (HAVE_GAS_CFI_DIRECTIVE): New.
        * config.in, configure: Rebuild.
        * dwarf2asm.c (dw2_asm_output_data_raw): New.
        (dw2_asm_output_data_uleb128_raw, dw2_asm_output_data_sleb128_raw): New.
        (dw2_force_const_mem): Externalize.
        * dwarf2asm.h: Update.
        * dwarf2out.c (dwarf2out_cfi_label): If flag_dwarf2_cfi_asm, don't
        generate a real label.
        (output_cfi_directive): New.
        (add_fde_cfi): If flag_dwarf2_cfi_asm, use it.
        (output_call_frame_info): Do nothing if flag_dwarf2_cfi_asm.
        (dwarf2out_begin_prologue): Emit .cfi_startproc, .cfi_personality,
        and .cfi_lsda.
        (dwarf2out_end_epilogue): Emit .cfi_endproc.
        (output_loc_operands_raw, output_loc_sequence_raw): New.
        (output_cfa_loc_raw): New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@138733 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/c-cppbuiltin.c
gcc/common.opt
gcc/config.in
gcc/configure
gcc/configure.ac
gcc/doc/cpp.texi
gcc/dwarf2asm.c
gcc/dwarf2asm.h
gcc/dwarf2out.c

index 7444d7e..7884fa8 100644 (file)
@@ -1,3 +1,26 @@
+2008-08-05  Richard Henderson  <rth@redhat.com>
+
+       * Makefile.in (c-cppbuiltin.o): Depend on debug.h.
+       * c-cppbuiltin.c (c_cpp_builtins): Define __GCC_HAVE_DWARF2_CFI_ASM.
+       * doc/cpp.texi (__GCC_HAVE_DWARF2_CFI_ASM): Document it.
+       * common.opt (fdwarf2-cfi-asm): New.
+       * configure.ac (HAVE_GAS_CFI_DIRECTIVE): New.
+       * config.in, configure: Rebuild.
+       * dwarf2asm.c (dw2_asm_output_data_raw): New.
+       (dw2_asm_output_data_uleb128_raw, dw2_asm_output_data_sleb128_raw): New.
+       (dw2_force_const_mem): Externalize.
+       * dwarf2asm.h: Update.
+       * dwarf2out.c (dwarf2out_cfi_label): If flag_dwarf2_cfi_asm, don't
+       generate a real label.
+       (output_cfi_directive): New.
+       (add_fde_cfi): If flag_dwarf2_cfi_asm, use it.
+       (output_call_frame_info): Do nothing if flag_dwarf2_cfi_asm.
+       (dwarf2out_begin_prologue): Emit .cfi_startproc, .cfi_personality,
+       and .cfi_lsda.
+       (dwarf2out_end_epilogue): Emit .cfi_endproc.
+       (output_loc_operands_raw, output_loc_sequence_raw): New.
+       (output_cfa_loc_raw): New.
+       
 2008-08-05  Paul Brook  <paul@codesourcery.com>
 
        * doc/invoke.texi: Document new ARM -mfpu= and -mcpu= options.
index 479277a..1c22966 100644 (file)
@@ -1870,8 +1870,9 @@ c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)           \
                $< $(OUTPUT_OPTION) @TARGET_SYSTEM_ROOT_DEFINE@
 
 c-cppbuiltin.o : c-cppbuiltin.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
-       $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) $(FLAGS_H) $(TOPLEV_H) \
-       output.h except.h $(REAL_H) $(TARGET_H) $(TM_P_H) $(BASEVER)
+       $(TREE_H) version.h $(C_COMMON_H) $(C_PRAGMA_H) $(FLAGS_H) \
+       $(TOPLEV_H) output.h except.h $(REAL_H) $(TARGET_H) $(TM_P_H) \
+       $(BASEVER) debug.h
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) -DBASEVER=$(BASEVER_s) \
                $< $(OUTPUT_OPTION)
 
index 2d951fe..01f9215 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-pragma.h"
 #include "output.h"
 #include "except.h"            /* For USING_SJLJ_EXCEPTIONS.  */
+#include "debug.h"             /* For dwarf2out_do_frame.  */
 #include "toplev.h"
 #include "tm_p.h"              /* Target prototypes.  */
 #include "target.h"
@@ -691,6 +692,11 @@ c_cpp_builtins (cpp_reader *pfile)
     cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
 #endif
 
+#ifdef DWARF2_UNWIND_INFO
+  if (flag_dwarf2_cfi_asm && dwarf2out_do_frame ())
+    cpp_define (pfile, "__GCC_HAVE_DWARF2_CFI_ASM");
+#endif
+
   /* Make the choice of ObjC runtime visible to source code.  */
   if (c_dialect_objc () && flag_next_runtime)
     cpp_define (pfile, "__NEXT_RUNTIME__");
index 08f95c2..02bdef2 100644 (file)
@@ -459,6 +459,10 @@ fdump-unnumbered
 Common Report Var(flag_dump_unnumbered) VarExists
 Suppress output of instruction numbers, line number notes and addresses in debugging dumps
 
+fdwarf2-cfi-asm
+Common Report Var(flag_dwarf2_cfi_asm) Init(HAVE_GAS_CFI_DIRECTIVE)
+Enable CFI tables via GAS assembler directives.
+
 fearly-inlining
 Common Report Var(flag_early_inlining) Init(1) Optimization
 Perform early inlining
index b4261d9..47ec2ab 100644 (file)
 #endif
 
 
+/* Define 0/1 if your assembler supports CFI directives. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_CFI_DIRECTIVE
+#endif
+
+
 /* Define if your assembler uses the new HImode fild and fist notation. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_FILDS_FISTS
index a79664b..d1996bb 100755 (executable)
@@ -20832,6 +20832,50 @@ _ACEOF
 
 fi
 
+# Check if we have assembler support for unwind directives.
+echo "$as_me:$LINENO: checking assembler for cfi directives" >&5
+echo $ECHO_N "checking assembler for cfi directives... $ECHO_C" >&6
+if test "${gcc_cv_as_cfi_directive+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  gcc_cv_as_cfi_directive=no
+    if test $in_tree_gas = yes; then
+    if test $in_tree_gas_is_elf = yes \
+  && test $gcc_cv_gas_vers -ge `expr \( \( 2 \* 1000 \) + 17 \) \* 1000 + 0`
+  then gcc_cv_as_cfi_directive=yes
+fi
+  elif test x$gcc_cv_as != x; then
+    echo '     .text
+       .cfi_startproc
+       .cfi_offset 0, 0
+       .cfi_same_value 1
+       .cfi_def_cfa 1, 2
+       .cfi_escape 1, 2, 3, 4, 5
+       .cfi_endproc' > conftest.s
+    if { ac_try='$gcc_cv_as  -o conftest.o conftest.s >&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }
+    then
+       gcc_cv_as_cfi_directive=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+echo "$as_me:$LINENO: result: $gcc_cv_as_cfi_directive" >&5
+echo "${ECHO_T}$gcc_cv_as_cfi_directive" >&6
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_GAS_CFI_DIRECTIVE `if test $gcc_cv_as_cfi_directive = yes; then echo 1; else echo 0; fi`
+_ACEOF
+
+
 # GAS versions up to and including 2.11.0 may mis-optimize
 # .eh_frame data.
 echo "$as_me:$LINENO: checking assembler for eh_frame optimization" >&5
index ced1a7c..4f7fc32 100644 (file)
@@ -2180,6 +2180,20 @@ changequote([,])dnl
   [AC_DEFINE(HAVE_AS_LEB128, 1,
     [Define if your assembler supports .sleb128 and .uleb128.])])
 
+# Check if we have assembler support for unwind directives.
+gcc_GAS_CHECK_FEATURE([cfi directives], gcc_cv_as_cfi_directive,
+  [elf,2,17,0],,
+[      .text
+       .cfi_startproc
+       .cfi_offset 0, 0
+       .cfi_same_value 1
+       .cfi_def_cfa 1, 2
+       .cfi_escape 1, 2, 3, 4, 5
+       .cfi_endproc])
+AC_DEFINE_UNQUOTED(HAVE_GAS_CFI_DIRECTIVE,
+  [`if test $gcc_cv_as_cfi_directive = yes; then echo 1; else echo 0; fi`],
+[Define 0/1 if your assembler supports CFI directives.])
+
 # GAS versions up to and including 2.11.0 may mis-optimize
 # .eh_frame data.
 gcc_GAS_CHECK_FEATURE(eh_frame optimization, gcc_cv_as_eh_frame,
index aaf83f9..0eaece1 100644 (file)
@@ -2239,6 +2239,10 @@ If GCC cannot determine the current date, it will emit a warning message
 These macros are defined when the target processor supports atomic compare
 and swap operations on operands 1, 2, 4, 8 or 16 bytes in length, respectively.
 
+@item __GCC_HAVE_DWARF2_CFI_ASM
+This macro is defined when the compiler is emitting Dwarf2 CFI directives
+to the assembler.  When this is defined, it is possible to emit those same
+directives in inline assembly.
 @end table
 
 @node System-specific Predefined Macros
index 43d57e9..9ae9420 100644 (file)
@@ -62,6 +62,34 @@ dw2_assemble_integer (int size, rtx x)
 }
 
 
+/* Output a value of a given size in target byte order.  */
+
+void
+dw2_asm_output_data_raw (int size, unsigned HOST_WIDE_INT value)
+{
+  unsigned char bytes[8];
+  int i;
+
+  for (i = 0; i < 8; ++i)
+    {
+      bytes[i] = value & 0xff;
+      value >>= 8;
+    }
+
+  if (BYTES_BIG_ENDIAN)
+    {
+      for (i = size - 1; i > 0; --i)
+       fprintf (asm_out_file, "0x%x,", bytes[i]);
+      fprintf (asm_out_file, "0x%x", bytes[0]);
+    }
+  else
+    {
+      for (i = 0; i < size - 1; ++i)
+       fprintf (asm_out_file, "0x%x,", bytes[i]);
+      fprintf (asm_out_file, "0x%x", bytes[i]);
+    }
+}
+
 /* Output an immediate constant in a given SIZE in bytes.  */
 
 void
@@ -505,6 +533,26 @@ eh_data_format_name (int format)
 #endif
 }
 
+/* Output an unsigned LEB128 quantity, but only the byte values.  */
+
+void
+dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT value)
+{
+  while (1)
+    {
+      int byte = (value & 0x7f);
+      value >>= 7;
+      if (value != 0)
+       /* More bytes to follow.  */
+       byte |= 0x80;
+
+      fprintf (asm_out_file, "0x%x", byte);
+      if (value == 0)
+       break;
+      fputc (',', asm_out_file);
+    }
+}
+
 /* Output an unsigned LEB128 quantity.  */
 
 void
@@ -566,6 +614,29 @@ dw2_asm_output_data_uleb128 (unsigned HOST_WIDE_INT value,
   va_end (ap);
 }
 
+/* Output an signed LEB128 quantity, but only the byte values.  */
+
+void
+dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT value)
+{
+  int byte, more;
+
+  while (1)
+    {
+      byte = (value & 0x7f);
+      value >>= 7;
+      more = !((value == 0 && (byte & 0x40) == 0)
+               || (value == -1 && (byte & 0x40) != 0));
+      if (more)
+       byte |= 0x80;
+
+      fprintf (asm_out_file, "0x%x", byte);
+      if (!more)
+       break;
+      fputc (',', asm_out_file);
+    }
+}
+
 /* Output a signed LEB128 quantity.  */
 
 void
@@ -689,7 +760,6 @@ dw2_asm_output_delta_sleb128 (const char *lab1 ATTRIBUTE_UNUSED,
 }
 #endif /* 0 */
 \f
-static rtx dw2_force_const_mem (rtx, bool);
 static int dw2_output_indirect_constant_1 (splay_tree_node, void *);
 
 static GTY((param1_is (char *), param2_is (tree))) splay_tree indirect_pool;
@@ -733,7 +803,7 @@ splay_tree_compare_strings (splay_tree_key k1, splay_tree_key k2)
    "near" the function in any interesting sense.  IS_PUBLIC controls whether
    the symbol can be shared across the entire application (or DSO).  */
 
-static rtx
+rtx
 dw2_force_const_mem (rtx x, bool is_public)
 {
   splay_tree_node node;
index 03fc0ca..70fbd4c 100644 (file)
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3.  If not see
 
 extern void dw2_assemble_integer (int, rtx);
 
+extern void dw2_asm_output_data_raw (int, unsigned HOST_WIDE_INT);
+
 extern void dw2_asm_output_data (int, unsigned HOST_WIDE_INT,
                                 const char *, ...)
      ATTRIBUTE_NULL_PRINTF_3;
@@ -46,10 +48,14 @@ extern void dw2_asm_output_nstring (const char *, size_t,
                                    const char *, ...)
      ATTRIBUTE_NULL_PRINTF_3;
 
+extern void dw2_asm_output_data_uleb128_raw (unsigned HOST_WIDE_INT);
+
 extern void dw2_asm_output_data_uleb128        (unsigned HOST_WIDE_INT,
                                         const char *, ...)
      ATTRIBUTE_NULL_PRINTF_2;
 
+extern void dw2_asm_output_data_sleb128_raw (HOST_WIDE_INT);
+
 extern void dw2_asm_output_data_sleb128        (HOST_WIDE_INT,
                                         const char *, ...)
      ATTRIBUTE_NULL_PRINTF_2;
@@ -63,6 +69,7 @@ extern int size_of_sleb128 (HOST_WIDE_INT);
 extern int size_of_encoded_value (int);
 extern const char *eh_data_format_name (int);
 
+extern rtx dw2_force_const_mem (rtx, bool);
 extern void dw2_output_indirect_constants (void);
 
 /* These are currently unused.  */
index e5128d4..ad09949 100644 (file)
@@ -384,6 +384,7 @@ static void initial_return_save (rtx);
 #endif
 static HOST_WIDE_INT stack_adjust_offset (const_rtx);
 static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
+static void output_cfi_directive (dw_cfi_ref);
 static void output_call_frame_info (int);
 static void dwarf2out_note_section_used (void);
 static void dwarf2out_stack_adjust (rtx, bool);
@@ -394,6 +395,7 @@ static void dwarf2out_frame_debug_expr (rtx, const char *);
 
 /* Support for complex CFA locations.  */
 static void output_cfa_loc (dw_cfi_ref);
+static void output_cfa_loc_raw (dw_cfi_ref);
 static void get_cfa_from_loc_descr (dw_cfa_location *,
                                    struct dw_loc_descr_struct *);
 static struct dw_loc_descr_struct *build_cfa_loc
@@ -665,8 +667,19 @@ dwarf2out_cfi_label (void)
 {
   static char label[20];
 
-  ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
-  ASM_OUTPUT_LABEL (asm_out_file, label);
+  if (flag_dwarf2_cfi_asm)
+    {
+      /* In this case, we will be emitting the asm directive instead of
+        the label, so just return a placeholder to keep the rest of the
+        interfaces happy.  */
+      strcpy (label, "<do not output>");
+    }
+  else
+    {
+      ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
+      ASM_OUTPUT_LABEL (asm_out_file, label);
+    }
+
   return label;
 }
 
@@ -676,7 +689,25 @@ dwarf2out_cfi_label (void)
 static void
 add_fde_cfi (const char *label, dw_cfi_ref cfi)
 {
-  if (label)
+  dw_cfi_ref *list_head = &cie_cfi_head;
+
+  if (flag_dwarf2_cfi_asm)
+    {
+      if (label)
+       {
+         output_cfi_directive (cfi);
+
+         /* We still have to add the cfi to the list so that
+            lookup_cfa works later on.  */
+         list_head = &current_fde ()->dw_fde_cfi;
+       }
+      /* ??? If this is a CFI for the CIE, we don't emit.  This
+        assumes that the standard CIE contents that the assembler
+        uses matches the standard CIE contents that the compiler
+        uses.  This is probably a bad assumption.  I'm not quite
+        sure how to address this for now.  */
+    }
+  else if (label)
     {
       dw_fde_ref fde = current_fde ();
 
@@ -705,11 +736,10 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
          fde->dw_fde_current_label = label;
        }
 
-      add_cfi (&fde->dw_fde_cfi, cfi);
+      list_head = &fde->dw_fde_cfi;
     }
 
-  else
-    add_cfi (&cie_cfi_head, cfi);
+  add_cfi (list_head, cfi);
 }
 
 /* Subroutine of lookup_cfa.  */
@@ -2619,6 +2649,100 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
     }
 }
 
+/* Similar, but do it via assembler directives instead.  */
+
+static void
+output_cfi_directive (dw_cfi_ref cfi)
+{
+  unsigned long r, r2;
+
+  switch (cfi->dw_cfi_opc)
+    {
+    case DW_CFA_advance_loc:
+    case DW_CFA_advance_loc1:
+    case DW_CFA_advance_loc2:
+    case DW_CFA_advance_loc4:
+    case DW_CFA_MIPS_advance_loc8:
+    case DW_CFA_set_loc:
+      /* Should only be created by add_fde_cfi in a code path not
+        followed when emitting via directives.  The assembler is
+        going to take care of this for us.  */
+      gcc_unreachable ();
+
+    case DW_CFA_offset:
+    case DW_CFA_offset_extended:
+    case DW_CFA_offset_extended_sf:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
+              r, cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT);
+      break;
+
+    case DW_CFA_restore:
+    case DW_CFA_restore_extended:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_restore %lu\n", r);
+      break;
+
+    case DW_CFA_undefined:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_undefined %lu\n", r);
+      break;
+
+    case DW_CFA_same_value:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_same_value %lu\n", r);
+      break;
+
+    case DW_CFA_def_cfa:
+    case DW_CFA_def_cfa_sf:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
+              r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      break;
+
+    case DW_CFA_def_cfa_register:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_def_cfa_register %lu\n", r);
+      break;
+
+    case DW_CFA_register:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0);
+      r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 0);
+      fprintf (asm_out_file, "\t.cfi_register %lu, %lu\n", r, r2);
+      break;
+
+    case DW_CFA_def_cfa_offset:
+    case DW_CFA_def_cfa_offset_sf:
+      fprintf (asm_out_file, "\t.cfi_def_cfa_offset "
+              HOST_WIDE_INT_PRINT_DEC"\n",
+              cfi->dw_cfi_oprnd1.dw_cfi_offset);
+      break;
+
+    case DW_CFA_GNU_args_size:
+      fprintf (asm_out_file, "\t.cfi_escape 0x%x,", DW_CFA_GNU_args_size);
+      dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+      if (flag_debug_asm)
+       fprintf (asm_out_file, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC,
+                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
+      fputc ('\n', asm_out_file);
+      break;
+
+    case DW_CFA_GNU_window_save:
+      fprintf (asm_out_file, "\t.cfi_window_save\n");
+      break;
+
+    case DW_CFA_def_cfa_expression:
+    case DW_CFA_expression:
+      fprintf (asm_out_file, "\t.cfi_escape 0x%x,", cfi->dw_cfi_opc);
+      output_cfa_loc_raw (cfi);
+      fputc ('\n', asm_out_file);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Output the call frame information used to record information
    that relates to calculating the frame pointer, and records the
    location of saved registers.  */
@@ -2642,6 +2766,10 @@ output_call_frame_info (int for_eh)
   if (fde_table_in_use == 0)
     return;
 
+  /* Nothing to do if the assembler's doing it all.  */
+  if (flag_dwarf2_cfi_asm)
+    return;
+
   /* If we make FDEs linkonce, we may have to emit an empty label for
      an FDE that wouldn't otherwise be emitted.  We want to avoid
      having an FDE kept around when the function it refers to is
@@ -3058,6 +3186,49 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   if (file)
     dwarf2out_source_line (line, file);
 #endif
+
+  if (flag_dwarf2_cfi_asm)
+    {
+      int enc;
+      rtx ref;
+
+      fprintf (asm_out_file, "\t.cfi_startproc\n");
+
+      if (eh_personality_libfunc)
+       {
+         enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1); 
+         ref = eh_personality_libfunc;
+
+         /* ??? The GAS support isn't entirely consistent.  We have to
+            handle indirect support ourselves, but PC-relative is done
+            in the assembler.  Further, the assembler can't handle any
+            of the weirder relocation types.  */
+         if (enc & DW_EH_PE_indirect)
+           ref = dw2_force_const_mem (ref, true);
+
+         fprintf (asm_out_file, "\t.cfi_personality 0x%x,", enc);
+         output_addr_const (asm_out_file, ref);
+         fputc ('\n', asm_out_file);
+       }
+
+      if (crtl->uses_eh_lsda)
+       {
+         char lab[20];
+
+         enc = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
+         ASM_GENERATE_INTERNAL_LABEL (lab, "LLSDA",
+                                      current_function_funcdef_no);
+         ref = gen_rtx_SYMBOL_REF (Pmode, lab);
+         SYMBOL_REF_FLAGS (ref) = SYMBOL_FLAG_LOCAL;
+
+         if (enc & DW_EH_PE_indirect)
+           ref = dw2_force_const_mem (ref, true);
+
+         fprintf (asm_out_file, "\t.cfi_lsda 0x%x,", enc);
+         output_addr_const (asm_out_file, ref);
+         fputc ('\n', asm_out_file);
+       }
+    }
 }
 
 /* Output a marker (i.e. a label) for the absolute end of the generated code
@@ -3071,6 +3242,9 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   dw_fde_ref fde;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
+  if (flag_dwarf2_cfi_asm)
+    fprintf (asm_out_file, "\t.cfi_endproc\n");
+
   /* Output a label to mark the endpoint of the code generated for this
      function.  */
   ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
@@ -3931,6 +4105,141 @@ output_loc_sequence (dw_loc_descr_ref loc)
     }
 }
 
+/* Output location description stack opcode's operands (if any).
+   The output is single bytes on a line, suitable for .cfi_escape.  */
+
+static void
+output_loc_operands_raw (dw_loc_descr_ref loc)
+{
+  dw_val_ref val1 = &loc->dw_loc_oprnd1;
+  dw_val_ref val2 = &loc->dw_loc_oprnd2;
+
+  switch (loc->dw_loc_opc)
+    {
+    case DW_OP_addr:
+      /* We cannot output addresses in .cfi_escape, only bytes.  */
+      gcc_unreachable ();
+
+    case DW_OP_const1u:
+    case DW_OP_const1s:
+    case DW_OP_pick:
+    case DW_OP_deref_size:
+    case DW_OP_xderef_size:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_raw (1, val1->v.val_int);
+      break;
+
+    case DW_OP_const2u:
+    case DW_OP_const2s:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_raw (2, val1->v.val_int);
+      break;
+
+    case DW_OP_const4u:
+    case DW_OP_const4s:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_raw (4, val1->v.val_int);
+      break;
+
+    case DW_OP_const8u:
+    case DW_OP_const8s:
+      gcc_assert (HOST_BITS_PER_LONG >= 64);
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_raw (8, val1->v.val_int);
+      break;
+
+    case DW_OP_skip:
+    case DW_OP_bra:
+      {
+       int offset;
+
+       gcc_assert (val1->val_class == dw_val_class_loc);
+       offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
+
+        fputc (',', asm_out_file);
+       dw2_asm_output_data_raw (2, offset);
+      }
+      break;
+
+    case DW_OP_constu:
+    case DW_OP_plus_uconst:
+    case DW_OP_regx:
+    case DW_OP_piece:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
+      break;
+
+    case DW_OP_consts:
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+    case DW_OP_fbreg:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_sleb128_raw (val1->v.val_int);
+      break;
+
+    case DW_OP_bregx:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_sleb128_raw (val2->v.val_int);
+      break;
+
+    case INTERNAL_DW_OP_tls_addr:
+      gcc_unreachable ();
+
+    default:
+      /* Other codes have no operands.  */
+      break;
+    }
+}
+
+static void
+output_loc_sequence_raw (dw_loc_descr_ref loc)
+{
+  while (1)
+    {
+      /* Output the opcode.  */
+      fprintf (asm_out_file, "0x%x", loc->dw_loc_opc);
+      output_loc_operands_raw (loc);
+
+      if (!loc->dw_loc_next)
+       break;
+      loc = loc->dw_loc_next;
+
+      fputc (',', asm_out_file);
+    }
+}
+
 /* This routine will generate the correct assembly data for a location
    description based on a cfi entry with a complex address.  */
 
@@ -3952,6 +4261,27 @@ output_cfa_loc (dw_cfi_ref cfi)
   output_loc_sequence (loc);
 }
 
+/* Similar, but used for .cfi_escape.  */
+
+static void
+output_cfa_loc_raw (dw_cfi_ref cfi)
+{
+  dw_loc_descr_ref loc;
+  unsigned long size;
+
+  if (cfi->dw_cfi_opc == DW_CFA_expression)
+    fprintf (asm_out_file, "0x%x,", cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
+
+  /* Output the size of the block.  */
+  loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
+  size = size_of_locs (loc);
+  dw2_asm_output_data_uleb128_raw (size);
+  fputc (',', asm_out_file);
+
+  /* Now output the operations themselves.  */
+  output_loc_sequence_raw (loc);
+}
+
 /* This function builds a dwarf location descriptor sequence from a
    dw_cfa_location, adding the given OFFSET to the result of the
    expression.  */