OSDN Git Service

* unwind-dw2-fde.c (__deregister_frame_info_bases):
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 1d245b7..164b051 100644 (file)
@@ -22,8 +22,7 @@ along with GCC; see the file COPYING.  If not, write to the Free
 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
-/* TODO: Implement .debug_str handling, and share entries somehow.
-        Emit .debug_line header even when there are no functions, since
+/* TODO: Emit .debug_line header even when there are no functions, since
           the file numbers are used by .debug_info.  Alternately, leave
           out locations for types and decls.
         Avoid talking about ctors and op= for PODs.
@@ -59,6 +58,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "diagnostic.h"
 #include "debug.h"
+#include "target.h"
+#include "langhooks.h"
+#include "hashtable.h"
 
 #ifdef DWARF2_DEBUGGING_INFO
 static void dwarf2out_source_line      PARAMS ((unsigned int, const char *));
@@ -106,6 +108,30 @@ dwarf2out_do_frame ()
    unique to each function definition.  */
 unsigned current_funcdef_number = 0;
 
+/* The size of the target's pointer type.  */
+#ifndef PTR_SIZE
+#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
+/* Default version of targetm.eh_frame_section.  Note this must appear
+   outside the DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO macro
+   guards.  */
+
+void
+default_eh_frame_section ()
+{
+#ifdef EH_FRAME_SECTION_NAME
+  named_section_flags (EH_FRAME_SECTION_NAME, SECTION_WRITE);
+#else
+  tree label = get_file_function_name ('F');
+
+  data_section ();
+  ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+  ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+  ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+#endif
+}
+
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 
 /* How to start an assembler comment.  */
@@ -174,11 +200,6 @@ dw_fde_node;
 /* Maximum size (in bytes) of an artificially generated label.  */
 #define MAX_ARTIFICIAL_LABEL_BYTES     30
 
-/* The size of the target's pointer type.  */
-#ifndef PTR_SIZE
-#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
-#endif
-
 /* The size of addresses as they appear in the Dwarf 2 data.
    Some architectures use word addresses to refer to code locations,
    but Dwarf 2 info always uses byte addresses.  On such machines,
@@ -235,6 +256,16 @@ static dw_cfi_ref cie_cfi_head;
    associated with the current function (body) definition.  */
 static unsigned current_funcdef_fde;
 
+struct ht *debug_str_hash;
+
+struct indirect_string_node
+{
+  struct ht_identifier id;
+  unsigned int refcount;
+  unsigned int form;
+  char *label;
+};
+
 /* Forward declarations for functions defined in this file.  */
 
 static char *stripattributes           PARAMS ((const char *));
@@ -264,6 +295,11 @@ static struct dw_loc_descr_struct *build_cfa_loc
                                        PARAMS ((dw_cfa_location *));
 static void def_cfa_1                  PARAMS ((const char *, dw_cfa_location *));
 
+/* .debug_str support.  */
+static hashnode indirect_string_alloc  PARAMS ((hash_table *));
+static int output_indirect_string      PARAMS ((struct cpp_reader *,
+                                                hashnode, const PTR));
+
 /* How to start an assembler comment.  */
 #ifndef ASM_COMMENT_START
 #define ASM_COMMENT_START ";#"
@@ -943,7 +979,8 @@ dwarf2out_stack_adjust (insn)
   long offset;
   const char *label;
 
-  if (! flag_non_call_exceptions && GET_CODE (insn) == CALL_INSN)
+  if (!flag_asynchronous_unwind_tables
+      && GET_CODE (insn) == CALL_INSN)
     {
       /* Extract the size of the args from the CALL rtx itself.  */
 
@@ -960,7 +997,7 @@ dwarf2out_stack_adjust (insn)
 
   /* If only calls can throw, and we have a frame pointer,
      save up adjustments until we see the CALL_INSN.  */
-  else if (! flag_non_call_exceptions
+  else if (!flag_asynchronous_unwind_tables
           && cfa.reg != STACK_POINTER_REGNUM)
     return;
 
@@ -1721,7 +1758,7 @@ output_call_frame_info (for_eh)
      emit any EH unwind information.  */
   if (for_eh)
     {
-      int any_eh_needed = 0;
+      int any_eh_needed = flag_asynchronous_unwind_tables;
       for (i = 0; i < fde_table_in_use; ++i)
        if (fde_table[i].uses_eh_lsda)
          any_eh_needed = any_lsda_needed = 1;
@@ -1737,18 +1774,7 @@ output_call_frame_info (for_eh)
     app_enable ();
 
   if (for_eh)
-    {
-#ifdef EH_FRAME_SECTION_NAME
-      named_section_flags (EH_FRAME_SECTION_NAME, SECTION_WRITE);
-#else
-      tree label = get_file_function_name ('F');
-
-      data_section ();
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-      ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
-      ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
-#endif
-    }
+    (*targetm.asm_out.eh_frame_section) ();
   else
     named_section_flags (DEBUG_FRAME_SECTION, SECTION_DEBUG);
 
@@ -2166,7 +2192,7 @@ typedef struct dw_val_struct
        int external;
       } val_die_ref;
       unsigned val_fde_index;
-      char *val_str;
+      struct indirect_string_node *val_str;
       char *val_lbl_id;
       unsigned char val_flag;
     }
@@ -3463,7 +3489,6 @@ static void break_out_includes            PARAMS ((dw_die_ref));
 static void add_sibling_attributes     PARAMS ((dw_die_ref));
 static void build_abbrev_table         PARAMS ((dw_die_ref));
 static void output_location_lists      PARAMS ((dw_die_ref));
-static unsigned long size_of_string    PARAMS ((const char *));
 static int constant_size               PARAMS ((long unsigned));
 static unsigned long size_of_die       PARAMS ((dw_die_ref));
 static void calc_die_sizes             PARAMS ((dw_die_ref));
@@ -3619,6 +3644,14 @@ static char *gen_internal_sym            PARAMS ((const char *));
 #define TEXT_SECTION_NAME      ".text"
 #endif
 
+/* Section flags for .debug_str section.  */
+#ifdef HAVE_GAS_SHF_MERGE
+#define DEBUG_STR_SECTION_FLAGS \
+  (SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1)
+#else
+#define DEBUG_STR_SECTION_FLAGS        SECTION_DEBUG
+#endif
+
 /* Labels we insert at beginning sections we can reference instead of
    the section names themselves.  */
 
@@ -4396,11 +4429,23 @@ add_AT_string (die, attr_kind, str)
      const char *str;
 {
   dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+  struct indirect_string_node *node;
+  
+  if (! debug_str_hash)
+    {
+      debug_str_hash = ht_create (10);
+      debug_str_hash->alloc_node = indirect_string_alloc;
+    }
+
+  node = (struct indirect_string_node *)
+        ht_lookup (debug_str_hash, (const unsigned char *) str,
+                   strlen (str), HT_ALLOC);
+  node->refcount++;
 
   attr->dw_attr_next = NULL;
   attr->dw_attr = attr_kind;
   attr->dw_attr_val.val_class = dw_val_class_str;
-  attr->dw_attr_val.v.val_str = xstrdup (str);
+  attr->dw_attr_val.v.val_str = node;
   add_dwarf_attr (die, attr);
 }
 
@@ -4410,7 +4455,52 @@ AT_string (a)
      dw_attr_ref a;
 {
   if (a && AT_class (a) == dw_val_class_str)
-    return a->dw_attr_val.v.val_str;
+    return (const char *) HT_STR (&a->dw_attr_val.v.val_str->id);
+
+  abort ();
+}
+
+/* Find out whether a string should be output inline in DIE
+   or out-of-line in .debug_str section.  */
+
+static int AT_string_form PARAMS ((dw_attr_ref));
+static int
+AT_string_form (a)
+     dw_attr_ref a;
+{
+  if (a && AT_class (a) == dw_val_class_str)
+    {
+      struct indirect_string_node *node;
+      unsigned int len;
+      extern int const_labelno;
+      char label[32];
+
+      node = a->dw_attr_val.v.val_str;
+      if (node->form)
+       return node->form;
+
+      len = HT_LEN (&node->id) + 1;
+
+      /* If the string is shorter or equal to the size
+        of the reference, it is always better to put it
+        inline.  */
+      if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
+       return node->form = DW_FORM_string;
+
+      if ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0)
+       {
+         /* If we cannot expect the linker to merge strings
+            in .debug_str section, only put it into .debug_str
+            if it is worth even in this single module.  */
+         if ((len - DWARF_OFFSET_SIZE) * node->refcount <= len)
+           return node->form = DW_FORM_string;
+       }
+
+      ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+      ++const_labelno;
+      node->label = xstrdup (label);
+      return node->form = DW_FORM_strp;
+    }
 
   abort ();
 }
