OSDN Git Service

PR debug/55608
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 21 Mar 2013 17:35:39 +0000 (17:35 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 21 Mar 2013 17:35:39 +0000 (17:35 +0000)
* dwarf2out.c (tree_add_const_value_attribute): Call ggc_free (array)
on failure.
(resolve_one_addr): Fail if referenced STRING_CST hasn't been written.
(string_cst_pool_decl): New function.
(optimize_one_addr_into_implicit_ptr): New function.
(resolve_addr_in_expr): Optimize DWARF location expression
DW_OP_addr DW_OP_stack_value where DW_OP_addr refers to some variable
which doesn't live in memory, but has DW_AT_location or
DW_AT_const_value, or refers to a string literal, into
DW_OP_GNU_implicit_pointer.
(optimize_location_into_implicit_ptr): New function.
(resolve_addr): If removing DW_AT_location of a variable because
it was DW_OP_addr of address of the variable, but the variable doesn't
live in memory, try to emit const value attribute for the initializer.

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

gcc/ChangeLog
gcc/dwarf2out.c

index 3992373..b8a1b19 100644 (file)
@@ -1,3 +1,21 @@
+2013-03-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR debug/55608
+       * dwarf2out.c (tree_add_const_value_attribute): Call ggc_free (array)
+       on failure.
+       (resolve_one_addr): Fail if referenced STRING_CST hasn't been written.
+       (string_cst_pool_decl): New function.
+       (optimize_one_addr_into_implicit_ptr): New function.
+       (resolve_addr_in_expr): Optimize DWARF location expression
+       DW_OP_addr DW_OP_stack_value where DW_OP_addr refers to some variable
+       which doesn't live in memory, but has DW_AT_location or
+       DW_AT_const_value, or refers to a string literal, into
+       DW_OP_GNU_implicit_pointer.
+       (optimize_location_into_implicit_ptr): New function.
+       (resolve_addr): If removing DW_AT_location of a variable because
+       it was DW_OP_addr of address of the variable, but the variable doesn't
+       live in memory, try to emit const value attribute for the initializer.
+
 2013-03-21  Marc Glisse  <marc.glisse@inria.fr>
 
        * tree.h (VECTOR_TYPE_P): New macro.
index a5d5dc4..9be7728 100644 (file)
@@ -15527,6 +15527,7 @@ tree_add_const_value_attribute (dw_die_ref die, tree t)
              add_AT_vec (die, DW_AT_const_value, size, 1, array);
              return true;
            }
+         ggc_free (array);
        }
     }
   return false;
@@ -22494,6 +22495,10 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
       if (!rtl || !MEM_P (rtl))
        return 1;
       rtl = XEXP (rtl, 0);
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && SYMBOL_REF_DECL (rtl)
+         && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
+       return 1;
       vec_safe_push (used_rtx_array, rtl);
       *addr = rtl;
       return 0;
@@ -22518,6 +22523,103 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
   return 0;
 }
 
