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
#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;
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 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);
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 (in_lto_p && !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 and incremental linking we currently use DIEs
- to store the decl <-> label + offset map. That's quite inefficient
- but it works for now. */
- if (in_lto_p)
- {
- 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
- || flag_incremental_link == INCREMENTAL_LINK_LTO) && !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
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
switch (TREE_CODE (decl))
{
case TRANSLATION_UNIT_DECL:
- if (! flag_wpa && flag_incremental_link != INCREMENTAL_LINK_LTO)
- {
- 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. */
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. */
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
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
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);
*/
|| (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)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
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 (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 || 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____:
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)
/* 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 if (BLOCK_DIE (stmt))
+ 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)
- || BLOCK_ABSTRACT (stmt))
+ || TREE_ASM_WRITTEN (stmt))
{
/* Determine if this block directly contains any "significant"
local declarations which we will need to output DIEs for. */
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. */
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. */
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)
{
&& (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));
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:
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;
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);
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)
- /* FIXME: Disable debug info generation for PE-COFF targets since the
+ /* 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_PECOFF || TARGET_COFF)
return;
/* Now as we are going to output for LTO initialize sections and labels