@@ -4766,9 +4856,13 @@ free_AT (a)
   switch (AT_class (a))
     {
     case dw_val_class_str:
+      if (a->dw_attr_val.v.val_str->refcount)
+       a->dw_attr_val.v.val_str->refcount--;
+      break;
+
     case dw_val_class_lbl_id:
     case dw_val_class_lbl_offset:
-      free (a->dw_attr_val.v.val_str);
+      free (a->dw_attr_val.v.val_lbl_id);
       break;
 
     case dw_val_class_float:
@@ -5660,20 +5754,6 @@ build_abbrev_table (die)
     build_abbrev_table (c);
 }
 \f
-/* Return the size of a string, including the null byte.
-
-   This used to treat backslashes as escapes, and hence they were not included
-   in the count.  However, that conflicts with what ASM_OUTPUT_ASCII does,
-   which treats a backslash as a backslash, escaping it if necessary, and hence
-   we must include them in the count.  */
-
-static unsigned long
-size_of_string (str)
-     const char *str;
-{
-  return strlen (str) + 1;
-}
-
 /* Return the power-of-two number of bytes necessary to represent VALUE.  */
 
 static int
@@ -5754,7 +5834,10 @@ size_of_die (die)
          size += DWARF_OFFSET_SIZE;
          break;
        case dw_val_class_str:
-         size += size_of_string (AT_string (a));
+         if (AT_string_form (a) == DW_FORM_strp)
+           size += DWARF_OFFSET_SIZE;
+         else
+           size += HT_LEN (&a->dw_attr_val.v.val_str->id) + 1;
          break;
        default:
          abort ();
@@ -5826,7 +5909,7 @@ size_of_pubnames ()
   for (i = 0; i < pubname_table_in_use; ++i)
     {
       pubname_ref p = &pubname_table[i];
-      size += DWARF_OFFSET_SIZE + size_of_string (p->name);
+      size += DWARF_OFFSET_SIZE + strlen (p->name) + 1;
     }
 
   size += DWARF_OFFSET_SIZE;
@@ -5915,7 +5998,7 @@ value_format (a)
     case dw_val_class_lbl_offset:
       return DW_FORM_data;
     case dw_val_class_str:
-      return DW_FORM_string;
+      return AT_string_form (a);
 
     default:
       abort ();
@@ -6074,6 +6157,7 @@ output_loc_list (list_head)
                       "Location list terminator end (%s)",
                       list_head->ll_symbol);
 }
+
 /* Output the DIE and its attributes.  Called recursively to generate
    the definitions of each child DIE.  */
 
@@ -6213,7 +6297,12 @@ output_die (die)
          break;
 
        case dw_val_class_str:
-         dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
+         if (AT_string_form (a) == DW_FORM_strp)
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+                                  a->dw_attr_val.v.val_str->label,
+                                  "%s", name);
+         else
+           dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
          break;
 
        default:
@@ -6567,6 +6656,7 @@ struct dir_info
 
 /* Callback function for file_info comparison.  We sort by looking at
    the directories in the path.  */
+
 static int
 file_info_cmp (p1, p2)
      const void *p1;
@@ -6577,11 +6667,13 @@ file_info_cmp (p1, p2)
   unsigned char *cp1;
   unsigned char *cp2;
 
-  /* Take care of file names without directories.  */
-  if (s1->path == s1->fname)
-    return -1;
-  else if (s2->path == s2->fname)
-    return 1;
+  /* Take care of file names without directories.  We need to make sure that
+     we return consistent values to qsort since some will get confused if
+     we return the same value when identical operands are passed in opposite
+     orders.  So if neither has a directory, return 0 and otherwise return
+     1 or -1 depending on which one has the directory.  */
+  if ((s1->path == s1->fname || s2->path == s2->fname))
+    return (s2->path == s2->fname) - (s1->path == s1->fname);
 
   cp1 = (unsigned char *) s1->path;
   cp2 = (unsigned char *) s2->path;
@@ -6590,17 +6682,14 @@ file_info_cmp (p1, p2)
     {
       ++cp1;
       ++cp2;
-      /* Reached the end of the first path?  */
-      if (cp1 == (unsigned char *) s1->fname)
-       /* It doesn't really matter in which order files from the
-          same directory are sorted in.  Therefore don't test for
-          the second path reaching the end.  */
-       return -1;
-      else if (cp2 == (unsigned char *) s2->fname)
-       return 1;
+      /* Reached the end of the first path?  If so, handle like above.  */
+      if ((cp1 == (unsigned char *) s1->fname)
+         || (cp2 == (unsigned char *) s2->fname))
+       return ((cp2 == (unsigned char *) s2->fname)
+               - (cp1 == (unsigned char *) s1->fname));
 
       /* Character of current path component the same?  */
-      if (*cp1 != *cp2)
+      else if (*cp1 != *cp2)
        return *cp1 - *cp2;
     }
 }
@@ -7428,24 +7517,25 @@ reg_number (rtl)
   unsigned regno = REGNO (rtl);
 
   if (regno >= FIRST_PSEUDO_REGISTER)
-    {
-      warning ("internal regno botch: regno = %d\n", regno);
-      regno = 0;
-    }
+    abort ();
 
-  regno = DBX_REGISTER_NUMBER (regno);
-  return regno;
+  return DBX_REGISTER_NUMBER (regno);
 }
 
-/* Return a location descriptor that designates a machine register.  */
+/* Return a location descriptor that designates a machine register or
+   zero if there is no such.  */
 
 static dw_loc_descr_ref
 reg_loc_descriptor (rtl)
      rtx rtl;
 {
   dw_loc_descr_ref loc_result = NULL;
-  unsigned reg = reg_number (rtl);
+  unsigned reg;
+
+  if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
+    return 0;
 
+  reg = reg_number (rtl);
   if (reg <= 31)
     loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
   else
@@ -7527,6 +7617,7 @@ is_based_loc (rtl)
 {
     return (GET_CODE (rtl) == PLUS
            && ((GET_CODE (XEXP (rtl, 0)) == REG
+                && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
                 && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
 }
 
@@ -7541,7 +7632,9 @@ is_based_loc (rtl)
    it into Dwarf postfix code as it goes.
 
    MODE is the mode of the memory reference, needed to handle some
-   autoincrement addressing modes.  */
+   autoincrement addressing modes.
+
+   Return 0 if we can't represent the location.  */
 
 static dw_loc_descr_ref
 mem_loc_descriptor (rtl, mode)
@@ -7549,6 +7642,7 @@ mem_loc_descriptor (rtl, mode)
      enum machine_mode mode;
 {
   dw_loc_descr_ref mem_loc_result = NULL;
+
   /* Note that for a dynamically sized array, the location we will generate a
      description of here will be the lowest numbered location which is
      actually within the array.  That's *not* necessarily the same as the
@@ -7592,12 +7686,14 @@ mem_loc_descriptor (rtl, mode)
          the object in question was allocated to a register (rather than in
          memory) so DWARF consumers need to be aware of the subtle
          distinction between OP_REG and OP_BASEREG.  */
-      mem_loc_result = based_loc_descr (reg_number (rtl), 0);
+      if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
+       mem_loc_result = based_loc_descr (reg_number (rtl), 0);
       break;
 
     case MEM:
       mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+      if (mem_loc_result != 0)
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
       break;
 
     case LABEL_REF:
@@ -7646,14 +7742,14 @@ mem_loc_descriptor (rtl, mode)
       else
        {
          mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
+         if (mem_loc_result == 0)
+           break;
 
          if (GET_CODE (XEXP (rtl, 1)) == CONST_INT
              && INTVAL (XEXP (rtl, 1)) >= 0)
-           {
-             add_loc_descr (&mem_loc_result,
-                            new_loc_descr (DW_OP_plus_uconst,
-                                           INTVAL (XEXP (rtl, 1)), 0));
-           }
+           add_loc_descr (&mem_loc_result,
+                          new_loc_descr (DW_OP_plus_uconst,
+                                         INTVAL (XEXP (rtl, 1)), 0));
          else
            {
              add_loc_descr (&mem_loc_result,
@@ -7665,14 +7761,20 @@ mem_loc_descriptor (rtl, mode)
       break;
 
     case MULT:
-      /* If a pseudo-reg is optimized away, it is possible for it to
-        be replaced with a MEM containing a multiply.  */
-      add_loc_descr (&mem_loc_result,
-                    mem_loc_descriptor (XEXP (rtl, 0), mode));
-      add_loc_descr (&mem_loc_result,
-                    mem_loc_descriptor (XEXP (rtl, 1), mode));
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
-      break;
+      {
+       /* If a pseudo-reg is optimized away, it is possible for it to
+          be replaced with a MEM containing a multiply.  */
+       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode);
+       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode);
+
+       if (op0 == 0 || op1 == 0)
+         break;
+
+       mem_loc_result = op0;
+       add_loc_descr (&mem_loc_result, op1);
+       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+       break;
+      }
 
     case CONST_INT:
       mem_loc_result = int_loc_descriptor (INTVAL (rtl));
@@ -7693,18 +7795,21 @@ concat_loc_descriptor (x0, x1)
      rtx x0, x1;
 {
   dw_loc_descr_ref cc_loc_result = NULL;
+  dw_loc_descr_ref x0_ref = loc_descriptor (x0);
+  dw_loc_descr_ref x1_ref = loc_descriptor (x1);
 
-  if (!is_pseudo_reg (x0)
-      && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0))))
-    add_loc_descr (&cc_loc_result, loc_descriptor (x0));
+  if (x0_ref == 0 || x1_ref == 0)
+    return 0;
+
+  cc_loc_result = x0_ref;
   add_loc_descr (&cc_loc_result,
-                new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0));
+                new_loc_descr (DW_OP_piece,
+                               GET_MODE_SIZE (GET_MODE (x0)), 0));
 
-  if (!is_pseudo_reg (x1)
-      && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0))))
-    add_loc_descr (&cc_loc_result, loc_descriptor (x1));
+  add_loc_descr (&cc_loc_result, x1_ref);
   add_loc_descr (&cc_loc_result,
-                new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0));
+                new_loc_descr (DW_OP_piece,
+                               GET_MODE_SIZE (GET_MODE (x1)), 0));
 
   return cc_loc_result;
 }
@@ -7713,13 +7818,16 @@ concat_loc_descriptor (x0, x1)
    which is either allocated in a register or in a memory location.  For a
    register, we just generate an OP_REG and the register number.  For a
    memory location we provide a Dwarf postfix expression describing how to
-   generate the (dynamic) address of the object onto the address stack.  */
+   generate the (dynamic) address of the object onto the address stack.
+
+   If we don't know how to describe it, return 0.  */
 
 static dw_loc_descr_ref
 loc_descriptor (rtl)
      rtx rtl;
 {
   dw_loc_descr_ref loc_result = NULL;
+
   switch (GET_CODE (rtl))
     {
     case SUBREG:
@@ -7752,15 +7860,17 @@ loc_descriptor (rtl)
 }
 
 /* Similar, but generate the descriptor from trees instead of rtl.
-   This comes up particularly with variable length arrays.  */
+   This comes up particularly with variable length arrays.  If ADDRESSP
+   is nonzero, we are looking for an address.  Otherwise, we return a
+   value.  If we can't find a value, return 0.  */
 
 static dw_loc_descr_ref
 loc_descriptor_from_tree (loc, addressp)
      tree loc;
      int addressp;
 {
-  dw_loc_descr_ref ret = NULL;
-  int indirect_size = 0;
+  dw_loc_descr_ref ret, ret1;
+  int indirect_p = 0;
   int unsignedp = TREE_UNSIGNED (TREE_TYPE (loc));
   enum dwarf_location_atom op;
 
@@ -7771,35 +7881,36 @@ loc_descriptor_from_tree (loc, addressp)
   switch (TREE_CODE (loc))
     {
     case ERROR_MARK:
-      break;
+      return 0;
 
     case WITH_RECORD_EXPR:
+    case PLACEHOLDER_EXPR:
       /* This case involves extracting fields from an object to determine the
         position of other fields.  We don't try to encode this here.  The
         only user of this is Ada, which encodes the needed information using
         the names of types.  */
-      return ret;
+      return 0;
 
     case VAR_DECL:
     case PARM_DECL:
       {
        rtx rtl = rtl_for_decl_location (loc);
-       enum machine_mode mode = DECL_MODE (loc);
+       enum machine_mode mode = GET_MODE (rtl);
 
        if (rtl == NULL_RTX)
-         break;
+         return 0;
        else if (CONSTANT_P (rtl))
          {
            ret = new_loc_descr (DW_OP_addr, 0, 0);
            ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
            ret->dw_loc_oprnd1.v.val_addr = rtl;
-           indirect_size = GET_MODE_SIZE (mode);
+           indirect_p = 1;
          }
        else
          {
            if (GET_CODE (rtl) == MEM)
              {
-               indirect_size = GET_MODE_SIZE (mode);
+               indirect_p = 1;
                rtl = XEXP (rtl, 0);
              }
            ret = mem_loc_descriptor (rtl, mode);
@@ -7809,12 +7920,16 @@ loc_descriptor_from_tree (loc, addressp)
 
     case INDIRECT_REF:
       ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
-      indirect_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (loc)));
+      indirect_p = 1;
       break;
 
+    case COMPOUND_EXPR:
+      return loc_descriptor_from_tree (TREE_OPERAND (loc, 1), addressp);
+
     case NOP_EXPR:
     case CONVERT_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
       return loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp);
 
@@ -7827,11 +7942,18 @@ loc_descriptor_from_tree (loc, addressp)
        HOST_WIDE_INT bitsize, bitpos, bytepos;
        enum machine_mode mode;
        int volatilep;
-       unsigned int alignment;
 
        obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
-                                  &unsignedp, &volatilep, &alignment);
+                                  &unsignedp, &volatilep);
+
+       if (obj == loc)
+         return 0;
+
        ret = loc_descriptor_from_tree (obj, 1);
