DWARF: handle variable-length records and variant parts

Enhance the DWARF back-end to emit proper descriptions for
variable-length records as well as variant parts in records.

In order to achieve this, generate DWARF expressions ("location
descriptions" in dwarf2out's parlance) for size and data member location
attributes.  Also match QUAL_UNION_TYPE data types as variant parts,
assuming the formers appear only to implement the latters (which is the
case at the moment: only the Ada front-end emits them).

Note that very few debuggers can handle these descriptions (GDB does not
yet), so in order to ease the the transition enable these only when
-fgnat-encodings=minimal.

gcc/ada/ChangeLog:

	* gcc-interface/decl.c (gnat_to_gnu_entity): Disable ___XVS GNAT
	encodings when -fgnat-encodings=minimal.
	(components_to_record): Disable ___XVE, ___XVN, ___XVU and
	___XVZ GNAT encodings when -fgnat-encodings=minimal.
	* gcc-interface/utils.c (maybe_pad_type): Disable __XVS GNAT
	encodings when -fgnat-encodings=minimal.

gcc/ChangeLog:

	* debug.h (struct gcc_debug_hooks): Add a new size_function
	hook.
	* debug.c (do_nothing_debug_hooks): Set the size_function field
	to no-op.
	* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
	* sdbout.c (sdb_debug_hooks): Likewise.
	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
	* stor-layout.c (finalize_size_functions): Let the debug info
	back-end know about the implementation of size functions.
	* dwarf2out.h (dw_discr_list_ref): New typedef.
	(enum dw_val_class): Add value classes for discriminant values
	and discriminant lists.
	(struct dw_discr_value): New structure.
	(struct dw_val_node): Add discriminant values and discriminant
	lists to the union.
	(struct dw_loc_descr_node): Add frame_offset_rel and
	dw_loc_frame_offset (only for checking) fields to handle DWARF
	procedures generation.
	(struct dw_discr_list_node): New structure.
	* dwarf2out.c (dwarf2out_size_function): New.
	(dwarf2_debug_hooks): Set the size_function field to
	dwarf2out_size_function.
	(dwarf2_lineno_debug_hooks): Set the size_function field to
	no-op.
	(new_loc_descr): Initialize the
	dw_loc_frame_offset field.
	(dwarf_proc_stack_usage_map): New.
	(dw_val_equal_p): Handle discriminants.
	(size_of_discr_value): New.
	(size_of_discr_list): New.
	(size_of_die): Handle discriminants.
	(add_loc_descr_to_each): New.
	(add_loc_list): New.
	(print_discr_value): New.
	(print_dw_val): Handle discriminants.
	(value_format): Handle discriminants.
	(output_discr_value): New.
	(output_die): Handle discriminants.
	(output_loc_operands): Handle DW_OP_call2 and DW_OP_call4.
	(uint_loc_descriptor): New.
	(uint_comparison_loc_list): New.
	(loc_list_from_uint_comparison): New.
	(add_discr_value): New.
	(add_discr_list): New.
	(AT_discr_list): New.
	(loc_descr_to_next_no_op): New.
	(free_loc_descr): New.
	(loc_descr_without_nops): New.
	(struct loc_descr_context): Add a dpi field.
	(struct dwarf_procedure_info): New helper structure.
	(new_dwarf_proc_die): New.
	(is_handled_procedure_type): New.
	(resolve_args_picking_1): New.
	(resolve_args_picking): New.
	(function_to_dwarf_procedure): New.
	(copy_dwarf_procedure): New.
	(copy_dwarf_procs_ref_in_attrs): New.
	(copy_dwarf_procs_ref_in_dies): New.
	(break_out_comdat_types): Copy DWARF procedures along with the
	types that reference them.
	(loc_list_from_tree): Rename into loc_list_from_tree_1.  Handle
	CALL_EXPR in the cases suitable for DWARF procedures.  Handle
	for PARM_DECL when generating a location description for a DWARF
	procedure.  Handle big unsigned INTEGER_CST nodes.  Handle
	NON_LVALUE_EXPR, EXACT_DIV_EXPR and all unsigned comparison
	operators.  Add a wrapper for loc_list_from_tree that strips
	DW_OP_nop operations from the result.
	(type_byte_size): New.
	(struct vlr_context): New helper structure.
	(field_byte_offset): Change signature to return either a
	constant offset or a location description for dynamic ones.
	Handle dynamic byte offsets with constant bit offsets and handle
	fields in variant parts.
	(add_data_member_location): Change signature to handle dynamic
	member offsets and fields in variant parts.  Update call to
	field_byte_offset.  Handle location lists.  Emit a variable data
	member location only when -fgnat-encodings=minimal.
	(add_bound_info): Emit self-referential bounds only when
	-fgnat-encodings=minimal.
	(add_byte_size_attribute): Use type_byte_size in order to handle
	dynamic type sizes.  Emit variable byte size only when
	-fgnat-encodings=minimal and when the target DWARF version
	allows them.
	(add_bit_offset_attribute): Change signature to handle
	variable-length records.  Update call to field_byte_offset.
	(gen_descr_array_type_die): Update call to gen_field_die.
	Update loc_descr_context literal.
	(gen_type_die_for_member): Likewise.
	(gen_subprogram_die): Update calls to get_decl_die.
	(gen_field_die): Change signature to handle variable-length
	records.  Update calls to add_bit_offset_attribute and
	add_data_member_location_attribute.
	(gen_inheritance_die): Update call to
	add_data_member_location_attribute.
	(gen_decl_die): Change signature to handle variable-length
	records.  Update call to gen_field_die.
	(gen_inheritance_die): Change signature to handle
	variable-length records.  Update call to
	add_data_member_location_attribute.
	(is_variant_part): New.
	(analyze_discr_in_predicate): New.
	(get_discr_value): New.
	(analyze_variants_discr): New.
	(gen_variant_part): New.
	(gen_member_die): Update calls to gen_decl_die.  Call instead
	gen_variant_part for variant parts.
	(gen_type_die_with_usage): Update calls to gen_decl_die.
	(process_scope_var): Likewise.
	(force_decl_die): Likewise.
	(declare_in_namespace): Likewise.
	(dwarf2out_decl): Likewise.
	(prune_unused_types_walk_loc_descr): New.
	(prune_unused_types_walk_attribs): Mark DIEs referenced by
	location descriptions and loc. descr. lists.
	(prune_unused_types_walk): Don't mark DWARF procedures by
	default.  Mark variant parts since nothing is supposed to
	reference them.
	(dwarf2out_init): Allocate dwarf_proc_stack_usage_map.
	(dwarf2out_c_finalize): Deallocate and reset
	dwarf_proc_stack_usage_map.

gcc/testsuite/ChangeLog:

	* gnat.dg/specs/debug1.ads: Update the expected number of
	DW_AT_artificial attribute in compiler output.

From-SVN: r231762
This commit is contained in:
Pierre-Marie de Rodat 2015-12-17 14:09:36 +00:00 committed by Pierre-Marie de Rodat
parent 6592d14b43
commit 986ccd2171
14 changed files with 2067 additions and 126 deletions

View File

@ -1,3 +1,126 @@
2015-12-17 Pierre-Marie de Rodat <derodat@adacore.com>
* debug.h (struct gcc_debug_hooks): Add a new size_function
hook.
* debug.c (do_nothing_debug_hooks): Set the size_function field
to no-op.
* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise.
* sdbout.c (sdb_debug_hooks): Likewise.
* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
* stor-layout.c (finalize_size_functions): Let the debug info
back-end know about the implementation of size functions.
* dwarf2out.h (dw_discr_list_ref): New typedef.
(enum dw_val_class): Add value classes for discriminant values
and discriminant lists.
(struct dw_discr_value): New structure.
(struct dw_val_node): Add discriminant values and discriminant
lists to the union.
(struct dw_loc_descr_node): Add frame_offset_rel and
dw_loc_frame_offset (only for checking) fields to handle DWARF
procedures generation.
(struct dw_discr_list_node): New structure.
* dwarf2out.c (dwarf2out_size_function): New.
(dwarf2_debug_hooks): Set the size_function field to
dwarf2out_size_function.
(dwarf2_lineno_debug_hooks): Set the size_function field to
no-op.
(new_loc_descr): Initialize the
dw_loc_frame_offset field.
(dwarf_proc_stack_usage_map): New.
(dw_val_equal_p): Handle discriminants.
(size_of_discr_value): New.
(size_of_discr_list): New.
(size_of_die): Handle discriminants.
(add_loc_descr_to_each): New.
(add_loc_list): New.
(print_discr_value): New.
(print_dw_val): Handle discriminants.
(value_format): Handle discriminants.
(output_discr_value): New.
(output_die): Handle discriminants.
(output_loc_operands): Handle DW_OP_call2 and DW_OP_call4.
(uint_loc_descriptor): New.
(uint_comparison_loc_list): New.
(loc_list_from_uint_comparison): New.
(add_discr_value): New.
(add_discr_list): New.
(AT_discr_list): New.
(loc_descr_to_next_no_op): New.
(free_loc_descr): New.
(loc_descr_without_nops): New.
(struct loc_descr_context): Add a dpi field.
(struct dwarf_procedure_info): New helper structure.
(new_dwarf_proc_die): New.
(is_handled_procedure_type): New.
(resolve_args_picking_1): New.
(resolve_args_picking): New.
(function_to_dwarf_procedure): New.
(copy_dwarf_procedure): New.
(copy_dwarf_procs_ref_in_attrs): New.
(copy_dwarf_procs_ref_in_dies): New.
(break_out_comdat_types): Copy DWARF procedures along with the
types that reference them.
(loc_list_from_tree): Rename into loc_list_from_tree_1. Handle
CALL_EXPR in the cases suitable for DWARF procedures. Handle
for PARM_DECL when generating a location description for a DWARF
procedure. Handle big unsigned INTEGER_CST nodes. Handle
NON_LVALUE_EXPR, EXACT_DIV_EXPR and all unsigned comparison
operators. Add a wrapper for loc_list_from_tree that strips
DW_OP_nop operations from the result.
(type_byte_size): New.
(struct vlr_context): New helper structure.
(field_byte_offset): Change signature to return either a
constant offset or a location description for dynamic ones.
Handle dynamic byte offsets with constant bit offsets and handle
fields in variant parts.
(add_data_member_location): Change signature to handle dynamic
member offsets and fields in variant parts. Update call to
field_byte_offset. Handle location lists. Emit a variable data
member location only when -fgnat-encodings=minimal.
(add_bound_info): Emit self-referential bounds only when
-fgnat-encodings=minimal.
(add_byte_size_attribute): Use type_byte_size in order to handle
dynamic type sizes. Emit variable byte size only when
-fgnat-encodings=minimal and when the target DWARF version
allows them.
(add_bit_offset_attribute): Change signature to handle
variable-length records. Update call to field_byte_offset.
(gen_descr_array_type_die): Update call to gen_field_die.
Update loc_descr_context literal.
(gen_type_die_for_member): Likewise.
(gen_subprogram_die): Update calls to get_decl_die.
(gen_field_die): Change signature to handle variable-length
records. Update calls to add_bit_offset_attribute and
add_data_member_location_attribute.
(gen_inheritance_die): Update call to
add_data_member_location_attribute.
(gen_decl_die): Change signature to handle variable-length
records. Update call to gen_field_die.
(gen_inheritance_die): Change signature to handle
variable-length records. Update call to
add_data_member_location_attribute.
(is_variant_part): New.
(analyze_discr_in_predicate): New.
(get_discr_value): New.
(analyze_variants_discr): New.
(gen_variant_part): New.
(gen_member_die): Update calls to gen_decl_die. Call instead
gen_variant_part for variant parts.
(gen_type_die_with_usage): Update calls to gen_decl_die.
(process_scope_var): Likewise.
(force_decl_die): Likewise.
(declare_in_namespace): Likewise.
(dwarf2out_decl): Likewise.
(prune_unused_types_walk_loc_descr): New.
(prune_unused_types_walk_attribs): Mark DIEs referenced by
location descriptions and loc. descr. lists.
(prune_unused_types_walk): Don't mark DWARF procedures by
default. Mark variant parts since nothing is supposed to
reference them.
(dwarf2out_init): Allocate dwarf_proc_stack_usage_map.
(dwarf2out_c_finalize): Deallocate and reset
dwarf_proc_stack_usage_map.
2015-12-17 Pierre-Marie de Rodat <derodat@adacore.com>
* common.opt (gnat_encodings): New variable

View File

@ -1,3 +1,12 @@
2015-12-17 Pierre-Marie de Rodat <derodat@adacore.com>
* gcc-interface/decl.c (gnat_to_gnu_entity): Disable ___XVS GNAT
encodings when -fgnat-encodings=minimal.
(components_to_record): Disable ___XVE, ___XVN, ___XVU and
___XVZ GNAT encodings when -fgnat-encodings=minimal.
* gcc-interface/utils.c (maybe_pad_type): Disable __XVS GNAT
encodings when -fgnat-encodings=minimal.
2015-12-17 Pierre-Marie de Rodat <derodat@adacore.com>
* gcc-interface/misc.c (gnat_encodings): Undefine macro and

View File

@ -3556,10 +3556,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
/* Fill in locations of fields. */
annotate_rep (gnat_entity, gnu_type);
/* If debugging information is being written for the type, write
a record that shows what we are a subtype of and also make a
variable that indicates our size, if still variable. */
if (debug_info_p)
/* If debugging information is being written for the type and if
we are asked to output such encodings, write a record that
shows what we are a subtype of and also make a variable that
indicates our size, if still variable. */
if (gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL)
{
tree gnu_subtype_marker = make_node (RECORD_TYPE);
tree gnu_unpad_base_name
@ -7029,6 +7030,8 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
bool debug_info, bool maybe_unused, bool reorder,
tree first_free_pos, tree *p_gnu_rep_list)
{
const bool needs_xv_encodings
= debug_info && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL;
bool all_rep_and_size = all_rep && TYPE_SIZE (gnu_record_type);
bool variants_have_rep = all_rep;
bool layout_with_rep = false;
@ -7211,7 +7214,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
NULL_TREE, packed, definition,
!all_rep_and_size, all_rep,
unchecked_union,
true, debug_info, true, reorder,
true, needs_xv_encodings, true, reorder,
this_first_free_pos,
all_rep || this_first_free_pos
? NULL : &gnu_rep_list);
@ -7301,7 +7304,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
if (debug_info)
rest_of_record_type_compilation (gnu_variant_type);
create_type_decl (TYPE_NAME (gnu_variant_type), gnu_variant_type,
true, debug_info, gnat_component_list);
true, needs_xv_encodings, gnat_component_list);
gnu_field
= create_field_decl (gnu_variant->name, gnu_variant_type,
@ -7334,7 +7337,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
}
finish_record_type (gnu_union_type, nreverse (gnu_variant_list),
all_rep_and_size ? 1 : 0, debug_info);
all_rep_and_size ? 1 : 0, needs_xv_encodings);
/* If GNU_UNION_TYPE is our record type, it means we must have an
Unchecked_Union with no fields. Verify that and, if so, just
@ -7348,7 +7351,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
}
create_type_decl (TYPE_NAME (gnu_union_type), gnu_union_type, true,
debug_info, gnat_component_list);
needs_xv_encodings, gnat_component_list);
/* Deal with packedness like in gnat_to_gnu_field. */
if (union_field_needs_strict_alignment)

View File

@ -1348,8 +1348,10 @@ maybe_pad_type (tree type, tree size, unsigned int align,
/* Unless debugging information isn't being written for the input type,
write a record that shows what we are a subtype of and also make a
variable that indicates our size, if still variable. */
if (TREE_CODE (orig_size) != INTEGER_CST
variable that indicates our size, if still variable. Don't do this if
asked to output as few encodings as possible. */
if (gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL
&& TREE_CODE (orig_size) != INTEGER_CST
&& TYPE_NAME (record)
&& TYPE_NAME (type)
&& !(TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
@ -1890,7 +1892,7 @@ rest_of_record_type_compilation (tree record_type)
/* If this record type is of variable size, make a parallel record type that
will tell the debugger how the former is laid out (see exp_dbug.ads). */
if (var_size)
if (var_size && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL)
{
tree new_record_type
= make_node (TREE_CODE (record_type) == QUAL_UNION_TYPE

View File

@ -375,6 +375,7 @@ const struct gcc_debug_hooks dbx_debug_hooks =
debug_nothing_rtx_code_label, /* label */
dbxout_handle_pch, /* handle_pch */
debug_nothing_rtx_insn, /* var_location */
debug_nothing_tree, /* size_function */
debug_nothing_void, /* switch_text_section */
debug_nothing_tree_tree, /* set_name */
0, /* start_end_main_source_file */
@ -414,6 +415,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
debug_nothing_rtx_code_label, /* label */
dbxout_handle_pch, /* handle_pch */
debug_nothing_rtx_insn, /* var_location */
debug_nothing_tree, /* size_function */
debug_nothing_void, /* switch_text_section */
debug_nothing_tree_tree, /* set_name */
0, /* start_end_main_source_file */

View File

@ -53,6 +53,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
debug_nothing_rtx_code_label, /* label */
debug_nothing_int, /* handle_pch */
debug_nothing_rtx_insn, /* var_location */
debug_nothing_tree, /* size_function */
debug_nothing_void, /* switch_text_section */
debug_nothing_tree_tree, /* set_name */
0, /* start_end_main_source_file */

View File

@ -166,6 +166,11 @@ struct gcc_debug_hooks
/* Called from final_scan_insn for any NOTE_INSN_VAR_LOCATION note. */
void (* var_location) (rtx_insn *);
/* Called from finalize_size_functions for size functions so that their body
can be encoded in the debug info to describe the layout of variable-length
structures. */
void (* size_function) (tree decl);
/* Called from final_scan_insn if there is a switch between hot and cold
text sections. */
void (* switch_text_section) (void);

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@ typedef struct dw_val_node *dw_val_ref;
typedef struct dw_cfi_node *dw_cfi_ref;
typedef struct dw_loc_descr_node *dw_loc_descr_ref;
typedef struct dw_loc_list_struct *dw_loc_list_ref;
typedef struct dw_discr_list_node *dw_discr_list_ref;
typedef wide_int *wide_int_ptr;
@ -150,7 +151,9 @@ enum dw_val_class
dw_val_class_data8,
dw_val_class_decl_ref,
dw_val_class_vms_delta,
dw_val_class_high_pc
dw_val_class_high_pc,
dw_val_class_discr_value,
dw_val_class_discr_list
};
/* Describe a floating point constant value, or a vector constant value. */
@ -161,6 +164,25 @@ struct GTY(()) dw_vec_const {
unsigned elt_size;
};
/* Describe a single value that a discriminant can match.
Discriminants (in the "record variant part" meaning) are scalars.
dw_discr_list_ref and dw_discr_value are a mean to describe a set of
discriminant values that are matched by a particular variant.
Discriminants can be signed or unsigned scalars, and can be discriminants
values. Both have to be consistent, though. */
struct GTY(()) dw_discr_value {
int pos; /* Whether the discriminant value is positive (unsigned). */
union
{
HOST_WIDE_INT GTY ((tag ("0"))) sval;
unsigned HOST_WIDE_INT GTY ((tag ("1"))) uval;
}
GTY ((desc ("%1.pos"))) v;
};
struct addr_table_entry;
/* The dw_val_node describes an attribute's value, as it is
@ -197,6 +219,8 @@ struct GTY(()) dw_val_node {
char * lbl1;
char * lbl2;
} GTY ((tag ("dw_val_class_vms_delta"))) val_vms_delta;
dw_discr_value GTY ((tag ("dw_val_class_discr_value"))) val_discr_value;
dw_discr_list_ref GTY ((tag ("dw_val_class_discr_list"))) val_discr_list;
}
GTY ((desc ("%1.val_class"))) v;
};
@ -210,11 +234,35 @@ struct GTY((chain_next ("%h.dw_loc_next"))) dw_loc_descr_node {
/* Used to distinguish DW_OP_addr with a direct symbol relocation
from DW_OP_addr with a dtp-relative symbol relocation. */
unsigned int dtprel : 1;
/* For DW_OP_pick operations: true iff. it targets a DWARF prodecure
argument. In this case, it needs to be relocated according to the current
frame offset. */
unsigned int frame_offset_rel : 1;
int dw_loc_addr;
#if ENABLE_CHECKING
/* When translating a function into a DWARF procedure, contains the frame
offset *before* evaluating this operation. It is -1 when not yet
initialized. */
int dw_loc_frame_offset;
#endif
dw_val_node dw_loc_oprnd1;
dw_val_node dw_loc_oprnd2;
};
/* A variant (inside a record variant part) is selected when the corresponding
discriminant matches its set of values (see the comment for dw_discr_value).
The following datastructure holds such matching information. */
struct GTY(()) dw_discr_list_node {
dw_discr_list_ref dw_discr_next;
dw_discr_value dw_discr_lower_bound;
dw_discr_value dw_discr_upper_bound;
/* This node represents only the value in dw_discr_lower_bound when it's
zero. It represents the range between the two fields (bounds included)
otherwise. */
int dw_discr_range;
};
/* Interface from dwarf2out.c to dwarf2cfi.c. */
extern struct dw_loc_descr_node *build_cfa_loc

View File

@ -304,6 +304,7 @@ const struct gcc_debug_hooks sdb_debug_hooks =
sdbout_label, /* label */
debug_nothing_int, /* handle_pch */
debug_nothing_rtx_insn, /* var_location */
debug_nothing_tree, /* size_function */
debug_nothing_void, /* switch_text_section */
debug_nothing_tree_tree, /* set_name */
0, /* start_end_main_source_file */

View File

@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-inline.h"
#include "tree-dump.h"
#include "gimplify.h"
#include "debug.h"
/* Data type for the expressions representing sizes of data types.
It is the first integer type laid out. */
@ -292,6 +293,10 @@ finalize_size_functions (void)
allocate_struct_function (fndecl, false);
set_cfun (NULL);
dump_function (TDI_original, fndecl);
/* As these functions are used to describe the layout of variable-length
structures, debug info generation needs their implementation. */
debug_hooks->size_function (fndecl);
gimplify_function_tree (fndecl);
cgraph_node::finalize_function (fndecl, false);
}

View File

@ -1,3 +1,8 @@
2015-12-17 Pierre-Marie de Rodat <derodat@adacore.com>
* gnat.dg/specs/debug1.ads: Update the expected number of
DW_AT_artificial attribute in compiler output.
2015-12-17 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/68835

View File

@ -11,4 +11,4 @@ package Debug1 is
end Debug1;
-- { dg-final { scan-assembler-times "DW_AT_artificial" 15 } }
-- { dg-final { scan-assembler-times "DW_AT_artificial" 17 } }

View File

@ -201,6 +201,7 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks
debug_nothing_rtx_code_label, /* label */
debug_nothing_int, /* handle_pch */
debug_nothing_rtx_insn, /* var_location */
debug_nothing_tree, /* size_function */
debug_nothing_void, /* switch_text_section */
debug_nothing_tree_tree, /* set_name */
0, /* start_end_main_source_file */