PR debug/41404
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 2 Oct 2009 15:01:22 +0000 (15:01 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 2 Oct 2009 15:01:22 +0000 (15:01 +0000)
PR debug/41353
* cfgexpand.c (expand_debug_expr) <case STRING_CST>: Don't create
CONST_STRING if STRING_CST contains embedded '\0's or doesn't end with
'\0'.
(expand_debug_expr) <case VAR_DECL>: For TREE_STATIC !DECL_EXTERNAL
vars use DECL_RTL with resetting it back to NULL afterwards.
* dwarf2out.c (same_dw_val_p): For dw_val_class_addr compare with
rtx_equal_p instead of asserting it is a SYMBOL_REF.
(value_format): For dw_val_class_addr only use DW_FORM_addr if
the attribute type allows it, otherwise use DW_FORM_dataN.
(mem_loc_descriptor): Handle CONST_STRING.
(add_const_value_attribute): Handle CONST_STRING using add_AT_addr.
Handle MEM with CONST_STRING address using add_AT_string.
(rtl_for_decl_init): Return MEM with CONST_STRING address instead of
CONST_STRING for const arrays initialized with a string literal.
(resolve_one_addr, resolve_addr_in_expr, resolve_addr): New functions.
(dwarf2out_finish): Call resolve_addr.

* gcc.dg/guality/pr41404-1.c: New test.
* gcc.dg/guality/pr41353-2.c: New test.

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

gcc/ChangeLog
gcc/cfgexpand.c
gcc/dwarf2out.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/guality/pr41353-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/guality/pr41404-1.c [new file with mode: 0644]

index 37b433f..00a6055 100644 (file)
@@ -1,3 +1,24 @@
+2009-10-02  Jakub Jelinek  <jakub@redhat.com>
+
+       PR debug/41404
+       PR debug/41353
+       * cfgexpand.c (expand_debug_expr) <case STRING_CST>: Don't create
+       CONST_STRING if STRING_CST contains embedded '\0's or doesn't end with
+       '\0'.
+       (expand_debug_expr) <case VAR_DECL>: For TREE_STATIC !DECL_EXTERNAL
+       vars use DECL_RTL with resetting it back to NULL afterwards.
+       * dwarf2out.c (same_dw_val_p): For dw_val_class_addr compare with
+       rtx_equal_p instead of asserting it is a SYMBOL_REF.
+       (value_format): For dw_val_class_addr only use DW_FORM_addr if
+       the attribute type allows it, otherwise use DW_FORM_dataN.
+       (mem_loc_descriptor): Handle CONST_STRING.
+       (add_const_value_attribute): Handle CONST_STRING using add_AT_addr.
+       Handle MEM with CONST_STRING address using add_AT_string.
+       (rtl_for_decl_init): Return MEM with CONST_STRING address instead of
+       CONST_STRING for const arrays initialized with a string literal.
+       (resolve_one_addr, resolve_addr_in_expr, resolve_addr): New functions.
+       (dwarf2out_finish): Call resolve_addr.
+
 2009-10-02  Andreas Schwab  <schwab@linux-m68k.org>
            Maxim Kuvyrkov  <maxim@codesourcery.com>
  
index f4a9f5e..2117ee3 100644 (file)
@@ -2337,6 +2337,9 @@ expand_debug_expr (tree exp)
     case STRING_CST:
       if (!lookup_constant_def (exp))
        {
+         if (strlen (TREE_STRING_POINTER (exp)) + 1
+             != (size_t) TREE_STRING_LENGTH (exp))
+           return NULL_RTX;
          op0 = gen_rtx_CONST_STRING (Pmode, TREE_STRING_POINTER (exp));
          op0 = gen_rtx_MEM (BLKmode, op0);
          set_mem_attributes (op0, exp, 0);
@@ -2368,9 +2371,23 @@ expand_debug_expr (tree exp)
 
       /* This decl was probably optimized away.  */
       if (!op0)
-       return NULL;
-
-      op0 = copy_rtx (op0);
+       {
+         if (TREE_CODE (exp) != VAR_DECL
+             || DECL_EXTERNAL (exp)
+             || !TREE_STATIC (exp)
+             || !DECL_NAME (exp)
+             || DECL_HARD_REGISTER (exp))
+           return NULL;
+
+         op0 = DECL_RTL (exp);
+         SET_DECL_RTL (exp, NULL);
+         if (!MEM_P (op0)
+             || GET_CODE (XEXP (op0, 0)) != SYMBOL_REF
+             || SYMBOL_REF_DECL (XEXP (op0, 0)) != exp)
+           return NULL;
+       }
+      else
+       op0 = copy_rtx (op0);
 
       if (GET_MODE (op0) == BLKmode)
        {
index 43e1a7b..3a0e4f3 100644 (file)
@@ -5948,6 +5948,7 @@ static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
 static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
                                         enum var_init_status);
 static int is_based_loc (const_rtx);
+static int resolve_one_addr (rtx *, void *);
 static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
                                            enum var_init_status);
 static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
@@ -7905,8 +7906,7 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
       r2 = v2->v.val_addr;
       if (GET_CODE (r1) != GET_CODE (r2))
        return 0;
-      gcc_assert (GET_CODE (r1) == SYMBOL_REF);
-      return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
+      return !rtx_equal_p (r1, r2);
 
     case dw_val_class_offset:
       return v1->v.val_offset == v2->v.val_offset;
@@ -8662,7 +8662,30 @@ value_format (dw_attr_ref a)
   switch (a->dw_attr_val.val_class)
     {
     case dw_val_class_addr:
-      return DW_FORM_addr;
+      /* Only very few attributes allow DW_FORM_addr.  */
+      switch (a->dw_attr)
+       {
+       case DW_AT_low_pc:
+       case DW_AT_high_pc:
+       case DW_AT_entry_pc:
+       case DW_AT_trampoline:
+         return DW_FORM_addr;
+       default:
+         break;
+       }
+      switch (DWARF2_ADDR_SIZE)
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       case 8:
+         return DW_FORM_data8;
+       default:
+         gcc_unreachable ();
+       }
     case dw_val_class_range_list:
     case dw_val_class_offset:
     case dw_val_class_loc_list:
@@ -11345,6 +11368,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       if (!const_ok_for_output (rtl))
        break;
 
+    symref:
       mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
       mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
       mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
@@ -11759,8 +11783,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode,
       break;
 
     case CONST_STRING:
-      /* These can't easily be tracked, see PR41404.  */
-      break;
+      resolve_one_addr (&rtl, NULL);
+      goto symref;
 
     default:
 #ifdef ENABLE_CHECKING
@@ -13525,7 +13549,9 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       return true;
 
     case CONST_STRING:
-      add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
+      resolve_one_addr (&rtl, NULL);
+      add_AT_addr (die, DW_AT_const_value, rtl);
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
       return true;
 
     case CONST:
@@ -13558,6 +13584,16 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
     case CONST_FIXED:
       return false;
 
+    case MEM:
+      if (GET_CODE (XEXP (rtl, 0)) == CONST_STRING
+         && MEM_READONLY_P (rtl)
+         && GET_MODE (rtl) == BLKmode)
+       {
+         add_AT_string (die, DW_AT_const_value, XSTR (XEXP (rtl, 0), 0));
+         return true;
+       }
+      return false;
+
     default:
       /* No other kinds of rtx should be possible here.  */
       gcc_unreachable ();
@@ -13629,8 +13665,12 @@ rtl_for_decl_init (tree init, tree type)
                               TREE_STRING_LENGTH (init) - 1) == 0
          && ((size_t) TREE_STRING_LENGTH (init)
              == strlen (TREE_STRING_POINTER (init)) + 1))
-       rtl = gen_rtx_CONST_STRING (VOIDmode,
-                                   ggc_strdup (TREE_STRING_POINTER (init)));
+       {
+         rtl = gen_rtx_CONST_STRING (VOIDmode,
+                                     ggc_strdup (TREE_STRING_POINTER (init)));
+         rtl = gen_rtx_MEM (BLKmode, rtl);
+         MEM_READONLY_P (rtl) = 1;
+       }
     }
   /* Other aggregates, and complex values, could be represented using
      CONCAT: FIXME!  */
@@ -18982,6 +19022,104 @@ move_linkage_attr (dw_die_ref die)
     }
 }
 
+/* Helper function for resolve_addr, attempt to resolve
+   one CONST_STRING, return non-zero if not successful.  Similarly verify that
+   SYMBOL_REFs refer to variables emitted in the current CU.  */
+
+static int
+resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
+{
+  rtx rtl = *addr;
+
+  if (GET_CODE (rtl) == CONST_STRING)
+    {
+      size_t len = strlen (XSTR (rtl, 0)) + 1;
+      tree t = build_string (len, XSTR (rtl, 0));
+      tree tlen = build_int_cst (NULL_TREE, len - 1);
+      TREE_TYPE (t)
+       = build_array_type (char_type_node, build_index_type (tlen));
+      rtl = lookup_constant_def (t);
+      if (!rtl || !MEM_P (rtl))
+       return 1;
+      rtl = XEXP (rtl, 0);
+      VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+      *addr = rtl;
+      return 0;
+    }
+
+  if (GET_CODE (rtl) == SYMBOL_REF
+      && SYMBOL_REF_DECL (rtl)
+      && TREE_CODE (SYMBOL_REF_DECL (rtl)) == VAR_DECL
+      && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
+    return 1;
+
+  if (GET_CODE (rtl) == CONST
+      && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
+    return 1;
+
+  return 0;
+}
+
+/* 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.  */
+
+static bool
+resolve_addr_in_expr (dw_loc_descr_ref loc)
+{
+  for (; loc; loc = loc->dw_loc_next)
+    if ((loc->dw_loc_opc == DW_OP_addr
+        && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
+       || (loc->dw_loc_opc == DW_OP_implicit_value
+           && loc->dw_loc_oprnd2.val_class == dw_val_class_addr
+           && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)))
+      return false;
+  return true;
+}
+
+/* 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
+   with DW_AT_location and empty location expression, if it isn't found
+   in .rodata.  Similarly for SYMBOL_REFs, keep only those that refer
+   to something that has been emitted in the current CU.  */
+
+static void
+resolve_addr (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_attr_ref a;
+  dw_loc_list_ref curr;
+  unsigned ix;
+
+  for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+    switch (AT_class (a))
+      {
+      case dw_val_class_loc_list:
+       for (curr = AT_loc_list (a); curr != NULL; curr = curr->dw_loc_next)
+         if (!resolve_addr_in_expr (curr->expr))
+           curr->expr = NULL;
+       break;
+      case dw_val_class_loc:
+       if (!resolve_addr_in_expr (AT_loc (a)))
+         a->dw_attr_val.v.val_loc = NULL;
+       break;
+      case dw_val_class_addr:
+       if (a->dw_attr == DW_AT_const_value
+           && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
+         {
+           a->dw_attr = DW_AT_location;
+           a->dw_attr_val.val_class = dw_val_class_loc;
+           a->dw_attr_val.v.val_loc = NULL;
+         }
+       break;
+      default:
+       break;
+      }
+
+  FOR_EACH_CHILD (die, c, resolve_addr (c));
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -19072,6 +19210,8 @@ dwarf2out_finish (const char *filename)
 
   limbo_die_list = NULL;
 
+  resolve_addr (comp_unit_die);
+
   for (node = deferred_asm_name; node; node = node->next)
     {
       tree decl = node->created_for;
index b52d1f1..4bbabcb 100644 (file)
@@ -1,3 +1,10 @@
+2009-10-02  Jakub Jelinek  <jakub@redhat.com>
+
+       PR debug/41404
+       PR debug/41353
+       * gcc.dg/guality/pr41404-1.c: New test.
+       * gcc.dg/guality/pr41353-2.c: New test.
+
 2009-10-02  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR testsuite/41546
diff --git a/gcc/testsuite/gcc.dg/guality/pr41353-2.c b/gcc/testsuite/gcc.dg/guality/pr41353-2.c
new file mode 100644 (file)
index 0000000..3ff8d36
--- /dev/null
@@ -0,0 +1,24 @@
+/* PR debug/41353 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+int varh;
+int vari = 17, varj;
+
+__attribute__((noinline)) int
+f1 (void)
+{
+  int vari1 = 2 * vari; /* { dg-final { gdb-test 13 "vari1" "2 * 17" } } */
+  int vari2 = 3 * vari; /* { dg-final { gdb-test 13 "vari2" "3 * 17" } } */
+  return varj;
+}
+
+int (*volatile fnp1) (void) = f1;
+
+int
+main (int argc, char *argv[])
+{
+  asm volatile ("" : : "r" (&fnp1) : "memory");
+  fnp1 ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/guality/pr41404-1.c b/gcc/testsuite/gcc.dg/guality/pr41404-1.c
new file mode 100644 (file)
index 0000000..59a8293
--- /dev/null
@@ -0,0 +1,41 @@
+/* PR debug/41404 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+__attribute__ ((noinline))
+int bar1 (int i)
+{
+  const char *foo = "foo";
+  asm volatile ("" : "+r" (i) : : "memory");
+  i++; /* { dg-final { gdb-test 10 "*foo" "'f'" } } */
+  asm volatile ("" : "+r" (i) : : "memory");
+  foo = "bar";
+  asm volatile ("" : "+r" (i) : : "memory");
+  i++; /* { dg-final { gdb-test 14 "*foo" "'b'" } } */
+  asm volatile ("" : "+r" (i) : : "memory");
+  return i;
+}
+
+__attribute__ ((noinline))
+int bar2 (int i)
+{
+  const char *foo = "foo";
+  asm volatile ("" : "+r" (i) : : "memory");
+  i++; /* { dg-final { gdb-test 24 "*foo" "'f'" } } */
+  asm volatile ("" : "+r" (i) : : "memory");
+  return i;
+}
+
+__attribute__ ((noinline))
+const char *baz (int i)
+{
+  return i ? "foo" : "bar";
+}
+
+int
+main (void)
+{
+  bar1 (6);
+  bar2 (6);
+  return 0;
+}