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 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 ();
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 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
}
/* 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. */
-
-static inline void
-add_AT_vms_delta (dw_die_ref die, enum dwarf_attribute attr_kind,
- const char *lbl1, const char *lbl2)
-{
- 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_entry = NULL;
- attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
- attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
- add_dwarf_attr (die, &attr);
-}
-
/* Add a symbolic view identifier attribute value to a DIE. */
static inline void
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. */
- dw_die_ref die
- = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+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;
+
+ 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
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>");
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);
}
}
-/* 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. */
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;
}
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;
}
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++;
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;
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 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
}
}
+/* Generate a DW_AT_description attribute given some string value to be included
+ as the value of the attribute. */
+
+static void
+add_desc_attribute (dw_die_ref die, const char *name_string)
+{
+ if (!flag_describe_dies || (dwarf_version < 3 && dwarf_strict))
+ return;
+
+ if (name_string == NULL || *name_string == 0)
+ return;
+
+ 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.
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
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
? XEXP (ca_loc->call_arg_loc_note, 0)
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)
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)
}
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 (BLOCK_ABSTRACT_ORIGIN (stmt))
{
+ /* 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)
- {
- /* 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 this is an inlined 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 || debug_inline_points)
- 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. */
{
/* 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);
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));
true));
gcc_assert (inlined_function_outer_scope_p (block));
- gcc_assert (!BLOCK_DIE (block));
+ gcc_assert (!lookup_block_die (block));
if (BLOCK_FRAGMENT_ORIGIN (block))
block = BLOCK_FRAGMENT_ORIGIN (block);
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)
{
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 && !dwarf2out_as_loc_support)
+ 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;
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 "
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 (!dwarf2out_as_loc_support
+ 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;