+/* For STRING_CST, return SYMBOL_REF of its constant pool entry,
+   if possible, and create DW_TAG_dwarf_procedure that can be referenced
+   from DW_OP_GNU_implicit_pointer if the string hasn't been seen yet.  */
+
+static rtx
+string_cst_pool_decl (tree t)
+{
+  rtx rtl = output_constant_def (t, 1);
+  unsigned char *array;
+  dw_loc_descr_ref l;
+  tree decl;
+  size_t len;
+  dw_die_ref ref;
+
+  if (!rtl || !MEM_P (rtl))
+    return NULL_RTX;
+  rtl = XEXP (rtl, 0);
+  if (GET_CODE (rtl) != SYMBOL_REF
+      || SYMBOL_REF_DECL (rtl) == NULL_TREE)
+    return NULL_RTX;
+
+  decl = SYMBOL_REF_DECL (rtl);
+  if (!lookup_decl_die (decl))
+    {
+      len = TREE_STRING_LENGTH (t);
+      vec_safe_push (used_rtx_array, rtl);
+      ref = new_die (DW_TAG_dwarf_procedure, comp_unit_die (), decl);
+      array = (unsigned char *) ggc_alloc_atomic (len);
+      memcpy (array, TREE_STRING_POINTER (t), len);
+      l = new_loc_descr (DW_OP_implicit_value, len, 0);
+      l->dw_loc_oprnd2.val_class = dw_val_class_vec;
+      l->dw_loc_oprnd2.v.val_vec.length = len;
+      l->dw_loc_oprnd2.v.val_vec.elt_size = 1;
+      l->dw_loc_oprnd2.v.val_vec.array = array;
+      add_AT_loc (ref, DW_AT_location, l);
+      equate_decl_number_to_die (decl, ref);
+    }
+  return rtl;
+}
+
+/* Helper function of resolve_addr_in_expr.  LOC is
+   a DW_OP_addr followed by DW_OP_stack_value, either at the start
+   of exprloc or after DW_OP_{,bit_}piece, and val_addr can't be
+   resolved.  Replace it (both DW_OP_addr and DW_OP_stack_value)
+   with DW_OP_GNU_implicit_pointer if possible
+   and return true, if unsuccesful, return false.  */
+
+static bool
+optimize_one_addr_into_implicit_ptr (dw_loc_descr_ref loc)
+{
+  rtx rtl = loc->dw_loc_oprnd1.v.val_addr;
+  HOST_WIDE_INT offset = 0;
+  dw_die_ref ref = NULL;
+  tree decl;
+
+  if (GET_CODE (rtl) == CONST
+      && GET_CODE (XEXP (rtl, 0)) == PLUS
+      && CONST_INT_P (XEXP (XEXP (rtl, 0), 1)))
+    {
+      offset = INTVAL (XEXP (XEXP (rtl, 0), 1));
+      rtl = XEXP (XEXP (rtl, 0), 0);
+    }
+  if (GET_CODE (rtl) == CONST_STRING)
+    {
+      size_t len = strlen (XSTR (rtl, 0)) + 1;
+      tree t = build_string (len, XSTR (rtl, 0));
+      tree tlen = size_int (len - 1);
+
+      TREE_TYPE (t)
+       = build_array_type (char_type_node, build_index_type (tlen));
+      rtl = string_cst_pool_decl (t);
+      if (!rtl)
+       return false;
+    }
+  if (GET_CODE (rtl) == SYMBOL_REF && SYMBOL_REF_DECL (rtl))
+    {
+      decl = SYMBOL_REF_DECL (rtl);
+      if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+       {
+         ref = lookup_decl_die (decl);
+         if (ref && (get_AT (ref, DW_AT_location)
+                     || get_AT (ref, DW_AT_const_value)))
+           {
+             loc->dw_loc_opc = DW_OP_GNU_implicit_pointer;
+             loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+             loc->dw_loc_oprnd1.val_entry = NULL;
+             loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
+             loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
+             loc->dw_loc_next = loc->dw_loc_next->dw_loc_next;
+             loc->dw_loc_oprnd2.v.val_int = offset;
+             return true;
+           }
+       }
+    }
+  return false;
+}
+
 /* Helper function for resolve_addr, handle one location
    expression, return false if at least one CONST_STRING or SYMBOL_REF in
    the location list couldn't be resolved.  */
@@ -22526,23 +22628,31 @@ static bool
 resolve_addr_in_expr (dw_loc_descr_ref loc)
 {
   dw_loc_descr_ref keep = NULL;
-  for (; loc; loc = loc->dw_loc_next)
+  for (dw_loc_descr_ref prev = NULL; loc; prev = loc, loc = loc->dw_loc_next)
     switch (loc->dw_loc_opc)
       {
       case DW_OP_addr:
        if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
-         return false;
+         {
+           if ((prev == NULL
+                || prev->dw_loc_opc == DW_OP_piece
+                || prev->dw_loc_opc == DW_OP_bit_piece)
+               && loc->dw_loc_next
+               && loc->dw_loc_next->dw_loc_opc == DW_OP_stack_value
+               && !dwarf_strict
+               && optimize_one_addr_into_implicit_ptr (loc))
+             break;
+           return false;
+         }
        break;
       case DW_OP_GNU_addr_index:
       case DW_OP_GNU_const_index:
-        {
-          if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
-               || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
-              && resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl,
-                                   NULL))
-            return false;
-        }
-       break;
+       if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
+            || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
+           && resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl,
+                                NULL))
+         return false;
+       break;
       case DW_OP_const4u:
       case DW_OP_const8u:
        if (loc->dtprel
@@ -22637,6 +22747,80 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
   return true;
 }
 
+/* Helper function of resolve_addr.  DIE had DW_AT_location of
+   DW_OP_addr alone, which referred to DECL in DW_OP_addr's operand
+   and DW_OP_addr couldn't be resolved.  resolve_addr has already
+   removed the DW_AT_location attribute.  This function attempts to
+   add a new DW_AT_location attribute with DW_OP_GNU_implicit_pointer
+   to it or DW_AT_const_value attribute, if possible.  */
+
+static void
+optimize_location_into_implicit_ptr (dw_die_ref die, tree decl)
+{
+  if (TREE_CODE (decl) != VAR_DECL
+      || lookup_decl_die (decl) != die
+      || DECL_EXTERNAL (decl)
+      || !TREE_STATIC (decl)
+      || DECL_INITIAL (decl) == NULL_TREE
+      || DECL_P (DECL_INITIAL (decl))
+      || get_AT (die, DW_AT_const_value))
+    return;
+
+  tree init = DECL_INITIAL (decl);
+  HOST_WIDE_INT offset = 0;
+  /* For variables that have been optimized away and thus
+     don't have a memory location, see if we can emit
+     DW_AT_const_value instead.  */
+  if (tree_add_const_value_attribute (die, init))
+    return;
+  if (dwarf_strict)
+    return;
+  /* If init is ADDR_EXPR or POINTER_PLUS_EXPR of ADDR_EXPR,
+     and ADDR_EXPR refers to a decl that has DW_AT_location or
+     DW_AT_const_value (but isn't addressable, otherwise
+     resolving the original DW_OP_addr wouldn't fail), see if
+     we can add DW_OP_GNU_implicit_pointer.  */
+  STRIP_NOPS (init);
+  if (TREE_CODE (init) == POINTER_PLUS_EXPR
+      && host_integerp (TREE_OPERAND (init, 1), 0))
+    {
+      offset = tree_low_cst (TREE_OPERAND (init, 1), 0);
+      init = TREE_OPERAND (init, 0);
+      STRIP_NOPS (init);
+    }
+  if (TREE_CODE (init) != ADDR_EXPR)
+    return;
+  if ((TREE_CODE (TREE_OPERAND (init, 0)) == STRING_CST
+       && !TREE_ASM_WRITTEN (TREE_OPERAND (init, 0)))
+      || (TREE_CODE (TREE_OPERAND (init, 0)) == VAR_DECL
+         && !DECL_EXTERNAL (TREE_OPERAND (init, 0))
+         && TREE_OPERAND (init, 0) != decl))
+    {
+      dw_die_ref ref;
+      dw_loc_descr_ref l;
+
+      if (TREE_CODE (TREE_OPERAND (init, 0)) == STRING_CST)
+       {
+         rtx rtl = string_cst_pool_decl (TREE_OPERAND (init, 0));
+         if (!rtl)
+           return;
+         decl = SYMBOL_REF_DECL (rtl);
+       }
+      else
+       decl = TREE_OPERAND (init, 0);
+      ref = lookup_decl_die (decl);
+      if (ref == NULL
+         || (!get_AT (ref, DW_AT_location)
+             && !get_AT (ref, DW_AT_const_value)))
+       return;
+      l = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
+      l->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+      l->dw_loc_oprnd1.v.val_die_ref.die = ref;
+      l->dw_loc_oprnd1.v.val_die_ref.external = 0;
+      add_AT_loc (die, DW_AT_location, l);
+    }
+}
+
 /* Resolve DW_OP_addr and DW_AT_const_value CONST_STRING arguments to
    an address in .rodata section if the string literal is emitted there,
    or remove the containing location list or replace DW_AT_const_value
@@ -22723,8 +22907,21 @@ resolve_addr (dw_die_ref die)
               || l->dw_loc_next != NULL)
              && !resolve_addr_in_expr (l))
            {
-              if (dwarf_split_debug_info)
-                remove_loc_list_addr_table_entries (l);
+             if (dwarf_split_debug_info)
+               remove_loc_list_addr_table_entries (l);
+             if (l != NULL
+                 && l->dw_loc_next == NULL
+                 && l->dw_loc_opc == DW_OP_addr
+                 && GET_CODE (l->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF
+                 && SYMBOL_REF_DECL (l->dw_loc_oprnd1.v.val_addr)
+                 && a->dw_attr == DW_AT_location)
+               {
+                 tree decl = SYMBOL_REF_DECL (l->dw_loc_oprnd1.v.val_addr);
+                 remove_AT (die, a->dw_attr);
+                 ix--;
+                 optimize_location_into_implicit_ptr (die, decl);
+                 break;
+               }
              remove_AT (die, a->dw_attr);
              ix--;
            }