+       if (ret == 0
+           || bitpos % BITS_PER_UNIT != 0
+           || bitsize % BITS_PER_UNIT != 0)
+         return 0;
 
        if (offset != NULL_TREE)
          {
@@ -7840,24 +7962,8 @@ loc_descriptor_from_tree (loc, addressp)
            add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
          }
 
-       if (addressp)
-         {
-           /* We cannot address anything not on a unit boundary.  */
-           if (bitpos % BITS_PER_UNIT != 0)
-             abort ();
-         }
-       else
-         {
-           if (bitpos % BITS_PER_UNIT != 0
-               || bitsize % BITS_PER_UNIT != 0)
-             {
-               /* ??? We could handle this by loading and shifting etc.
-                  Wait until someone needs it before expending the effort.  */
-               abort ();
-             }
-
-           indirect_size = bitsize / BITS_PER_UNIT;
-         }
+       if (!addressp)
+         indirect_p = 1;
 
        bytepos = bitpos / BITS_PER_UNIT;
        if (bytepos > 0)
@@ -7873,40 +7979,54 @@ loc_descriptor_from_tree (loc, addressp)
     case INTEGER_CST:
       if (host_integerp (loc, 0))
        ret = int_loc_descriptor (tree_low_cst (loc, 0));
+      else
+       return 0;
       break;
 
     case BIT_AND_EXPR:
       op = DW_OP_and;
       goto do_binop;
+
     case BIT_XOR_EXPR:
       op = DW_OP_xor;
       goto do_binop;
+
     case BIT_IOR_EXPR:
       op = DW_OP_or;
       goto do_binop;
+
     case TRUNC_DIV_EXPR:
       op = DW_OP_div;
       goto do_binop;
+
     case MINUS_EXPR:
       op = DW_OP_minus;
       goto do_binop;
+
     case TRUNC_MOD_EXPR:
       op = DW_OP_mod;
       goto do_binop;
+
     case MULT_EXPR:
       op = DW_OP_mul;
       goto do_binop;
+
     case LSHIFT_EXPR:
       op = DW_OP_shl;
       goto do_binop;
+
     case RSHIFT_EXPR:
       op = (unsignedp ? DW_OP_shr : DW_OP_shra);
       goto do_binop;
+
     case PLUS_EXPR:
       if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
          && host_integerp (TREE_OPERAND (loc, 1), 0))
        {
          ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+         if (ret == 0)
+           return 0;
+
          add_loc_descr (&ret,
                         new_loc_descr (DW_OP_plus_uconst,
                                        tree_low_cst (TREE_OPERAND (loc, 1),
@@ -7914,53 +8034,72 @@ loc_descriptor_from_tree (loc, addressp)
                                        0));
          break;
        }
+
       op = DW_OP_plus;
       goto do_binop;
     case LE_EXPR:
       if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       break;
+       return 0;
+
       op = DW_OP_le;
       goto do_binop;
+
     case GE_EXPR:
       if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       break;
+       return 0;
+
       op = DW_OP_ge;
       goto do_binop;
+
     case LT_EXPR:
       if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       break;
+       return 0;
+
       op = DW_OP_lt;
       goto do_binop;
+
     case GT_EXPR:
       if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
-       break;
+       return 0;
+
       op = DW_OP_gt;
       goto do_binop;
+
     case EQ_EXPR:
       op = DW_OP_eq;
       goto do_binop;
+
     case NE_EXPR:
       op = DW_OP_ne;
       goto do_binop;
 
     do_binop:
       ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
-      add_loc_descr (&ret, loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0));
+      ret1 = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+      if (ret == 0 || ret1 == 0)
+       return 0;
+
+      add_loc_descr (&ret, ret1);
       add_loc_descr (&ret, new_loc_descr (op, 0, 0));
       break;
 
     case BIT_NOT_EXPR:
       op = DW_OP_not;
       goto do_unop;
+
     case ABS_EXPR:
       op = DW_OP_abs;
       goto do_unop;
+
     case NEGATE_EXPR:
       op = DW_OP_neg;
       goto do_unop;
 
     do_unop:
       ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+      if (ret == 0)
+       return 0;
+
       add_loc_descr (&ret, new_loc_descr (op, 0, 0));
       break;
 
