mirror of git://gcc.gnu.org/git/gcc.git
re PR debug/77589 (fortran: Missing DW_AT_byte_stride for an array record field selection)
PR debug/77589 include/ * dwarf2.def (DW_OP_GNU_variable_value): New opcode. gcc/ * dwarf2out.c (struct dw_loc_list_struct): Add noted_variable_value bitfield. (size_of_loc_descr): Handle DW_OP_GNU_variable_value. (output_loc_operands): Handle DW_OP_call_ref and DW_OP_GNU_variable_value. (struct variable_value_struct): New type. (struct variable_value_hasher): Likewise. (variable_value_hash): New variable. (string_types): Remove. (copy_loc_descr): New function. (add_loc_descr_to_each): Clarify comment. Use copy_loc_descr. (prepend_loc_descr_to_each): New function. (add_loc_list): Fix comment typo. Use prepend_loc_descr_to_each instead of add_loc_descr_to_each if the first argument is single location list and the second has multiple. (resolve_args_picking_1): Handle DW_OP_GNU_variable_value. (loc_list_from_tree_1): For early_dwarf, emit DW_OP_GNU_variable_value when looking for variable value which doesn't have other location info. (loc_list_from_tree): Formatting fix. (gen_array_type_die): Simplify DW_AT_string_length handling. (adjust_string_types): Remove. (gen_subprogram_die): Don't call adjust_string_types nor test/set string_types. Call resolve_variable_values. (prune_unused_types_walk_loc_descr): Handle DW_OP_GNU_variable_value. (resolve_addr_in_expr): Likewise. Add A argument. (copy_deref_exprloc): Remove deref argument. Adjust for the original expression being DW_OP_GNU_variable_value with optionally DW_OP_stack_value after it instead of DW_OP_call4 with DW_OP_deref optionally after it. (optimize_string_length): Rework for DW_OP_GNU_variable_value. (resolve_addr): Adjust optimize_string_length and resolve_addr_in_expr callers. Set remove_AT_byte_size if removing DW_AT_string_length. (variable_value_hasher::hash, variable_value_hasher::equal): New methods. (resolve_variable_value_in_expr, resolve_variable_value, resolve_variable_values, note_variable_value_in_expr, note_variable_value): New functions. (dwarf2out_early_finish): Call note_variable_value on all toplevel DIEs. From-SVN: r245733
This commit is contained in:
parent
a920ed32a7
commit
680c60feb4
|
|
@ -1,3 +1,46 @@
|
||||||
|
2017-02-25 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
|
PR debug/77589
|
||||||
|
* dwarf2out.c (struct dw_loc_list_struct): Add noted_variable_value
|
||||||
|
bitfield.
|
||||||
|
(size_of_loc_descr): Handle DW_OP_GNU_variable_value.
|
||||||
|
(output_loc_operands): Handle DW_OP_call_ref and
|
||||||
|
DW_OP_GNU_variable_value.
|
||||||
|
(struct variable_value_struct): New type.
|
||||||
|
(struct variable_value_hasher): Likewise.
|
||||||
|
(variable_value_hash): New variable.
|
||||||
|
(string_types): Remove.
|
||||||
|
(copy_loc_descr): New function.
|
||||||
|
(add_loc_descr_to_each): Clarify comment. Use copy_loc_descr.
|
||||||
|
(prepend_loc_descr_to_each): New function.
|
||||||
|
(add_loc_list): Fix comment typo. Use prepend_loc_descr_to_each
|
||||||
|
instead of add_loc_descr_to_each if the first argument is single
|
||||||
|
location list and the second has multiple.
|
||||||
|
(resolve_args_picking_1): Handle DW_OP_GNU_variable_value.
|
||||||
|
(loc_list_from_tree_1): For early_dwarf, emit DW_OP_GNU_variable_value
|
||||||
|
when looking for variable value which doesn't have other location info.
|
||||||
|
(loc_list_from_tree): Formatting fix.
|
||||||
|
(gen_array_type_die): Simplify DW_AT_string_length handling.
|
||||||
|
(adjust_string_types): Remove.
|
||||||
|
(gen_subprogram_die): Don't call adjust_string_types nor test/set
|
||||||
|
string_types. Call resolve_variable_values.
|
||||||
|
(prune_unused_types_walk_loc_descr): Handle DW_OP_GNU_variable_value.
|
||||||
|
(resolve_addr_in_expr): Likewise. Add A argument.
|
||||||
|
(copy_deref_exprloc): Remove deref argument. Adjust for the
|
||||||
|
original expression being DW_OP_GNU_variable_value with optionally
|
||||||
|
DW_OP_stack_value after it instead of DW_OP_call4 with DW_OP_deref
|
||||||
|
optionally after it.
|
||||||
|
(optimize_string_length): Rework for DW_OP_GNU_variable_value.
|
||||||
|
(resolve_addr): Adjust optimize_string_length and resolve_addr_in_expr
|
||||||
|
callers. Set remove_AT_byte_size if removing DW_AT_string_length.
|
||||||
|
(variable_value_hasher::hash, variable_value_hasher::equal): New
|
||||||
|
methods.
|
||||||
|
(resolve_variable_value_in_expr, resolve_variable_value,
|
||||||
|
resolve_variable_values, note_variable_value_in_expr,
|
||||||
|
note_variable_value): New functions.
|
||||||
|
(dwarf2out_early_finish): Call note_variable_value on all toplevel
|
||||||
|
DIEs.
|
||||||
|
|
||||||
2017-02-24 Jakub Jelinek <jakub@redhat.com>
|
2017-02-24 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR c/79677
|
PR c/79677
|
||||||
|
|
|
||||||
637
gcc/dwarf2out.c
637
gcc/dwarf2out.c
|
|
@ -1293,6 +1293,8 @@ typedef struct GTY(()) dw_loc_list_struct {
|
||||||
unsigned char num_assigned : 1;
|
unsigned char num_assigned : 1;
|
||||||
/* True if .debug_loclists.dwo offset has been emitted for it already. */
|
/* True if .debug_loclists.dwo offset has been emitted for it already. */
|
||||||
unsigned char offset_emitted : 1;
|
unsigned char offset_emitted : 1;
|
||||||
|
/* True if note_variable_value_in_expr has been called on it. */
|
||||||
|
unsigned char noted_variable_value : 1;
|
||||||
/* True if the range should be emitted even if begin and end
|
/* True if the range should be emitted even if begin and end
|
||||||
are the same. */
|
are the same. */
|
||||||
bool force;
|
bool force;
|
||||||
|
|
@ -1791,6 +1793,7 @@ size_of_loc_descr (dw_loc_descr_ref loc)
|
||||||
size += 4;
|
size += 4;
|
||||||
break;
|
break;
|
||||||
case DW_OP_call_ref:
|
case DW_OP_call_ref:
|
||||||
|
case DW_OP_GNU_variable_value:
|
||||||
size += DWARF_REF_SIZE;
|
size += DWARF_REF_SIZE;
|
||||||
break;
|
break;
|
||||||
case DW_OP_implicit_value:
|
case DW_OP_implicit_value:
|
||||||
|
|
@ -2214,6 +2217,17 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DW_OP_call_ref:
|
||||||
|
case DW_OP_GNU_variable_value:
|
||||||
|
{
|
||||||
|
char label[MAX_ARTIFICIAL_LABEL_BYTES
|
||||||
|
+ HOST_BITS_PER_WIDE_INT / 2 + 2];
|
||||||
|
gcc_assert (val1->val_class == dw_val_class_die_ref);
|
||||||
|
get_ref_die_offset_label (label, val1->v.val_die_ref.die);
|
||||||
|
dw2_asm_output_offset (DWARF_REF_SIZE, label, debug_info_section, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case DW_OP_implicit_pointer:
|
case DW_OP_implicit_pointer:
|
||||||
case DW_OP_GNU_implicit_pointer:
|
case DW_OP_GNU_implicit_pointer:
|
||||||
{
|
{
|
||||||
|
|
@ -3097,6 +3111,23 @@ struct decl_die_hasher : ggc_ptr_hash<die_node>
|
||||||
The key is a DECL_UID() which is a unique number identifying each decl. */
|
The key is a DECL_UID() which is a unique number identifying each decl. */
|
||||||
static GTY (()) hash_table<decl_die_hasher> *decl_die_table;
|
static GTY (()) hash_table<decl_die_hasher> *decl_die_table;
|
||||||
|
|
||||||
|
struct GTY ((for_user)) variable_value_struct {
|
||||||
|
unsigned int decl_id;
|
||||||
|
vec<dw_die_ref, va_gc> *dies;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct variable_value_hasher : ggc_ptr_hash<variable_value_struct>
|
||||||
|
{
|
||||||
|
typedef tree compare_type;
|
||||||
|
|
||||||
|
static hashval_t hash (variable_value_struct *);
|
||||||
|
static bool equal (variable_value_struct *, tree);
|
||||||
|
};
|
||||||
|
/* A hash table of DIEs that contain DW_OP_GNU_variable_value with
|
||||||
|
dw_val_class_decl_ref class, indexed by FUNCTION_DECLs which is
|
||||||
|
DECL_CONTEXT of the referenced VAR_DECLs. */
|
||||||
|
static GTY (()) hash_table<variable_value_hasher> *variable_value_hash;
|
||||||
|
|
||||||
struct block_die_hasher : ggc_ptr_hash<die_struct>
|
struct block_die_hasher : ggc_ptr_hash<die_struct>
|
||||||
{
|
{
|
||||||
static hashval_t hash (die_struct *);
|
static hashval_t hash (die_struct *);
|
||||||
|
|
@ -3287,10 +3318,6 @@ static bool frame_pointer_fb_offset_valid;
|
||||||
|
|
||||||
static vec<dw_die_ref> base_types;
|
static vec<dw_die_ref> base_types;
|
||||||
|
|
||||||
/* Pointer to vector of DW_TAG_string_type DIEs that need finalization
|
|
||||||
once all arguments are parsed. */
|
|
||||||
static vec<dw_die_ref> *string_types;
|
|
||||||
|
|
||||||
/* Flags to represent a set of attribute classes for attributes that represent
|
/* Flags to represent a set of attribute classes for attributes that represent
|
||||||
a scalar value (bounds, pointers, ...). */
|
a scalar value (bounds, pointers, ...). */
|
||||||
enum dw_scalar_form
|
enum dw_scalar_form
|
||||||
|
|
@ -3605,6 +3632,7 @@ static void gen_remaining_tmpl_value_param_die_attribute (void);
|
||||||
static bool generic_type_p (tree);
|
static bool generic_type_p (tree);
|
||||||
static void schedule_generic_params_dies_gen (tree t);
|
static void schedule_generic_params_dies_gen (tree t);
|
||||||
static void gen_scheduled_generic_parms_dies (void);
|
static void gen_scheduled_generic_parms_dies (void);
|
||||||
|
static void resolve_variable_values (void);
|
||||||
|
|
||||||
static const char *comp_dir_string (void);
|
static const char *comp_dir_string (void);
|
||||||
|
|
||||||
|
|
@ -16292,7 +16320,17 @@ single_element_loc_list_p (dw_loc_list_ref list)
|
||||||
return !list->ll_symbol;
|
return !list->ll_symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To each location in list LIST add loc descr REF. */
|
/* Duplicate a single element of location list. */
|
||||||
|
|
||||||
|
static inline dw_loc_descr_ref
|
||||||
|
copy_loc_descr (dw_loc_descr_ref ref)
|
||||||
|
{
|
||||||
|
dw_loc_descr_ref copy = ggc_alloc<dw_loc_descr_node> ();
|
||||||
|
memcpy (copy, ref, sizeof (dw_loc_descr_node));
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To each location in list LIST append loc descr REF. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
|
add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
|
||||||
|
|
@ -16302,16 +16340,31 @@ add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
|
||||||
list = list->dw_loc_next;
|
list = list->dw_loc_next;
|
||||||
while (list)
|
while (list)
|
||||||
{
|
{
|
||||||
copy = ggc_alloc<dw_loc_descr_node> ();
|
copy = copy_loc_descr (ref);
|
||||||
memcpy (copy, ref, sizeof (dw_loc_descr_node));
|
|
||||||
add_loc_descr (&list->expr, copy);
|
add_loc_descr (&list->expr, copy);
|
||||||
while (copy->dw_loc_next)
|
while (copy->dw_loc_next)
|
||||||
{
|
copy = copy->dw_loc_next = copy_loc_descr (copy->dw_loc_next);
|
||||||
dw_loc_descr_ref new_copy = ggc_alloc<dw_loc_descr_node> ();
|
list = list->dw_loc_next;
|
||||||
memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
|
}
|
||||||
copy->dw_loc_next = new_copy;
|
}
|
||||||
copy = new_copy;
|
|
||||||
}
|
/* To each location in list LIST prepend loc descr REF. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prepend_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
|
||||||
|
{
|
||||||
|
dw_loc_descr_ref copy;
|
||||||
|
dw_loc_descr_ref ref_end = list->expr;
|
||||||
|
add_loc_descr (&ref, list->expr);
|
||||||
|
list->expr = ref;
|
||||||
|
list = list->dw_loc_next;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
dw_loc_descr_ref end = list->expr;
|
||||||
|
list->expr = copy = copy_loc_descr (ref);
|
||||||
|
while (copy->dw_loc_next != ref_end)
|
||||||
|
copy = copy->dw_loc_next = copy_loc_descr (copy->dw_loc_next);
|
||||||
|
copy->dw_loc_next = end;
|
||||||
list = list->dw_loc_next;
|
list = list->dw_loc_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16322,7 +16375,7 @@ add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref)
|
||||||
Might be destructive on both RET and LIST.
|
Might be destructive on both RET and LIST.
|
||||||
|
|
||||||
TODO: We handle only simple cases of RET or LIST having at most one
|
TODO: We handle only simple cases of RET or LIST having at most one
|
||||||
element. General case would inolve sorting the lists in program order
|
element. General case would involve sorting the lists in program order
|
||||||
and merging them that will need some additional work.
|
and merging them that will need some additional work.
|
||||||
Adding that will improve quality of debug info especially for SRA-ed
|
Adding that will improve quality of debug info especially for SRA-ed
|
||||||
structures. */
|
structures. */
|
||||||
|
|
@ -16344,7 +16397,7 @@ add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
|
||||||
}
|
}
|
||||||
if (!(*ret)->dw_loc_next)
|
if (!(*ret)->dw_loc_next)
|
||||||
{
|
{
|
||||||
add_loc_descr_to_each (list, (*ret)->expr);
|
prepend_loc_descr_to_each (list, (*ret)->expr);
|
||||||
*ret = list;
|
*ret = list;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -16824,6 +16877,7 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset,
|
||||||
case DW_OP_fbreg:
|
case DW_OP_fbreg:
|
||||||
case DW_OP_push_object_address:
|
case DW_OP_push_object_address:
|
||||||
case DW_OP_call_frame_cfa:
|
case DW_OP_call_frame_cfa:
|
||||||
|
case DW_OP_GNU_variable_value:
|
||||||
++frame_offset_;
|
++frame_offset_;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -17299,6 +17353,31 @@ loc_list_from_tree_1 (tree loc, int want_address,
|
||||||
rtl = rtl_for_decl_location (loc);
|
rtl = rtl_for_decl_location (loc);
|
||||||
if (rtl == NULL_RTX)
|
if (rtl == NULL_RTX)
|
||||||
{
|
{
|
||||||
|
if (TREE_CODE (loc) != FUNCTION_DECL
|
||||||
|
&& early_dwarf
|
||||||
|
&& current_function_decl
|
||||||
|
&& want_address != 1
|
||||||
|
&& (INTEGRAL_TYPE_P (TREE_TYPE (loc))
|
||||||
|
|| POINTER_TYPE_P (TREE_TYPE (loc)))
|
||||||
|
&& DECL_CONTEXT (loc) == current_function_decl
|
||||||
|
&& (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (loc)))
|
||||||
|
<= DWARF2_ADDR_SIZE))
|
||||||
|
{
|
||||||
|
dw_die_ref ref = lookup_decl_die (loc);
|
||||||
|
ret = new_loc_descr (DW_OP_GNU_variable_value, 0, 0);
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
||||||
|
ret->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
||||||
|
ret->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
|
||||||
|
ret->dw_loc_oprnd1.v.val_decl_ref = loc;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
expansion_failed (loc, NULL_RTX, "DECL has no RTL");
|
expansion_failed (loc, NULL_RTX, "DECL has no RTL");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -17873,8 +17952,7 @@ loc_list_from_tree (tree loc, int want_address,
|
||||||
dw_loc_list_ref result = loc_list_from_tree_1 (loc, want_address, context);
|
dw_loc_list_ref result = loc_list_from_tree_1 (loc, want_address, context);
|
||||||
|
|
||||||
for (dw_loc_list_ref loc_cur = result;
|
for (dw_loc_list_ref loc_cur = result;
|
||||||
loc_cur != NULL; loc_cur =
|
loc_cur != NULL; loc_cur = loc_cur->dw_loc_next)
|
||||||
loc_cur->dw_loc_next)
|
|
||||||
loc_descr_without_nops (loc_cur->expr);
|
loc_descr_without_nops (loc_cur->expr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -20685,7 +20763,6 @@ gen_array_type_die (tree type, dw_die_ref context_die)
|
||||||
{
|
{
|
||||||
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
|
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
|
||||||
tree rszdecl = szdecl;
|
tree rszdecl = szdecl;
|
||||||
HOST_WIDE_INT rsize = 0;
|
|
||||||
|
|
||||||
size = int_size_in_bytes (TREE_TYPE (szdecl));
|
size = int_size_in_bytes (TREE_TYPE (szdecl));
|
||||||
if (!DECL_P (szdecl))
|
if (!DECL_P (szdecl))
|
||||||
|
|
@ -20694,8 +20771,8 @@ gen_array_type_die (tree type, dw_die_ref context_die)
|
||||||
&& DECL_P (TREE_OPERAND (szdecl, 0)))
|
&& DECL_P (TREE_OPERAND (szdecl, 0)))
|
||||||
{
|
{
|
||||||
rszdecl = TREE_OPERAND (szdecl, 0);
|
rszdecl = TREE_OPERAND (szdecl, 0);
|
||||||
rsize = int_size_in_bytes (TREE_TYPE (rszdecl));
|
if (int_size_in_bytes (TREE_TYPE (rszdecl))
|
||||||
if (rsize <= 0)
|
!= DWARF2_ADDR_SIZE)
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -20703,41 +20780,9 @@ gen_array_type_die (tree type, dw_die_ref context_die)
|
||||||
}
|
}
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2, NULL);
|
dw_loc_list_ref loc
|
||||||
if (loc == NULL
|
= loc_list_from_tree (rszdecl, szdecl == rszdecl ? 2 : 0,
|
||||||
&& early_dwarf
|
NULL);
|
||||||
&& current_function_decl
|
|
||||||
&& DECL_CONTEXT (rszdecl) == current_function_decl)
|
|
||||||
{
|
|
||||||
dw_die_ref ref = lookup_decl_die (rszdecl);
|
|
||||||
dw_loc_descr_ref l = NULL;
|
|
||||||
if (ref)
|
|
||||||
{
|
|
||||||
l = new_loc_descr (DW_OP_call4, 0, 0);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else if (TREE_CODE (rszdecl) == PARM_DECL
|
|
||||||
&& string_types)
|
|
||||||
{
|
|
||||||
l = new_loc_descr (DW_OP_call4, 0, 0);
|
|
||||||
l->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
|
|
||||||
l->dw_loc_oprnd1.v.val_decl_ref = rszdecl;
|
|
||||||
string_types->safe_push (array_die);
|
|
||||||
}
|
|
||||||
if (l && rszdecl != szdecl)
|
|
||||||
{
|
|
||||||
if (rsize == DWARF2_ADDR_SIZE)
|
|
||||||
add_loc_descr (&l, new_loc_descr (DW_OP_deref,
|
|
||||||
0, 0));
|
|
||||||
else
|
|
||||||
add_loc_descr (&l, new_loc_descr (DW_OP_deref_size,
|
|
||||||
rsize, 0));
|
|
||||||
}
|
|
||||||
if (l)
|
|
||||||
loc = new_loc_list (l, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
if (loc)
|
if (loc)
|
||||||
{
|
{
|
||||||
add_AT_location_description (array_die, DW_AT_string_length,
|
add_AT_location_description (array_die, DW_AT_string_length,
|
||||||
|
|
@ -20814,39 +20859,6 @@ gen_array_type_die (tree type, dw_die_ref context_die)
|
||||||
add_alignment_attribute (array_die, type);
|
add_alignment_attribute (array_die, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After all arguments are created, adjust any DW_TAG_string_type
|
|
||||||
DIEs DW_AT_string_length attributes. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
adjust_string_types (void)
|
|
||||||
{
|
|
||||||
dw_die_ref array_die;
|
|
||||||
unsigned int i;
|
|
||||||
FOR_EACH_VEC_ELT (*string_types, i, array_die)
|
|
||||||
{
|
|
||||||
dw_attr_node *a = get_AT (array_die, DW_AT_string_length);
|
|
||||||
if (a == NULL)
|
|
||||||
continue;
|
|
||||||
dw_loc_descr_ref loc = AT_loc (a);
|
|
||||||
gcc_assert (loc->dw_loc_opc == DW_OP_call4
|
|
||||||
&& loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref);
|
|
||||||
dw_die_ref ref = lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
|
|
||||||
if (ref)
|
|
||||||
{
|
|
||||||
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
|
||||||
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
|
||||||
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
remove_AT (array_die, DW_AT_string_length);
|
|
||||||
remove_AT (array_die, dwarf_version >= 5
|
|
||||||
? DW_AT_string_length_byte_size
|
|
||||||
: DW_AT_byte_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This routine generates DIE for array with hidden descriptor, details
|
/* This routine generates DIE for array with hidden descriptor, details
|
||||||
are filled into *info by a langhook. */
|
are filled into *info by a langhook. */
|
||||||
|
|
||||||
|
|
@ -22289,6 +22301,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
|
||||||
add_AT_location_description (subr_die, DW_AT_static_link,
|
add_AT_location_description (subr_die, DW_AT_static_link,
|
||||||
loc_list_from_tree (fb_expr, 0, NULL));
|
loc_list_from_tree (fb_expr, 0, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve_variable_values ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate child dies for template paramaters. */
|
/* Generate child dies for template paramaters. */
|
||||||
|
|
@ -22321,9 +22335,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
|
||||||
tree generic_decl_parm = generic_decl
|
tree generic_decl_parm = generic_decl
|
||||||
? DECL_ARGUMENTS (generic_decl)
|
? DECL_ARGUMENTS (generic_decl)
|
||||||
: NULL;
|
: NULL;
|
||||||
auto_vec<dw_die_ref> string_types_vec;
|
|
||||||
if (string_types == NULL)
|
|
||||||
string_types = &string_types_vec;
|
|
||||||
|
|
||||||
/* Now we want to walk the list of parameters of the function and
|
/* Now we want to walk the list of parameters of the function and
|
||||||
emit their relevant DIEs.
|
emit their relevant DIEs.
|
||||||
|
|
@ -22386,14 +22397,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
|
||||||
else if (DECL_INITIAL (decl) == NULL_TREE)
|
else if (DECL_INITIAL (decl) == NULL_TREE)
|
||||||
gen_unspecified_parameters_die (decl, subr_die);
|
gen_unspecified_parameters_die (decl, subr_die);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust DW_TAG_string_type DIEs if needed, now that all arguments
|
|
||||||
have DIEs. */
|
|
||||||
if (string_types == &string_types_vec)
|
|
||||||
{
|
|
||||||
adjust_string_types ();
|
|
||||||
string_types = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subr_die != old_die)
|
if (subr_die != old_die)
|
||||||
|
|
@ -27532,6 +27535,18 @@ prune_unused_types_walk_loc_descr (dw_loc_descr_ref loc)
|
||||||
if (loc->dw_loc_oprnd1.val_class == dw_val_class_die_ref)
|
if (loc->dw_loc_oprnd1.val_class == dw_val_class_die_ref)
|
||||||
prune_unused_types_mark (loc->dw_loc_oprnd1.v.val_die_ref.die, 1);
|
prune_unused_types_mark (loc->dw_loc_oprnd1.v.val_die_ref.die, 1);
|
||||||
break;
|
break;
|
||||||
|
case DW_OP_GNU_variable_value:
|
||||||
|
if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
|
||||||
|
{
|
||||||
|
dw_die_ref ref
|
||||||
|
= lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
|
||||||
|
if (ref == NULL)
|
||||||
|
break;
|
||||||
|
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
|
}
|
||||||
|
/* FALLTHRU */
|
||||||
case DW_OP_call2:
|
case DW_OP_call2:
|
||||||
case DW_OP_call4:
|
case DW_OP_call4:
|
||||||
case DW_OP_call_ref:
|
case DW_OP_call_ref:
|
||||||
|
|
@ -28300,7 +28315,7 @@ optimize_one_addr_into_implicit_ptr (dw_loc_descr_ref loc)
|
||||||
the location list couldn't be resolved. */
|
the location list couldn't be resolved. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
resolve_addr_in_expr (dw_loc_descr_ref loc)
|
resolve_addr_in_expr (dw_attr_node *a, dw_loc_descr_ref loc)
|
||||||
{
|
{
|
||||||
dw_loc_descr_ref keep = NULL;
|
dw_loc_descr_ref keep = NULL;
|
||||||
for (dw_loc_descr_ref prev = NULL; loc; prev = loc, loc = loc->dw_loc_next)
|
for (dw_loc_descr_ref prev = NULL; loc; prev = loc, loc = loc->dw_loc_next)
|
||||||
|
|
@ -28360,6 +28375,7 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
|
||||||
case DW_OP_implicit_pointer:
|
case DW_OP_implicit_pointer:
|
||||||
case DW_OP_GNU_implicit_pointer:
|
case DW_OP_GNU_implicit_pointer:
|
||||||
case DW_OP_GNU_parameter_ref:
|
case DW_OP_GNU_parameter_ref:
|
||||||
|
case DW_OP_GNU_variable_value:
|
||||||
if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
|
if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
|
||||||
{
|
{
|
||||||
dw_die_ref ref
|
dw_die_ref ref
|
||||||
|
|
@ -28370,6 +28386,37 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
|
||||||
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
||||||
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
}
|
}
|
||||||
|
if (loc->dw_loc_opc == DW_OP_GNU_variable_value)
|
||||||
|
{
|
||||||
|
if (prev == NULL
|
||||||
|
&& loc->dw_loc_next == NULL
|
||||||
|
&& AT_class (a) == dw_val_class_loc)
|
||||||
|
switch (a->dw_attr)
|
||||||
|
{
|
||||||
|
/* Following attributes allow both exprloc and reference,
|
||||||
|
so if the whole expression is DW_OP_GNU_variable_value
|
||||||
|
alone we could transform it into reference. */
|
||||||
|
case DW_AT_byte_size:
|
||||||
|
case DW_AT_bit_size:
|
||||||
|
case DW_AT_lower_bound:
|
||||||
|
case DW_AT_upper_bound:
|
||||||
|
case DW_AT_bit_stride:
|
||||||
|
case DW_AT_count:
|
||||||
|
case DW_AT_allocated:
|
||||||
|
case DW_AT_associated:
|
||||||
|
case DW_AT_byte_stride:
|
||||||
|
a->dw_attr_val.val_class = dw_val_class_die_ref;
|
||||||
|
a->dw_attr_val.val_entry = NULL;
|
||||||
|
a->dw_attr_val.v.val_die_ref.die
|
||||||
|
= loc->dw_loc_oprnd1.v.val_die_ref.die;
|
||||||
|
a->dw_attr_val.v.val_die_ref.external = 0;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dwarf_strict)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DW_OP_const_type:
|
case DW_OP_const_type:
|
||||||
case DW_OP_regval_type:
|
case DW_OP_regval_type:
|
||||||
|
|
@ -28544,18 +28591,18 @@ non_dwarf_expression (dw_loc_descr_ref l)
|
||||||
/* Return adjusted copy of EXPR:
|
/* Return adjusted copy of EXPR:
|
||||||
If it is empty DWARF expression, return it.
|
If it is empty DWARF expression, return it.
|
||||||
If it is valid non-empty DWARF expression,
|
If it is valid non-empty DWARF expression,
|
||||||
return copy of EXPR with copy of DEREF appended to it.
|
return copy of EXPR with DW_OP_deref appended to it.
|
||||||
If it is DWARF expression followed by DW_OP_reg{N,x}, return
|
If it is DWARF expression followed by DW_OP_reg{N,x}, return
|
||||||
copy of the DWARF expression with DW_OP_breg{N,x} <0> appended
|
copy of the DWARF expression with DW_OP_breg{N,x} <0> appended.
|
||||||
and no DEREF.
|
|
||||||
If it is DWARF expression followed by DW_OP_stack_value, return
|
If it is DWARF expression followed by DW_OP_stack_value, return
|
||||||
copy of the DWARF expression without anything appended.
|
copy of the DWARF expression without anything appended.
|
||||||
Otherwise, return NULL. */
|
Otherwise, return NULL. */
|
||||||
|
|
||||||
static dw_loc_descr_ref
|
static dw_loc_descr_ref
|
||||||
copy_deref_exprloc (dw_loc_descr_ref expr, dw_loc_descr_ref deref)
|
copy_deref_exprloc (dw_loc_descr_ref expr)
|
||||||
{
|
{
|
||||||
|
dw_loc_descr_ref tail = NULL;
|
||||||
|
|
||||||
if (expr == NULL)
|
if (expr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
@ -28566,26 +28613,24 @@ copy_deref_exprloc (dw_loc_descr_ref expr, dw_loc_descr_ref deref)
|
||||||
if (l)
|
if (l)
|
||||||
{
|
{
|
||||||
if (l->dw_loc_opc >= DW_OP_reg0 && l->dw_loc_opc <= DW_OP_reg31)
|
if (l->dw_loc_opc >= DW_OP_reg0 && l->dw_loc_opc <= DW_OP_reg31)
|
||||||
deref = new_loc_descr ((enum dwarf_location_atom)
|
tail = new_loc_descr ((enum dwarf_location_atom)
|
||||||
(DW_OP_breg0 + (l->dw_loc_opc - DW_OP_reg0)),
|
(DW_OP_breg0 + (l->dw_loc_opc - DW_OP_reg0)),
|
||||||
0, 0);
|
0, 0);
|
||||||
else
|
else
|
||||||
switch (l->dw_loc_opc)
|
switch (l->dw_loc_opc)
|
||||||
{
|
{
|
||||||
case DW_OP_regx:
|
case DW_OP_regx:
|
||||||
deref = new_loc_descr (DW_OP_bregx,
|
tail = new_loc_descr (DW_OP_bregx,
|
||||||
l->dw_loc_oprnd1.v.val_unsigned, 0);
|
l->dw_loc_oprnd1.v.val_unsigned, 0);
|
||||||
break;
|
break;
|
||||||
case DW_OP_stack_value:
|
case DW_OP_stack_value:
|
||||||
deref = NULL;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
deref = new_loc_descr (deref->dw_loc_opc,
|
tail = new_loc_descr (DW_OP_deref, 0, 0);
|
||||||
deref->dw_loc_oprnd1.v.val_int, 0);
|
|
||||||
|
|
||||||
dw_loc_descr_ref ret = NULL, *p = &ret;
|
dw_loc_descr_ref ret = NULL, *p = &ret;
|
||||||
while (expr != l)
|
while (expr != l)
|
||||||
|
|
@ -28596,29 +28641,55 @@ copy_deref_exprloc (dw_loc_descr_ref expr, dw_loc_descr_ref deref)
|
||||||
p = &(*p)->dw_loc_next;
|
p = &(*p)->dw_loc_next;
|
||||||
expr = expr->dw_loc_next;
|
expr = expr->dw_loc_next;
|
||||||
}
|
}
|
||||||
*p = deref;
|
*p = tail;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For DW_AT_string_length attribute with DW_OP_call4 reference to a variable
|
/* For DW_AT_string_length attribute with DW_OP_GNU_variable_value
|
||||||
or argument, adjust it if needed and return:
|
reference to a variable or argument, adjust it if needed and return:
|
||||||
-1 if the DW_AT_string_length attribute and DW_AT_{string_length_,}byte_size
|
-1 if the DW_AT_string_length attribute and DW_AT_{string_length_,}byte_size
|
||||||
attribute if present should be removed
|
attribute if present should be removed
|
||||||
0 keep the attribute as is if the referenced var or argument has
|
0 keep the attribute perhaps with minor modifications, no need to rescan
|
||||||
only DWARF expression that covers all ranges
|
|
||||||
1 if the attribute has been successfully adjusted. */
|
1 if the attribute has been successfully adjusted. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
optimize_string_length (dw_attr_node *a)
|
optimize_string_length (dw_attr_node *a)
|
||||||
{
|
{
|
||||||
dw_loc_descr_ref l = AT_loc (a), lv;
|
dw_loc_descr_ref l = AT_loc (a), lv;
|
||||||
dw_die_ref die = l->dw_loc_oprnd1.v.val_die_ref.die;
|
dw_die_ref die;
|
||||||
|
if (l->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
|
||||||
|
{
|
||||||
|
tree decl = l->dw_loc_oprnd1.v.val_decl_ref;
|
||||||
|
die = lookup_decl_die (decl);
|
||||||
|
if (die)
|
||||||
|
{
|
||||||
|
l->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
||||||
|
l->dw_loc_oprnd1.v.val_die_ref.die = die;
|
||||||
|
l->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
die = l->dw_loc_oprnd1.v.val_die_ref.die;
|
||||||
|
|
||||||
|
/* DWARF5 allows reference class, so we can then reference the DIE.
|
||||||
|
Only do this for DW_OP_GNU_variable_value DW_OP_stack_value. */
|
||||||
|
if (l->dw_loc_next != NULL && dwarf_version >= 5)
|
||||||
|
{
|
||||||
|
a->dw_attr_val.val_class = dw_val_class_die_ref;
|
||||||
|
a->dw_attr_val.val_entry = NULL;
|
||||||
|
a->dw_attr_val.v.val_die_ref.die = die;
|
||||||
|
a->dw_attr_val.v.val_die_ref.external = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
dw_attr_node *av = get_AT (die, DW_AT_location);
|
dw_attr_node *av = get_AT (die, DW_AT_location);
|
||||||
dw_loc_list_ref d;
|
dw_loc_list_ref d;
|
||||||
bool non_dwarf_expr = false;
|
bool non_dwarf_expr = false;
|
||||||
|
|
||||||
if (av == NULL)
|
if (av == NULL)
|
||||||
return -1;
|
return dwarf_strict ? -1 : 0;
|
||||||
switch (AT_class (av))
|
switch (AT_class (av))
|
||||||
{
|
{
|
||||||
case dw_val_class_loc_list:
|
case dw_val_class_loc_list:
|
||||||
|
|
@ -28629,22 +28700,31 @@ optimize_string_length (dw_attr_node *a)
|
||||||
case dw_val_class_loc:
|
case dw_val_class_loc:
|
||||||
lv = AT_loc (av);
|
lv = AT_loc (av);
|
||||||
if (lv == NULL)
|
if (lv == NULL)
|
||||||
return -1;
|
return dwarf_strict ? -1 : 0;
|
||||||
if (non_dwarf_expression (lv))
|
if (non_dwarf_expression (lv))
|
||||||
non_dwarf_expr = true;
|
non_dwarf_expr = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return dwarf_strict ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If it is safe to keep DW_OP_call4 in, keep it. */
|
/* If it is safe to transform DW_OP_GNU_variable_value DW_OP_stack_value
|
||||||
|
into DW_OP_call4 or DW_OP_GNU_variable_value into
|
||||||
|
DW_OP_call4 DW_OP_deref, do so. */
|
||||||
if (!non_dwarf_expr
|
if (!non_dwarf_expr
|
||||||
&& (l->dw_loc_next == NULL || AT_class (av) == dw_val_class_loc))
|
&& (l->dw_loc_next != NULL || AT_class (av) == dw_val_class_loc))
|
||||||
return 0;
|
{
|
||||||
|
l->dw_loc_opc = DW_OP_call4;
|
||||||
|
if (l->dw_loc_next)
|
||||||
|
l->dw_loc_next = NULL;
|
||||||
|
else
|
||||||
|
l->dw_loc_next = new_loc_descr (DW_OP_deref, 0, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* If not dereferencing the DW_OP_call4 afterwards, we can just
|
/* For DW_OP_GNU_variable_value DW_OP_stack_value, we can just
|
||||||
copy over the DW_AT_location attribute from die to a. */
|
copy over the DW_AT_location attribute from die to a. */
|
||||||
if (l->dw_loc_next == NULL)
|
if (l->dw_loc_next != NULL)
|
||||||
{
|
{
|
||||||
a->dw_attr_val = av->dw_attr_val;
|
a->dw_attr_val = av->dw_attr_val;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -28658,23 +28738,25 @@ optimize_string_length (dw_attr_node *a)
|
||||||
list = NULL;
|
list = NULL;
|
||||||
for (d = AT_loc_list (av); d != NULL; d = d->dw_loc_next)
|
for (d = AT_loc_list (av); d != NULL; d = d->dw_loc_next)
|
||||||
{
|
{
|
||||||
lv = copy_deref_exprloc (d->expr, l->dw_loc_next);
|
lv = copy_deref_exprloc (d->expr);
|
||||||
if (lv)
|
if (lv)
|
||||||
{
|
{
|
||||||
*p = new_loc_list (lv, d->begin, d->end, d->section);
|
*p = new_loc_list (lv, d->begin, d->end, d->section);
|
||||||
p = &(*p)->dw_loc_next;
|
p = &(*p)->dw_loc_next;
|
||||||
}
|
}
|
||||||
|
else if (!dwarf_strict && d->expr)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (list == NULL)
|
if (list == NULL)
|
||||||
return -1;
|
return dwarf_strict ? -1 : 0;
|
||||||
a->dw_attr_val.val_class = dw_val_class_loc_list;
|
a->dw_attr_val.val_class = dw_val_class_loc_list;
|
||||||
gen_llsym (list);
|
gen_llsym (list);
|
||||||
*AT_loc_list_ptr (a) = list;
|
*AT_loc_list_ptr (a) = list;
|
||||||
return 1;
|
return 1;
|
||||||
case dw_val_class_loc:
|
case dw_val_class_loc:
|
||||||
lv = copy_deref_exprloc (AT_loc (av), l->dw_loc_next);
|
lv = copy_deref_exprloc (AT_loc (av));
|
||||||
if (lv == NULL)
|
if (lv == NULL)
|
||||||
return -1;
|
return dwarf_strict ? -1 : 0;
|
||||||
a->dw_attr_val.v.val_loc = lv;
|
a->dw_attr_val.v.val_loc = lv;
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
|
|
@ -28720,7 +28802,7 @@ resolve_addr (dw_die_ref die)
|
||||||
while (*curr)
|
while (*curr)
|
||||||
{
|
{
|
||||||
gcc_assert (!(*curr)->replaced && !(*curr)->resolved_addr);
|
gcc_assert (!(*curr)->replaced && !(*curr)->resolved_addr);
|
||||||
if (!resolve_addr_in_expr ((*curr)->expr))
|
if (!resolve_addr_in_expr (a, (*curr)->expr))
|
||||||
{
|
{
|
||||||
dw_loc_list_ref next = (*curr)->dw_loc_next;
|
dw_loc_list_ref next = (*curr)->dw_loc_next;
|
||||||
dw_loc_descr_ref l = (*curr)->expr;
|
dw_loc_descr_ref l = (*curr)->expr;
|
||||||
|
|
@ -28757,19 +28839,19 @@ resolve_addr (dw_die_ref die)
|
||||||
case dw_val_class_loc:
|
case dw_val_class_loc:
|
||||||
{
|
{
|
||||||
dw_loc_descr_ref l = AT_loc (a);
|
dw_loc_descr_ref l = AT_loc (a);
|
||||||
/* Using DW_OP_call4 or DW_OP_call4 DW_OP_deref in
|
/* DW_OP_GNU_variable_value DW_OP_stack_value or
|
||||||
DW_AT_string_length is only a rough approximation; unfortunately
|
DW_OP_GNU_variable_value in DW_AT_string_length can be converted
|
||||||
DW_AT_string_length can't be a reference to a DIE. DW_OP_call4
|
into DW_OP_call4 or DW_OP_call4 DW_OP_deref, which is standard
|
||||||
needs a DWARF expression, while DW_AT_location of the referenced
|
DWARF4 unlike DW_OP_GNU_variable_value. Or for DWARF5
|
||||||
variable or argument might be any location description. */
|
DW_OP_GNU_variable_value DW_OP_stack_value can be replaced
|
||||||
|
with DW_FORM_ref referencing the same DIE as
|
||||||
|
DW_OP_GNU_variable_value used to reference. */
|
||||||
if (a->dw_attr == DW_AT_string_length
|
if (a->dw_attr == DW_AT_string_length
|
||||||
&& l
|
&& l
|
||||||
&& l->dw_loc_opc == DW_OP_call4
|
&& l->dw_loc_opc == DW_OP_GNU_variable_value
|
||||||
&& l->dw_loc_oprnd1.val_class == dw_val_class_die_ref
|
|
||||||
&& (l->dw_loc_next == NULL
|
&& (l->dw_loc_next == NULL
|
||||||
|| (l->dw_loc_next->dw_loc_next == NULL
|
|| (l->dw_loc_next->dw_loc_next == NULL
|
||||||
&& (l->dw_loc_next->dw_loc_opc == DW_OP_deref
|
&& l->dw_loc_next->dw_loc_opc == DW_OP_stack_value)))
|
||||||
|| l->dw_loc_next->dw_loc_opc != DW_OP_deref_size))))
|
|
||||||
{
|
{
|
||||||
switch (optimize_string_length (a))
|
switch (optimize_string_length (a))
|
||||||
{
|
{
|
||||||
|
|
@ -28799,7 +28881,7 @@ resolve_addr (dw_die_ref die)
|
||||||
|| l == NULL
|
|| l == NULL
|
||||||
|| l->dw_loc_opc != DW_OP_plus_uconst
|
|| l->dw_loc_opc != DW_OP_plus_uconst
|
||||||
|| l->dw_loc_next != NULL)
|
|| l->dw_loc_next != NULL)
|
||||||
&& !resolve_addr_in_expr (l))
|
&& !resolve_addr_in_expr (a, 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);
|
||||||
|
|
@ -28816,6 +28898,10 @@ resolve_addr (dw_die_ref die)
|
||||||
optimize_location_into_implicit_ptr (die, decl);
|
optimize_location_into_implicit_ptr (die, decl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (a->dw_attr == DW_AT_string_length)
|
||||||
|
/* If we drop DW_AT_string_length, we need to drop also
|
||||||
|
DW_AT_{string_length_,}byte_size. */
|
||||||
|
remove_AT_byte_size = true;
|
||||||
remove_AT (die, a->dw_attr);
|
remove_AT (die, a->dw_attr);
|
||||||
ix--;
|
ix--;
|
||||||
}
|
}
|
||||||
|
|
@ -29874,6 +29960,262 @@ dwarf2out_finish (const char *)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns a hash value for X (which really is a variable_value_struct). */
|
||||||
|
|
||||||
|
inline hashval_t
|
||||||
|
variable_value_hasher::hash (variable_value_struct *x)
|
||||||
|
{
|
||||||
|
return (hashval_t) x->decl_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return nonzero if decl_id of variable_value_struct X is the same as
|
||||||
|
UID of decl Y. */
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
variable_value_hasher::equal (variable_value_struct *x, tree y)
|
||||||
|
{
|
||||||
|
return x->decl_id == DECL_UID (y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper function for resolve_variable_value, handle
|
||||||
|
DW_OP_GNU_variable_value in one location expression.
|
||||||
|
Return true if exprloc has been changed into loclist. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
resolve_variable_value_in_expr (dw_attr_node *a, dw_loc_descr_ref loc)
|
||||||
|
{
|
||||||
|
dw_loc_descr_ref next;
|
||||||
|
for (dw_loc_descr_ref prev = NULL; loc; prev = loc, loc = next)
|
||||||
|
{
|
||||||
|
next = loc->dw_loc_next;
|
||||||
|
if (loc->dw_loc_opc != DW_OP_GNU_variable_value
|
||||||
|
|| loc->dw_loc_oprnd1.val_class != dw_val_class_decl_ref)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tree decl = loc->dw_loc_oprnd1.v.val_decl_ref;
|
||||||
|
if (DECL_CONTEXT (decl) != current_function_decl)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dw_die_ref ref = lookup_decl_die (decl);
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dw_loc_list_ref l = loc_list_from_tree (decl, 0, NULL);
|
||||||
|
if (l == NULL)
|
||||||
|
continue;
|
||||||
|
if (l->dw_loc_next)
|
||||||
|
{
|
||||||
|
if (AT_class (a) != dw_val_class_loc)
|
||||||
|
continue;
|
||||||
|
switch (a->dw_attr)
|
||||||
|
{
|
||||||
|
/* Following attributes allow both exprloc and loclist
|
||||||
|
classes, so we can change them into a loclist. */
|
||||||
|
case DW_AT_location:
|
||||||
|
case DW_AT_string_length:
|
||||||
|
case DW_AT_return_addr:
|
||||||
|
case DW_AT_data_member_location:
|
||||||
|
case DW_AT_frame_base:
|
||||||
|
case DW_AT_segment:
|
||||||
|
case DW_AT_static_link:
|
||||||
|
case DW_AT_use_location:
|
||||||
|
case DW_AT_vtable_elem_location:
|
||||||
|
if (prev)
|
||||||
|
{
|
||||||
|
prev->dw_loc_next = NULL;
|
||||||
|
prepend_loc_descr_to_each (l, AT_loc (a));
|
||||||
|
}
|
||||||
|
if (next)
|
||||||
|
add_loc_descr_to_each (l, next);
|
||||||
|
a->dw_attr_val.val_class = dw_val_class_loc_list;
|
||||||
|
a->dw_attr_val.val_entry = NULL;
|
||||||
|
a->dw_attr_val.v.val_loc_list = l;
|
||||||
|
have_location_lists = true;
|
||||||
|
return true;
|
||||||
|
/* Following attributes allow both exprloc and reference,
|
||||||
|
so if the whole expression is DW_OP_GNU_variable_value alone
|
||||||
|
we could transform it into reference. */
|
||||||
|
case DW_AT_byte_size:
|
||||||
|
case DW_AT_bit_size:
|
||||||
|
case DW_AT_lower_bound:
|
||||||
|
case DW_AT_upper_bound:
|
||||||
|
case DW_AT_bit_stride:
|
||||||
|
case DW_AT_count:
|
||||||
|
case DW_AT_allocated:
|
||||||
|
case DW_AT_associated:
|
||||||
|
case DW_AT_byte_stride:
|
||||||
|
if (prev == NULL && next == NULL)
|
||||||
|
break;
|
||||||
|
/* FALLTHRU */
|
||||||
|
default:
|
||||||
|
if (dwarf_strict)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Create DW_TAG_variable that we can refer to. */
|
||||||
|
ref = gen_decl_die (decl, NULL_TREE, NULL,
|
||||||
|
lookup_decl_die (current_function_decl));
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (prev)
|
||||||
|
{
|
||||||
|
prev->dw_loc_next = l->expr;
|
||||||
|
add_loc_descr (&prev->dw_loc_next, next);
|
||||||
|
free_loc_descr (loc, NULL);
|
||||||
|
next = prev->dw_loc_next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (loc, l->expr, sizeof (dw_loc_descr_node));
|
||||||
|
add_loc_descr (&loc, next);
|
||||||
|
next = loc;
|
||||||
|
}
|
||||||
|
loc = prev;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to resolve DW_OP_GNU_variable_value using loc_list_from_tree. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
resolve_variable_value (dw_die_ref die)
|
||||||
|
{
|
||||||
|
dw_attr_node *a;
|
||||||
|
dw_loc_list_ref loc;
|
||||||
|
unsigned ix;
|
||||||
|
|
||||||
|
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
|
||||||
|
switch (AT_class (a))
|
||||||
|
{
|
||||||
|
case dw_val_class_loc:
|
||||||
|
if (!resolve_variable_value_in_expr (a, AT_loc (a)))
|
||||||
|
break;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case dw_val_class_loc_list:
|
||||||
|
loc = AT_loc_list (a);
|
||||||
|
gcc_assert (loc);
|
||||||
|
for (; loc; loc = loc->dw_loc_next)
|
||||||
|
resolve_variable_value_in_expr (a, loc->expr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to optimize DW_OP_GNU_variable_value refering to
|
||||||
|
temporaries in the current function. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
resolve_variable_values (void)
|
||||||
|
{
|
||||||
|
if (!variable_value_hash || !current_function_decl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct variable_value_struct *node
|
||||||
|
= variable_value_hash->find_with_hash (current_function_decl,
|
||||||
|
DECL_UID (current_function_decl));
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
dw_die_ref die;
|
||||||
|
FOR_EACH_VEC_SAFE_ELT (node->dies, i, die)
|
||||||
|
resolve_variable_value (die);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper function for note_variable_value, handle one location
|
||||||
|
expression. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
note_variable_value_in_expr (dw_die_ref die, dw_loc_descr_ref loc)
|
||||||
|
{
|
||||||
|
for (; loc; loc = loc->dw_loc_next)
|
||||||
|
if (loc->dw_loc_opc == DW_OP_GNU_variable_value
|
||||||
|
&& loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
|
||||||
|
{
|
||||||
|
tree decl = loc->dw_loc_oprnd1.v.val_decl_ref;
|
||||||
|
dw_die_ref ref = lookup_decl_die (decl);
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
|
||||||
|
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
|
||||||
|
}
|
||||||
|
if (VAR_P (decl)
|
||||||
|
&& DECL_CONTEXT (decl)
|
||||||
|
&& TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL
|
||||||
|
&& lookup_decl_die (DECL_CONTEXT (decl)))
|
||||||
|
{
|
||||||
|
if (!variable_value_hash)
|
||||||
|
variable_value_hash
|
||||||
|
= hash_table<variable_value_hasher>::create_ggc (10);
|
||||||
|
|
||||||
|
tree fndecl = DECL_CONTEXT (decl);
|
||||||
|
struct variable_value_struct *node;
|
||||||
|
struct variable_value_struct **slot
|
||||||
|
= variable_value_hash->find_slot_with_hash (fndecl,
|
||||||
|
DECL_UID (fndecl),
|
||||||
|
INSERT);
|
||||||
|
if (*slot == NULL)
|
||||||
|
{
|
||||||
|
node = ggc_cleared_alloc<variable_value_struct> ();
|
||||||
|
node->decl_id = DECL_UID (fndecl);
|
||||||
|
*slot = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
node = *slot;
|
||||||
|
|
||||||
|
vec_safe_push (node->dies, die);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk the tree DIE and note DIEs with DW_OP_GNU_variable_value still
|
||||||
|
with dw_val_class_decl_ref operand. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
note_variable_value (dw_die_ref die)
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
dw_attr_node *a;
|
||||||
|
dw_loc_list_ref loc;
|
||||||
|
unsigned ix;
|
||||||
|
|
||||||
|
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
|
||||||
|
switch (AT_class (a))
|
||||||
|
{
|
||||||
|
case dw_val_class_loc_list:
|
||||||
|
loc = AT_loc_list (a);
|
||||||
|
gcc_assert (loc);
|
||||||
|
if (!loc->noted_variable_value)
|
||||||
|
{
|
||||||
|
loc->noted_variable_value = 1;
|
||||||
|
for (; loc; loc = loc->dw_loc_next)
|
||||||
|
note_variable_value_in_expr (die, loc->expr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case dw_val_class_loc:
|
||||||
|
note_variable_value_in_expr (die, AT_loc (a));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark children. */
|
||||||
|
FOR_EACH_CHILD (die, c, note_variable_value (c));
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform any cleanups needed after the early debug generation pass
|
/* Perform any cleanups needed after the early debug generation pass
|
||||||
has run. */
|
has run. */
|
||||||
|
|
||||||
|
|
@ -30000,6 +30342,17 @@ dwarf2out_early_finish (const char *filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Traverse the DIE's and note DIEs with DW_OP_GNU_variable_value still
|
||||||
|
with dw_val_class_decl_ref operand. */
|
||||||
|
note_variable_value (comp_unit_die ());
|
||||||
|
for (limbo_die_node *node = cu_die_list; node; node = node->next)
|
||||||
|
note_variable_value (node->die);
|
||||||
|
for (comdat_type_node *ctnode = comdat_type_list; ctnode != NULL;
|
||||||
|
ctnode = ctnode->next)
|
||||||
|
note_variable_value (ctnode->root_die);
|
||||||
|
for (limbo_die_node *node = limbo_die_list; node; node = node->next)
|
||||||
|
note_variable_value (node->die);
|
||||||
|
|
||||||
/* The early debug phase is now finished. */
|
/* The early debug phase is now finished. */
|
||||||
early_dwarf_finished = true;
|
early_dwarf_finished = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
2017-02-25 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
|
PR debug/77589
|
||||||
|
* dwarf2.def (DW_OP_GNU_variable_value): New opcode.
|
||||||
|
|
||||||
2017-01-30 Alexandre Oliva <aoliva@redhat.com>
|
2017-01-30 Alexandre Oliva <aoliva@redhat.com>
|
||||||
|
|
||||||
Introduce C++ support in libcc1.
|
Introduce C++ support in libcc1.
|
||||||
|
|
|
||||||
|
|
@ -675,6 +675,9 @@ DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
|
||||||
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
|
/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */
|
||||||
DW_OP (DW_OP_GNU_addr_index, 0xfb)
|
DW_OP (DW_OP_GNU_addr_index, 0xfb)
|
||||||
DW_OP (DW_OP_GNU_const_index, 0xfc)
|
DW_OP (DW_OP_GNU_const_index, 0xfc)
|
||||||
|
/* The GNU variable value extension.
|
||||||
|
See http://dwarfstd.org/ShowIssue.php?issue=161109.2 . */
|
||||||
|
DW_OP (DW_OP_GNU_variable_value, 0xfd)
|
||||||
/* HP extensions. */
|
/* HP extensions. */
|
||||||
DW_OP_DUP (DW_OP_HP_unknown, 0xe0) /* Ouch, the same as GNU_push_tls_address. */
|
DW_OP_DUP (DW_OP_HP_unknown, 0xe0) /* Ouch, the same as GNU_push_tls_address. */
|
||||||
DW_OP (DW_OP_HP_is_value, 0xe1)
|
DW_OP (DW_OP_HP_is_value, 0xe1)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue