Commit c845cfe1 by Jakub Jelinek Committed by Jakub Jelinek

re PR debug/55608 (Debug info quality regressions with file scope vars)

	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.

From-SVN: r196886
parent 4a5e2469
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> 2013-03-21 Marc Glisse <marc.glisse@inria.fr>
* tree.h (VECTOR_TYPE_P): New macro. * tree.h (VECTOR_TYPE_P): New macro.
......
...@@ -15527,6 +15527,7 @@ tree_add_const_value_attribute (dw_die_ref die, tree t) ...@@ -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); add_AT_vec (die, DW_AT_const_value, size, 1, array);
return true; return true;
} }
ggc_free (array);
} }
} }
return false; return false;
...@@ -22494,6 +22495,10 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED) ...@@ -22494,6 +22495,10 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
if (!rtl || !MEM_P (rtl)) if (!rtl || !MEM_P (rtl))
return 1; return 1;
rtl = XEXP (rtl, 0); 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); vec_safe_push (used_rtx_array, rtl);
*addr = rtl; *addr = rtl;
return 0; return 0;
...@@ -22518,6 +22523,103 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED) ...@@ -22518,6 +22523,103 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
return 0; 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 /* Helper function for resolve_addr, handle one location
expression, return false if at least one CONST_STRING or SYMBOL_REF in expression, return false if at least one CONST_STRING or SYMBOL_REF in
the location list couldn't be resolved. */ the location list couldn't be resolved. */
...@@ -22526,23 +22628,31 @@ static bool ...@@ -22526,23 +22628,31 @@ static bool
resolve_addr_in_expr (dw_loc_descr_ref loc) resolve_addr_in_expr (dw_loc_descr_ref loc)
{ {
dw_loc_descr_ref keep = NULL; 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) switch (loc->dw_loc_opc)
{ {
case DW_OP_addr: case DW_OP_addr:
if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL)) 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; break;
case DW_OP_GNU_addr_index: case DW_OP_GNU_addr_index:
case DW_OP_GNU_const_index: case DW_OP_GNU_const_index:
{ if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
if ((loc->dw_loc_opc == DW_OP_GNU_addr_index || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
|| (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel)) && resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl,
&& resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl, NULL))
NULL)) return false;
return false; break;
}
break;
case DW_OP_const4u: case DW_OP_const4u:
case DW_OP_const8u: case DW_OP_const8u:
if (loc->dtprel if (loc->dtprel
...@@ -22637,6 +22747,80 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) ...@@ -22637,6 +22747,80 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
return true; 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 /* 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, an address in .rodata section if the string literal is emitted there,
or remove the containing location list or replace DW_AT_const_value or remove the containing location list or replace DW_AT_const_value
...@@ -22723,8 +22907,21 @@ resolve_addr (dw_die_ref die) ...@@ -22723,8 +22907,21 @@ resolve_addr (dw_die_ref die)
|| l->dw_loc_next != NULL) || l->dw_loc_next != NULL)
&& !resolve_addr_in_expr (l)) && !resolve_addr_in_expr (l))
{ {
if (dwarf_split_debug_info) if (dwarf_split_debug_info)
remove_loc_list_addr_table_entries (l); 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); remove_AT (die, a->dw_attr);
ix--; ix--;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment