static rtx_insn *last_var_location_insn;
static rtx_insn *cached_next_real_insn;
static void dwarf2out_decl (tree);
+static bool is_redundant_typedef (const_tree);
#ifndef XCOFF_DEBUGGING_INFO
#define XCOFF_DEBUGGING_INFO 0
it. */
static GTY(()) vec<tree, va_gc> *incomplete_types;
-/* A pointer to the base of a table of references to declaration
- scopes. This table is a display which tracks the nesting
- of declaration scopes at the current scope and containing
- scopes. This table is used to find the proper place to
- define type declaration DIE's. */
-static GTY(()) vec<tree, va_gc> *decl_scope_table;
-
/* Pointers to various DWARF2 sections. */
static GTY(()) section *debug_info_section;
static GTY(()) section *debug_skeleton_info_section;
That is, the comp_dir and dwo_name will appear in both places.
2) Strings can use four forms: DW_FORM_string, DW_FORM_strp,
- DW_FORM_line_strp or DW_FORM_GNU_str_index.
+ DW_FORM_line_strp or DW_FORM_strx/GNU_str_index.
3) GCC chooses the form to use late, depending on the size and
reference count.
#define FUNC_BEGIN_LABEL "LFB"
#endif
+#ifndef FUNC_SECOND_SECT_LABEL
+#define FUNC_SECOND_SECT_LABEL "LFSB"
+#endif
+
#ifndef FUNC_END_LABEL
#define FUNC_END_LABEL "LFE"
#endif
void
dwarf2out_switch_text_section (void)
{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
section *sect;
dw_fde_ref fde = cfun->fde;
gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL);
+ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_SECOND_SECT_LABEL,
+ current_function_funcdef_no);
+
+ fde->dw_fde_second_begin = ggc_strdup (label);
if (!in_cold_section_p)
{
fde->dw_fde_end = crtl->subsections.cold_section_end_label;
- fde->dw_fde_second_begin = crtl->subsections.hot_section_label;
fde->dw_fde_second_end = crtl->subsections.hot_section_end_label;
}
else
{
fde->dw_fde_end = crtl->subsections.hot_section_end_label;
- fde->dw_fde_second_begin = crtl->subsections.cold_section_label;
fde->dw_fde_second_end = crtl->subsections.cold_section_end_label;
}
have_multiple_function_sections = true;
return a->v.val_die_ref.die == b->v.val_die_ref.die;
case dw_val_class_fde_ref:
return a->v.val_fde_index == b->v.val_fde_index;
+ case dw_val_class_symview:
+ return strcmp (a->v.val_symbolic_view, b->v.val_symbolic_view) == 0;
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
return DW_OP_GNU_reinterpret;
break;
+ case DW_OP_addrx:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_addr_index;
+ break;
+
+ case DW_OP_constx:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_const_index;
+ break;
+
default:
break;
}
return DW_AT_GNU_dwo_name;
break;
+ case DW_AT_addr_base:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_addr_base;
+ break;
+
default:
break;
}
return tag;
}
+/* And similarly for forms. */
+static inline enum dwarf_form
+dwarf_FORM (enum dwarf_form form)
+{
+ switch (form)
+ {
+ case DW_FORM_addrx:
+ if (dwarf_version < 5)
+ return DW_FORM_GNU_addr_index;
+ break;
+
+ case DW_FORM_strx:
+ if (dwarf_version < 5)
+ return DW_FORM_GNU_str_index;
+ break;
+
+ default:
+ break;
+ }
+ return form;
+}
+
static unsigned long int get_base_type_offset (dw_die_ref);
/* Return the size of a location descriptor. */
size += DWARF2_ADDR_SIZE;
break;
case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
case DW_OP_GNU_const_index:
+ case DW_OP_constx:
gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
size += size_of_uleb128 (loc->dw_loc_oprnd1.val_entry->index);
break;
break;
case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
case DW_OP_GNU_const_index:
+ case DW_OP_constx:
gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED);
dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_entry->index,
"(index into .debug_addr)");
{
case DW_OP_addr:
case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
case DW_OP_GNU_const_index:
+ case DW_OP_constx:
case DW_OP_implicit_value:
/* We cannot output addresses in .cfi_escape, only bytes. */
gcc_unreachable ();
dw_die_ref);
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx_insn *);
+static void dwarf2out_inline_entry (tree);
static void dwarf2out_size_function (tree);
static void dwarf2out_begin_function (tree);
static void dwarf2out_end_function (unsigned int);
debug_nothing_rtx_code_label, /* label */
debug_nothing_int, /* handle_pch */
dwarf2out_var_location,
- debug_nothing_tree, /* inline_entry */
+ dwarf2out_inline_entry, /* inline_entry */
dwarf2out_size_function, /* size_function */
dwarf2out_switch_text_section,
dwarf2out_set_name,
If it is 0, it is known that the NEXT view will be the first view
at the given PC.
- If it is -1, we've advanced PC but we haven't emitted a line location yet,
- so we shouldn't use this view number.
+ If it is -1, we're forcing the view number to be reset, e.g. at a
+ function entry.
The meaning of other nonzero values depends on whether we're
computing views internally or leaving it for the assembler to do
going to ask the assembler to assign. */
var_loc_view view;
+ /* This counts the number of symbolic views emitted in this table
+ since the latest view reset. Its max value, over all tables,
+ sets symview_upper_bound. */
+ var_loc_view symviews_since_reset;
+
+#define FORCE_RESET_NEXT_VIEW(x) ((x) = (var_loc_view)-1)
#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
-#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
+#define FORCE_RESETTING_VIEW_P(x) ((x) == (var_loc_view)-1)
+#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0 || FORCE_RESETTING_VIEW_P (x))
vec<dw_line_info_entry, va_gc> *entries;
};
+/* This is an upper bound for view numbers that the assembler may
+ assign to symbolic views output in this translation. It is used to
+ decide how big a field to use to represent view numbers in
+ symview-classed attributes. */
+
+static var_loc_view symview_upper_bound;
+
+/* If we're keep track of location views and their reset points, and
+ INSN is a reset point (i.e., it necessarily advances the PC), mark
+ the next view in TABLE as reset. */
+
+static void
+maybe_reset_location_view (rtx_insn *insn, dw_line_info_table *table)
+{
+ if (!debug_internal_reset_location_views)
+ return;
+
+ /* Maybe turn (part of?) this test into a default target hook. */
+ int reset = 0;
+
+ if (targetm.reset_location_view)
+ reset = targetm.reset_location_view (insn);
+
+ if (reset)
+ ;
+ else if (JUMP_TABLE_DATA_P (insn))
+ reset = 1;
+ else if (GET_CODE (insn) == USE
+ || GET_CODE (insn) == CLOBBER
+ || GET_CODE (insn) == ASM_INPUT
+ || asm_noperands (insn) >= 0)
+ ;
+ else if (get_attr_min_length (insn) > 0)
+ reset = 1;
+
+ if (reset > 0 && !RESETTING_VIEW_P (table->view))
+ RESET_NEXT_VIEW (table->view);
+}
/* Each DIE attribute has a field specifying the attribute kind,
a link to the next attribute in the chain, and an attribute value.
#endif
#endif
+/* Return true if GCC configure detected assembler support for .loc. */
+
+bool
+dwarf2out_default_as_loc_support (void)
+{
+ return DWARF2_ASM_LINE_DEBUG_INFO;
+#if (GCC_VERSION >= 3000)
+# undef DWARF2_ASM_LINE_DEBUG_INFO
+# pragma GCC poison DWARF2_ASM_LINE_DEBUG_INFO
+#endif
+}
+
+/* Return true if GCC configure detected assembler support for views
+ in .loc directives. */
+
+bool
+dwarf2out_default_as_locview_support (void)
+{
+ return DWARF2_ASM_VIEW_DEBUG_INFO;
+#if (GCC_VERSION >= 3000)
+# undef DWARF2_ASM_VIEW_DEBUG_INFO
+# pragma GCC poison DWARF2_ASM_VIEW_DEBUG_INFO
+#endif
+}
+
/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
view computation, and it refers to a view identifier for which we
will not emit a label because it is known to map to a view number
that must be view number zero. Otherwise, ZERO_VIEW_P is allocated
and views label numbers recorded in it are the ones known to be
zero. */
-#define ZERO_VIEW_P(N) (zero_view_p \
- ? bitmap_bit_p (zero_view_p, (N)) \
- : (N) == 0)
+#define ZERO_VIEW_P(N) ((N) == (var_loc_view)0 \
+ || (N) == (var_loc_view)-1 \
+ || (zero_view_p \
+ && bitmap_bit_p (zero_view_p, (N))))
/* Return true iff we're to emit .loc directives for the assembler to
generate line number sections.
static bool
output_asm_line_debug_info (void)
{
- return (DWARF2_ASM_VIEW_DEBUG_INFO
- || (DWARF2_ASM_LINE_DEBUG_INFO
- && !debug_variable_location_views));
+ return (dwarf2out_as_loc_support
+ && (dwarf2out_as_locview_support
+ || !debug_variable_location_views));
}
/* Minimum line offset in a special line info. opcode.
static inline dw_die_ref AT_ref (dw_attr_node *);
static inline int AT_ref_external (dw_attr_node *);
static inline void set_AT_ref_external (dw_attr_node *, int);
-static void add_AT_fde_ref (dw_die_ref, enum dwarf_attribute, unsigned);
static void add_AT_loc (dw_die_ref, enum dwarf_attribute, dw_loc_descr_ref);
static inline dw_loc_descr_ref AT_loc (dw_attr_node *);
static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
static void remove_addr_table_entry (addr_table_entry *);
static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
static inline rtx AT_addr (dw_attr_node *);
+static void add_AT_symview (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
-static void add_AT_loclistsptr (dw_die_ref, enum dwarf_attribute,
- const char *);
-static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
- unsigned HOST_WIDE_INT);
static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
unsigned long, bool);
static inline const char *AT_lbl (dw_attr_node *);
static dw_attr_node *get_AT (dw_die_ref, enum dwarf_attribute);
static const char *get_AT_low_pc (dw_die_ref);
-static const char *get_AT_hi_pc (dw_die_ref);
static const char *get_AT_string (dw_die_ref, enum dwarf_attribute);
static int get_AT_flag (dw_die_ref, enum dwarf_attribute);
static unsigned get_AT_unsigned (dw_die_ref, enum dwarf_attribute);
static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
+static bool is_c (void);
static bool is_cxx (void);
static bool is_cxx (const_tree);
static bool is_fortran (void);
static int same_attr_p (dw_attr_node *, dw_attr_node *, int *);
static int same_die_p (dw_die_ref, dw_die_ref, int *);
static int is_type_die (dw_die_ref);
-static int is_comdat_die (dw_die_ref);
static inline bool is_template_instantiation (dw_die_ref);
static int is_declaration_die (dw_die_ref);
static int should_move_die_to_comdat (dw_die_ref);
static dw_die_ref modified_type_die (tree, int, bool, dw_die_ref);
static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
-static int type_is_enum (const_tree);
static unsigned int dbx_reg_number (const_rtx);
static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
static dw_loc_descr_ref reg_loc_descriptor (rtx, enum var_init_status);
struct loc_descr_context *);
static dw_loc_descr_ref loc_descriptor_from_tree (tree, int,
struct loc_descr_context *);
-static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
static tree field_type (const_tree);
static unsigned int simple_type_align_in_bits (const_tree);
static unsigned int simple_decl_align_in_bits (const_tree);
static bool tree_add_const_value_attribute (dw_die_ref, tree);
static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
static void add_name_attribute (dw_die_ref, const char *);
+static void add_desc_attribute (dw_die_ref, tree);
static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref);
static void add_comp_dir_attribute (dw_die_ref);
static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int,
struct vlr_context *);
static void add_bit_size_attribute (dw_die_ref, tree);
static void add_prototyped_attribute (dw_die_ref, tree);
-static dw_die_ref add_abstract_origin_attribute (dw_die_ref, tree);
+static void add_abstract_origin_attribute (dw_die_ref, tree);
static void add_pure_or_virtual_attribute (dw_die_ref, tree);
static void add_src_coords_attributes (dw_die_ref, tree);
static void add_name_and_src_coords_attributes (dw_die_ref, tree, bool = false);
static void add_discr_value (dw_die_ref, dw_discr_value *);
static void add_discr_list (dw_die_ref, dw_discr_list_ref);
static inline dw_discr_list_ref AT_discr_list (dw_attr_node *);
-static void push_decl_scope (tree);
-static void pop_decl_scope (void);
static dw_die_ref scope_die_for (tree, dw_die_ref);
static inline int local_scope_p (dw_die_ref);
static inline int class_scope_p (dw_die_ref);
static void gen_typedef_die (tree, dw_die_ref);
static void gen_type_die (tree, dw_die_ref);
static void gen_block_die (tree, dw_die_ref);
-static void decls_for_scope (tree, dw_die_ref);
+static void decls_for_scope (tree, dw_die_ref, bool = true);
static bool is_naming_typedef_decl (const_tree);
static inline dw_die_ref get_context_die (tree);
static void gen_namespace_die (tree, dw_die_ref);
static int maybe_emit_file (struct dwarf_file_data *fd);
static inline const char *AT_vms_delta1 (dw_attr_node *);
static inline const char *AT_vms_delta2 (dw_attr_node *);
-static inline void add_AT_vms_delta (dw_die_ref, enum dwarf_attribute,
- const char *, const char *);
static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree);
static void gen_remaining_tmpl_value_param_die_attribute (void);
static bool generic_type_p (tree);
dw_addr_op (enum dtprel_bool dtprel)
{
if (dtprel == dtprel_true)
- return (dwarf_split_debug_info ? DW_OP_GNU_const_index
+ return (dwarf_split_debug_info ? dwarf_OP (DW_OP_constx)
: (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
else
- return dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr;
+ return dwarf_split_debug_info ? dwarf_OP (DW_OP_addrx) : DW_OP_addr;
}
/* Return a pointer to a newly allocated address location description. If
#ifndef BLOCK_BEGIN_LABEL
#define BLOCK_BEGIN_LABEL "LBB"
#endif
+#ifndef BLOCK_INLINE_ENTRY_LABEL
+#define BLOCK_INLINE_ENTRY_LABEL "LBI"
+#endif
#ifndef BLOCK_END_LABEL
#define BLOCK_END_LABEL "LBE"
#endif
}
/* Return the index for any attribute that will be referenced with a
- DW_FORM_GNU_addr_index or DW_FORM_GNU_str_index. String indices
- are stored in dw_attr_val.v.val_str for reference counting
+ DW_FORM_addrx/GNU_addr_index or DW_FORM_strx/GNU_str_index. String
+ indices are stored in dw_attr_val.v.val_str for reference counting
pruning. */
static inline unsigned int
/* Already indirect is a no op. */
if (node->form == DW_FORM_strp
|| node->form == DW_FORM_line_strp
- || node->form == DW_FORM_GNU_str_index)
+ || node->form == dwarf_FORM (DW_FORM_strx))
{
gcc_assert (node->label);
return;
}
else
{
- node->form = DW_FORM_GNU_str_index;
+ node->form = dwarf_FORM (DW_FORM_strx);
node->index = NO_INDEX_ASSIGNED;
}
}
reset_indirect_string (indirect_string_node **h, void *)
{
struct indirect_string_node *node = *h;
- if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+ if (node->form == DW_FORM_strp || node->form == dwarf_FORM (DW_FORM_strx))
{
free (node->label);
node->label = NULL;
a->dw_attr_val.v.val_die_ref.external = i;
}
-/* Add an FDE reference attribute value to a DIE. */
-
-static inline void
-add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
-{
- dw_attr_node attr;
-
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_fde_ref;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_fde_index = targ_fde;
- add_dwarf_attr (die, &attr);
-}
-
/* Add a location description attribute value to a DIE. */
static inline void
return a->dw_attr_val.v.val_file;
}
-/* Add a vms delta attribute value to a DIE. */
+/* Add a symbolic view identifier attribute value to a DIE. */
static inline void
-add_AT_vms_delta (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *lbl1, const char *lbl2)
+add_AT_symview (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *view_label)
{
dw_attr_node attr;
attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_vms_delta;
+ attr.dw_attr_val.val_class = dw_val_class_symview;
attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
- attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
+ attr.dw_attr_val.v.val_symbolic_view = xstrdup (view_label);
add_dwarf_attr (die, &attr);
}
add_dwarf_attr (die, &attr);
}
-/* Add a section offset attribute value to a DIE, an offset into the
- debug_loclists section. */
-
-static inline void
-add_AT_loclistsptr (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *label)
-{
- dw_attr_node attr;
-
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_loclistsptr;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
- add_dwarf_attr (die, &attr);
-}
-
/* Add a section offset attribute value to a DIE, an offset into the
debug_macinfo section. */
add_dwarf_attr (die, &attr);
}
-/* Add an offset attribute value to a DIE. */
-
-static inline void
-add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
- unsigned HOST_WIDE_INT offset)
-{
- dw_attr_node attr;
-
- attr.dw_attr = attr_kind;
- attr.dw_attr_val.val_class = dw_val_class_offset;
- attr.dw_attr_val.val_entry = NULL;
- attr.dw_attr_val.v.val_offset = offset;
- add_dwarf_attr (die, &attr);
-}
-
/* Add a range_list attribute value to a DIE. When using
dwarf_split_debug_info, address attributes in dies destined for the
final executable should be direct references--setting the parameter
return a ? AT_lbl (a) : NULL;
}
-/* Return the "high pc" attribute value, typically associated with a subprogram
- DIE. Return null if the "high pc" attribute is either not present, or if it
- cannot be represented as an assembler label identifier. */
-
-static inline const char *
-get_AT_hi_pc (dw_die_ref die)
-{
- dw_attr_node *a = get_AT (die, DW_AT_high_pc);
-
- return a ? AT_lbl (a) : NULL;
-}
-
/* Return the value of the string attribute designated by ATTR_KIND, or
NULL if it is not present. */
return a ? AT_file (a) : NULL;
}
+/* Return TRUE if the language is C. */
+
+static inline bool
+is_c (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
+
+ return (lang == DW_LANG_C || lang == DW_LANG_C89 || lang == DW_LANG_C99
+ || lang == DW_LANG_C11 || lang == DW_LANG_ObjC);
+
+
+}
+
/* Return TRUE if the language is C++. */
static inline bool
return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
}
+/* Return TRUE if the language is D. */
+
+static inline bool
+is_dlang (void)
+{
+ unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
+
+ return lang == DW_LANG_D;
+}
+
/* Remove the specified attribute if present. Return TRUE if removal
was successful. */
TYPE_SYMTAB_DIE (type) = type_die;
}
+static dw_die_ref maybe_create_die_with_external_ref (tree);
+struct GTY(()) sym_off_pair
+{
+ const char * GTY((skip)) sym;
+ unsigned HOST_WIDE_INT off;
+};
+static GTY(()) hash_map<tree, sym_off_pair> *external_die_map;
+
/* Returns a hash value for X (which really is a die_struct). */
inline hashval_t
dw_die_ref *die = decl_die_table->find_slot_with_hash (decl, DECL_UID (decl),
NO_INSERT);
if (!die)
- return NULL;
+ {
+ if (in_lto_p)
+ return maybe_create_die_with_external_ref (decl);
+ return NULL;
+ }
if ((*die)->removed)
{
decl_die_table->clear_slot (die);
}
+/* Return the DIE associated with BLOCK. */
+
+static inline dw_die_ref
+lookup_block_die (tree block)
+{
+ dw_die_ref die = BLOCK_DIE (block);
+ if (!die && in_lto_p)
+ return maybe_create_die_with_external_ref (block);
+ return die;
+}
+
+/* Associate DIE with BLOCK. */
+
+static inline void
+equate_block_to_die (tree block, dw_die_ref die)
+{
+ BLOCK_DIE (block) = die;
+}
+#undef BLOCK_DIE
+
+
/* For DECL which might have early dwarf output query a SYMBOL + OFFSET
style reference. Return true if we found one refering to a DIE for
DECL, otherwise return false. */
{
dw_die_ref die;
- if (flag_wpa && !decl_die_table)
- return false;
+ if (in_lto_p)
+ {
+ /* During WPA stage and incremental linking we use a hash-map
+ to store the decl <-> label + offset map. */
+ if (!external_die_map)
+ return false;
+ sym_off_pair *desc = external_die_map->get (decl);
+ if (!desc)
+ return false;
+ *sym = desc->sym;
+ *off = desc->off;
+ return true;
+ }
if (TREE_CODE (decl) == BLOCK)
- die = BLOCK_DIE (decl);
+ die = lookup_block_die (decl);
else
die = lookup_decl_die (decl);
if (!die)
return false;
- /* During WPA stage we currently use DIEs to store the
- decl <-> label + offset map. That's quite inefficient but it
- works for now. */
- if (flag_wpa)
- {
- dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
- if (!ref)
- {
- gcc_assert (die == comp_unit_die ());
- return false;
- }
- *off = ref->die_offset;
- *sym = ref->die_id.die_symbol;
- return true;
- }
-
/* Similar to get_ref_die_offset_label, but using the "correct"
label. */
*off = die->die_offset;
{
/* Create a fake DIE that contains the reference. Don't use
new_die because we don't want to end up in the limbo list. */
+ /* ??? We probably want to share these, thus put a ref to the DIE
+ we create here to the external_die_map entry. */
dw_die_ref ref = new_die_raw (die->die_tag);
- ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
+ ref->die_id.die_symbol = symbol;
ref->die_offset = offset;
ref->with_offset = 1;
add_AT_die_ref (die, attr_kind, ref);
if (debug_info_level == DINFO_LEVEL_NONE)
return;
- if (flag_wpa && !decl_die_table)
- decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
+ if (!external_die_map)
+ external_die_map = hash_map<tree, sym_off_pair>::create_ggc (1000);
+ gcc_checking_assert (!external_die_map->get (decl));
+ sym_off_pair p = { IDENTIFIER_POINTER (get_identifier (sym)), off };
+ external_die_map->put (decl, p);
+}
+
+/* If we have a registered external DIE for DECL return a new DIE for
+ the concrete instance with an appropriate abstract origin. */
+
+static dw_die_ref
+maybe_create_die_with_external_ref (tree decl)
+{
+ if (!external_die_map)
+ return NULL;
+ sym_off_pair *desc = external_die_map->get (decl);
+ if (!desc)
+ return NULL;
+
+ const char *sym = desc->sym;
+ unsigned HOST_WIDE_INT off = desc->off;
- dw_die_ref die
- = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+ in_lto_p = false;
+ dw_die_ref die = (TREE_CODE (decl) == BLOCK
+ ? lookup_block_die (decl) : lookup_decl_die (decl));
gcc_assert (!die);
+ in_lto_p = true;
tree ctx;
dw_die_ref parent = NULL;
/* ??? We do not output DIEs for all scopes thus skip as
many DIEs as needed. */
while (TREE_CODE (ctx) == BLOCK
- && !BLOCK_DIE (ctx))
+ && !lookup_block_die (ctx))
ctx = BLOCK_SUPERCONTEXT (ctx);
}
else
ctx = DECL_CONTEXT (decl);
+ /* Peel types in the context stack. */
while (ctx && TYPE_P (ctx))
ctx = TYPE_CONTEXT (ctx);
+ /* Likewise namespaces in case we do not want to emit DIEs for them. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ while (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)
+ ctx = DECL_CONTEXT (ctx);
if (ctx)
{
if (TREE_CODE (ctx) == BLOCK)
- parent = BLOCK_DIE (ctx);
+ parent = lookup_block_die (ctx);
else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
/* Keep the 1:1 association during WPA. */
- && !flag_wpa)
+ && !flag_wpa
+ && flag_incremental_link != INCREMENTAL_LINK_LTO)
/* Otherwise all late annotations go to the main CU which
imports the original CUs. */
parent = comp_unit_die ();
else if (TREE_CODE (ctx) == FUNCTION_DECL
+ && TREE_CODE (decl) != FUNCTION_DECL
&& TREE_CODE (decl) != PARM_DECL
+ && TREE_CODE (decl) != RESULT_DECL
&& TREE_CODE (decl) != BLOCK)
/* Leave function local entities parent determination to when
we process scope vars. */
switch (TREE_CODE (decl))
{
case TRANSLATION_UNIT_DECL:
- if (! flag_wpa)
- {
- die = comp_unit_die ();
- dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
- add_AT_external_die_ref (import, DW_AT_import, sym, off);
- /* We re-target all CU decls to the LTRANS CU DIE, so no need
- to create a DIE for the original CUs. */
- return;
- }
- /* Keep the 1:1 association during WPA. */
- die = new_die (DW_TAG_compile_unit, NULL, decl);
- break;
+ {
+ die = comp_unit_die ();
+ /* We re-target all CU decls to the LTRANS CU DIE, so no need
+ to create a DIE for the original CUs. */
+ return die;
+ }
case NAMESPACE_DECL:
if (is_fortran (decl))
die = new_die (DW_TAG_module, parent, decl);
gcc_unreachable ();
}
if (TREE_CODE (decl) == BLOCK)
- BLOCK_DIE (decl) = die;
+ equate_block_to_die (decl, die);
else
equate_decl_number_to_die (decl, die);
+ add_desc_attribute (die, decl);
+
/* Add a reference to the DIE providing early debug at $sym + off. */
add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
+
+ return die;
}
/* Returns a hash value for X (which really is a var_loc_list). */
print_indent -= 4;
}
else
- fprintf (outfile, " (%p)\n", (void *) val->v.val_loc);
+ {
+ if (flag_dump_noaddr || flag_dump_unnumbered)
+ fprintf (outfile, " #\n");
+ else
+ fprintf (outfile, " (%p)\n", (void *) val->v.val_loc);
+ }
break;
case dw_val_class_loc_list:
fprintf (outfile, "location list -> label:%s",
}
else
fprintf (outfile, "die -> %ld", die->die_offset);
- fprintf (outfile, " (%p)", (void *) die);
+ if (flag_dump_noaddr || flag_dump_unnumbered)
+ fprintf (outfile, " #");
+ else
+ fprintf (outfile, " (%p)", (void *) die);
}
else
fprintf (outfile, "die -> <null>");
fprintf (outfile, "delta: @slotcount(%s-%s)",
val->v.val_vms_delta.lbl2, val->v.val_vms_delta.lbl1);
break;
+ case dw_val_class_symview:
+ fprintf (outfile, "view: %s", val->v.val_symbolic_view);
+ break;
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
for (l = loc; l != NULL; l = l->dw_loc_next)
{
print_spaces (outfile);
- fprintf (outfile, "(%p) %s",
- (void *) l,
+ if (flag_dump_noaddr || flag_dump_unnumbered)
+ fprintf (outfile, "#");
+ else
+ fprintf (outfile, "(%p)", (void *) l);
+ fprintf (outfile, " %s",
dwarf_stack_op_name (l->dw_loc_opc));
if (l->dw_loc_oprnd1.val_class != dw_val_class_none)
{
unsigned ix;
print_spaces (outfile);
- fprintf (outfile, "DIE %4ld: %s (%p)\n",
- die->die_offset, dwarf_tag_name (die->die_tag),
- (void*) die);
+ fprintf (outfile, "DIE %4ld: %s ",
+ die->die_offset, dwarf_tag_name (die->die_tag));
+ if (flag_dump_noaddr || flag_dump_unnumbered)
+ fprintf (outfile, "#\n");
+ else
+ fprintf (outfile, "(%p)\n", (void*) die);
print_spaces (outfile);
fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
fprintf (outfile, " offset: %ld", die->die_offset);
case dw_val_class_fde_ref:
case dw_val_class_vms_delta:
+ case dw_val_class_symview:
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
break;
case dw_val_class_fde_ref:
+ case dw_val_class_symview:
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
case dw_val_class_die_ref:
return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+ case dw_val_class_symview:
+ return strcmp (v1->v.val_symbolic_view, v2->v.val_symbolic_view) == 0;
+
case dw_val_class_fde_ref:
case dw_val_class_vms_delta:
case dw_val_class_lbl_id:
}
}
-/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU.
- Basically, we want to choose the bits that are likely to be shared between
- compilations (types) and leave out the bits that are specific to individual
- compilations (functions). */
-
-static int
-is_comdat_die (dw_die_ref c)
-{
- /* I think we want to leave base types and __vtbl_ptr_type in the main CU, as
- we do for stabs. The advantage is a greater likelihood of sharing between
- objects that don't include headers in the same order (and therefore would
- put the base types in a different comdat). jason 8/28/00 */
-
- if (c->die_tag == DW_TAG_base_type)
- return 0;
-
- if (c->die_tag == DW_TAG_pointer_type
- || c->die_tag == DW_TAG_reference_type
- || c->die_tag == DW_TAG_rvalue_reference_type
- || c->die_tag == DW_TAG_const_type
- || c->die_tag == DW_TAG_volatile_type)
- {
- dw_die_ref t = get_AT_ref (c, DW_AT_type);
-
- return t ? is_comdat_die (t) : 0;
- }
-
- return is_type_die (c);
-}
-
/* Returns true iff C is a compile-unit DIE. */
static inline bool
return c && c->die_tag == DW_TAG_namespace;
}
-/* Returns true iff C is a class or structure DIE. */
-
-static inline bool
-is_class_die (dw_die_ref c)
-{
- return c && (c->die_tag == DW_TAG_class_type
- || c->die_tag == DW_TAG_structure_type);
-}
-
/* Return non-zero if this DIE is a template parameter. */
static inline bool
struct external_ref *ref_p;
gcc_assert (AT_ref (a)->comdat_type_p || AT_ref (a)->die_id.die_symbol);
- ref_p = lookup_external_ref (extern_map, c);
- if (ref_p->stub && ref_p->stub != die)
+ if (is_type_die (c)
+ && (ref_p = lookup_external_ref (extern_map, c))
+ && ref_p->stub && ref_p->stub != die)
change_AT_die_ref (a, ref_p->stub);
else
/* We aren't changing this reference, so mark it external. */
size += csize;
}
break;
+ case dw_val_class_symview:
+ if (symview_upper_bound <= 0xff)
+ size += 1;
+ else if (symview_upper_bound <= 0xffff)
+ size += 2;
+ else if (symview_upper_bound <= 0xffffffff)
+ size += 4;
+ else
+ size += 8;
+ break;
case dw_val_class_const_implicit:
case dw_val_class_unsigned_const_implicit:
case dw_val_class_file_implicit:
form = AT_string_form (a);
if (form == DW_FORM_strp || form == DW_FORM_line_strp)
size += DWARF_OFFSET_SIZE;
- else if (form == DW_FORM_GNU_str_index)
+ else if (form == dwarf_FORM (DW_FORM_strx))
size += size_of_uleb128 (AT_index (a));
else
size += strlen (a->dw_attr_val.v.val_str->str) + 1;
case DW_AT_entry_pc:
case DW_AT_trampoline:
return (AT_index (a) == NOT_INDEXED
- ? DW_FORM_addr : DW_FORM_GNU_addr_index);
+ ? DW_FORM_addr : dwarf_FORM (DW_FORM_addrx));
default:
break;
}
default:
return DW_FORM_block1;
}
+ case dw_val_class_symview:
+ /* ??? We might use uleb128, but then we'd have to compute
+ .debug_info offsets in the assembler. */
+ if (symview_upper_bound <= 0xff)
+ return DW_FORM_data1;
+ else if (symview_upper_bound <= 0xffff)
+ return DW_FORM_data2;
+ else if (symview_upper_bound <= 0xffffffff)
+ return DW_FORM_data4;
+ else
+ return DW_FORM_data8;
case dw_val_class_vec:
switch (constant_size (a->dw_attr_val.v.val_vec.length
* a->dw_attr_val.v.val_vec.elt_size))
return DW_FORM_data;
case dw_val_class_lbl_id:
return (AT_index (a) == NOT_INDEXED
- ? DW_FORM_addr : DW_FORM_GNU_addr_index);
+ ? DW_FORM_addr : dwarf_FORM (DW_FORM_addrx));
case dw_val_class_lineptr:
case dw_val_class_macptr:
case dw_val_class_loclistsptr:
return retlist;
}
-/* Return true iff there's any nonzero view number in the loc list. */
+/* Return true iff there's any nonzero view number in the loc list.
+
+ ??? When views are not enabled, we'll often extend a single range
+ to the entire function, so that we emit a single location
+ expression rather than a location list. With views, even with a
+ single range, we'll output a list if start or end have a nonzero
+ view. If we change this, we may want to stop splitting a single
+ range in dw_loc_list just because of a nonzero view, even if it
+ straddles across hot/cold partitions. */
static bool
loc_list_has_views (dw_loc_list_ref list)
gen_llsym (list);
}
-/* Determine whether or not to skip loc_list entry CURR. If we're not
+/* Determine whether or not to skip loc_list entry CURR. If SIZEP is
+ NULL, don't consider size of the location expression. If we're not
to skip it, and SIZEP is non-null, store the size of CURR->expr's
representation in *SIZEP. */
static bool
-skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0)
+skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = NULL)
{
/* Don't output an entry that starts and ends at the same address. */
if (strcmp (curr->begin, curr->end) == 0
&& curr->vbegin == curr->vend && !curr->force)
return true;
+ if (!sizep)
+ return false;
+
unsigned long size = size_of_locs (curr->expr);
/* If the expression is too large, drop it on the floor. We could
if (dwarf_version < 5 && size > 0xffff)
return true;
- if (sizep)
- *sizep = size;
+ *sizep = size;
return false;
}
#ifdef DW_LLE_view_pair
dw2_asm_output_data (1, DW_LLE_view_pair, "DW_LLE_view_pair");
-# if DWARF2_ASM_VIEW_DEBUG_INFO
- if (ZERO_VIEW_P (curr->vbegin))
- dw2_asm_output_data_uleb128 (0, "Location view begin");
- else
+ if (dwarf2out_as_locview_support)
{
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
- dw2_asm_output_symname_uleb128 (label, "Location view begin");
- }
+ if (ZERO_VIEW_P (curr->vbegin))
+ dw2_asm_output_data_uleb128 (0, "Location view begin");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label, "Location view begin");
+ }
- if (ZERO_VIEW_P (curr->vend))
- dw2_asm_output_data_uleb128 (0, "Location view end");
+ if (ZERO_VIEW_P (curr->vend))
+ dw2_asm_output_data_uleb128 (0, "Location view end");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label, "Location view end");
+ }
+ }
else
{
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
- ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
- dw2_asm_output_symname_uleb128 (label, "Location view end");
+ dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
+ dw2_asm_output_data_uleb128 (curr->vend, "Location view end");
}
-# else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
- dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
- dw2_asm_output_data_uleb128 (curr->vend, "Location view end");
-# endif /* DWARF2_ASM_VIEW_DEBUG_INFO */
#endif /* DW_LLE_view_pair */
return;
for (dw_loc_list_ref curr = list_head; curr != NULL;
curr = curr->dw_loc_next)
{
- if (skip_loc_list_entry (curr))
+ unsigned long size;
+
+ if (skip_loc_list_entry (curr, &size))
continue;
vcount++;
/* ?? dwarf_split_debug_info? */
-#if DWARF2_ASM_VIEW_DEBUG_INFO
- char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
- if (!ZERO_VIEW_P (curr->vbegin))
+ if (dwarf2out_as_locview_support)
{
- ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
- dw2_asm_output_symname_uleb128 (label,
- "View list begin (%s)",
- list_head->vl_symbol);
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (!ZERO_VIEW_P (curr->vbegin))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+
+ if (!ZERO_VIEW_P (curr->vend))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list end (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list end (%s)",
+ list_head->vl_symbol);
}
else
- dw2_asm_output_data_uleb128 (0,
- "View list begin (%s)",
- list_head->vl_symbol);
-
- if (!ZERO_VIEW_P (curr->vend))
{
- ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
- dw2_asm_output_symname_uleb128 (label,
- "View list end (%s)",
- list_head->vl_symbol);
+ dw2_asm_output_data_uleb128 (curr->vbegin,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ dw2_asm_output_data_uleb128 (curr->vend,
+ "View list end (%s)",
+ list_head->vl_symbol);
}
- else
- dw2_asm_output_data_uleb128 (0,
- "View list end (%s)",
- list_head->vl_symbol);
-#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
- dw2_asm_output_data_uleb128 (curr->vbegin,
- "View list begin (%s)",
- list_head->vl_symbol);
- dw2_asm_output_data_uleb128 (curr->vend,
- "View list end (%s)",
- list_head->vl_symbol);
-#endif
}
}
}
break;
+ case dw_val_class_symview:
+ {
+ int vsize;
+ if (symview_upper_bound <= 0xff)
+ vsize = 1;
+ else if (symview_upper_bound <= 0xffff)
+ vsize = 2;
+ else if (symview_upper_bound <= 0xffffffff)
+ vsize = 4;
+ else
+ vsize = 8;
+ dw2_asm_output_addr (vsize, a->dw_attr_val.v.val_symbolic_view,
+ "%s", name);
+ }
+ break;
+
case dw_val_class_const_implicit:
if (flag_debug_asm)
fprintf (asm_out_file, "\t\t\t%s %s ("
a->dw_attr_val.v.val_str->label,
debug_line_str_section,
"%s: \"%s\"", name, AT_string (a));
- else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
+ else if (a->dw_attr_val.v.val_str->form == dwarf_FORM (DW_FORM_strx))
dw2_asm_output_data_uleb128 (AT_index (a),
"%s: \"%s\"", name, AT_string (a));
else
node = find_AT_string_in_table (str, skeleton_debug_str_hash);
find_string_form (node);
- if (node->form == DW_FORM_GNU_str_index)
+ if (node->form == dwarf_FORM (DW_FORM_strx))
node->form = DW_FORM_strp;
attr.dw_attr = attr_kind;
if (comp_dir != NULL)
add_skeleton_AT_string (die, DW_AT_comp_dir, comp_dir);
add_AT_pubnames (die);
- add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
+ add_AT_lineptr (die, dwarf_AT (DW_AT_addr_base), debug_addr_section_label);
}
/* Output skeleton debug sections that point to the dwo file. */
we return consistent values to qsort since some will get confused if
we return the same value when identical operands are passed in opposite
orders. So if neither has a directory, return 0 and otherwise return
- 1 or -1 depending on which one has the directory. */
+ 1 or -1 depending on which one has the directory. We want the one with
+ the directory to sort after the one without, so all no directory files
+ are at the start (normally only the compilation unit file). */
if ((s1->path == s1->fname || s2->path == s2->fname))
return (s2->path == s2->fname) - (s1->path == s1->fname);
{
++cp1;
++cp2;
- /* Reached the end of the first path? If so, handle like above. */
+ /* Reached the end of the first path? If so, handle like above,
+ but now we want longer directory prefixes before shorter ones. */
if ((cp1 == (const unsigned char *) s1->fname)
|| (cp2 == (const unsigned char *) s2->fname))
- return ((cp2 == (const unsigned char *) s2->fname)
- - (cp1 == (const unsigned char *) s1->fname));
+ return ((cp1 == (const unsigned char *) s1->fname)
+ - (cp2 == (const unsigned char *) s2->fname));
/* Character of current path component the same? */
else if (*cp1 != *cp2)
case FIXED_POINT_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
- case POINTER_BOUNDS_TYPE:
return 1;
case VOID_TYPE:
return die;
}
-/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
- an enumerated type. */
-
-static inline int
-type_is_enum (const_tree type)
-{
- return TREE_CODE (type) == ENUMERAL_TYPE;
-}
-
/* Return the DBX register number described by a given RTL node. */
static unsigned int
if (elim != reg)
{
+ /* Allow hard frame pointer here even if frame pointer
+ isn't used since hard frame pointer is encoded with
+ DW_OP_fbreg which uses the DW_AT_frame_base attribute,
+ not hard frame pointer directly. */
elim = strip_offset_and_add (elim, &offset);
- gcc_assert ((SUPPORTS_STACK_ALIGNMENT
- && (elim == hard_frame_pointer_rtx
- || elim == stack_pointer_rtx))
- || elim == (frame_pointer_needed
- ? hard_frame_pointer_rtx
- : stack_pointer_rtx));
+ gcc_assert (elim == hard_frame_pointer_rtx
+ || elim == stack_pointer_rtx);
/* If drap register is used to align stack, use frame
pointer + offset to access stack variables. If stack
if (dwarf_strict && dwarf_version < 5)
break;
- if (REGNO (rtl) > FIRST_PSEUDO_REGISTER)
+ if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
break;
type_die = base_type_for_mode (mode, SCALAR_INT_MODE_P (mode));
if (type_die == NULL)
case CONST_FIXED:
case CLRSB:
case CLOBBER:
+ case CLOBBER_HIGH:
/* If delegitimize_address couldn't do anything with the UNSPEC, we
can't express it in the debug info. This can happen e.g. with some
TLS UNSPECs. */
of first partition and second one starting at the
beginning of second partition. */
if (node == loc_list->last_before_switch
- && (node != loc_list->first || loc_list->first->next)
+ && (node != loc_list->first || loc_list->first->next
+ /* If we are to emit a view number, we will emit
+ a loclist rather than a single location
+ expression for the entire function (see
+ loc_list_has_views), so we have to split the
+ range that straddles across partitions. */
+ || !ZERO_VIEW_P (node->view))
&& current_function_decl)
{
endname = cfun->fde->dw_fde_end;
representable, we don't want to pretend a single entry that was
applies to the entire scope in which the variable is
available. */
- maybe_gen_llsym (list);
+ if (list && loc_list->first->next)
+ gen_llsym (list);
+ else
+ maybe_gen_llsym (list);
return list;
}
return ret->expr;
}
-/* Given a value, round it up to the lowest multiple of `boundary'
- which is not less than the value itself. */
-
-static inline HOST_WIDE_INT
-ceiling (HOST_WIDE_INT value, unsigned int boundary)
-{
- return (((value + boundary - 1) / boundary) * boundary);
-}
-
/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
pointer to the declared type for the relevant field variable, or return
`integer_type_node' if the given node turns out to be an
if (is_int_mode (TYPE_MODE (enttype), &mode)
&& GET_MODE_SIZE (mode) == 1
&& domain
+ && TYPE_MAX_VALUE (domain)
+ && TREE_CODE (TYPE_MAX_VALUE (domain)) == INTEGER_CST
&& integer_zerop (TYPE_MIN_VALUE (domain))
&& compare_tree_int (TYPE_MAX_VALUE (domain),
TREE_STRING_LENGTH (init) - 1) == 0
in the current CU, resolve_addr will remove the expression referencing
it. */
if (rtl == NULL_RTX
+ && !(early_dwarf && (flag_generate_lto || flag_generate_offload))
&& VAR_P (decl)
&& !DECL_EXTERNAL (decl)
&& TREE_STATIC (decl)
in which to eliminate. This is because it's stack pointer isn't
directly accessible as a register within the ISA. To work around
this, assume that while we cannot provide a proper value for
- frame_pointer_fb_offset, we won't need one either. */
+ frame_pointer_fb_offset, we won't need one either. We can use
+ hard frame pointer in debug info even if frame pointer isn't used
+ since hard frame pointer in debug info is encoded with DW_OP_fbreg
+ which uses the DW_AT_frame_base attribute, not hard frame pointer
+ directly. */
frame_pointer_fb_offset_valid
- = ((SUPPORTS_STACK_ALIGNMENT
- && (elim == hard_frame_pointer_rtx
- || elim == stack_pointer_rtx))
- || elim == (frame_pointer_needed
- ? hard_frame_pointer_rtx
- : stack_pointer_rtx));
+ = (elim == hard_frame_pointer_rtx || elim == stack_pointer_rtx);
}
/* Generate a DW_AT_name attribute given some string value to be included as
}
}
-/* Retrieve the descriptive type of TYPE, if any, make sure it has a
- DIE and attach a DW_AT_GNAT_descriptive_type attribute to the DIE
- of TYPE accordingly.
-
- ??? This is a temporary measure until after we're able to generate
- regular DWARF for the complex Ada type system. */
+/* Generate a DW_AT_description attribute given some string value to be included
+ as the value of the attribute. */
-static void
-add_gnat_descriptive_type_attribute (dw_die_ref die, tree type,
- dw_die_ref context_die)
+static void
+add_desc_attribute (dw_die_ref die, const char *name_string)
{
- tree dtype;
- dw_die_ref dtype_die;
+ if (!flag_describe_dies || (dwarf_version < 3 && dwarf_strict))
+ return;
- if (!lang_hooks.types.descriptive_type)
+ if (name_string == NULL || *name_string == 0)
return;
- dtype = lang_hooks.types.descriptive_type (type);
+ if (demangle_name_func)
+ name_string = (*demangle_name_func) (name_string);
+
+ add_AT_string (die, DW_AT_description, name_string);
+}
+
+/* Generate a DW_AT_description attribute given some decl to be included
+ as the value of the attribute. */
+
+static void
+add_desc_attribute (dw_die_ref die, tree decl)
+{
+ tree decl_name;
+
+ if (!flag_describe_dies || (dwarf_version < 3 && dwarf_strict))
+ return;
+
+ if (decl == NULL_TREE || !DECL_P (decl))
+ return;
+ decl_name = DECL_NAME (decl);
+
+ if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
+ {
+ const char *name = dwarf2_name (decl, 0);
+ add_desc_attribute (die, name ? name : IDENTIFIER_POINTER (decl_name));
+ }
+ else
+ {
+ char *desc = print_generic_expr_to_str (decl);
+ add_desc_attribute (die, desc);
+ free (desc);
+ }
+}
+
+/* Retrieve the descriptive type of TYPE, if any, make sure it has a
+ DIE and attach a DW_AT_GNAT_descriptive_type attribute to the DIE
+ of TYPE accordingly.
+
+ ??? This is a temporary measure until after we're able to generate
+ regular DWARF for the complex Ada type system. */
+
+static void
+add_gnat_descriptive_type_attribute (dw_die_ref die, tree type,
+ dw_die_ref context_die)
+{
+ tree dtype;
+ dw_die_ref dtype_die;
+
+ if (!lang_hooks.types.descriptive_type)
+ return;
+
+ dtype = lang_hooks.types.descriptive_type (type);
if (!dtype)
return;
add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
int forms, struct loc_descr_context *context)
{
- dw_die_ref context_die, decl_die;
+ dw_die_ref context_die, decl_die = NULL;
dw_loc_list_ref list;
bool strip_conversions = true;
bool placeholder_seen = false;
if (decl != NULL_TREE)
{
- dw_die_ref decl_die = lookup_decl_die (decl);
+ decl_die = lookup_decl_die (decl);
/* ??? Can this happen, or should the variable have been bound
first? Probably it can, since I imagine that we try to create
later parameter. */
if (decl_die != NULL)
{
- add_AT_die_ref (die, attr, decl_die);
- return;
+ if (get_AT (decl_die, DW_AT_location)
+ || get_AT (decl_die, DW_AT_const_value))
+ {
+ add_AT_die_ref (die, attr, decl_die);
+ return;
+ }
}
}
}
|| placeholder_seen)
return;
- if (current_function_decl == 0)
- context_die = comp_unit_die ();
- else
- context_die = lookup_decl_die (current_function_decl);
+ if (!decl_die)
+ {
+ if (current_function_decl == 0)
+ context_die = comp_unit_die ();
+ else
+ context_die = lookup_decl_die (current_function_decl);
+
+ decl_die = new_die (DW_TAG_variable, context_die, value);
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+ add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, false,
+ context_die);
+ }
- decl_die = new_die (DW_TAG_variable, context_die, value);
- add_AT_flag (decl_die, DW_AT_artificial, 1);
- add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, false,
- context_die);
add_AT_location_description (decl_die, DW_AT_location, list);
add_AT_die_ref (die, attr, decl_die);
}
if (!get_AT (subrange_die, DW_AT_lower_bound))
add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
- if (upper && !get_AT (subrange_die, DW_AT_upper_bound))
- add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
+ if (!get_AT (subrange_die, DW_AT_upper_bound)
+ && !get_AT (subrange_die, DW_AT_count))
+ {
+ if (upper)
+ add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
+ else if ((is_c () || is_cxx ()) && COMPLETE_TYPE_P (type))
+ /* Zero-length array. */
+ add_bound_info (subrange_die, DW_AT_count,
+ build_int_cst (TREE_TYPE (lower), 0), NULL);
+ }
}
/* Otherwise we have an array type with an unspecified length. The
by looking in the type declaration, the object declaration equate table or
the block mapping. */
-static inline dw_die_ref
+static inline void
add_abstract_origin_attribute (dw_die_ref die, tree origin)
{
dw_die_ref origin_die = NULL;
- if (DECL_P (origin))
+ /* For late LTO debug output we want to refer directly to the abstract
+ DIE in the early debug rather to the possibly existing concrete
+ instance and avoid creating that just for this purpose. */
+ sym_off_pair *desc;
+ if (in_lto_p
+ && external_die_map
+ && (desc = external_die_map->get (origin)))
{
- dw_die_ref c;
- origin_die = lookup_decl_die (origin);
- /* "Unwrap" the decls DIE which we put in the imported unit context.
- We are looking for the abstract copy here. */
- if (in_lto_p
- && origin_die
- && (c = get_AT_ref (origin_die, DW_AT_abstract_origin))
- /* ??? Identify this better. */
- && c->with_offset)
- origin_die = c;
+ add_AT_external_die_ref (die, DW_AT_abstract_origin,
+ desc->sym, desc->off);
+ return;
}
+
+ if (DECL_P (origin))
+ origin_die = lookup_decl_die (origin);
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
else if (TREE_CODE (origin) == BLOCK)
- origin_die = BLOCK_DIE (origin);
+ origin_die = lookup_block_die (origin);
/* XXX: Functions that are never lowered don't always have correct block
trees (in the case of java, they simply have no block tree, in some other
if (origin_die)
add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
- return origin_die;
}
/* We do not currently support the pure_virtual attribute. */
const char *name = dwarf2_name (decl, 0);
if (name)
add_name_attribute (die, name);
+ else
+ add_desc_attribute (die, decl);
+
if (! DECL_ARTIFICIAL (decl))
add_src_coords_attributes (die, decl);
if (!no_linkage_name)
add_linkage_name (die, decl);
}
+ else
+ add_desc_attribute (die, decl);
#ifdef VMS_DEBUGGING_INFO
/* Get the function's name, as described by its RTL. This may be different
}
#endif /* VMS_DEBUGGING_INFO */
-/* Push a new declaration scope. */
-
-static void
-push_decl_scope (tree scope)
-{
- vec_safe_push (decl_scope_table, scope);
-}
-
-/* Pop a declaration scope. */
-
-static inline void
-pop_decl_scope (void)
-{
- decl_scope_table->pop ();
-}
-
/* walk_tree helper function for uses_local_type, below. */
static tree
gen_enumeration_type_die (tree type, dw_die_ref context_die)
{
dw_die_ref type_die = lookup_type_die (type);
+ dw_die_ref orig_type_die = type_die;
if (type_die == NULL)
{
scope_die_for (type, context_die), type);
equate_type_number_to_die (type, type_die);
add_name_attribute (type_die, type_tag (type));
- if (dwarf_version >= 4 || !dwarf_strict)
- {
- if (ENUM_IS_SCOPED (type))
- add_AT_flag (type_die, DW_AT_enum_class, 1);
- if (ENUM_IS_OPAQUE (type))
- add_AT_flag (type_die, DW_AT_declaration, 1);
- }
+ if ((dwarf_version >= 4 || !dwarf_strict)
+ && ENUM_IS_SCOPED (type))
+ add_AT_flag (type_die, DW_AT_enum_class, 1);
+ if (ENUM_IS_OPAQUE (type) && TYPE_SIZE (type))
+ add_AT_flag (type_die, DW_AT_declaration, 1);
if (!dwarf_strict)
add_AT_unsigned (type_die, DW_AT_encoding,
TYPE_UNSIGNED (type)
? DW_ATE_unsigned
: DW_ATE_signed);
}
- else if (! TYPE_SIZE (type))
+ else if (! TYPE_SIZE (type) || ENUM_IS_OPAQUE (type))
return type_die;
else
remove_AT (type_die, DW_AT_declaration);
{
tree link;
- TREE_ASM_WRITTEN (type) = 1;
- add_byte_size_attribute (type_die, type);
- add_alignment_attribute (type_die, type);
- if (dwarf_version >= 3 || !dwarf_strict)
+ if (!ENUM_IS_OPAQUE (type))
+ TREE_ASM_WRITTEN (type) = 1;
+ if (!orig_type_die || !get_AT (type_die, DW_AT_byte_size))
+ add_byte_size_attribute (type_die, type);
+ if (!orig_type_die || !get_AT (type_die, DW_AT_alignment))
+ add_alignment_attribute (type_die, type);
+ if ((dwarf_version >= 3 || !dwarf_strict)
+ && (!orig_type_die || !get_AT (type_die, DW_AT_type)))
{
tree underlying = lang_hooks.types.enum_underlying_base_type (type);
add_type_attribute (type_die, underlying, TYPE_UNQUALIFIED, false,
}
if (TYPE_STUB_DECL (type) != NULL_TREE)
{
- add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
- add_accessibility_attribute (type_die, TYPE_STUB_DECL (type));
+ if (!orig_type_die || !get_AT (type_die, DW_AT_decl_file))
+ add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+ if (!orig_type_die || !get_AT (type_die, DW_AT_accessibility))
+ add_accessibility_attribute (type_die, TYPE_STUB_DECL (type));
}
/* If the first reference to this type was as the return type of an
dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
tree value = TREE_VALUE (link);
+ gcc_assert (!ENUM_IS_OPAQUE (type));
add_name_attribute (enum_die,
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
}
add_gnat_descriptive_type_attribute (type_die, type, context_die);
- if (TYPE_ARTIFICIAL (type))
+ if (TYPE_ARTIFICIAL (type)
+ && (!orig_type_die || !get_AT (type_die, DW_AT_artificial)))
add_AT_flag (type_die, DW_AT_artificial, 1);
}
else
break;
/* Output a (nameless) DIE to represent the formal parameter itself. */
- if (!POINTER_BOUNDS_TYPE_P (formal_type))
+ parm_die = gen_formal_parameter_die (formal_type, NULL,
+ true /* Emit name attribute. */,
+ context_die);
+ if (TREE_CODE (function_or_method_type) == METHOD_TYPE
+ && link == first_parm_type)
{
- parm_die = gen_formal_parameter_die (formal_type, NULL,
- true /* Emit name attribute. */,
- context_die);
- if (TREE_CODE (function_or_method_type) == METHOD_TYPE
- && link == first_parm_type)
- {
- add_AT_flag (parm_die, DW_AT_artificial, 1);
- if (dwarf_version >= 3 || !dwarf_strict)
- add_AT_die_ref (context_die, DW_AT_object_pointer, parm_die);
- }
- else if (arg && DECL_ARTIFICIAL (arg))
- add_AT_flag (parm_die, DW_AT_artificial, 1);
+ add_AT_flag (parm_die, DW_AT_artificial, 1);
+ if (dwarf_version >= 3 || !dwarf_strict)
+ add_AT_die_ref (context_die, DW_AT_object_pointer, parm_die);
}
+ else if (arg && DECL_ARTIFICIAL (arg))
+ add_AT_flag (parm_die, DW_AT_artificial, 1);
link = TREE_CHAIN (link);
if (arg)
dw_die_ref type_die;
gcc_assert (!decl_ultimate_origin (member));
- push_decl_scope (type);
type_die = lookup_type_die_strip_naming_typedef (type);
if (TREE_CODE (member) == FUNCTION_DECL)
gen_subprogram_die (member, type_die);
}
else
gen_variable_die (member, NULL_TREE, type_die);
-
- pop_decl_scope ();
}
}
\f
if (DECL_IGNORED_P (decl))
return;
- old_die = lookup_decl_die (decl);
- /* With early debug we always have an old DIE unless we are in LTO
- and the user did not compile but only link with debug. */
- if (in_lto_p && ! old_die)
+ /* In LTO we're all set. We already created abstract instances
+ early and we want to avoid creating a concrete instance of that
+ if we don't output it. */
+ if (in_lto_p)
return;
+
+ old_die = lookup_decl_die (decl);
gcc_assert (old_die != NULL);
- if (get_AT (old_die, DW_AT_inline)
- || get_AT (old_die, DW_AT_abstract_origin))
+ if (get_AT (old_die, DW_AT_inline))
/* We've already generated the abstract instance. */
return;
&& block != DECL_INITIAL (decl)
&& TREE_CODE (block) == BLOCK)
{
- stmt_die = BLOCK_DIE (block);
+ stmt_die = lookup_block_die (block);
if (stmt_die)
break;
block = BLOCK_SUPERCONTEXT (block);
apply; we just use the old DIE. */
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
struct dwarf_file_data * file_index = lookup_filename (s.file);
- if ((is_cu_die (old_die->die_parent)
- /* This condition fixes the inconsistency/ICE with the
- following Fortran test (or some derivative thereof) while
- building libgfortran:
-
- module some_m
- contains
- logical function funky (FLAG)
- funky = .true.
- end function
- end module
- */
- || (old_die->die_parent
- && old_die->die_parent->die_tag == DW_TAG_module)
- || context_die == NULL)
+ if (((is_unit_die (old_die->die_parent)
+ /* This condition fixes the inconsistency/ICE with the
+ following Fortran test (or some derivative thereof) while
+ building libgfortran:
+
+ module some_m
+ contains
+ logical function funky (FLAG)
+ funky = .true.
+ end function
+ end module
+ */
+ || (old_die->die_parent
+ && old_die->die_parent->die_tag == DW_TAG_module)
+ || local_scope_p (old_die->die_parent)
+ || context_die == NULL)
&& (DECL_ARTIFICIAL (decl)
- /* The location attributes may be in the abstract origin
- which in the case of LTO might be not available to
- look at. */
- || get_AT (old_die, DW_AT_abstract_origin)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) s.line)
|| s.column == 0
|| (get_AT_unsigned (old_die, DW_AT_decl_column)
== (unsigned) s.column)))))
+ /* With LTO if there's an abstract instance for
+ the old DIE, this is a concrete instance and
+ thus re-use the DIE. */
+ || get_AT (old_die, DW_AT_abstract_origin))
{
subr_die = old_die;
gen_formal_parameter_pack_die (generic_decl_parm,
parm, subr_die,
&parm);
- else if (parm && !POINTER_BOUNDS_P (parm))
+ else if (parm)
{
dw_die_ref parm_die = gen_decl_die (parm, NULL, NULL, subr_die);
dw_die_ref die = NULL;
rtx tloc = NULL_RTX, tlocc = NULL_RTX;
rtx arg, next_arg;
+ tree arg_decl = NULL_TREE;
for (arg = (ca_loc->call_arg_loc_note != NULL_RTX
- ? NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note)
+ ? XEXP (ca_loc->call_arg_loc_note, 0)
: NULL_RTX);
arg; arg = next_arg)
{
tdie = lookup_decl_die (tdecl);
if (tdie == NULL)
continue;
+ arg_decl = tdecl;
}
else
continue;
die = gen_call_site_die (decl, subr_die, ca_loc);
cdie = new_die (dwarf_TAG (DW_TAG_call_site_parameter), die,
NULL_TREE);
+ add_desc_attribute (cdie, arg_decl);
if (reg != NULL)
add_AT_loc (cdie, DW_AT_location, reg);
else if (tdie != NULL)
return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
}
+/* Hold information about markers for inlined entry points. */
+struct GTY ((for_user)) inline_entry_data
+{
+ /* The block that's the inlined_function_outer_scope for an inlined
+ function. */
+ tree block;
+
+ /* The label at the inlined entry point. */
+ const char *label_pfx;
+ unsigned int label_num;
+
+ /* The view number to be used as the inlined entry point. */
+ var_loc_view view;
+};
+
+struct inline_entry_data_hasher : ggc_ptr_hash <inline_entry_data>
+{
+ typedef tree compare_type;
+ static inline hashval_t hash (const inline_entry_data *);
+ static inline bool equal (const inline_entry_data *, const_tree);
+};
+
+/* Hash table routines for inline_entry_data. */
+
+inline hashval_t
+inline_entry_data_hasher::hash (const inline_entry_data *data)
+{
+ return htab_hash_pointer (data->block);
+}
+
+inline bool
+inline_entry_data_hasher::equal (const inline_entry_data *data,
+ const_tree block)
+{
+ return data->block == block;
+}
+
+/* Inlined entry points pending DIE creation in this compilation unit. */
+
+static GTY(()) hash_table<inline_entry_data_hasher> *inline_entry_data_table;
+
+
/* Return TRUE if DECL, which may have been previously generated as
OLD_DIE, is a candidate for a DW_AT_specification. DECLARATION is
true if decl (or its origin) is either an extern declaration or a
/* ??? In LTRANS we cannot annotate early created variably
modified type DIEs without copying them and adjusting all
- references to them. Thus we dumped them again, also add a
- reference to them. */
+ references to them. Thus we dumped them again. Also add a
+ reference to them but beware of -g0 compile and -g link
+ in which case the reference will be already present. */
tree type = TREE_TYPE (decl_or_origin);
if (in_lto_p
+ && ! get_AT (var_die, DW_AT_type)
&& variably_modified_type_p
(type, decl_function_context (decl_or_origin)))
{
static inline void
add_call_src_coords_attributes (tree stmt, dw_die_ref die)
{
+ /* We can end up with BUILTINS_LOCATION here. */
+ if (RESERVED_LOCATION_P (BLOCK_SOURCE_LOCATION (stmt)))
+ return;
+
expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
if (dwarf_version >= 3 || !dwarf_strict)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ if (inline_entry_data **iedp
+ = !inline_entry_data_table ? NULL
+ : inline_entry_data_table->find_slot_with_hash (stmt,
+ htab_hash_pointer (stmt),
+ NO_INSERT))
+ {
+ inline_entry_data *ied = *iedp;
+ gcc_assert (MAY_HAVE_DEBUG_MARKER_INSNS);
+ gcc_assert (debug_inline_points);
+ gcc_assert (inlined_function_outer_scope_p (stmt));
+
+ ASM_GENERATE_INTERNAL_LABEL (label, ied->label_pfx, ied->label_num);
+ add_AT_lbl_id (die, DW_AT_entry_pc, label);
+
+ if (debug_variable_location_views && !ZERO_VIEW_P (ied->view)
+ && !dwarf_strict)
+ {
+ if (!output_asm_line_debug_info ())
+ add_AT_unsigned (die, DW_AT_GNU_entry_view, ied->view);
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", ied->view);
+ /* FIXME: this will resolve to a small number. Could we
+ possibly emit smaller data? Ideally we'd emit a
+ uleb128, but that would make the size of DIEs
+ impossible for the compiler to compute, since it's
+ the assembler that computes the value of the view
+ label in this case. Ideally, we'd have a single form
+ encompassing both the address and the view, and
+ indirecting them through a table might make things
+ easier, but even that would be more wasteful,
+ space-wise, than what we have now. */
+ add_AT_symview (die, DW_AT_GNU_entry_view, label);
+ }
+ }
+
+ inline_entry_data_table->clear_slot (iedp);
+ }
+
if (BLOCK_FRAGMENT_CHAIN (stmt)
&& (dwarf_version >= 3 || !dwarf_strict))
{
dw_die_ref pdie;
dw_attr_node *attr = NULL;
- if (inlined_function_outer_scope_p (stmt))
+ if (!debug_inline_points && inlined_function_outer_scope_p (stmt))
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
}
if (attr != NULL
&& ((*ranges_table)[attr->dw_attr_val.v.val_offset].num
- == BLOCK_NUMBER (superblock))
+ == (int)BLOCK_NUMBER (superblock))
&& BLOCK_FRAGMENT_CHAIN (superblock))
{
unsigned long off = attr->dw_attr_val.v.val_offset;
{
++supercnt;
gcc_checking_assert ((*ranges_table)[off + supercnt].num
- == BLOCK_NUMBER (chain));
+ == (int)BLOCK_NUMBER (chain));
}
gcc_checking_assert ((*ranges_table)[off + supercnt + 1].num == 0);
for (chain = BLOCK_FRAGMENT_CHAIN (stmt);
static void
gen_lexical_block_die (tree stmt, dw_die_ref context_die)
{
- dw_die_ref old_die = BLOCK_DIE (stmt);
+ dw_die_ref old_die = lookup_block_die (stmt);
dw_die_ref stmt_die = NULL;
if (!old_die)
{
stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
- BLOCK_DIE (stmt) = stmt_die;
+ equate_block_to_die (stmt, stmt_die);
}
- if (BLOCK_ABSTRACT (stmt))
- {
- if (old_die)
- {
- /* This must have been generated early and it won't even
- need location information since it's a DW_AT_inline
- function. */
- if (flag_checking)
- for (dw_die_ref c = context_die; c; c = c->die_parent)
- if (c->die_tag == DW_TAG_inlined_subroutine
- || c->die_tag == DW_TAG_subprogram)
- {
- gcc_assert (get_AT (c, DW_AT_inline));
- break;
- }
- return;
- }
- }
- else if (BLOCK_ABSTRACT_ORIGIN (stmt))
+ if (BLOCK_ABSTRACT_ORIGIN (stmt))
{
- /* If this is an inlined instance, create a new lexical die for
- anything below to attach DW_AT_abstract_origin to. */
+ /* If this is an inlined or conrecte instance, create a new lexical
+ die for anything below to attach DW_AT_abstract_origin to. */
if (old_die)
- {
- stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
- BLOCK_DIE (stmt) = stmt_die;
- old_die = NULL;
- }
+ stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
tree origin = block_ultimate_origin (stmt);
- if (origin != NULL_TREE && origin != stmt)
+ if (origin != NULL_TREE && (origin != stmt || old_die))
add_abstract_origin_attribute (stmt_die, origin);
+
+ old_die = NULL;
}
if (old_die)
/* A non abstract block whose blocks have already been reordered
should have the instruction range for this block. If so, set the
high/low attributes. */
- if (!early_dwarf && !BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
+ if (!early_dwarf && TREE_ASM_WRITTEN (stmt))
{
gcc_assert (stmt_die);
add_high_low_attributes (stmt, stmt_die);
static void
gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
{
- tree decl;
-
- /* The instance of function that is effectively being inlined shall not
- be abstract. */
- gcc_assert (! BLOCK_ABSTRACT (stmt));
-
- decl = block_ultimate_origin (stmt);
+ tree decl = block_ultimate_origin (stmt);
/* Make sure any inlined functions are known to be inlineable. */
gcc_checking_assert (DECL_ABSTRACT_P (decl)
|| cgraph_function_possibly_inlined_p (decl));
- if (! BLOCK_ABSTRACT (stmt))
- {
- dw_die_ref subr_die
- = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
+ dw_die_ref subr_die = new_die (DW_TAG_inlined_subroutine, context_die, stmt);
- if (call_arg_locations)
- BLOCK_DIE (stmt) = subr_die;
- add_abstract_origin_attribute (subr_die, decl);
- if (TREE_ASM_WRITTEN (stmt))
- add_high_low_attributes (stmt, subr_die);
- add_call_src_coords_attributes (stmt, subr_die);
+ if (call_arg_locations || debug_inline_points)
+ equate_block_to_die (stmt, subr_die);
+ add_abstract_origin_attribute (subr_die, decl);
+ if (TREE_ASM_WRITTEN (stmt))
+ add_high_low_attributes (stmt, subr_die);
+ add_call_src_coords_attributes (stmt, subr_die);
- decls_for_scope (stmt, subr_die);
+ /* The inliner creates an extra BLOCK for the parameter setup,
+ we want to merge that with the actual outermost BLOCK of the
+ inlined function to avoid duplicate locals in consumers.
+ Do that by doing the recursion to subblocks on the single subblock
+ of STMT. */
+ bool unwrap_one = false;
+ if (BLOCK_SUBBLOCKS (stmt) && !BLOCK_CHAIN (BLOCK_SUBBLOCKS (stmt)))
+ {
+ tree origin = block_ultimate_origin (BLOCK_SUBBLOCKS (stmt));
+ if (origin
+ && TREE_CODE (origin) == BLOCK
+ && BLOCK_SUPERCONTEXT (origin) == decl)
+ unwrap_one = true;
}
+ decls_for_scope (stmt, subr_die, !unwrap_one);
+ if (unwrap_one)
+ decls_for_scope (BLOCK_SUBBLOCKS (stmt), subr_die);
}
/* Generate a DIE for a field in a record, or structure. CTX is required: see
case OPT_U:
case OPT_SPECIAL_unknown:
case OPT_SPECIAL_ignore:
+ case OPT_SPECIAL_deprecated:
case OPT_SPECIAL_program_name:
case OPT_SPECIAL_input_file:
case OPT_grecord_gcc_switches:
case OPT_fdiagnostics_show_location_:
case OPT_fdiagnostics_show_option:
case OPT_fdiagnostics_show_caret:
+ case OPT_fdiagnostics_show_labels:
+ case OPT_fdiagnostics_show_line_numbers:
case OPT_fdiagnostics_color_:
case OPT_fverbose_asm:
case OPT____:
case OPT_fmacro_prefix_map_:
case OPT_ffile_prefix_map_:
case OPT_fcompare_debug:
+ case OPT_fchecking:
+ case OPT_fchecking_:
/* Ignore these. */
continue;
default:
if (strcmp ("GNU C++98", lang1) == 0 || strcmp ("GNU C++98", lang2) == 0)
return "GNU C++98";
+ if (strcmp ("GNU C2X", lang1) == 0 || strcmp ("GNU C2X", lang2) == 0)
+ return "GNU C2X";
if (strcmp ("GNU C17", lang1) == 0 || strcmp ("GNU C17", lang2) == 0)
return "GNU C17";
if (strcmp ("GNU C11", lang1) == 0 || strcmp ("GNU C11", lang2) == 0)
if (dwarf_version >= 5 /* || !dwarf_strict */)
if (strcmp (language_string, "GNU C11") == 0
- || strcmp (language_string, "GNU C17") == 0)
+ || strcmp (language_string, "GNU C17") == 0
+ || strcmp (language_string, "GNU C2X"))
language = DW_LANG_C11;
}
}
language = DW_LANG_ObjC;
else if (strcmp (language_string, "GNU Objective-C++") == 0)
language = DW_LANG_ObjC_plus_plus;
+ else if (strcmp (language_string, "GNU D") == 0)
+ language = DW_LANG_D;
else if (dwarf_version >= 5 || !dwarf_strict)
{
if (strcmp (language_string, "GNU Go") == 0)
/* Use a degraded Fortran setting in strict DWARF2 so is_fortran works. */
else if (strncmp (language_string, "GNU Fortran", 11) == 0)
language = DW_LANG_Fortran90;
+ /* Likewise for Ada. */
+ else if (strcmp (language_string, "GNU Ada") == 0)
+ language = DW_LANG_Ada83;
add_AT_unsigned (die, DW_AT_language, language);
if (type_die->die_parent == NULL)
add_child_die (scope_die, type_die);
- push_decl_scope (type);
gen_member_die (type, type_die);
- pop_decl_scope ();
add_gnat_descriptive_type_attribute (type_die, type, context_die);
if (TYPE_ARTIFICIAL (type))
dw_die_ref context_die,
enum debug_info_usage usage)
{
- int need_pop;
-
if (type == NULL_TREE
|| !is_tagged_type (type))
return;
if (TREE_ASM_WRITTEN (type))
- need_pop = 0;
+ ;
/* If this is a nested type whose containing class hasn't been written
out yet, writing it out will cover this one, too. This does not apply
to instantiations of member class templates; they need to be added to
return;
/* If that failed, attach ourselves to the stub. */
- push_decl_scope (TYPE_CONTEXT (type));
context_die = lookup_type_die (TYPE_CONTEXT (type));
- need_pop = 1;
}
else if (TYPE_CONTEXT (type) != NULL_TREE
&& (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL))
specification. */
if (context_die && is_declaration_die (context_die))
context_die = NULL;
- need_pop = 0;
}
else
- {
- context_die = declare_in_namespace (type, context_die);
- need_pop = 0;
- }
+ context_die = declare_in_namespace (type, context_die);
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
else
gen_struct_or_union_type_die (type, context_die, usage);
- if (need_pop)
- pop_decl_scope ();
-
/* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
it up if it is ever completed. gen_*_type_die will set it for us
when appropriate. */
generate debug info for the typedef. */
if (is_naming_typedef_decl (TYPE_NAME (type)))
{
- /* Use the DIE of the containing namespace as the parent DIE of
- the type description DIE we want to generate. */
- if (DECL_CONTEXT (TYPE_NAME (type))
- && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL)
- context_die = get_context_die (DECL_CONTEXT (TYPE_NAME (type)));
+ /* Give typedefs the right scope. */
+ context_die = scope_die_for (type, context_die);
gen_decl_die (TYPE_NAME (type), NULL, NULL, context_die);
return;
case FIXED_POINT_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
- case POINTER_BOUNDS_TYPE:
/* No DIEs needed for fundamental types. */
break;
/* The outer scopes for inlinings *must* always be represented. We
generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */
must_output_die = 1;
- else
+ else if (lookup_block_die (stmt))
+ /* If we already have a DIE then it was filled early. Meanwhile
+ we might have pruned all BLOCK_VARS as optimized out but we
+ still want to generate high/low PC attributes so output it. */
+ must_output_die = 1;
+ else if (TREE_USED (stmt)
+ || TREE_ASM_WRITTEN (stmt))
{
/* Determine if this block directly contains any "significant"
local declarations which we will need to output DIEs for. */
if (debug_info_level > DINFO_LEVEL_TERSE)
- /* We are not in terse mode so *any* local declaration counts
- as being a "significant" one. */
- must_output_die = ((BLOCK_VARS (stmt) != NULL
- || BLOCK_NUM_NONLOCALIZED_VARS (stmt))
- && (TREE_USED (stmt)
- || TREE_ASM_WRITTEN (stmt)
- || BLOCK_ABSTRACT (stmt)));
- else if ((TREE_USED (stmt)
- || TREE_ASM_WRITTEN (stmt)
- || BLOCK_ABSTRACT (stmt))
- && !dwarf2out_ignore_block (stmt))
+ {
+ /* We are not in terse mode so any local declaration that
+ is not ignored for debug purposes counts as being a
+ "significant" one. */
+ if (BLOCK_NUM_NONLOCALIZED_VARS (stmt))
+ must_output_die = 1;
+ else
+ for (tree var = BLOCK_VARS (stmt); var; var = DECL_CHAIN (var))
+ if (!DECL_IGNORED_P (var))
+ {
+ must_output_die = 1;
+ break;
+ }
+ }
+ else if (!dwarf2out_ignore_block (stmt))
must_output_die = 1;
}
if (must_output_die)
{
if (inlined_func)
- {
- /* If STMT block is abstract, that means we have been called
- indirectly from dwarf2out_abstract_function.
- That function rightfully marks the descendent blocks (of
- the abstract function it is dealing with) as being abstract,
- precisely to prevent us from emitting any
- DW_TAG_inlined_subroutine DIE as a descendent
- of an abstract function instance. So in that case, we should
- not call gen_inlined_subroutine_die.
-
- Later though, when cgraph asks dwarf2out to emit info
- for the concrete instance of the function decl into which
- the concrete instance of STMT got inlined, the later will lead
- to the generation of a DW_TAG_inlined_subroutine DIE. */
- if (! BLOCK_ABSTRACT (stmt))
- gen_inlined_subroutine_die (stmt, context_die);
- }
+ gen_inlined_subroutine_die (stmt, context_die);
else
gen_lexical_block_die (stmt, context_die);
}
all of its sub-blocks. */
static void
-decls_for_scope (tree stmt, dw_die_ref context_die)
+decls_for_scope (tree stmt, dw_die_ref context_die, bool recurse)
{
tree decl;
unsigned int i;
/* Output the DIEs to represent all sub-blocks (and the items declared
therein) of this block. */
- for (subblocks = BLOCK_SUBBLOCKS (stmt);
- subblocks != NULL;
- subblocks = BLOCK_CHAIN (subblocks))
- gen_block_die (subblocks, context_die);
+ if (recurse)
+ for (subblocks = BLOCK_SUBBLOCKS (stmt);
+ subblocks != NULL;
+ subblocks = BLOCK_CHAIN (subblocks))
+ gen_block_die (subblocks, context_die);
}
/* Is this a typedef we can avoid emitting? */
-bool
+static bool
is_redundant_typedef (const_tree decl)
{
if (TYPE_DECL_IS_STUB (decl))
if (ns_context != context_die)
{
- if (is_fortran ())
+ if (is_fortran () || is_dlang ())
return ns_context;
if (DECL_P (thing))
gen_decl_die (thing, NULL, NULL, ns_context);
{
/* Output a real namespace or module. */
context_die = setup_namespace_context (decl, comp_unit_die ());
- namespace_die = new_die (is_fortran ()
+ namespace_die = new_die (is_fortran () || is_dlang ()
? DW_TAG_module : DW_TAG_namespace,
context_die, decl);
/* For Fortran modules defined in different CU don't add src coords. */
if (DECL_P (decl_or_origin) && DECL_IGNORED_P (decl_or_origin))
return NULL;
- /* Ignore pointer bounds decls. */
- if (DECL_P (decl_or_origin)
- && TREE_TYPE (decl_or_origin)
- && POINTER_BOUNDS_P (decl_or_origin))
- return NULL;
-
switch (TREE_CODE (decl_or_origin))
{
case ERROR_MARK:
break;
case CONST_DECL:
- if (!is_fortran () && !is_ada ())
+ if (!is_fortran () && !is_ada () && !is_dlang ())
{
/* The individual enumerators of an enum type get output when we output
the Dwarf representation of the relevant enum type itself. */
symtab->global_info_ready = save;
}
+/* Return whether EXPR is an expression with the following pattern:
+ INDIRECT_REF (NOP_EXPR (INTEGER_CST)). */
+
+static bool
+is_trivial_indirect_ref (tree expr)
+{
+ if (expr == NULL_TREE || TREE_CODE (expr) != INDIRECT_REF)
+ return false;
+
+ tree nop = TREE_OPERAND (expr, 0);
+ if (nop == NULL_TREE || TREE_CODE (nop) != NOP_EXPR)
+ return false;
+
+ tree int_cst = TREE_OPERAND (nop, 0);
+ return int_cst != NULL_TREE && TREE_CODE (int_cst) == INTEGER_CST;
+}
+
/* Output debug information for global decl DECL. Called from
toplev.c after compilation proper has finished. */
{
/* Fill-in any location information we were unable to determine
on the first pass. */
- if (VAR_P (decl) && !POINTER_BOUNDS_P (decl))
+ if (VAR_P (decl))
{
dw_die_ref die = lookup_decl_die (decl);
if (die)
{
/* We get called via the symtab code invoking late_global_decl
- for symbols that are optimized out. Do not add locations
- for those, except if they have a DECL_VALUE_EXPR, in which case
- they are relevant for debuggers. */
+ for symbols that are optimized out.
+
+ Do not add locations for those, except if they have a
+ DECL_VALUE_EXPR, in which case they are relevant for debuggers.
+ Still don't add a location if the DECL_VALUE_EXPR is not a trivial
+ INDIRECT_REF expression, as this could generate relocations to
+ text symbols in LTO object files, which is invalid. */
varpool_node *node = varpool_node::get (decl);
- if ((! node || ! node->definition) && ! DECL_HAS_VALUE_EXPR_P (decl))
+ if ((! node || ! node->definition)
+ && ! (DECL_HAS_VALUE_EXPR_P (decl)
+ && is_trivial_indirect_ref (DECL_VALUE_EXPR (decl))))
tree_add_const_value_attribute_for_decl (die, decl);
else
add_location_or_const_value_attribute (die, decl, false);
case FUNCTION_DECL:
/* If we're a nested function, initially use a parent of NULL; if we're
a plain function, this will be fixed up in decls_for_scope. If
- we're a method, it will be ignored, since we already have a DIE. */
- if (decl_function_context (decl)
+ we're a method, it will be ignored, since we already have a DIE.
+ Avoid doing this late though since clones of class methods may
+ otherwise end up in limbo and create type DIEs late. */
+ if (early_dwarf
+ && decl_function_context (decl)
/* But if we're in terse mode, we don't care about scope. */
&& debug_info_level > DINFO_LEVEL_TERSE)
context_die = NULL;
case CONST_DECL:
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
- if (!is_fortran () && !is_ada ())
+ if (!is_fortran () && !is_ada () && !is_dlang ())
return;
if (TREE_STATIC (decl) && decl_function_context (decl))
context_die = lookup_decl_die (DECL_CONTEXT (decl));
{
if (CALL_P (loc_note))
{
- RESET_NEXT_VIEW (cur_line_info_table->view);
+ maybe_reset_location_view (loc_note, cur_line_info_table);
call_site_count++;
if (SIBLING_CALL_P (loc_note))
tail_call_site_count++;
+ if (find_reg_note (loc_note, REG_CALL_ARG_LOCATION, NULL_RTX))
+ {
+ call_insn = loc_note;
+ loc_note = NULL;
+ var_loc_p = false;
+
+ next_real = dwarf2out_next_real_insn (call_insn);
+ next_note = NULL;
+ cached_next_real_insn = NULL;
+ goto create_label;
+ }
if (optimize == 0 && !flag_var_tracking)
{
/* When the var-tracking pass is not running, there is no note
}
else if (!debug_variable_location_views)
gcc_unreachable ();
- else if (JUMP_TABLE_DATA_P (loc_note))
- RESET_NEXT_VIEW (cur_line_info_table->view);
- else if (GET_CODE (loc_note) == USE
- || GET_CODE (loc_note) == CLOBBER
- || GET_CODE (loc_note) == ASM_INPUT
- || asm_noperands (loc_note) >= 0)
- ;
- else if (get_attr_min_length (loc_note) > 0)
- RESET_NEXT_VIEW (cur_line_info_table->view);
+ else
+ maybe_reset_location_view (loc_note, cur_line_info_table);
return;
}
|| ! NOTE_P (next_note)
|| (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
&& NOTE_KIND (next_note) != NOTE_INSN_BEGIN_STMT
- && NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
+ && NOTE_KIND (next_note) != NOTE_INSN_INLINE_ENTRY))
next_note = NULL;
if (! next_real)
{
struct call_arg_loc_node *ca_loc
= ggc_cleared_alloc<call_arg_loc_node> ();
- rtx_insn *prev
- = loc_note != NULL_RTX ? prev_real_insn (loc_note) : call_insn;
+ rtx_insn *prev = call_insn;
- ca_loc->call_arg_loc_note = loc_note;
+ ca_loc->call_arg_loc_note
+ = find_reg_note (call_insn, REG_CALL_ARG_LOCATION, NULL_RTX);
ca_loc->next = NULL;
ca_loc->label = last_label;
gcc_assert (prev
last_postcall_label = ggc_strdup (loclabel);
}
newloc->label = last_postcall_label;
+ /* ??? This view is at last_label, not last_label-1, but we
+ could only assume view at last_label-1 is zero if we could
+ assume calls always have length greater than one. This is
+ probably true in general, though there might be a rare
+ exception to this rule, e.g. if a call insn is optimized out
+ by target magic. Then, even the -1 in the label will be
+ wrong, which might invalidate the range. Anyway, using view,
+ though technically possibly incorrect, will work as far as
+ ranges go: since L-1 is in the middle of the call insn,
+ (L-1).0 and (L-1).V shouldn't make any difference, and having
+ the loclist entry refer to the .loc entry might be useful, so
+ leave it like this. */
newloc->view = view;
}
last_in_cold_section_p = in_cold_section_p;
}
+/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
+ OUTER itself. If BOTHWAYS, check not only that BLOCK can reach
+ OUTER through BLOCK_SUPERCONTEXT links, but also that there is a
+ path from OUTER to BLOCK through BLOCK_SUBBLOCKs and
+ BLOCK_FRAGMENT_ORIGIN links. */
+static bool
+block_within_block_p (tree block, tree outer, bool bothways)
+{
+ if (block == outer)
+ return true;
+
+ /* Quickly check that OUTER is up BLOCK's supercontext chain. */
+ for (tree context = BLOCK_SUPERCONTEXT (block);
+ context != outer;
+ context = BLOCK_SUPERCONTEXT (context))
+ if (!context || TREE_CODE (context) != BLOCK)
+ return false;
+
+ if (!bothways)
+ return true;
+
+ /* Now check that each block is actually referenced by its
+ parent. */
+ for (tree context = BLOCK_SUPERCONTEXT (block); ;
+ context = BLOCK_SUPERCONTEXT (context))
+ {
+ if (BLOCK_FRAGMENT_ORIGIN (context))
+ {
+ gcc_assert (!BLOCK_SUBBLOCKS (context));
+ context = BLOCK_FRAGMENT_ORIGIN (context);
+ }
+ for (tree sub = BLOCK_SUBBLOCKS (context);
+ sub != block;
+ sub = BLOCK_CHAIN (sub))
+ if (!sub)
+ return false;
+ if (context == outer)
+ return true;
+ else
+ block = context;
+ }
+}
+
+/* Called during final while assembling the marker of the entry point
+ for an inlined function. */
+
+static void
+dwarf2out_inline_entry (tree block)
+{
+ gcc_assert (debug_inline_points);
+
+ /* If we can't represent it, don't bother. */
+ if (!(dwarf_version >= 3 || !dwarf_strict))
+ return;
+
+ gcc_assert (DECL_P (block_ultimate_origin (block)));
+
+ /* Sanity check the block tree. This would catch a case in which
+ BLOCK got removed from the tree reachable from the outermost
+ lexical block, but got retained in markers. It would still link
+ back to its parents, but some ancestor would be missing a link
+ down the path to the sub BLOCK. If the block got removed, its
+ BLOCK_NUMBER will not be a usable value. */
+ if (flag_checking)
+ gcc_assert (block_within_block_p (block,
+ DECL_INITIAL (current_function_decl),
+ true));
+
+ gcc_assert (inlined_function_outer_scope_p (block));
+ gcc_assert (!lookup_block_die (block));
+
+ if (BLOCK_FRAGMENT_ORIGIN (block))
+ block = BLOCK_FRAGMENT_ORIGIN (block);
+ /* Can the entry point ever not be at the beginning of an
+ unfragmented lexical block? */
+ else if (!(BLOCK_FRAGMENT_CHAIN (block)
+ || (cur_line_info_table
+ && !ZERO_VIEW_P (cur_line_info_table->view))))
+ return;
+
+ if (!inline_entry_data_table)
+ inline_entry_data_table
+ = hash_table<inline_entry_data_hasher>::create_ggc (10);
+
+
+ inline_entry_data **iedp
+ = inline_entry_data_table->find_slot_with_hash (block,
+ htab_hash_pointer (block),
+ INSERT);
+ if (*iedp)
+ /* ??? Ideally, we'd record all entry points for the same inlined
+ function (some may have been duplicated by e.g. unrolling), but
+ we have no way to represent that ATM. */
+ return;
+
+ inline_entry_data *ied = *iedp = ggc_cleared_alloc<inline_entry_data> ();
+ ied->block = block;
+ ied->label_pfx = BLOCK_INLINE_ENTRY_LABEL;
+ ied->label_num = BLOCK_NUMBER (block);
+ if (cur_line_info_table)
+ ied->view = cur_line_info_table->view;
+
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_INLINE_ENTRY_LABEL,
+ BLOCK_NUMBER (block));
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+}
+
/* 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. */
table->file_num = 1;
table->line_num = 1;
table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
- RESET_NEXT_VIEW (table->view);
+ FORCE_RESET_NEXT_VIEW (table->view);
+ table->symviews_since_reset = 0;
return table;
}
tail_call_site_count = 0;
set_cur_line_info_table (sec);
+ FORCE_RESET_NEXT_VIEW (cur_line_info_table->view);
}
/* Helper function of dwarf2out_end_function, called only after emitting
{
unsigned int file_num;
dw_line_info_table *table;
+ static var_loc_view lvugid;
- if (debug_info_level < DINFO_LEVEL_TERSE || line == 0)
+ if (debug_info_level < DINFO_LEVEL_TERSE)
return;
+ table = cur_line_info_table;
+
+ if (line == 0)
+ {
+ if (debug_variable_location_views
+ && output_asm_line_debug_info ()
+ && table && !RESETTING_VIEW_P (table->view))
+ {
+ /* If we're using the assembler to compute view numbers, we
+ can't issue a .loc directive for line zero, so we can't
+ get a view number at this point. We might attempt to
+ compute it from the previous view, or equate it to a
+ subsequent view (though it might not be there!), but
+ since we're omitting the line number entry, we might as
+ well omit the view number as well. That means pretending
+ it's a view number zero, which might very well turn out
+ to be correct. ??? Extend the assembler so that the
+ compiler could emit e.g. ".locview .LVU#", to output a
+ view without changing line number information. We'd then
+ have to count it in symviews_since_reset; when it's omitted,
+ it doesn't count. */
+ if (!zero_view_p)
+ zero_view_p = BITMAP_GGC_ALLOC ();
+ bitmap_set_bit (zero_view_p, table->view);
+ if (flag_debug_asm)
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
+ fprintf (asm_out_file, "\t%s line 0, omitted view ",
+ ASM_COMMENT_START);
+ assemble_name (asm_out_file, label);
+ putc ('\n', asm_out_file);
+ }
+ table->view = ++lvugid;
+ }
+ return;
+ }
+
/* The discriminator column was added in dwarf4. Simplify the below
by simply removing it if we're not supposed to output it. */
if (dwarf_version < 4 && dwarf_strict)
if (!debug_column_info)
column = 0;
- table = cur_line_info_table;
file_num = maybe_emit_file (lookup_filename (filename));
/* ??? TODO: Elide duplicate line number entries. Traditionally,
if (is_stmt != table->is_stmt)
{
+#if HAVE_GAS_LOC_STMT
fputs (" is_stmt ", asm_out_file);
putc (is_stmt ? '1' : '0', asm_out_file);
+#endif
}
if (SUPPORTS_DISCRIMINATOR && discriminator != 0)
{
}
if (debug_variable_location_views)
{
- static var_loc_view lvugid;
- if (!lvugid)
- {
- gcc_assert (!zero_view_p);
- zero_view_p = BITMAP_GGC_ALLOC ();
- bitmap_set_bit (zero_view_p, 0);
- }
if (!RESETTING_VIEW_P (table->view))
{
+ table->symviews_since_reset++;
+ if (table->symviews_since_reset > symview_upper_bound)
+ symview_upper_bound = table->symviews_since_reset;
/* When we're using the assembler to compute view
numbers, we output symbolic labels after "view" in
.loc directives, and the assembler will set them for
}
else
{
- if (!table->in_use)
+ table->symviews_since_reset = 0;
+ if (FORCE_RESETTING_VIEW_P (table->view))
fputs (" view -0", asm_out_file);
else
fputs (" view 0", asm_out_file);
known to be zero, because then we may be able to
optimize out locviews that are all zeros, so take
note of it in zero_view_p. */
+ if (!zero_view_p)
+ zero_view_p = BITMAP_GGC_ALLOC ();
bitmap_set_bit (zero_view_p, lvugid);
table->view = ++lvugid;
}
targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
- if (debug_variable_location_views && table->view)
+ if (debug_variable_location_views && !RESETTING_VIEW_P (table->view))
push_dw_line_info_entry (table, LI_adv_address, label_num);
else
push_dw_line_info_entry (table, LI_set_address, label_num);
if (debug_variable_location_views)
{
+ bool resetting = FORCE_RESETTING_VIEW_P (table->view);
+ if (resetting)
+ table->view = 0;
+
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s view %s%d\n",
ASM_COMMENT_START,
- table->in_use ? "" : "-",
+ resetting ? "-" : "",
table->view);
+
table->view++;
}
if (file_num != table->file_num)
node = find_AT_string (ref->info);
gcc_assert (node
&& (node->form == DW_FORM_strp
- || node->form == DW_FORM_GNU_str_index));
+ || node->form == dwarf_FORM (DW_FORM_strx)));
dw2_asm_output_data (1, ref->code,
ref->code == DW_MACRO_define_strp
? "Define macro strp"
&& (debug_str_section->common.flags & SECTION_MERGE) != 0)
set_indirect_string (find_AT_string (ref->info));
break;
+ case DW_MACINFO_start_file:
+ /* -gsplit-dwarf -g3 will also output filename as indirect
+ string. */
+ if (!dwarf_split_debug_info)
+ break;
+ /* Fall through. */
case DW_MACRO_define_strp:
case DW_MACRO_undef_strp:
set_indirect_string (find_AT_string (ref->info));
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG
| SECTION_EXCLUDE, NULL);
- /* For macro info we have to refer to a debug_line section, so
- similar to split-dwarf emit a skeleton one for early debug. */
- debug_skeleton_line_section
- = get_section (DEBUG_LTO_LINE_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
- DEBUG_SKELETON_LINE_SECTION_LABEL,
- generation);
}
else
{
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
}
+ /* For macro info and the file table we have to refer to a
+ debug_line section. */
+ debug_line_section = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
+ DEBUG_LINE_SECTION_LABEL, generation);
+
debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
DEBUG_STR_SECTION_FLAGS
| SECTION_EXCLUDE, NULL);
- if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ if (!dwarf_split_debug_info)
debug_line_str_section
= get_section (DEBUG_LTO_LINE_STR_SECTION,
DEBUG_STR_SECTION_FLAGS | SECTION_EXCLUDE, NULL);
/* Allocate the cached_dw_loc_list_table. */
cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
- /* Allocate the initial hunk of the decl_scope_table. */
- vec_alloc (decl_scope_table, 256);
-
/* Allocate the initial hunk of the abbrev_die_table. */
vec_alloc (abbrev_die_table, 256);
/* Zero-th entry is allocated, but unused. */
indirect_string_node *node = *h;
find_string_form (node);
- if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
+ if (node->form == dwarf_FORM (DW_FORM_strx) && node->refcount > 0)
{
gcc_assert (node->index == NO_INDEX_ASSIGNED);
node->index = *index;
{
indirect_string_node *node = *h;
- if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
+ if (node->form == dwarf_FORM (DW_FORM_strx) && node->refcount > 0)
{
/* Assert that this node has been assigned an index. */
gcc_assert (node->index != NO_INDEX_ASSIGNED
{
struct indirect_string_node *node = *h;
- if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
+ if (node->form == dwarf_FORM (DW_FORM_strx) && node->refcount > 0)
{
/* Assert that the strings are output in the same order as their
indexes were assigned. */
return 1;
}
+/* A helper function for output_indirect_strings. Counts the number
+ of index strings offsets. Must match the logic of the functions
+ output_index_string[_offsets] above. */
+int
+count_index_strings (indirect_string_node **h, unsigned int *last_idx)
+{
+ struct indirect_string_node *node = *h;
+
+ if (node->form == dwarf_FORM (DW_FORM_strx) && node->refcount > 0)
+ *last_idx += 1;
+ return 1;
+}
+
/* A helper function for dwarf2out_finish called through
htab_traverse. Emit one queued .debug_str string. */
output_indirect_string> (DW_FORM_strp);
switch_to_section (debug_str_offsets_section);
+ /* For DWARF5 the .debug_str_offsets[.dwo] section needs a unit
+ header. Note that we don't need to generate a label to the
+ actual index table following the header here, because this is
+ for the split dwarf case only. In an .dwo file there is only
+ one string offsets table (and one debug info section). But
+ if we would start using string offset tables for the main (or
+ skeleton) unit, then we have to add a DW_AT_str_offsets_base
+ pointing to the actual index after the header. Split dwarf
+ units will never have a string offsets base attribute. When
+ a split unit is moved into a .dwp file the string offsets can
+ be found through the .debug_cu_index section table. */
+ if (dwarf_version >= 5)
+ {
+ unsigned int last_idx = 0;
+ unsigned long str_offsets_length;
+
+ debug_str_hash->traverse_noresize
+ <unsigned int *, count_index_strings> (&last_idx);
+ str_offsets_length = last_idx * DWARF_OFFSET_SIZE + 4;
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Escape value for 64-bit DWARF extension");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, str_offsets_length,
+ "Length of string offsets unit");
+ dw2_asm_output_data (2, 5, "DWARF string offsets version");
+ dw2_asm_output_data (2, 0, "Header zero padding");
+ }
debug_str_hash->traverse_noresize
<unsigned int *, output_index_string_offset> (&offset);
switch_to_section (debug_str_dwo_section);
return 1;
}
+/* A helper function for dwarf2out_finish. Counts the number
+ of indexed addresses. Must match the logic of the functions
+ output_addr_table_entry above. */
+int
+count_index_addrs (addr_table_entry **slot, unsigned int *last_idx)
+{
+ addr_table_entry *entry = *slot;
+
+ if (entry->refcount > 0)
+ *last_idx += 1;
+ return 1;
+}
+
/* Produce the .debug_addr section. */
static void
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_class_type:
+ case DW_TAG_interface_type:
break;
case DW_TAG_subprogram:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_class_type:
+ case DW_TAG_interface_type:
if (die->die_perennial_p)
break;
case DW_TAG_volatile_type:
case DW_TAG_typedef:
case DW_TAG_array_type:
- case DW_TAG_interface_type:
case DW_TAG_friend:
case DW_TAG_enumeration_type:
case DW_TAG_subroutine_type:
}
break;
case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
case DW_OP_GNU_const_index:
- if (loc->dw_loc_opc == DW_OP_GNU_addr_index
- || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
+ case DW_OP_constx:
+ if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
+ || loc->dw_loc_opc == DW_OP_addrx)
+ || ((loc->dw_loc_opc == DW_OP_GNU_const_index
+ || loc->dw_loc_opc == DW_OP_constx)
+ && loc->dtprel))
{
rtx rtl = loc->dw_loc_oprnd1.val_entry->addr.rtl;
if (!resolve_one_addr (&rtl))
inchash::add_rtx (val1->v.val_addr, hstate);
break;
case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
case DW_OP_GNU_const_index:
+ case DW_OP_constx:
{
if (loc->dtprel)
{
hash_addr:
return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
case DW_OP_GNU_const_index:
+ case DW_OP_constx:
{
rtx ax1 = valx1->val_entry->addr.rtl;
rtx ay1 = valy1->val_entry->addr.rtl;
for (curr = list; curr != NULL; curr = curr->dw_loc_next)
{
/* Don't index an entry that has already been indexed
- or won't be output. */
+ or won't be output. Make sure skip_loc_list_entry doesn't
+ call size_of_locs, because that might cause circular dependency,
+ index_location_lists requiring address table indexes to be
+ computed, but adding new indexes through add_addr_table_entry
+ and address table index computation requiring no new additions
+ to the hash table. In the rare case of DWARF[234] >= 64KB
+ location expression, we'll just waste unused address table entry
+ for it. */
if (curr->begin_entry != NULL
|| skip_loc_list_entry (curr))
continue;
and generate the DWARF-2 debugging info. */
static void
-dwarf2out_finish (const char *)
+dwarf2out_finish (const char *filename)
{
comdat_type_node *ctnode;
dw_die_ref main_comp_unit_die;
/* Flush out any latecomers to the limbo party. */
flush_limbo_die_list ();
+ if (inline_entry_data_table)
+ gcc_assert (inline_entry_data_table->elements () == 0);
+
if (flag_checking)
{
verify_die (comp_unit_die ());
if (*slot != HTAB_EMPTY_ENTRY)
continue;
- /* Add a pointer to the line table for the main compilation unit
- so that the debugger can make sense of DW_AT_decl_file
- attributes. */
+ /* Remove the pointer to the line table. */
+ remove_AT (ctnode->root_die, DW_AT_stmt_list);
+
if (debug_info_level >= DINFO_LEVEL_TERSE)
reset_dies (ctnode->root_die);
/* Reset die CU symbol so we don't output it twice. */
comp_unit_die ()->die_id.die_symbol = NULL;
- /* Remove DW_AT_macro from the early output. */
+ /* Remove DW_AT_macro and DW_AT_stmt_list from the early output. */
+ remove_AT (comp_unit_die (), DW_AT_stmt_list);
if (have_macinfo)
remove_AT (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE);
/* Remove indirect string decisions. */
debug_str_hash->traverse<void *, reset_indirect_string> (NULL);
+ if (debug_line_str_hash)
+ {
+ debug_line_str_hash->traverse<void *, reset_indirect_string> (NULL);
+ debug_line_str_hash = NULL;
+ }
}
#if ENABLE_ASSERT_CHECKING
resolve_addr (comp_unit_die ());
move_marked_base_types ();
+ if (dump_file)
+ {
+ fprintf (dump_file, "DWARF for %s\n", filename);
+ print_die (comp_unit_die (), dump_file);
+ }
+
/* Initialize sections and labels used for actual assembler output. */
unsigned generation = init_sections_and_labels (false);
{
if (have_location_lists)
{
- if (dwarf_version >= 5)
- add_AT_loclistsptr (comp_unit_die (), DW_AT_loclists_base,
- loc_section_label);
+ /* Since we generate the loclists in the split DWARF .dwo
+ file itself, we don't need to generate a loclists_base
+ attribute for the split compile unit DIE. That attribute
+ (and using relocatable sec_offset FORMs) isn't allowed
+ for a split compile unit. Only if the .debug_loclists
+ section was in the main file, would we need to generate a
+ loclists_base attribute here (for the full or skeleton
+ unit DIE). */
+
/* optimize_location_lists calculates the size of the lists,
so index them first, and assign indices to the entries.
Although optimize_location_lists will remove entries from
}
switch_to_section (debug_addr_section);
+ /* GNU DebugFission https://gcc.gnu.org/wiki/DebugFission
+ which GCC uses to implement -gsplit-dwarf as DWARF GNU extension
+ before DWARF5, didn't have a header for .debug_addr units.
+ DWARF5 specifies a small header when address tables are used. */
+ if (dwarf_version >= 5)
+ {
+ unsigned int last_idx = 0;
+ unsigned long addrs_length;
+
+ addr_index_table->traverse_noresize
+ <unsigned int *, count_index_addrs> (&last_idx);
+ addrs_length = last_idx * DWARF2_ADDR_SIZE + 4;
+
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Escape value for 64-bit DWARF extension");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, addrs_length,
+ "Length of Address Unit");
+ dw2_asm_output_data (2, 5, "DWARF addr version");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
+ dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
+ }
ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
output_addr_table ();
}
switch_to_section (debug_loc_section);
if (dwarf_version >= 5)
{
- ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_LOC_SECTION_LABEL, 1);
- ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_LOC_SECTION_LABEL, 2);
+ ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_LOC_SECTION_LABEL, 2);
+ ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_LOC_SECTION_LABEL, 3);
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
dw2_asm_output_data (4, 0xffffffff,
"Initial length escape value indicating "
debug_line_str_hash->traverse<enum dwarf_form,
output_indirect_string> (form);
}
+
+ /* ??? Move lvugid out of dwarf2out_source_line and reset it too? */
+ symview_upper_bound = 0;
+ if (zero_view_p)
+ bitmap_clear (zero_view_p);
}
/* Returns a hash value for X (which really is a variable_value_struct). */
dwarf2out_early_finish (const char *filename)
{
set_early_dwarf s;
+ char dl_section_ref[MAX_ARTIFICIAL_LABEL_BYTES];
/* PCH might result in DW_AT_producer string being restored from the
header compilation, so always fill it with empty string initially
/* When emitting DWARF5 .debug_line_str, move DW_AT_name and
DW_AT_comp_dir into .debug_line_str section. */
- if (!DWARF2_ASM_LINE_DEBUG_INFO
+ if (!output_asm_line_debug_info ()
&& dwarf_version >= 5
&& DWARF5_USE_DEBUG_LINE_STR)
{
sure to adjust the phase after annotating the LTRANS CU DIE. */
if (in_lto_p)
{
+ /* Force DW_TAG_imported_unit to be created now, otherwise
+ we might end up without it or ordered after DW_TAG_inlined_subroutine
+ referencing DIEs from it. */
+ if (! flag_wpa && flag_incremental_link != INCREMENTAL_LINK_LTO)
+ {
+ unsigned i;
+ tree tu;
+ if (external_die_map)
+ FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, tu)
+ if (sym_off_pair *desc = external_die_map->get (tu))
+ {
+ dw_die_ref import = new_die (DW_TAG_imported_unit,
+ comp_unit_die (), NULL_TREE);
+ add_AT_external_die_ref (import, DW_AT_import,
+ desc->sym, desc->off);
+ }
+ }
+
early_dwarf_finished = true;
+ if (dump_file)
+ {
+ fprintf (dump_file, "LTO EARLY DWARF for %s\n", filename);
+ print_die (comp_unit_die (), dump_file);
+ }
return;
}
/* The early debug phase is now finished. */
early_dwarf_finished = true;
+ if (dump_file)
+ {
+ fprintf (dump_file, "EARLY DWARF for %s\n", filename);
+ print_die (comp_unit_die (), dump_file);
+ }
/* Do not generate DWARF assembler now when not producing LTO bytecode. */
- if (!flag_generate_lto && !flag_generate_offload)
+ if ((!flag_generate_lto && !flag_generate_offload)
+ /* FIXME: Disable debug info generation for (PE-)COFF targets since the
+ copy_lto_debug_sections operation of the simple object support in
+ libiberty is not implemented for them yet. */
+ || TARGET_PECOFF || TARGET_COFF)
return;
/* Now as we are going to output for LTO initialize sections and labels
ctnode != NULL; ctnode = ctnode->next)
add_sibling_attributes (ctnode->root_die);
+ /* AIX Assembler inserts the length, so adjust the reference to match the
+ offset expected by debuggers. */
+ strcpy (dl_section_ref, debug_line_section_label);
+ if (XCOFF_DEBUGGING_INFO)
+ strcat (dl_section_ref, DWARF_INITIAL_LENGTH_SIZE_STR);
+
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list, dl_section_ref);
+
if (have_macinfo)
add_AT_macptr (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE,
macinfo_section_label);
switch_to_section (debug_macinfo_section);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
- output_macinfo (debug_skeleton_line_section_label, true);
+ output_macinfo (debug_line_section_label, true);
dw2_asm_output_data (1, 0, "End compilation unit");
- /* Emit a skeleton debug_line section. */
- switch_to_section (debug_skeleton_line_section);
- ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
- output_line_info (true);
-
if (flag_fat_lto_objects)
{
vec_free (macinfo_table);
}
}
+ /* Emit a skeleton debug_line section. */
+ switch_to_section (debug_line_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
+ output_line_info (true);
/* If we emitted any indirect strings, output the string table too. */
if (debug_str_hash || skeleton_debug_str_hash)
output_indirect_strings ();
+ if (debug_line_str_hash)
+ {
+ switch_to_section (debug_line_str_section);
+ const enum dwarf_form form = DW_FORM_line_strp;
+ debug_line_str_hash->traverse<enum dwarf_form,
+ output_indirect_string> (form);
+ }
/* Switch back to the text section. */
switch_to_section (text_section);
cached_next_real_insn = NULL;
used_rtx_array = NULL;
incomplete_types = NULL;
- decl_scope_table = NULL;
debug_info_section = NULL;
debug_skeleton_info_section = NULL;
debug_abbrev_section = NULL;