@@ -7973,21 +8112,26 @@ loc_descriptor_from_tree (loc, addressp)
 
     case COND_EXPR:
       {
+       dw_loc_descr_ref lhs
+         = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+       dw_loc_descr_ref rhs
+         = loc_descriptor_from_tree (TREE_OPERAND (loc, 2), 0);
        dw_loc_descr_ref bra_node, jump_node, tmp;
 
        ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+       if (ret == 0 || lhs == 0 || rhs == 0)
+         return 0;
+
        bra_node = new_loc_descr (DW_OP_bra, 0, 0);
        add_loc_descr (&ret, bra_node);
 
-       tmp = loc_descriptor_from_tree (TREE_OPERAND (loc, 2), 0);
-       add_loc_descr (&ret, tmp);
+       add_loc_descr (&ret, rhs);
        jump_node = new_loc_descr (DW_OP_skip, 0, 0);
        add_loc_descr (&ret, jump_node);
 
-       tmp = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
-       add_loc_descr (&ret, tmp);
+       add_loc_descr (&ret, lhs);
        bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
-       bra_node->dw_loc_oprnd1.v.val_loc = tmp;
+       bra_node->dw_loc_oprnd1.v.val_loc = lhs;
 
        /* ??? Need a node to point the skip at.  Use a nop.  */
        tmp = new_loc_descr (DW_OP_nop, 0, 0);
@@ -8001,20 +8145,23 @@ loc_descriptor_from_tree (loc, addressp)
       abort ();
     }
 
-  /* If we can't fill the request for an address, die.  */
-  if (addressp && indirect_size == 0)
-    abort ();
+  /* Show if we can't fill the request for an address.  */
+  if (addressp && indirect_p == 0)
+    return 0;
 
   /* If we've got an address and don't want one, dereference.  */
-  if (!addressp && indirect_size > 0)
+  if (!addressp && indirect_p > 0)
     {
-      if (indirect_size > DWARF2_ADDR_SIZE)
-       abort ();
-      if (indirect_size == DWARF2_ADDR_SIZE)
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
+
+      if (size > DWARF2_ADDR_SIZE || size == -1)
+       return 0;
+      if (size == DWARF2_ADDR_SIZE)
        op = DW_OP_deref;
       else
        op = DW_OP_deref_size;
-      add_loc_descr (&ret, new_loc_descr (op, indirect_size, 0));
+
+      add_loc_descr (&ret, new_loc_descr (op, size, 0));
     }
 
   return ret;
@@ -8230,31 +8377,10 @@ add_AT_location_description (die, attr_kind, rtl)
      enum dwarf_attribute attr_kind;
      rtx rtl;
 {
-  /* Handle a special case.  If we are about to output a location descriptor
-     for a variable or parameter which has been optimized out of existence,
-     don't do that.  A variable which has been optimized out
-     of existence will have a DECL_RTL value which denotes a pseudo-reg.
-     Currently, in some rare cases, variables can have DECL_RTL values which
-     look like (MEM (REG pseudo-reg#)).  These cases are due to bugs
-     elsewhere in the compiler.  We treat such cases as if the variable(s) in
-     question had been optimized out of existence.  */
-
-  if (is_pseudo_reg (rtl)
-      || (GET_CODE (rtl) == MEM
-         && is_pseudo_reg (XEXP (rtl, 0)))
-      /* This can happen for a PARM_DECL with a DECL_INCOMING_RTL which
-        references the internal argument pointer (a pseudo) in a function
-        where all references to the internal argument pointer were
-        eliminated via the optimizers.  */
-      || (GET_CODE (rtl) == MEM
-         && GET_CODE (XEXP (rtl, 0)) == PLUS
-         && is_pseudo_reg (XEXP (XEXP (rtl, 0), 0)))
-      || (GET_CODE (rtl) == CONCAT
-         && is_pseudo_reg (XEXP (rtl, 0))
-         && is_pseudo_reg (XEXP (rtl, 1))))
-    return;
+  dw_loc_descr_ref descr = loc_descriptor (rtl);
 
-  add_AT_loc (die, attr_kind, loc_descriptor (rtl));
+  if (descr != 0)
+    add_AT_loc (die, attr_kind, descr);
 }
 
 /* Attach the specialized form of location attribute used for data
@@ -8333,11 +8459,15 @@ add_const_value_attribute (die, rtl)
          add_AT_int (die, DW_AT_const_value, (long) val);
        else if ((unsigned long) val == (unsigned HOST_WIDE_INT) val)
          add_AT_unsigned (die, DW_AT_const_value, (unsigned long) val);
-       else if (2*HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT)
-         add_AT_long_long (die, DW_AT_const_value,
-                           val >> HOST_BITS_PER_LONG, val);
        else
-         abort ();
+         {
+#if HOST_BITS_PER_LONG * 2 == HOST_BITS_PER_WIDE_INT
+           add_AT_long_long (die, DW_AT_const_value,
+                             val >> HOST_BITS_PER_LONG, val);
+#else
+           abort ();
+#endif
+         }
       }
       break;
 
@@ -8700,12 +8830,6 @@ add_bound_info (subrange_die, bound_attr, bound)
      enum dwarf_attribute bound_attr;
      tree bound;
 {
-  /* If this is an Ada unconstrained array type, then don't emit any debug
-     info because the array bounds are unknown.  They are parameterized when
-     the type is instantiated.  */
-  if (contains_placeholder_p (bound))
-    return;
-
   switch (TREE_CODE (bound))
     {
     case ERROR_MARK:
@@ -8726,6 +8850,7 @@ add_bound_info (subrange_die, bound_attr, bound)
     case CONVERT_EXPR:
     case NOP_EXPR:
     case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
       add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
       break;
 
@@ -8806,7 +8931,10 @@ add_bound_info (subrange_die, bound_attr, bound)
        if (loc == NULL)
          break;
 
-       ctx = lookup_decl_die (current_function_decl);
+       if (current_function_decl == 0)
+         ctx = comp_unit_die;
+       else
+         ctx = lookup_decl_die (current_function_decl);
 
        decl_die = new_die (DW_TAG_variable, ctx);
        add_AT_flag (decl_die, DW_AT_artificial, 1);
@@ -10347,6 +10475,7 @@ gen_compile_unit_die (filename)
   dw_die_ref die;
   char producer[250];
   const char *wd = getpwd ();
+  const char *language_string = lang_hooks.name;
   int language;
 
   die = new_die (DW_TAG_compile_unit, NULL);
@@ -10444,7 +10573,7 @@ gen_member_die (type, context_die)
      members of this record or union type, we will also be trying to output
      DIEs to represent the *types* of those members. However the `type'
      function (above) will specifically avoid generating type DIEs for member
-     types *within* the list of member DIEs for this (containing) type execpt
+     types *within* the list of member DIEs for this (containing) type except
      for those types (of members) which are explicitly marked as also being
      members of this (containing) type themselves.  The g++ front- end can
      force any given type to be treated as a member of some other
@@ -11661,6 +11790,43 @@ dwarf2out_init (main_input_filename)
     }
 }
 
+/* Allocate a string in .debug_str hash table.  */
+
+static hashnode
+indirect_string_alloc (tab)
+     hash_table *tab ATTRIBUTE_UNUSED;
+{
+  struct indirect_string_node *node;
+
+  node = xmalloc (sizeof (struct indirect_string_node));
+  node->refcount = 0;
+  node->form = 0;
+  node->label = NULL;
+  return (hashnode) node;
+}
+
+/* A helper function for dwarf2out_finish called through
+   ht_forall.  Emit one queued .debug_str string.  */
+
+static int
+output_indirect_string (pfile, h, v)
+     struct cpp_reader *pfile ATTRIBUTE_UNUSED;
+     hashnode h;
+     const PTR v ATTRIBUTE_UNUSED;
+{
+  struct indirect_string_node *node;
+
+  node = (struct indirect_string_node *) h;
+  if (node->form == DW_FORM_strp)
+    {
+      named_section_flags (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS);
+      ASM_OUTPUT_LABEL (asm_out_file, node->label);
+      assemble_string ((const char *) HT_STR (&node->id),
+                      HT_LEN (&node->id) + 1);
+    }
+  return 1;
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -11688,6 +11854,9 @@ dwarf2out_finish (input_filename)
            add_child_die (origin->die_parent, die);
          else if (die == comp_unit_die)
            ;
+         else if (errorcount > 0 || sorrycount > 0)
+           /* It's OK to be confused by errors in the input.  */
+           add_child_die (comp_unit_die, die);
          else
            abort ();
        }
@@ -11800,5 +11969,10 @@ dwarf2out_finish (input_filename)
       named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
       dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
     }
+
+  /* If we emitted any DW_FORM_strp form attribute, output string
+     table too.  */
+  if (debug_str_hash)
+    ht_forall (debug_str_hash, output_indirect_string, NULL);
 }
-#endif /* DWARF2_DEBUGGING_INFO */
+#endif /* DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO */