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>
|
||||
|
||||
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;
|
||||
/* True if .debug_loclists.dwo offset has been emitted for it already. */
|
||||
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
|
||||
are the same. */
|
||||
bool force;
|
||||
@ -1791,6 +1793,7 @@ size_of_loc_descr (dw_loc_descr_ref loc)
|
||||
size += 4;
|
||||
break;
|
||||
case DW_OP_call_ref:
|
||||
case DW_OP_GNU_variable_value:
|
||||
size += DWARF_REF_SIZE;
|
||||
break;
|
||||
case DW_OP_implicit_value:
|
||||
@ -2214,6 +2217,17 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
|
||||
}
|
||||
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_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. */
|
||||
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>
|
||||
{
|
||||
static hashval_t hash (die_struct *);
|
||||
@ -3287,10 +3318,6 @@ static bool frame_pointer_fb_offset_valid;
|
||||
|
||||
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
|
||||
a scalar value (bounds, pointers, ...). */
|
||||
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 void schedule_generic_params_dies_gen (tree t);
|
||||
static void gen_scheduled_generic_parms_dies (void);
|
||||
static void resolve_variable_values (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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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;
|
||||
while (list)
|
||||
{
|
||||
copy = ggc_alloc<dw_loc_descr_node> ();
|
||||
memcpy (copy, ref, sizeof (dw_loc_descr_node));
|
||||
copy = copy_loc_descr (ref);
|
||||
add_loc_descr (&list->expr, copy);
|
||||
while (copy->dw_loc_next)
|
||||
{
|
||||
dw_loc_descr_ref new_copy = ggc_alloc<dw_loc_descr_node> ();
|
||||
memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node));
|
||||
copy->dw_loc_next = new_copy;
|
||||
copy = new_copy;
|
||||
}
|
||||
copy = copy->dw_loc_next = copy_loc_descr (copy->dw_loc_next);
|
||||
list = list->dw_loc_next;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
|
||||
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.
|
||||
Adding that will improve quality of debug info especially for SRA-ed
|
||||
structures. */
|
||||
@ -16344,7 +16397,7 @@ add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list)
|
||||
}
|
||||
if (!(*ret)->dw_loc_next)
|
||||
{
|
||||
add_loc_descr_to_each (list, (*ret)->expr);
|
||||
prepend_loc_descr_to_each (list, (*ret)->expr);
|
||||
*ret = list;
|
||||
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_push_object_address:
|
||||
case DW_OP_call_frame_cfa:
|
||||
case DW_OP_GNU_variable_value:
|
||||
++frame_offset_;
|
||||
break;
|
||||
|
||||
@ -17299,6 +17353,31 @@ loc_list_from_tree_1 (tree loc, int want_address,
|
||||
rtl = rtl_for_decl_location (loc);
|
||||
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");
|
||||
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);
|
||||
|
||||
for (dw_loc_list_ref loc_cur = result;
|
||||
loc_cur != NULL; loc_cur =
|
||||
loc_cur->dw_loc_next)
|
||||
loc_cur != NULL; loc_cur = loc_cur->dw_loc_next)
|
||||
loc_descr_without_nops (loc_cur->expr);
|
||||
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 rszdecl = szdecl;
|
||||
HOST_WIDE_INT rsize = 0;
|
||||
|
||||
size = int_size_in_bytes (TREE_TYPE (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)))
|
||||
{
|
||||
rszdecl = TREE_OPERAND (szdecl, 0);
|
||||
rsize = int_size_in_bytes (TREE_TYPE (rszdecl));
|
||||
if (rsize <= 0)
|
||||
if (int_size_in_bytes (TREE_TYPE (rszdecl))
|
||||
!= DWARF2_ADDR_SIZE)
|
||||
size = 0;
|
||||
}
|
||||
else
|
||||
@ -20703,41 +20780,9 @@ gen_array_type_die (tree type, dw_die_ref context_die)
|
||||
}
|
||||
if (size > 0)
|
||||
{
|
||||
dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2, NULL);
|
||||
if (loc == NULL
|
||||
&& early_dwarf
|
||||
&& 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);
|
||||
}
|
||||
dw_loc_list_ref loc
|
||||
= loc_list_from_tree (rszdecl, szdecl == rszdecl ? 2 : 0,
|
||||
NULL);
|
||||
if (loc)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
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,
|
||||
loc_list_from_tree (fb_expr, 0, NULL));
|
||||
}
|
||||
|
||||
resolve_variable_values ();
|
||||
}
|
||||
|
||||
/* 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
|
||||
? DECL_ARGUMENTS (generic_decl)
|
||||
: 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
|
||||
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)
|
||||
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)
|
||||
@ -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)
|
||||
prune_unused_types_mark (loc->dw_loc_oprnd1.v.val_die_ref.die, 1);
|
||||
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_call4:
|
||||
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. */
|
||||
|
||||
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;
|
||||
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_GNU_implicit_pointer:
|
||||
case DW_OP_GNU_parameter_ref:
|
||||
case DW_OP_GNU_variable_value:
|
||||
if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_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.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;
|
||||
case DW_OP_const_type:
|
||||
case DW_OP_regval_type:
|
||||
@ -28544,18 +28591,18 @@ non_dwarf_expression (dw_loc_descr_ref l)
|
||||
/* Return adjusted copy of EXPR:
|
||||
If it is empty DWARF expression, return it.
|
||||
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
|
||||
copy of the DWARF expression with DW_OP_breg{N,x} <0> appended
|
||||
and no DEREF.
|
||||
copy of the DWARF expression with DW_OP_breg{N,x} <0> appended.
|
||||
If it is DWARF expression followed by DW_OP_stack_value, return
|
||||
copy of the DWARF expression without anything appended.
|
||||
Otherwise, return NULL. */
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
@ -28566,26 +28613,24 @@ copy_deref_exprloc (dw_loc_descr_ref expr, dw_loc_descr_ref deref)
|
||||
if (l)
|
||||
{
|
||||
if (l->dw_loc_opc >= DW_OP_reg0 && l->dw_loc_opc <= DW_OP_reg31)
|
||||
deref = new_loc_descr ((enum dwarf_location_atom)
|
||||
(DW_OP_breg0 + (l->dw_loc_opc - DW_OP_reg0)),
|
||||
0, 0);
|
||||
tail = new_loc_descr ((enum dwarf_location_atom)
|
||||
(DW_OP_breg0 + (l->dw_loc_opc - DW_OP_reg0)),
|
||||
0, 0);
|
||||
else
|
||||
switch (l->dw_loc_opc)
|
||||
{
|
||||
case DW_OP_regx:
|
||||
deref = new_loc_descr (DW_OP_bregx,
|
||||
l->dw_loc_oprnd1.v.val_unsigned, 0);
|
||||
tail = new_loc_descr (DW_OP_bregx,
|
||||
l->dw_loc_oprnd1.v.val_unsigned, 0);
|
||||
break;
|
||||
case DW_OP_stack_value:
|
||||
deref = NULL;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
deref = new_loc_descr (deref->dw_loc_opc,
|
||||
deref->dw_loc_oprnd1.v.val_int, 0);
|
||||
tail = new_loc_descr (DW_OP_deref, 0, 0);
|
||||
|
||||
dw_loc_descr_ref ret = NULL, *p = &ret;
|
||||
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;
|
||||
expr = expr->dw_loc_next;
|
||||
}
|
||||
*p = deref;
|
||||
*p = tail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* For DW_AT_string_length attribute with DW_OP_call4 reference to a variable
|
||||
or argument, adjust it if needed and return:
|
||||
/* For DW_AT_string_length attribute with DW_OP_GNU_variable_value
|
||||
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
|
||||
attribute if present should be removed
|
||||
0 keep the attribute as is if the referenced var or argument has
|
||||
only DWARF expression that covers all ranges
|
||||
0 keep the attribute perhaps with minor modifications, no need to rescan
|
||||
1 if the attribute has been successfully adjusted. */
|
||||
|
||||
static int
|
||||
optimize_string_length (dw_attr_node *a)
|
||||
{
|
||||
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_loc_list_ref d;
|
||||
bool non_dwarf_expr = false;
|
||||
|
||||
if (av == NULL)
|
||||
return -1;
|
||||
return dwarf_strict ? -1 : 0;
|
||||
switch (AT_class (av))
|
||||
{
|
||||
case dw_val_class_loc_list:
|
||||
@ -28629,22 +28700,31 @@ optimize_string_length (dw_attr_node *a)
|
||||
case dw_val_class_loc:
|
||||
lv = AT_loc (av);
|
||||
if (lv == NULL)
|
||||
return -1;
|
||||
return dwarf_strict ? -1 : 0;
|
||||
if (non_dwarf_expression (lv))
|
||||
non_dwarf_expr = true;
|
||||
break;
|
||||
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
|
||||
&& (l->dw_loc_next == NULL || AT_class (av) == dw_val_class_loc))
|
||||
return 0;
|
||||
&& (l->dw_loc_next != NULL || AT_class (av) == dw_val_class_loc))
|
||||
{
|
||||
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. */
|
||||
if (l->dw_loc_next == NULL)
|
||||
if (l->dw_loc_next != NULL)
|
||||
{
|
||||
a->dw_attr_val = av->dw_attr_val;
|
||||
return 1;
|
||||
@ -28658,23 +28738,25 @@ optimize_string_length (dw_attr_node *a)
|
||||
list = NULL;
|
||||
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)
|
||||
{
|
||||
*p = new_loc_list (lv, d->begin, d->end, d->section);
|
||||
p = &(*p)->dw_loc_next;
|
||||
}
|
||||
else if (!dwarf_strict && d->expr)
|
||||
return 0;
|
||||
}
|
||||
if (list == NULL)
|
||||
return -1;
|
||||
return dwarf_strict ? -1 : 0;
|
||||
a->dw_attr_val.val_class = dw_val_class_loc_list;
|
||||
gen_llsym (list);
|
||||
*AT_loc_list_ptr (a) = list;
|
||||
return 1;
|
||||
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)
|
||||
return -1;
|
||||
return dwarf_strict ? -1 : 0;
|
||||
a->dw_attr_val.v.val_loc = lv;
|
||||
return 1;
|
||||
default:
|
||||
@ -28720,7 +28802,7 @@ resolve_addr (dw_die_ref die)
|
||||
while (*curr)
|
||||
{
|
||||
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_descr_ref l = (*curr)->expr;
|
||||
@ -28757,19 +28839,19 @@ resolve_addr (dw_die_ref die)
|
||||
case dw_val_class_loc:
|
||||
{
|
||||
dw_loc_descr_ref l = AT_loc (a);
|
||||
/* Using DW_OP_call4 or DW_OP_call4 DW_OP_deref in
|
||||
DW_AT_string_length is only a rough approximation; unfortunately
|
||||
DW_AT_string_length can't be a reference to a DIE. DW_OP_call4
|
||||
needs a DWARF expression, while DW_AT_location of the referenced
|
||||
variable or argument might be any location description. */
|
||||
/* DW_OP_GNU_variable_value DW_OP_stack_value or
|
||||
DW_OP_GNU_variable_value in DW_AT_string_length can be converted
|
||||
into DW_OP_call4 or DW_OP_call4 DW_OP_deref, which is standard
|
||||
DWARF4 unlike DW_OP_GNU_variable_value. Or for DWARF5
|
||||
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
|
||||
&& l
|
||||
&& l->dw_loc_opc == DW_OP_call4
|
||||
&& l->dw_loc_oprnd1.val_class == dw_val_class_die_ref
|
||||
&& l->dw_loc_opc == DW_OP_GNU_variable_value
|
||||
&& (l->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_deref_size))))
|
||||
&& l->dw_loc_next->dw_loc_opc == DW_OP_stack_value)))
|
||||
{
|
||||
switch (optimize_string_length (a))
|
||||
{
|
||||
@ -28799,7 +28881,7 @@ resolve_addr (dw_die_ref die)
|
||||
|| l == NULL
|
||||
|| l->dw_loc_opc != DW_OP_plus_uconst
|
||||
|| l->dw_loc_next != NULL)
|
||||
&& !resolve_addr_in_expr (l))
|
||||
&& !resolve_addr_in_expr (a, l))
|
||||
{
|
||||
if (dwarf_split_debug_info)
|
||||
remove_loc_list_addr_table_entries (l);
|
||||
@ -28816,6 +28898,10 @@ resolve_addr (dw_die_ref die)
|
||||
optimize_location_into_implicit_ptr (die, decl);
|
||||
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);
|
||||
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
|
||||
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. */
|
||||
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>
|
||||
|
||||
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. */
|
||||
DW_OP (DW_OP_GNU_addr_index, 0xfb)
|
||||
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. */
|
||||
DW_OP_DUP (DW_OP_HP_unknown, 0xe0) /* Ouch, the same as GNU_push_tls_address. */
|
||||
DW_OP (DW_OP_HP_is_value, 0xe1)
|
||||
|
Loading…
Reference in New Issue
Block a user