/* Output Dwarf2 format symbol table information from GCC.
- Copyright (C) 1992-2014 Free Software Foundation, Inc.
+ Copyright (C) 1992-2015 Free Software Foundation, Inc.
Contributed by Gary Funck (gary@intrepid.com).
Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
Extensively modified by Jason Merrill (jason@cygnus.com).
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stringpool.h"
#include "stor-layout.h"
#include "varasm.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
#include "hard-reg-set.h"
-#include "input.h"
#include "function.h"
#include "emit-rtl.h"
-#include "hash-table.h"
#include "version.h"
#include "flags.h"
#include "regs.h"
#include "insn-config.h"
#include "reload.h"
#include "output.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "stmt.h"
#include "expr.h"
#include "except.h"
#include "dwarf2.h"
#include "target.h"
#include "common/common-target.h"
#include "langhooks.h"
-#include "hash-map.h"
-#include "is-a.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
#include "cgraph.h"
#include "ira.h"
#include "lra.h"
unsigned int index;
};
-struct indirect_string_hasher : ggc_hasher<indirect_string_node *>
+struct indirect_string_hasher : ggc_ptr_hash<indirect_string_node>
{
typedef const char *compare_type;
int emitted_number;
};
-typedef struct GTY(()) deferred_locations_struct
-{
- tree variable;
- dw_die_ref die;
-} deferred_locations;
-
-
-static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
-
-
/* Describe an entry into the .debug_addr section. */
enum ate_kind {
static void dwarf2out_init (const char *);
static void dwarf2out_finish (const char *);
+static void dwarf2out_early_finish (void);
static void dwarf2out_assembly_start (void);
static void dwarf2out_define (unsigned int, const char *);
static void dwarf2out_undef (unsigned int, const char *);
static void dwarf2out_begin_block (unsigned, unsigned);
static void dwarf2out_end_block (unsigned, unsigned);
static bool dwarf2out_ignore_block (const_tree);
-static void dwarf2out_global_decl (tree);
+static void dwarf2out_early_global_decl (tree);
+static void dwarf2out_late_global_decl (tree);
static void dwarf2out_type_decl (tree, int);
static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
static void dwarf2out_var_location (rtx_insn *);
static void dwarf2out_begin_function (tree);
static void dwarf2out_end_function (unsigned int);
+static void dwarf2out_register_main_translation_unit (tree unit);
static void dwarf2out_set_name (tree, tree);
/* The debug hooks structure. */
{
dwarf2out_init,
dwarf2out_finish,
+ dwarf2out_early_finish,
dwarf2out_assembly_start,
dwarf2out_define,
dwarf2out_undef,
dwarf2out_end_epilogue,
dwarf2out_begin_function,
dwarf2out_end_function, /* end_function */
+ dwarf2out_register_main_translation_unit,
dwarf2out_function_decl, /* function_decl */
- dwarf2out_global_decl,
+ dwarf2out_early_global_decl,
+ dwarf2out_late_global_decl,
dwarf2out_type_decl, /* type_decl */
dwarf2out_imported_module_or_decl,
debug_nothing_tree, /* deferred_inline_function */
}
die_node;
+/* Set to TRUE while dwarf2out_early_global_decl is running. */
+static bool early_dwarf;
+struct set_early_dwarf {
+ bool saved;
+ set_early_dwarf () : saved(early_dwarf) { early_dwarf = true; }
+ ~set_early_dwarf () { early_dwarf = saved; }
+};
+
/* Evaluate 'expr' while 'c' is set to each child of DIE in order. */
#define FOR_EACH_CHILD(die, c, expr) do { \
c = die->die_child; \
}
comdat_type_node;
-/* The limbo die list structure. */
+/* A list of DIEs for which we can't determine ancestry (parent_die
+ field) just yet. Later in dwarf2out_finish we will fill in the
+ missing bits. */
typedef struct GTY(()) limbo_die_struct {
dw_die_ref die;
+ /* The tree for which this DIE was created. We use this to
+ determine ancestry later. */
tree created_for;
struct limbo_die_struct *next;
}
DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set. */
static GTY(()) limbo_die_node *deferred_asm_name;
-struct dwarf_file_hasher : ggc_hasher<dwarf_file_data *>
+struct dwarf_file_hasher : ggc_ptr_hash<dwarf_file_data>
{
typedef const char *compare_type;
/* Filenames referenced by this compilation unit. */
static GTY(()) hash_table<dwarf_file_hasher> *file_table;
-struct decl_die_hasher : ggc_hasher<die_node *>
+struct decl_die_hasher : ggc_ptr_hash<die_node>
{
typedef tree compare_type;
The key is a DECL_UID() which is a unique number identifying each decl. */
static GTY (()) hash_table<decl_die_hasher> *decl_die_table;
-struct block_die_hasher : ggc_hasher<die_struct *>
+struct block_die_hasher : ggc_ptr_hash<die_struct>
{
static hashval_t hash (die_struct *);
static bool equal (die_struct *, die_struct *);
};
-struct decl_loc_hasher : ggc_hasher<var_loc_list *>
+struct decl_loc_hasher : ggc_ptr_hash<var_loc_list>
{
typedef const_tree compare_type;
/* Number of tail call sites in the current function. */
static int tail_call_site_count = -1;
-/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
- DIEs. */
-static vec<dw_die_ref> block_map;
-
/* A cached location list. */
struct GTY ((for_user)) cached_dw_loc_list_def {
/* The DECL_UID of the decl that this entry describes. */
};
typedef struct cached_dw_loc_list_def cached_dw_loc_list;
-struct dw_loc_list_hasher : ggc_hasher<cached_dw_loc_list *>
+struct dw_loc_list_hasher : ggc_ptr_hash<cached_dw_loc_list>
{
typedef const_tree compare_type;
/* Number of elements currently allocated for abbrev_die_table. */
static GTY(()) unsigned abbrev_die_table_allocated;
-/* Number of elements in type_die_table currently in use. */
+/* Number of elements in abbrev_die_table currently in use. */
static GTY(()) unsigned abbrev_die_table_in_use;
/* Size (in elements) of increments by which we may expand the
/* Number of internal labels generated by gen_internal_sym(). */
static GTY(()) int label_num;
-/* Cached result of previous call to lookup_filename. */
-static GTY(()) struct dwarf_file_data * file_table_last_lookup;
-
static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
/* Instances of generic types for which we need to generate debug
static vec<dw_die_ref> base_types;
+/* Flags to represent a set of attribute classes for attributes that represent
+ a scalar value (bounds, pointers, ...). */
+enum dw_scalar_form
+{
+ dw_scalar_form_constant = 0x01,
+ dw_scalar_form_exprloc = 0x02,
+ dw_scalar_form_reference = 0x04
+};
+
/* Forward declarations for functions defined in this file. */
static int is_pseudo_reg (const_rtx);
static bool is_cxx (void);
static bool is_fortran (void);
static bool is_ada (void);
-static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static bool remove_AT (dw_die_ref, enum dwarf_attribute);
static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
static void add_child_die (dw_die_ref, dw_die_ref);
static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
static bool resolve_one_addr (rtx *);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
enum var_init_status);
-static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode,
+static dw_loc_descr_ref loc_descriptor (rtx, machine_mode mode,
enum var_init_status);
-static dw_loc_list_ref loc_list_from_tree (tree, int);
-static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
+struct loc_descr_context;
+static dw_loc_list_ref loc_list_from_tree (tree, int,
+ const struct loc_descr_context *);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree, int,
+ const 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 void add_name_attribute (dw_die_ref, const char *);
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_bound_info (dw_die_ref, enum dwarf_attribute, tree);
+static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int,
+ const struct loc_descr_context *);
+static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree,
+ const struct loc_descr_context *);
static void add_subscript_info (dw_die_ref, tree, bool);
static void add_byte_size_attribute (dw_die_ref, tree);
static void add_bit_offset_attribute (dw_die_ref, tree);
static void gen_variable_die (tree, tree, dw_die_ref);
static void gen_const_die (tree, dw_die_ref);
static void gen_label_die (tree, dw_die_ref);
-static void gen_lexical_block_die (tree, dw_die_ref, int);
-static void gen_inlined_subroutine_die (tree, dw_die_ref, int);
+static void gen_lexical_block_die (tree, dw_die_ref);
+static void gen_inlined_subroutine_die (tree, dw_die_ref);
static void gen_field_die (tree, dw_die_ref);
static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
static dw_die_ref gen_compile_unit_die (const char *);
static void gen_subroutine_type_die (tree, 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, int);
-static void decls_for_scope (tree, dw_die_ref, int);
+static void gen_block_die (tree, dw_die_ref);
+static void decls_for_scope (tree, dw_die_ref);
static inline int is_redundant_typedef (const_tree);
static bool is_naming_typedef_decl (const_tree);
static inline dw_die_ref get_context_die (tree);
attr.dw_attr = attr_kind;
attr.dw_attr_val.val_class = dw_val_class_wide_int;
- attr.dw_attr_val.v.val_wide = ggc_cleared_alloc<wide_int> ();
+ attr.dw_attr_val.val_entry = NULL;
+ attr.dw_attr_val.v.val_wide = ggc_alloc<wide_int> ();
*attr.dw_attr_val.v.val_wide = w;
add_dwarf_attr (die, &attr);
}
return &a->dw_attr_val.v.val_loc_list;
}
-struct addr_hasher : ggc_hasher<addr_table_entry *>
+struct addr_hasher : ggc_ptr_hash<addr_table_entry>
{
static hashval_t hash (addr_table_entry *);
static bool equal (addr_table_entry *, addr_table_entry *);
{
unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language);
- return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
+ return (lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus
+ || lang == DW_LANG_C_plus_plus_11 || lang == DW_LANG_C_plus_plus_14);
}
/* Return TRUE if the language is Java. */
return (lang == DW_LANG_Fortran77
|| lang == DW_LANG_Fortran90
- || lang == DW_LANG_Fortran95);
+ || lang == DW_LANG_Fortran95
+ || lang == DW_LANG_Fortran03
+ || lang == DW_LANG_Fortran08);
}
/* Return TRUE if the language is Ada. */
return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
}
-/* Remove the specified attribute if present. */
+/* Remove the specified attribute if present. Return TRUE if removal
+ was successful. */
-static void
+static bool
remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
unsigned ix;
if (! die)
- return;
+ return false;
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
if (a->dw_attr == attr_kind)
/* vec::ordered_remove should help reduce the number of abbrevs
that are needed. */
die->die_attr->ordered_remove (ix);
- return;
+ return true;
}
+ return false;
}
/* Remove CHILD from its parent. PREV must have the property that
while (c->die_tag == tag)
{
remove_child_with_prev (c, prev);
+ c->die_parent = NULL;
/* Might have removed every child. */
if (c == c->die_sib)
return;
die->die_child = child_die;
}
+/* Unassociate CHILD from its parent, and make its parent be
+ NEW_PARENT. */
+
+static void
+reparent_child (dw_die_ref child, dw_die_ref new_parent)
+{
+ for (dw_die_ref p = child->die_parent->die_child; ; p = p->die_sib)
+ if (p->die_sib == child)
+ {
+ remove_child_with_prev (child, p);
+ break;
+ }
+ add_child_die (new_parent, child);
+}
+
/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
is the specification, to the end of PARENT's list of children.
This is done by removing and re-adding it. */
static void
splice_child_die (dw_die_ref parent, dw_die_ref child)
{
- dw_die_ref p;
-
/* We want the declaration DIE from inside the class, not the
specification DIE at toplevel. */
if (child->die_parent != parent)
|| (child->die_parent
== get_AT_ref (parent, DW_AT_specification)));
- for (p = child->die_parent->die_child; ; p = p->die_sib)
- if (p->die_sib == child)
- {
- remove_child_with_prev (child, p);
- break;
- }
-
- add_child_die (parent, child);
+ reparent_child (child, parent);
}
-/* Return a pointer to a newly created DIE node. */
+/* Create and return a new die with a parent of PARENT_DIE. If
+ PARENT_DIE is NULL, the new DIE is placed in limbo and an
+ associated tree T must be supplied to determine parenthood
+ later. */
static inline dw_die_ref
new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
{
limbo_die_node *limbo_node;
+ /* No DIEs created after early dwarf should end up in limbo,
+ because the limbo list should not persist past LTO
+ streaming. */
+ if (tag_value != DW_TAG_compile_unit
+ /* These are allowed because they're generated while
+ breaking out COMDAT units late. */
+ && tag_value != DW_TAG_type_unit
+ && !early_dwarf
+ /* Allow nested functions to live in limbo because they will
+ only temporarily live there, as decls_for_scope will fix
+ them up. */
+ && (TREE_CODE (t) != FUNCTION_DECL
+ || !decl_function_context (t))
+ /* Same as nested functions above but for types. Types that
+ are local to a function will be fixed in
+ decls_for_scope. */
+ && (!RECORD_OR_UNION_TYPE_P (t)
+ || !TYPE_CONTEXT (t)
+ || TREE_CODE (TYPE_CONTEXT (t)) != FUNCTION_DECL)
+ /* FIXME debug-early: Allow late limbo DIE creation for LTO,
+ especially in the ltrans stage, but once we implement LTO
+ dwarf streaming, we should remove this exception. */
+ && !in_lto_p)
+ {
+ fprintf (stderr, "symbol ended up in limbo too late:");
+ debug_generic_stmt (t);
+ gcc_unreachable ();
+ }
+
limbo_node = ggc_cleared_alloc<limbo_die_node> ();
limbo_node->die = die;
limbo_node->created_for = t;
/* Return how many bits covers PIECE EXPR_LIST. */
-static int
+static HOST_WIDE_INT
decl_piece_bitsize (rtx piece)
{
int ret = (int) GET_MODE (piece);
static rtx_expr_list *
decl_piece_node (rtx loc_note, HOST_WIDE_INT bitsize, rtx next)
{
- if (bitsize <= (int) MAX_MACHINE_MODE)
+ if (bitsize > 0 && bitsize <= (int) MAX_MACHINE_MODE)
return alloc_EXPR_LIST (bitsize, loc_note, next);
else
return alloc_EXPR_LIST (0, gen_rtx_CONCAT (VOIDmode,
HOST_WIDE_INT bitpos, HOST_WIDE_INT piece_bitpos,
HOST_WIDE_INT bitsize, rtx loc_note)
{
- int diff;
+ HOST_WIDE_INT diff;
bool copy = inner != NULL;
if (copy)
{
struct var_loc_node *last = temp->last, *unused = NULL;
rtx *piece_loc = NULL, last_loc_note;
- int piece_bitpos = 0;
+ HOST_WIDE_INT piece_bitpos = 0;
if (last->next)
{
last = last->next;
piece_loc = &last->loc;
do
{
- int cur_bitsize = decl_piece_bitsize (*piece_loc);
+ HOST_WIDE_INT cur_bitsize = decl_piece_bitsize (*piece_loc);
if (piece_bitpos + cur_bitsize > bitpos)
break;
piece_bitpos += cur_bitsize;
fprintf (outfile, "%02x", sig[i] & 0xff);
}
+static void print_loc_descr (dw_loc_descr_ref, FILE *);
+
+/* Print the value associated to the VAL DWARF value node to OUTFILE. If
+ RECURSE, output location descriptor operations. */
+
+static void
+print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
+{
+ switch (val->val_class)
+ {
+ case dw_val_class_addr:
+ fprintf (outfile, "address");
+ break;
+ case dw_val_class_offset:
+ fprintf (outfile, "offset");
+ break;
+ case dw_val_class_loc:
+ fprintf (outfile, "location descriptor");
+ if (val->v.val_loc == NULL)
+ fprintf (outfile, " -> <null>\n");
+ else if (recurse)
+ {
+ fprintf (outfile, ":\n");
+ print_indent += 4;
+ print_loc_descr (val->v.val_loc, outfile);
+ print_indent -= 4;
+ }
+ else
+ fprintf (outfile, " (%p)\n", (void *) val->v.val_loc);
+ break;
+ case dw_val_class_loc_list:
+ fprintf (outfile, "location list -> label:%s",
+ val->v.val_loc_list->ll_symbol);
+ break;
+ case dw_val_class_range_list:
+ fprintf (outfile, "range list");
+ break;
+ case dw_val_class_const:
+ fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, val->v.val_int);
+ break;
+ case dw_val_class_unsigned_const:
+ fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, val->v.val_unsigned);
+ break;
+ case dw_val_class_const_double:
+ fprintf (outfile, "constant (" HOST_WIDE_INT_PRINT_DEC","\
+ HOST_WIDE_INT_PRINT_UNSIGNED")",
+ val->v.val_double.high,
+ val->v.val_double.low);
+ break;
+ case dw_val_class_wide_int:
+ {
+ int i = val->v.val_wide->get_len ();
+ fprintf (outfile, "constant (");
+ gcc_assert (i > 0);
+ if (val->v.val_wide->elt (i - 1) == 0)
+ fprintf (outfile, "0x");
+ fprintf (outfile, HOST_WIDE_INT_PRINT_HEX,
+ val->v.val_wide->elt (--i));
+ while (--i >= 0)
+ fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX,
+ val->v.val_wide->elt (i));
+ fprintf (outfile, ")");
+ break;
+ }
+ case dw_val_class_vec:
+ fprintf (outfile, "floating-point or vector constant");
+ break;
+ case dw_val_class_flag:
+ fprintf (outfile, "%u", val->v.val_flag);
+ break;
+ case dw_val_class_die_ref:
+ if (val->v.val_die_ref.die != NULL)
+ {
+ dw_die_ref die = val->v.val_die_ref.die;
+
+ if (die->comdat_type_p)
+ {
+ fprintf (outfile, "die -> signature: ");
+ print_signature (outfile,
+ die->die_id.die_type_node->signature);
+ }
+ else if (die->die_id.die_symbol)
+ fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ else
+ fprintf (outfile, "die -> %ld", die->die_offset);
+ fprintf (outfile, " (%p)", (void *) die);
+ }
+ else
+ fprintf (outfile, "die -> <null>");
+ break;
+ case dw_val_class_vms_delta:
+ fprintf (outfile, "delta: @slotcount(%s-%s)",
+ val->v.val_vms_delta.lbl2, val->v.val_vms_delta.lbl1);
+ break;
+ case dw_val_class_lbl_id:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ case dw_val_class_high_pc:
+ fprintf (outfile, "label: %s", val->v.val_lbl_id);
+ break;
+ case dw_val_class_str:
+ if (val->v.val_str->str != NULL)
+ fprintf (outfile, "\"%s\"", val->v.val_str->str);
+ else
+ fprintf (outfile, "<null>");
+ break;
+ case dw_val_class_file:
+ fprintf (outfile, "\"%s\" (%d)", val->v.val_file->filename,
+ val->v.val_file->emitted_number);
+ break;
+ case dw_val_class_data8:
+ {
+ int i;
+
+ for (i = 0; i < 8; i++)
+ fprintf (outfile, "%02x", val->v.val_data8[i]);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/* Likewise, for a DIE attribute. */
+
+static void
+print_attribute (dw_attr_ref a, bool recurse, FILE *outfile)
+{
+ print_dw_val (&a->dw_attr_val, recurse, outfile);
+}
+
+
+/* Print the list of operands in the LOC location description to OUTFILE. This
+ routine is a debugging aid only. */
+
+static void
+print_loc_descr (dw_loc_descr_ref loc, FILE *outfile)
+{
+ dw_loc_descr_ref l = loc;
+
+ if (loc == NULL)
+ {
+ print_spaces (outfile);
+ fprintf (outfile, "<null>\n");
+ return;
+ }
+
+ for (l = loc; l != NULL; l = l->dw_loc_next)
+ {
+ print_spaces (outfile);
+ fprintf (outfile, "(%p) %s",
+ (void *) l,
+ dwarf_stack_op_name (l->dw_loc_opc));
+ if (l->dw_loc_oprnd1.val_class != dw_val_class_none)
+ {
+ fprintf (outfile, " ");
+ print_dw_val (&l->dw_loc_oprnd1, false, outfile);
+ }
+ if (l->dw_loc_oprnd2.val_class != dw_val_class_none)
+ {
+ fprintf (outfile, ", ");
+ print_dw_val (&l->dw_loc_oprnd2, false, outfile);
+ }
+ fprintf (outfile, "\n");
+ }
+}
+
/* Print the information associated with a given DIE, and its children.
This routine is a debugging aid only. */
print_spaces (outfile);
fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
- switch (AT_class (a))
- {
- case dw_val_class_addr:
- fprintf (outfile, "address");
- break;
- case dw_val_class_offset:
- fprintf (outfile, "offset");
- break;
- case dw_val_class_loc:
- fprintf (outfile, "location descriptor");
- break;
- case dw_val_class_loc_list:
- fprintf (outfile, "location list -> label:%s",
- AT_loc_list (a)->ll_symbol);
- break;
- case dw_val_class_range_list:
- fprintf (outfile, "range list");
- break;
- case dw_val_class_const:
- fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, AT_int (a));
- break;
- case dw_val_class_unsigned_const:
- fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, AT_unsigned (a));
- break;
- case dw_val_class_const_double:
- fprintf (outfile, "constant ("HOST_WIDE_INT_PRINT_DEC","\
- HOST_WIDE_INT_PRINT_UNSIGNED")",
- a->dw_attr_val.v.val_double.high,
- a->dw_attr_val.v.val_double.low);
- break;
- case dw_val_class_wide_int:
- {
- int i = a->dw_attr_val.v.val_wide->get_len ();
- fprintf (outfile, "constant (");
- gcc_assert (i > 0);
- if (a->dw_attr_val.v.val_wide->elt (i - 1) == 0)
- fprintf (outfile, "0x");
- fprintf (outfile, HOST_WIDE_INT_PRINT_HEX,
- a->dw_attr_val.v.val_wide->elt (--i));
- while (--i >= 0)
- fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX,
- a->dw_attr_val.v.val_wide->elt (i));
- fprintf (outfile, ")");
- break;
- }
- case dw_val_class_vec:
- fprintf (outfile, "floating-point or vector constant");
- break;
- case dw_val_class_flag:
- fprintf (outfile, "%u", AT_flag (a));
- break;
- case dw_val_class_die_ref:
- if (AT_ref (a) != NULL)
- {
- if (AT_ref (a)->comdat_type_p)
- {
- fprintf (outfile, "die -> signature: ");
- print_signature (outfile,
- AT_ref (a)->die_id.die_type_node->signature);
- }
- else if (AT_ref (a)->die_id.die_symbol)
- fprintf (outfile, "die -> label: %s",
- AT_ref (a)->die_id.die_symbol);
- else
- fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset);
- fprintf (outfile, " (%p)", (void *) AT_ref (a));
- }
- else
- fprintf (outfile, "die -> <null>");
- break;
- case dw_val_class_vms_delta:
- fprintf (outfile, "delta: @slotcount(%s-%s)",
- AT_vms_delta2 (a), AT_vms_delta1 (a));
- break;
- case dw_val_class_lbl_id:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
- case dw_val_class_high_pc:
- fprintf (outfile, "label: %s", AT_lbl (a));
- break;
- case dw_val_class_str:
- if (AT_string (a) != NULL)
- fprintf (outfile, "\"%s\"", AT_string (a));
- else
- fprintf (outfile, "<null>");
- break;
- case dw_val_class_file:
- fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
- AT_file (a)->emitted_number);
- break;
- case dw_val_class_data8:
- {
- int i;
-
- for (i = 0; i < 8; i++)
- fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]);
- break;
- }
- default:
- break;
- }
-
+ print_attribute (a, true, outfile);
fprintf (outfile, "\n");
}
fprintf (outfile, "\n");
}
+/* Print the list of operations in the LOC location description. */
+
+DEBUG_FUNCTION void
+debug_dwarf_loc_descr (dw_loc_descr_ref loc)
+{
+ print_loc_descr (loc, stderr);
+}
+
/* Print the information collected for a given DIE. */
DEBUG_FUNCTION void
print_indent = 0;
print_die (comp_unit_die (), stderr);
}
+
+#ifdef ENABLE_CHECKING
+/* Sanity checks on DIEs. */
+
+static void
+check_die (dw_die_ref die)
+{
+ unsigned ix;
+ dw_attr_ref a;
+ bool inline_found = false;
+ int n_location = 0, n_low_pc = 0, n_high_pc = 0, n_artificial = 0;
+ int n_decl_line = 0, n_decl_file = 0;
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ {
+ switch (a->dw_attr)
+ {
+ case DW_AT_inline:
+ if (a->dw_attr_val.v.val_unsigned)
+ inline_found = true;
+ break;
+ case DW_AT_location:
+ ++n_location;
+ break;
+ case DW_AT_low_pc:
+ ++n_low_pc;
+ break;
+ case DW_AT_high_pc:
+ ++n_high_pc;
+ break;
+ case DW_AT_artificial:
+ ++n_artificial;
+ break;
+ case DW_AT_decl_line:
+ ++n_decl_line;
+ break;
+ case DW_AT_decl_file:
+ ++n_decl_file;
+ break;
+ default:
+ break;
+ }
+ }
+ if (n_location > 1 || n_low_pc > 1 || n_high_pc > 1 || n_artificial > 1
+ || n_decl_line > 1 || n_decl_file > 1)
+ {
+ fprintf (stderr, "Duplicate attributes in DIE:\n");
+ debug_dwarf_die (die);
+ gcc_unreachable ();
+ }
+ if (inline_found)
+ {
+ /* A debugging information entry that is a member of an abstract
+ instance tree [that has DW_AT_inline] should not contain any
+ attributes which describe aspects of the subroutine which vary
+ between distinct inlined expansions or distinct out-of-line
+ expansions. */
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ gcc_assert (a->dw_attr != DW_AT_low_pc
+ && a->dw_attr != DW_AT_high_pc
+ && a->dw_attr != DW_AT_location
+ && a->dw_attr != DW_AT_frame_base
+ && a->dw_attr != DW_AT_GNU_all_call_sites);
+ }
+}
+#endif
\f
/* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU
for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL
CHECKSUM (at->dw_attr_val.v.val_double);
break;
case dw_val_class_wide_int:
- CHECKSUM (*at->dw_attr_val.v.val_wide);
+ CHECKSUM_BLOCK (at->dw_attr_val.v.val_wide->get_val (),
+ get_full_len (*at->dw_attr_val.v.val_wide)
+ * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
break;
case dw_val_class_vec:
CHECKSUM_BLOCK (at->dw_attr_val.v.val_vec.array,
case dw_val_class_wide_int:
CHECKSUM_ULEB128 (DW_FORM_block);
- CHECKSUM_ULEB128 (sizeof (*at->dw_attr_val.v.val_wide));
- CHECKSUM (*at->dw_attr_val.v.val_wide);
+ CHECKSUM_ULEB128 (get_full_len (*at->dw_attr_val.v.val_wide)
+ * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
+ CHECKSUM_BLOCK (at->dw_attr_val.v.val_wide->get_val (),
+ get_full_len (*at->dw_attr_val.v.val_wide)
+ * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
break;
case dw_val_class_vec:
/* Helpers to manipulate hash table of CUs. */
-struct cu_hash_table_entry_hasher
+struct cu_hash_table_entry_hasher : pointer_hash <cu_hash_table_entry>
{
- typedef cu_hash_table_entry value_type;
- typedef die_struct compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
- static inline void remove (value_type *);
+ typedef die_struct *compare_type;
+ static inline hashval_t hash (const cu_hash_table_entry *);
+ static inline bool equal (const cu_hash_table_entry *, const die_struct *);
+ static inline void remove (cu_hash_table_entry *);
};
inline hashval_t
-cu_hash_table_entry_hasher::hash (const value_type *entry)
+cu_hash_table_entry_hasher::hash (const cu_hash_table_entry *entry)
{
return htab_hash_string (entry->cu->die_id.die_symbol);
}
inline bool
-cu_hash_table_entry_hasher::equal (const value_type *entry1,
- const compare_type *entry2)
+cu_hash_table_entry_hasher::equal (const cu_hash_table_entry *entry1,
+ const die_struct *entry2)
{
return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol);
}
inline void
-cu_hash_table_entry_hasher::remove (value_type *entry)
+cu_hash_table_entry_hasher::remove (cu_hash_table_entry *entry)
{
struct cu_hash_table_entry *next;
/* Hashtable helpers. */
-struct decl_table_entry_hasher : typed_free_remove <decl_table_entry>
+struct decl_table_entry_hasher : free_ptr_hash <decl_table_entry>
{
- typedef decl_table_entry value_type;
- typedef die_struct compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ typedef die_struct *compare_type;
+ static inline hashval_t hash (const decl_table_entry *);
+ static inline bool equal (const decl_table_entry *, const die_struct *);
};
inline hashval_t
-decl_table_entry_hasher::hash (const value_type *entry)
+decl_table_entry_hasher::hash (const decl_table_entry *entry)
{
return htab_hash_pointer (entry->orig);
}
inline bool
-decl_table_entry_hasher::equal (const value_type *entry1,
- const compare_type *entry2)
+decl_table_entry_hasher::equal (const decl_table_entry *entry1,
+ const die_struct *entry2)
{
return entry1->orig == entry2;
}
/* Hashtable helpers. */
-struct external_ref_hasher : typed_free_remove <external_ref>
+struct external_ref_hasher : free_ptr_hash <external_ref>
{
- typedef external_ref value_type;
- typedef external_ref compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const external_ref *);
+ static inline bool equal (const external_ref *, const external_ref *);
};
inline hashval_t
-external_ref_hasher::hash (const value_type *r)
+external_ref_hasher::hash (const external_ref *r)
{
dw_die_ref die = r->type;
hashval_t h = 0;
}
inline bool
-external_ref_hasher::equal (const value_type *r1, const compare_type *r2)
+external_ref_hasher::equal (const external_ref *r1, const external_ref *r2)
{
return r1->type == r2->type;
}
for (i = len - 1; i >= 0; --i)
{
dw2_asm_output_data (l, a->dw_attr_val.v.val_wide->elt (i),
- name);
+ "%s", name);
name = NULL;
}
else
for (i = 0; i < len; ++i)
{
dw2_asm_output_data (l, a->dw_attr_val.v.val_wide->elt (i),
- name);
+ "%s", name);
name = NULL;
}
}
break;
case dw_val_class_vms_delta:
+#ifdef ASM_OUTPUT_DWARF_VMS_DELTA
dw2_asm_output_vms_delta (DWARF_OFFSET_SIZE,
AT_vms_delta2 (a), AT_vms_delta1 (a),
"%s", name);
+#else
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE,
+ AT_vms_delta2 (a), AT_vms_delta1 (a),
+ "%s", name);
+#endif
break;
case dw_val_class_lbl_id:
static void
output_compilation_unit_header (void)
{
- int ver = dwarf_version;
+ /* We don't support actual DWARFv5 units yet, we just use some
+ DWARFv5 draft DIE tags in DWARFv4 format. */
+ int ver = dwarf_version < 5 ? dwarf_version : 4;
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
dw2_asm_output_data (4, 0xffffffff,
static void
output_skeleton_debug_sections (dw_die_ref comp_unit)
{
+ /* We don't support actual DWARFv5 units yet, we just use some
+ DWARFv5 draft DIE tags in DWARFv4 format. */
+ int ver = dwarf_version < 5 ? dwarf_version : 4;
+
/* These attributes will be found in the full debug_info section. */
remove_AT (comp_unit, DW_AT_producer);
remove_AT (comp_unit, DW_AT_language);
- DWARF_INITIAL_LENGTH_SIZE
+ size_of_die (comp_unit),
"Length of Compilation Unit Info");
- dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ dw2_asm_output_data (2, ver, "DWARF version number");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
debug_abbrev_section,
"Offset Into Abbrev. Section");
"Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
"Length of Address Ranges Info");
- /* Version number for aranges is still 2, even in DWARF3. */
+ /* Version number for aranges is still 2, even up to DWARF5. */
dw2_asm_output_data (2, 2, "DWARF Version");
if (dwarf_split_debug_info)
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
output_line_info (bool prologue_only)
{
char l1[20], l2[20], p1[20], p2[20];
- int ver = dwarf_version;
+ /* We don't support DWARFv5 line tables yet. */
+ int ver = dwarf_version < 5 ? dwarf_version : 4;
bool saw_one = false;
int opc;
case FIXED_POINT_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
+ case POINTER_BOUNDS_TYPE:
return 1;
case ARRAY_TYPE:
}
if (low)
- add_bound_info (subrange_die, DW_AT_lower_bound, low);
+ add_bound_info (subrange_die, DW_AT_lower_bound, low, NULL);
if (high)
- add_bound_info (subrange_die, DW_AT_upper_bound, high);
+ add_bound_info (subrange_die, DW_AT_upper_bound, high, NULL);
return subrange_die;
}
dw_die_ref mod_scope;
/* Only these cv-qualifiers are currently handled. */
const int cv_qual_mask = (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT);
+ | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC);
if (code == ERROR_MARK)
return NULL;
if (dwarf_version < 3)
cv_quals &= ~TYPE_QUAL_RESTRICT;
+ /* Likewise for DW_TAG_atomic_type for DWARFv5. */
+ if (dwarf_version < 5)
+ cv_quals &= ~TYPE_QUAL_ATOMIC;
+
/* See if we already have the appropriately qualified variant of
this type. */
qualified_type = get_qualified_type (type, cv_quals);
struct qual_info { int q; enum dwarf_tag t; };
static const struct qual_info qual_info[] =
{
+ { TYPE_QUAL_ATOMIC, DW_TAG_atomic_type },
{ TYPE_QUAL_RESTRICT, DW_TAG_restrict_type },
{ TYPE_QUAL_VOLATILE, DW_TAG_volatile_type },
{ TYPE_QUAL_CONST, DW_TAG_const_type },
regs = targetm.dwarf_register_span (rtl);
- if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
+ if (REG_NREGS (rtl) > 1 || regs)
return multiple_reg_loc_descriptor (rtl, regs, initialized);
else
{
#endif
gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
- nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
+ nregs = REG_NREGS (rtl);
size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
|| !DECL_THREAD_LOCAL_P (base))
return NULL;
- loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
+ loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1, NULL);
if (loc_result == NULL)
return NULL;
if possible, NULL otherwise. */
static dw_die_ref
-base_type_for_mode (enum machine_mode mode, bool unsignedp)
+base_type_for_mode (machine_mode mode, bool unsignedp)
{
dw_die_ref type_die;
tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
possible. */
static dw_loc_descr_ref
-convert_descriptor_to_mode (enum machine_mode mode, dw_loc_descr_ref op)
+convert_descriptor_to_mode (machine_mode mode, dw_loc_descr_ref op)
{
- enum machine_mode outer_mode = mode;
+ machine_mode outer_mode = mode;
dw_die_ref type_die;
dw_loc_descr_ref cvt;
static dw_loc_descr_ref
scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
- enum machine_mode mem_mode)
+ machine_mode mem_mode)
{
- enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+ machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
dw_loc_descr_ref op0, op1;
int shift;
static dw_loc_descr_ref
ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
- enum machine_mode mem_mode)
+ machine_mode mem_mode)
{
- enum machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
+ machine_mode op_mode = GET_MODE (XEXP (rtl, 0));
dw_loc_descr_ref op0, op1;
if (op_mode == VOIDmode)
/* Return location descriptor for {U,S}{MIN,MAX}. */
static dw_loc_descr_ref
-minmax_loc_descriptor (rtx rtl, enum machine_mode mode,
- enum machine_mode mem_mode)
+minmax_loc_descriptor (rtx rtl, machine_mode mode,
+ machine_mode mem_mode)
{
enum dwarf_location_atom op;
dw_loc_descr_ref op0, op1, ret;
static dw_loc_descr_ref
typed_binop (enum dwarf_location_atom op, rtx rtl, dw_die_ref type_die,
- enum machine_mode mode, enum machine_mode mem_mode)
+ machine_mode mode, machine_mode mem_mode)
{
dw_loc_descr_ref cvt, op0, op1;
L4: DW_OP_nop */
static dw_loc_descr_ref
-clz_loc_descriptor (rtx rtl, enum machine_mode mode,
- enum machine_mode mem_mode)
+clz_loc_descriptor (rtx rtl, machine_mode mode,
+ machine_mode mem_mode)
{
dw_loc_descr_ref op0, ret, tmp;
HOST_WIDE_INT valv;
L2: DW_OP_drop */
static dw_loc_descr_ref
-popcount_loc_descriptor (rtx rtl, enum machine_mode mode,
- enum machine_mode mem_mode)
+popcount_loc_descriptor (rtx rtl, machine_mode mode,
+ machine_mode mem_mode)
{
dw_loc_descr_ref op0, ret, tmp;
dw_loc_descr_ref l1jump, l1label;
L2: DW_OP_drop DW_OP_swap DW_OP_drop */
static dw_loc_descr_ref
-bswap_loc_descriptor (rtx rtl, enum machine_mode mode,
- enum machine_mode mem_mode)
+bswap_loc_descriptor (rtx rtl, machine_mode mode,
+ machine_mode mem_mode)
{
dw_loc_descr_ref op0, ret, tmp;
dw_loc_descr_ref l1jump, l1label;
[ DW_OP_swap constMASK DW_OP_and DW_OP_swap ] DW_OP_shr DW_OP_or */
static dw_loc_descr_ref
-rotate_loc_descriptor (rtx rtl, enum machine_mode mode,
- enum machine_mode mem_mode)
+rotate_loc_descriptor (rtx rtl, machine_mode mode,
+ machine_mode mem_mode)
{
rtx rtlop1 = XEXP (rtl, 1);
dw_loc_descr_ref op0, op1, ret, mask[2] = { NULL, NULL };
Return 0 if we can't represent the location. */
dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode,
- enum machine_mode mem_mode,
+mem_loc_descriptor (rtx rtl, machine_mode mode,
+ machine_mode mem_mode,
enum var_init_status initialized)
{
dw_loc_descr_ref mem_loc_result = NULL;
masking. */
&& GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= 4)
{
- enum machine_mode imode = GET_MODE (XEXP (rtl, 0));
+ machine_mode imode = GET_MODE (XEXP (rtl, 0));
mem_loc_result = op0;
add_loc_descr (&mem_loc_result,
int_loc_descriptor (GET_MODE_MASK (imode)));
}
if (!const_ok_for_output (rtl))
- break;
+ {
+ if (GET_CODE (rtl) == CONST)
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, mem_mode,
+ initialized);
+ break;
+ }
symref:
mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
|| GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT))
{
dw_die_ref type_die = base_type_for_mode (mode, 1);
- enum machine_mode amode;
+ machine_mode amode;
if (type_die == NULL)
return NULL;
amode = mode_for_size (DWARF2_ADDR_SIZE * BITS_PER_UNIT,
mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
mem_loc_result->dw_loc_oprnd2.val_class
= dw_val_class_wide_int;
- mem_loc_result->dw_loc_oprnd2.v.val_wide = ggc_cleared_alloc<wide_int> ();
+ mem_loc_result->dw_loc_oprnd2.v.val_wide = ggc_alloc<wide_int> ();
*mem_loc_result->dw_loc_oprnd2.v.val_wide = std::make_pair (rtl, mode);
}
break;
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum machine_mode mode,
+loc_descriptor (rtx rtl, machine_mode mode,
enum var_init_status initialized)
{
dw_loc_descr_ref loc_result = NULL;
{
rtvec par_elems = XVEC (rtl, 0);
int num_elem = GET_NUM_ELEM (par_elems);
- enum machine_mode mode;
+ machine_mode mode;
int i;
/* Create the first one, so we have something to add to. */
loc_result = new_loc_descr (DW_OP_implicit_value,
GET_MODE_SIZE (mode), 0);
loc_result->dw_loc_oprnd2.val_class = dw_val_class_wide_int;
- loc_result->dw_loc_oprnd2.v.val_wide = ggc_cleared_alloc<wide_int> ();
+ loc_result->dw_loc_oprnd2.v.val_wide = ggc_alloc<wide_int> ();
*loc_result->dw_loc_oprnd2.v.val_wide = std::make_pair (rtl, mode);
}
break;
= ggc_vec_alloc<unsigned char> (length * elt_size);
unsigned int i;
unsigned char *p;
- enum machine_mode imode = GET_MODE_INNER (mode);
+ machine_mode imode = GET_MODE_INNER (mode);
gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
switch (GET_MODE_CLASS (mode))
{
int have_address = 0;
dw_loc_descr_ref descr;
- enum machine_mode mode;
+ machine_mode mode;
if (want_address != 2)
{
dw_sra_loc_expr (tree decl, rtx loc)
{
rtx p;
- unsigned int padsize = 0;
+ unsigned HOST_WIDE_INT padsize = 0;
dw_loc_descr_ref descr, *descr_tail;
unsigned HOST_WIDE_INT decl_size;
rtx varloc;
for (p = loc; p; p = XEXP (p, 1))
{
- unsigned int bitsize = decl_piece_bitsize (p);
+ unsigned HOST_WIDE_INT bitsize = decl_piece_bitsize (p);
rtx loc_note = *decl_piece_varloc_ptr (p);
dw_loc_descr_ref cur_descr;
dw_loc_descr_ref *tail, last = NULL;
- unsigned int opsize = 0;
+ unsigned HOST_WIDE_INT opsize = 0;
if (loc_note == NULL_RTX
|| NOTE_VAR_LOCATION_LOC (loc_note) == NULL_RTX)
/* Return dw_loc_list representing address of addr_expr LOC
by looking for inner INDIRECT_REF expression and turning
- it into simple arithmetics. */
+ it into simple arithmetics.
+
+ See loc_list_from_tree for the meaning of CONTEXT. */
static dw_loc_list_ref
-loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev,
+ const loc_descr_context *context)
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
- enum machine_mode mode;
+ machine_mode mode;
int unsignedp, volatilep = 0;
dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
return 0;
}
if (!offset && !bitpos)
- list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+ list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1,
+ context);
else if (toplev
&& int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
&& (dwarf_version >= 4 || !dwarf_strict))
{
- list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0, context);
if (!list_ret)
return 0;
if (offset)
{
/* Variable offset. */
- list_ret1 = loc_list_from_tree (offset, 0);
+ list_ret1 = loc_list_from_tree (offset, 0, context);
if (list_ret1 == 0)
return 0;
add_loc_list (&list_ret, list_ret1);
}
+/* Helper structure for location descriptions generation. */
+struct loc_descr_context
+{
+ /* The type that is implicitly referenced by DW_OP_push_object_address, or
+ NULL_TREE if DW_OP_push_object_address in invalid for this location
+ description. This is used when processing PLACEHOLDER_EXPR nodes. */
+ tree context_type;
+ /* The ..._DECL node that should be translated as a
+ DW_OP_push_object_address operation. */
+ tree base_decl;
+};
+
/* Generate Dwarf location list representing LOC.
If WANT_ADDRESS is false, expression computing LOC will be computed
If WANT_ADDRESS is 1, expression computing address of LOC will be returned
if WANT_ADDRESS is 2, expression computing address useable in location
will be returned (i.e. DW_OP_reg can be used
- to refer to register values). */
+ to refer to register values).
+
+ CONTEXT provides information to customize the location descriptions
+ generation. Its context_type field specifies what type is implicitly
+ referenced by DW_OP_push_object_address. If it is NULL_TREE, this operation
+ will not be generated.
+
+ If CONTEXT is NULL, the behavior is the same as if both context_type and
+ base_decl fields were NULL_TREE. */
static dw_loc_list_ref
-loc_list_from_tree (tree loc, int want_address)
+loc_list_from_tree (tree loc, int want_address,
+ const struct loc_descr_context *context)
{
dw_loc_descr_ref ret = NULL, ret1 = NULL;
dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
extending the values properly. Hopefully this won't be a real
problem... */
+ if (context != NULL
+ && context->base_decl == loc
+ && want_address == 0)
+ {
+ if (dwarf_version >= 3 || !dwarf_strict)
+ return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
+ NULL, NULL, NULL);
+ else
+ return NULL;
+ }
+
switch (TREE_CODE (loc))
{
case ERROR_MARK:
case PLACEHOLDER_EXPR:
/* This case involves extracting fields from an object to determine the
- position of other fields. We don't try to encode this here. The
- only user of this is Ada, which encodes the needed information using
- the names of types. */
- expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
- return 0;
-
- case CALL_EXPR:
- expansion_failed (loc, NULL_RTX, "CALL_EXPR");
- /* There are no opcodes for these operations. */
- return 0;
-
- case PREINCREMENT_EXPR:
+ position of other fields. It is supposed to appear only as the first
+ operand of COMPONENT_REF nodes and to reference precisely the type
+ that the context allows. */
+ if (context != NULL
+ && TREE_TYPE (loc) == context->context_type
+ && want_address >= 1)
+ {
+ if (dwarf_version >= 3 || !dwarf_strict)
+ {
+ ret = new_loc_descr (DW_OP_push_object_address, 0, 0);
+ have_address = 1;
+ break;
+ }
+ else
+ return NULL;
+ }
+ else
+ expansion_failed (loc, NULL_RTX,
+ "PLACEHOLDER_EXPR for an unexpected type");
+ break;
+
+ case CALL_EXPR:
+ expansion_failed (loc, NULL_RTX, "CALL_EXPR");
+ /* There are no opcodes for these operations. */
+ return 0;
+
+ case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
if (want_address)
{
list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
- (loc, want_address == 2);
+ (loc, want_address == 2, context);
if (list_ret)
have_address = 1;
else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
}
/* Otherwise, process the argument and look for the address. */
if (!list_ret && !ret)
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1, context);
else
{
if (want_address)
case RESULT_DECL:
if (DECL_HAS_VALUE_EXPR_P (loc))
return loc_list_from_tree (DECL_VALUE_EXPR (loc),
- want_address);
+ want_address, context);
/* FALLTHRU */
case FUNCTION_DECL:
ret = new_addr_loc_descr (rtl, dtprel_false);
else
{
- enum machine_mode mode, mem_mode;
+ machine_mode mode, mem_mode;
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
}
/* Fallthru. */
case INDIRECT_REF:
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
have_address = 1;
break;
case TARGET_MEM_REF:
case SSA_NAME:
+ case DEBUG_EXPR_DECL:
return NULL;
case COMPOUND_EXPR:
- return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address);
+ return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address, context);
CASE_CONVERT:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
case MODIFY_EXPR:
- return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address);
+ return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address, context);
case COMPONENT_REF:
case BIT_FIELD_REF:
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
- enum machine_mode mode;
+ machine_mode mode;
int unsignedp, volatilep = 0;
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
list_ret = loc_list_from_tree (obj,
want_address == 2
- && !bitpos && !offset ? 2 : 1);
+ && !bitpos && !offset ? 2 : 1,
+ context);
/* TODO: We can extract value of the small expression via shifting even
for nonzero bitpos. */
if (list_ret == 0)
if (offset != NULL_TREE)
{
/* Variable offset. */
- list_ret1 = loc_list_from_tree (offset, 0);
+ list_ret1 = loc_list_from_tree (offset, 0, context);
if (list_ret1 == 0)
return 0;
add_loc_list (&list_ret, list_ret1);
op = DW_OP_mod;
goto do_binop;
}
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
- list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
+ list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
if (list_ret == 0 || list_ret1 == 0)
return 0;
do_plus:
if (tree_fits_shwi_p (TREE_OPERAND (loc, 1)))
{
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
if (list_ret == 0)
return 0;
goto do_binop;
do_binop:
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
- list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
+ list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
if (list_ret == 0 || list_ret1 == 0)
return 0;
goto do_unop;
do_unop:
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
if (list_ret == 0)
return 0;
case COND_EXPR:
{
dw_loc_descr_ref lhs
- = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+ = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0, context);
dw_loc_list_ref rhs
- = loc_list_from_tree (TREE_OPERAND (loc, 2), 0);
+ = loc_list_from_tree (TREE_OPERAND (loc, 2), 0, context);
dw_loc_descr_ref bra_node, jump_node, tmp;
- list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+ list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
if (list_ret == 0 || lhs == 0 || rhs == 0)
return 0;
/* Same as above but return only single location expression. */
static dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc, int want_address)
+loc_descriptor_from_tree (tree loc, int want_address,
+ const struct loc_descr_context *context)
{
- dw_loc_list_ref ret = loc_list_from_tree (loc, want_address);
+ dw_loc_list_ref ret = loc_list_from_tree (loc, want_address, context);
if (!ret)
return NULL;
if (ret->dw_loc_next)
bitpos_int = wi::to_offset (bit_position (decl));
-#ifdef PCC_BITFIELD_TYPE_MATTERS
if (PCC_BITFIELD_TYPE_MATTERS)
{
tree type;
}
}
else
-#endif /* PCC_BITFIELD_TYPE_MATTERS */
object_offset_in_bits = bitpos_int;
object_offset_in_bytes
constant requires more than one word in order to be adequately
represented. */
{
- enum machine_mode mode = GET_MODE (rtl);
+ machine_mode mode = GET_MODE (rtl);
if (TARGET_SUPPORTS_WIDE_INT == 0 && !SCALAR_FLOAT_MODE_P (mode))
add_AT_double (die, DW_AT_const_value,
case CONST_VECTOR:
{
- enum machine_mode mode = GET_MODE (rtl);
+ machine_mode mode = GET_MODE (rtl);
unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
unsigned int length = CONST_VECTOR_NUNITS (rtl);
unsigned char *array
= ggc_vec_alloc<unsigned char> (length * elt_size);
unsigned int i;
unsigned char *p;
- enum machine_mode imode = GET_MODE_INNER (mode);
+ machine_mode imode = GET_MODE_INNER (mode);
switch (GET_MODE_CLASS (mode))
{
{
tree enttype = TREE_TYPE (type);
tree domain = TYPE_DOMAIN (type);
- enum machine_mode mode = TYPE_MODE (enttype);
+ machine_mode mode = TYPE_MODE (enttype);
if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == 1
&& domain
{
tree declared_type = TREE_TYPE (decl);
tree passed_type = DECL_ARG_TYPE (decl);
- enum machine_mode dmode = TYPE_MODE (declared_type);
- enum machine_mode pmode = TYPE_MODE (passed_type);
+ machine_mode dmode = TYPE_MODE (declared_type);
+ machine_mode pmode = TYPE_MODE (passed_type);
/* This decl represents a formal parameter which was optimized out.
Note that DECL_INCOMING_RTL may be NULL in here, but we handle
&& (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))
< UNITS_PER_WORD))
{
- enum machine_mode addr_mode = get_address_mode (rtl);
+ machine_mode addr_mode = get_address_mode (rtl);
int offset = (UNITS_PER_WORD
- GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))));
&& GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
&& BYTES_BIG_ENDIAN)
{
- enum machine_mode addr_mode = get_address_mode (rtl);
+ machine_mode addr_mode = get_address_mode (rtl);
int rsize = GET_MODE_SIZE (GET_MODE (rtl));
int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
fortran_common (tree decl, HOST_WIDE_INT *value)
{
tree val_expr, cvar;
- enum machine_mode mode;
+ machine_mode mode;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
int unsignedp, volatilep = 0;
if (TREE_CODE (decl) == ERROR_MARK)
return false;
+ if (get_AT (die, attr))
+ return true;
+
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
}
if (list == NULL)
{
- list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
+ list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2,
+ NULL);
/* It is usually worth caching this result if the decl is from
BLOCK_NONLOCALIZED_VARS and if the list has at least two elements. */
if (cache_p && list && list->dw_loc_next)
return tree_add_const_value_attribute_for_decl (die, decl);
}
-/* Add VARIABLE and DIE into deferred locations list. */
-
-static void
-defer_location (tree variable, dw_die_ref die)
-{
- deferred_locations entry;
- entry.variable = variable;
- entry.die = die;
- vec_safe_push (deferred_locations_list, entry);
-}
-
/* Helper function for tree_add_const_value_attribute. Natively encode
initializer INIT into an array. Return true if successful. */
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree enttype = TREE_TYPE (type);
- enum machine_mode mode = TYPE_MODE (enttype);
+ machine_mode mode = TYPE_MODE (enttype);
if (GET_MODE_CLASS (mode) != MODE_INT || GET_MODE_SIZE (mode) != 1)
return false;
&& !TREE_STATIC (decl)))
return false;
- if (TREE_READONLY (decl)
- && ! TREE_THIS_VOLATILE (decl)
- && DECL_INITIAL (decl))
- /* OK */;
- else
- return false;
+ if (TREE_READONLY (decl)
+ && ! TREE_THIS_VOLATILE (decl)
+ && DECL_INITIAL (decl))
+ /* OK */;
+ else
+ return false;
/* Don't add DW_AT_const_value if abstract origin already has one. */
if (get_AT (var_die, DW_AT_const_value))
add_AT_string (die, DW_AT_comp_dir, wd);
}
+/* Given a tree node VALUE describing a scalar attribute ATTR (i.e. a bound, a
+ pointer computation, ...), output a representation for that bound according
+ to the accepted FORMS (see enum dw_scalar_form) and add it to DIE. See
+ loc_list_from_tree for the meaning of CONTEXT. */
+
+static void
+add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
+ int forms, const struct loc_descr_context *context)
+{
+ dw_die_ref ctx, decl_die;
+ dw_loc_list_ref list;
+
+ bool strip_conversions = true;
+
+ while (strip_conversions)
+ switch (TREE_CODE (value))
+ {
+ case ERROR_MARK:
+ case SAVE_EXPR:
+ return;
+
+ CASE_CONVERT:
+ case VIEW_CONVERT_EXPR:
+ value = TREE_OPERAND (value, 0);
+ break;
+
+ default:
+ strip_conversions = false;
+ break;
+ }
+
+ /* If possible and permitted, output the attribute as a constant. */
+ if ((forms & dw_scalar_form_constant) != 0
+ && TREE_CODE (value) == INTEGER_CST)
+ {
+ unsigned int prec = simple_type_size_in_bits (TREE_TYPE (value));
+
+ /* If HOST_WIDE_INT is big enough then represent the bound as
+ a constant value. We need to choose a form based on
+ whether the type is signed or unsigned. We cannot just
+ call add_AT_unsigned if the value itself is positive
+ (add_AT_unsigned might add the unsigned value encoded as
+ DW_FORM_data[1248]). Some DWARF consumers will lookup the
+ bounds type and then sign extend any unsigned values found
+ for signed types. This is needed only for
+ DW_AT_{lower,upper}_bound, since for most other attributes,
+ consumers will treat DW_FORM_data[1248] as unsigned values,
+ regardless of the underlying type. */
+ if (prec <= HOST_BITS_PER_WIDE_INT
+ || tree_fits_uhwi_p (value))
+ {
+ if (TYPE_UNSIGNED (TREE_TYPE (value)))
+ add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value));
+ else
+ add_AT_int (die, attr, TREE_INT_CST_LOW (value));
+ }
+ else
+ /* Otherwise represent the bound as an unsigned value with
+ the precision of its type. The precision and signedness
+ of the type will be necessary to re-interpret it
+ unambiguously. */
+ add_AT_wide (die, attr, value);
+ return;
+ }
+
+ /* Otherwise, if it's possible and permitted too, output a reference to
+ another DIE. */
+ if ((forms & dw_scalar_form_reference) != 0)
+ {
+ tree decl = NULL_TREE;
+
+ /* Some type attributes reference an outer type. For instance, the upper
+ bound of an array may reference an embedding record (this happens in
+ Ada). */
+ if (TREE_CODE (value) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (value, 0)) == PLACEHOLDER_EXPR
+ && TREE_CODE (TREE_OPERAND (value, 1)) == FIELD_DECL)
+ decl = TREE_OPERAND (value, 1);
+
+ else if (TREE_CODE (value) == VAR_DECL
+ || TREE_CODE (value) == PARM_DECL
+ || TREE_CODE (value) == RESULT_DECL)
+ decl = value;
+
+ if (decl != NULL_TREE)
+ {
+ dw_die_ref 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
+ the types of parameters in the order in which they exist in
+ the list, and won't have created a forward reference to a
+ later parameter. */
+ if (decl_die != NULL)
+ {
+ add_AT_die_ref (die, attr, decl_die);
+ return;
+ }
+ }
+ }
+
+ /* Last chance: try to create a stack operation procedure to evaluate the
+ value. Do nothing if even that is not possible or permitted. */
+ if ((forms & dw_scalar_form_exprloc) == 0)
+ return;
+
+ list = loc_list_from_tree (value, 2, context);
+ if (list == NULL || single_element_loc_list_p (list))
+ {
+ /* If this attribute is not a reference nor constant, it is
+ a DWARF expression rather than location description. For that
+ loc_list_from_tree (value, 0, &context) is needed. */
+ dw_loc_list_ref list2 = loc_list_from_tree (value, 0, context);
+ if (list2 && single_element_loc_list_p (list2))
+ {
+ add_AT_loc (die, attr, list2->expr);
+ return;
+ }
+ }
+
+ /* If that failed to give a single element location list, fall back to
+ outputting this as a reference... still if permitted. */
+ if (list == NULL || (forms & dw_scalar_form_reference) == 0)
+ return;
+
+ if (current_function_decl == 0)
+ ctx = comp_unit_die ();
+ else
+ ctx = lookup_decl_die (current_function_decl);
+
+ decl_die = new_die (DW_TAG_variable, ctx, value);
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+ add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, ctx);
+ add_AT_location_description (decl_die, DW_AT_location, list);
+ add_AT_die_ref (die, attr, decl_die);
+}
+
/* Return the default for DW_AT_lower_bound, or -1 if there is not any
default. */
case DW_LANG_C:
case DW_LANG_C89:
case DW_LANG_C99:
+ case DW_LANG_C11:
case DW_LANG_C_plus_plus:
+ case DW_LANG_C_plus_plus_11:
+ case DW_LANG_C_plus_plus_14:
case DW_LANG_ObjC:
case DW_LANG_ObjC_plus_plus:
case DW_LANG_Java:
case DW_LANG_Fortran77:
case DW_LANG_Fortran90:
case DW_LANG_Fortran95:
+ case DW_LANG_Fortran03:
+ case DW_LANG_Fortran08:
return 1;
case DW_LANG_UPC:
case DW_LANG_D:
a representation for that bound. */
static void
-add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
+add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
+ tree bound, const struct loc_descr_context *context)
{
- switch (TREE_CODE (bound))
- {
- case ERROR_MARK:
- return;
+ int dflt;
- /* All fixed-bounds are represented by INTEGER_CST nodes. */
- case INTEGER_CST:
+ while (1)
+ switch (TREE_CODE (bound))
{
- unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
- int dflt;
+ /* Strip all conversions. */
+ CASE_CONVERT:
+ case VIEW_CONVERT_EXPR:
+ bound = TREE_OPERAND (bound, 0);
+ break;
- /* Use the default if possible. */
+ /* All fixed-bounds are represented by INTEGER_CST nodes. Lower bounds
+ are even omitted when they are the default. */
+ case INTEGER_CST:
+ /* If the value for this bound is the default one, we can even omit the
+ attribute. */
if (bound_attr == DW_AT_lower_bound
&& tree_fits_shwi_p (bound)
&& (dflt = lower_bound_default ()) != -1
&& tree_to_shwi (bound) == dflt)
- ;
-
- /* If HOST_WIDE_INT is big enough then represent the bound as
- a constant value. We need to choose a form based on
- whether the type is signed or unsigned. We cannot just
- call add_AT_unsigned if the value itself is positive
- (add_AT_unsigned might add the unsigned value encoded as
- DW_FORM_data[1248]). Some DWARF consumers will lookup the
- bounds type and then sign extend any unsigned values found
- for signed types. This is needed only for
- DW_AT_{lower,upper}_bound, since for most other attributes,
- consumers will treat DW_FORM_data[1248] as unsigned values,
- regardless of the underlying type. */
- else if (prec <= HOST_BITS_PER_WIDE_INT
- || tree_fits_uhwi_p (bound))
- {
- if (TYPE_UNSIGNED (TREE_TYPE (bound)))
- add_AT_unsigned (subrange_die, bound_attr,
- TREE_INT_CST_LOW (bound));
- else
- add_AT_int (subrange_die, bound_attr, TREE_INT_CST_LOW (bound));
- }
- else
- /* Otherwise represent the bound as an unsigned value with
- the precision of its type. The precision and signedness
- of the type will be necessary to re-interpret it
- unambiguously. */
- add_AT_wide (subrange_die, bound_attr, bound);
- }
- break;
-
- CASE_CONVERT:
- case VIEW_CONVERT_EXPR:
- add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
- break;
-
- case SAVE_EXPR:
- break;
-
- case VAR_DECL:
- case PARM_DECL:
- case RESULT_DECL:
- {
- dw_die_ref decl_die = lookup_decl_die (bound);
-
- /* ??? Can this happen, or should the variable have been bound
- first? Probably it can, since I imagine that we try to create
- the types of parameters in the order in which they exist in
- the list, and won't have created a forward reference to a
- later parameter. */
- if (decl_die != NULL)
- {
- add_AT_die_ref (subrange_die, bound_attr, decl_die);
- break;
- }
- }
- /* FALLTHRU */
-
- default:
- {
- /* Otherwise try to create a stack operation procedure to
- evaluate the value of the array bound. */
-
- dw_die_ref ctx, decl_die;
- dw_loc_list_ref list;
-
- list = loc_list_from_tree (bound, 2);
- if (list == NULL || single_element_loc_list_p (list))
- {
- /* If DW_AT_*bound is not a reference nor constant, it is
- a DWARF expression rather than location description.
- For that loc_list_from_tree (bound, 0) is needed.
- If that fails to give a single element list,
- fall back to outputting this as a reference anyway. */
- dw_loc_list_ref list2 = loc_list_from_tree (bound, 0);
- if (list2 && single_element_loc_list_p (list2))
- {
- add_AT_loc (subrange_die, bound_attr, list2->expr);
- break;
- }
- }
- if (list == NULL)
- break;
+ return;
- if (current_function_decl == 0)
- ctx = comp_unit_die ();
- else
- ctx = lookup_decl_die (current_function_decl);
+ /* FALLTHRU */
- decl_die = new_die (DW_TAG_variable, ctx, bound);
- add_AT_flag (decl_die, DW_AT_artificial, 1);
- add_type_attribute (decl_die, TREE_TYPE (bound), TYPE_QUAL_CONST, ctx);
- add_AT_location_description (decl_die, DW_AT_location, list);
- add_AT_die_ref (subrange_die, bound_attr, decl_die);
- break;
+ default:
+ add_scalar_info (subrange_die, bound_attr, bound,
+ dw_scalar_form_constant
+ | dw_scalar_form_exprloc
+ | dw_scalar_form_reference,
+ context);
+ return;
}
- }
}
/* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
Note that the block of subscript information for an array type also
- includes information about the element type of the given array type. */
+ includes information about the element type of the given array type.
+
+ This function reuses previously set type and bound information if
+ available. */
static void
add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
{
unsigned dimension_number;
tree lower, upper;
- dw_die_ref subrange_die;
+ dw_die_ref child = type_die->die_child;
for (dimension_number = 0;
TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
/* Arrays come in three flavors: Unspecified bounds, fixed bounds,
and (in GNU C only) variable bounds. Handle all three forms
here. */
- subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
+ /* Find and reuse a previously generated DW_TAG_subrange_type if
+ available.
+
+ For multi-dimensional arrays, as we iterate through the
+ various dimensions in the enclosing for loop above, we also
+ iterate through the DIE children and pick at each
+ DW_TAG_subrange_type previously generated (if available).
+ Each child DW_TAG_subrange_type DIE describes the range of
+ the current dimension. At this point we should have as many
+ DW_TAG_subrange_type's as we have dimensions in the
+ array. */
+ dw_die_ref subrange_die = NULL;
+ if (child)
+ while (1)
+ {
+ child = child->die_sib;
+ if (child->die_tag == DW_TAG_subrange_type)
+ subrange_die = child;
+ if (child == type_die->die_child)
+ {
+ /* If we wrapped around, stop looking next time. */
+ child = NULL;
+ break;
+ }
+ if (child->die_tag == DW_TAG_subrange_type)
+ break;
+ }
+ if (!subrange_die)
+ subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
if (domain)
{
/* We have an array type with specified bounds. */
upper = TYPE_MAX_VALUE (domain);
/* Define the index type. */
- if (TREE_TYPE (domain))
+ if (TREE_TYPE (domain)
+ && !get_AT (subrange_die, DW_AT_type))
{
/* ??? This is probably an Ada unnamed subrange type. Ignore the
TREE_TYPE field. We can't emit debug info for this
to produce useful results, go ahead and output the lower
bound solo, and hope the debugger can cope. */
- add_bound_info (subrange_die, DW_AT_lower_bound, lower);
- if (upper)
- add_bound_info (subrange_die, DW_AT_upper_bound, upper);
+ 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);
}
/* Otherwise we have an array type with an unspecified length. The
static inline void
add_prototyped_attribute (dw_die_ref die, tree func_type)
{
- if (get_AT_unsigned (comp_unit_die (), DW_AT_language) == DW_LANG_C89
- && prototype_p (func_type))
- add_AT_flag (die, DW_AT_prototyped, 1);
+ switch (get_AT_unsigned (comp_unit_die (), DW_AT_language))
+ {
+ case DW_LANG_C:
+ case DW_LANG_C89:
+ case DW_LANG_C99:
+ case DW_LANG_C11:
+ case DW_LANG_ObjC:
+ if (prototype_p (func_type))
+ add_AT_flag (die, DW_AT_prototyped, 1);
+ break;
+ default:
+ break;
+ }
}
/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found
}
#endif
\f
+/* For variable-length arrays that have been previously generated, but
+ may be incomplete due to missing subscript info, fill the subscript
+ info. Return TRUE if this is one of those cases. */
+static bool
+fill_variable_array_bounds (tree type)
+{
+ if (TREE_ASM_WRITTEN (type)
+ && TREE_CODE (type) == ARRAY_TYPE
+ && variably_modified_type_p (type, NULL))
+ {
+ dw_die_ref array_die = lookup_type_die (type);
+ if (!array_die)
+ return false;
+ add_subscript_info (array_die, type, !is_ada ());
+ return true;
+ }
+ return false;
+}
+
/* These routines generate the internal representation of the DIE's for
the compilation unit. Debugging information is collected by walking
the declaration trees passed in from dwarf2out_decl(). */
static void
gen_array_type_die (tree type, dw_die_ref context_die)
{
- dw_die_ref scope_die = scope_die_for (type, context_die);
dw_die_ref array_die;
/* GNU compilers represent multidimensional array types as sequences of one
flexibilty wrt arrays of variable size. */
bool collapse_nested_arrays = !is_ada ();
+
+ if (fill_variable_array_bounds (type))
+ return;
+
+ dw_die_ref scope_die = scope_die_for (type, context_die);
tree element_type;
/* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
&& DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
{
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
- dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2);
+ dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2, NULL);
size = int_size_in_bytes (TREE_TYPE (szdecl));
if (loc && size > 0)
{
/* For VECTOR_TYPEs we use an array die with appropriate bounds. */
dw_die_ref subrange_die = new_die (DW_TAG_subrange_type, array_die, NULL);
- add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node);
+ add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node, NULL);
add_bound_info (subrange_die, DW_AT_upper_bound,
- size_int (TYPE_VECTOR_SUBPARTS (type) - 1));
+ size_int (TYPE_VECTOR_SUBPARTS (type) - 1), NULL);
}
else
add_subscript_info (array_die, type, collapse_nested_arrays);
add_pubtype (type, array_die);
}
-static dw_loc_descr_ref
-descr_info_loc (tree val, tree base_decl)
-{
- HOST_WIDE_INT size;
- dw_loc_descr_ref loc, loc2;
- enum dwarf_location_atom op;
-
- if (val == base_decl)
- return new_loc_descr (DW_OP_push_object_address, 0, 0);
-
- switch (TREE_CODE (val))
- {
- CASE_CONVERT:
- return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
- case VAR_DECL:
- return loc_descriptor_from_tree (val, 0);
- case INTEGER_CST:
- if (tree_fits_shwi_p (val))
- return int_loc_descriptor (tree_to_shwi (val));
- break;
- case INDIRECT_REF:
- size = int_size_in_bytes (TREE_TYPE (val));
- if (size < 0)
- break;
- loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
- if (!loc)
- break;
- if (size == DWARF2_ADDR_SIZE)
- add_loc_descr (&loc, new_loc_descr (DW_OP_deref, 0, 0));
- else
- add_loc_descr (&loc, new_loc_descr (DW_OP_deref_size, size, 0));
- return loc;
- case POINTER_PLUS_EXPR:
- case PLUS_EXPR:
- if (tree_fits_uhwi_p (TREE_OPERAND (val, 1))
- && tree_to_uhwi (TREE_OPERAND (val, 1)) < 16384)
- {
- loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
- if (!loc)
- break;
- loc_descr_plus_const (&loc, tree_to_shwi (TREE_OPERAND (val, 1)));
- }
- else
- {
- op = DW_OP_plus;
- do_binop:
- loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
- if (!loc)
- break;
- loc2 = descr_info_loc (TREE_OPERAND (val, 1), base_decl);
- if (!loc2)
- break;
- add_loc_descr (&loc, loc2);
- add_loc_descr (&loc2, new_loc_descr (op, 0, 0));
- }
- return loc;
- case MINUS_EXPR:
- op = DW_OP_minus;
- goto do_binop;
- case MULT_EXPR:
- op = DW_OP_mul;
- goto do_binop;
- case EQ_EXPR:
- op = DW_OP_eq;
- goto do_binop;
- case NE_EXPR:
- op = DW_OP_ne;
- goto do_binop;
- default:
- break;
- }
- return NULL;
-}
-
-static void
-add_descr_info_field (dw_die_ref die, enum dwarf_attribute attr,
- tree val, tree base_decl)
-{
- dw_loc_descr_ref loc;
-
- if (tree_fits_shwi_p (val))
- {
- add_AT_unsigned (die, attr, tree_to_shwi (val));
- return;
- }
-
- loc = descr_info_loc (val, base_decl);
- if (!loc)
- return;
-
- add_AT_loc (die, attr, loc);
-}
-
/* This routine generates DIE for array with hidden descriptor, details
are filled into *info by a langhook. */
gen_descr_array_type_die (tree type, struct array_descr_info *info,
dw_die_ref context_die)
{
- dw_die_ref scope_die = scope_die_for (type, context_die);
- dw_die_ref array_die;
+ const dw_die_ref scope_die = scope_die_for (type, context_die);
+ const dw_die_ref array_die = new_die (DW_TAG_array_type, scope_die, type);
+ const struct loc_descr_context context = { type, info->base_decl };
int dim;
- array_die = new_die (DW_TAG_array_type, scope_die, type);
add_name_attribute (array_die, type_tag (type));
equate_type_number_to_die (type, array_die);
- /* For Fortran multidimensional arrays use DW_ORD_col_major ordering. */
- if (is_fortran ()
- && info->ndimensions >= 2)
- add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
+ if (info->ndimensions > 1)
+ switch (info->ordering)
+ {
+ case array_descr_ordering_row_major:
+ add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
+ break;
+ case array_descr_ordering_column_major:
+ add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_col_major);
+ break;
+ default:
+ break;
+ }
- if (info->data_location)
- add_descr_info_field (array_die, DW_AT_data_location, info->data_location,
- info->base_decl);
- if (info->associated)
- add_descr_info_field (array_die, DW_AT_associated, info->associated,
- info->base_decl);
- if (info->allocated)
- add_descr_info_field (array_die, DW_AT_allocated, info->allocated,
- info->base_decl);
+ if (dwarf_version >= 3 || !dwarf_strict)
+ {
+ if (info->data_location)
+ add_scalar_info (array_die, DW_AT_data_location, info->data_location,
+ dw_scalar_form_exprloc, &context);
+ if (info->associated)
+ add_scalar_info (array_die, DW_AT_associated, info->associated,
+ dw_scalar_form_constant
+ | dw_scalar_form_exprloc
+ | dw_scalar_form_reference, &context);
+ if (info->allocated)
+ add_scalar_info (array_die, DW_AT_allocated, info->allocated,
+ dw_scalar_form_constant
+ | dw_scalar_form_exprloc
+ | dw_scalar_form_reference, &context);
+ }
+
+ add_gnat_descriptive_type_attribute (array_die, type, context_die);
for (dim = 0; dim < info->ndimensions; dim++)
{
dw_die_ref subrange_die
= new_die (DW_TAG_subrange_type, array_die, NULL);
+ if (info->dimen[dim].bounds_type)
+ add_type_attribute (subrange_die,
+ info->dimen[dim].bounds_type, 0,
+ context_die);
if (info->dimen[dim].lower_bound)
- {
- /* If it is the default value, omit it. */
- int dflt;
-
- if (tree_fits_shwi_p (info->dimen[dim].lower_bound)
- && (dflt = lower_bound_default ()) != -1
- && tree_to_shwi (info->dimen[dim].lower_bound) == dflt)
- ;
- else
- add_descr_info_field (subrange_die, DW_AT_lower_bound,
- info->dimen[dim].lower_bound,
- info->base_decl);
- }
+ add_bound_info (subrange_die, DW_AT_lower_bound,
+ info->dimen[dim].lower_bound, &context);
if (info->dimen[dim].upper_bound)
- add_descr_info_field (subrange_die, DW_AT_upper_bound,
- info->dimen[dim].upper_bound,
- info->base_decl);
- if (info->dimen[dim].stride)
- add_descr_info_field (subrange_die, DW_AT_byte_stride,
- info->dimen[dim].stride,
- info->base_decl);
+ add_bound_info (subrange_die, DW_AT_upper_bound,
+ info->dimen[dim].upper_bound, &context);
+ if ((dwarf_version >= 3 || !dwarf_strict) && info->dimen[dim].stride)
+ add_scalar_info (subrange_die, DW_AT_byte_stride,
+ info->dimen[dim].stride,
+ dw_scalar_form_constant
+ | dw_scalar_form_exprloc
+ | dw_scalar_form_reference,
+ &context);
}
gen_type_die (info->element_type, context_die);
{
tree node_or_origin = node ? node : origin;
tree ultimate_origin;
- dw_die_ref parm_die
- = new_die (DW_TAG_formal_parameter, context_die, node);
+ dw_die_ref parm_die = NULL;
+
+ if (TREE_CODE_CLASS (TREE_CODE (node_or_origin)) == tcc_declaration)
+ {
+ parm_die = lookup_decl_die (node);
+
+ /* If the contexts differ, we may not be talking about the same
+ thing. */
+ if (parm_die && parm_die->die_parent != context_die)
+ {
+ if (!DECL_ABSTRACT_P (node))
+ {
+ /* This can happen when creating an inlined instance, in
+ which case we need to create a new DIE that will get
+ annotated with DW_AT_abstract_origin. */
+ parm_die = NULL;
+ }
+ else
+ {
+ /* FIXME: Reuse DIE even with a differing context.
+
+ This can happen when calling
+ dwarf2out_abstract_function to build debug info for
+ the abstract instance of a function for which we have
+ already generated a DIE in
+ dwarf2out_early_global_decl.
+
+ Once we remove dwarf2out_abstract_function, we should
+ have a call to gcc_unreachable here. */
+ }
+ }
+
+ if (parm_die && parm_die->die_parent == NULL)
+ {
+ /* Check that parm_die already has the right attributes that
+ we would have added below. If any attributes are
+ missing, fall through to add them. */
+ if (! DECL_ABSTRACT_P (node_or_origin)
+ && !get_AT (parm_die, DW_AT_location)
+ && !get_AT (parm_die, DW_AT_const_value))
+ /* We are missing location info, and are about to add it. */
+ ;
+ else
+ {
+ add_child_die (context_die, parm_die);
+ return parm_die;
+ }
+ }
+ }
+
+ /* If we have a previously generated DIE, use it, unless this is an
+ concrete instance (origin != NULL), in which case we need a new
+ DIE with a corresponding DW_AT_abstract_origin. */
+ bool reusing_die;
+ if (parm_die && origin == NULL)
+ reusing_die = true;
+ else
+ {
+ parm_die = new_die (DW_TAG_formal_parameter, context_die, node);
+ reusing_die = false;
+ }
switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
{
ultimate_origin = decl_ultimate_origin (node_or_origin);
if (node || ultimate_origin)
origin = ultimate_origin;
+
+ if (reusing_die)
+ goto add_location;
+
if (origin != NULL)
add_abstract_origin_attribute (parm_die, origin);
else if (emit_name_p)
}
if (origin == NULL && DECL_ARTIFICIAL (node))
add_AT_flag (parm_die, DW_AT_artificial, 1);
-
+ add_location:
if (node && node != origin)
equate_decl_number_to_die (node, parm_die);
if (! DECL_ABSTRACT_P (node_or_origin))
break;
/* Output a (nameless) DIE to represent the formal parameter itself. */
- 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)
+ if (!POINTER_BOUNDS_TYPE_P (formal_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);
+ 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);
}
- else if (arg && DECL_ARTIFICIAL (arg))
- add_AT_flag (parm_die, DW_AT_artificial, 1);
link = TREE_CHAIN (link);
if (arg)
/* Forward declare these functions, because they are mutually recursive
with their set_block_* pairing functions. */
static void set_decl_origin_self (tree);
-static void set_decl_abstract_flags (tree, int);
+static void set_decl_abstract_flags (tree, vec<tree> &);
/* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
for (local_decl = BLOCK_VARS (stmt);
local_decl != NULL_TREE;
local_decl = DECL_CHAIN (local_decl))
- if (! DECL_EXTERNAL (local_decl))
- set_decl_origin_self (local_decl); /* Potential recursion. */
+ /* Do not recurse on nested functions since the inlining status
+ of parent and child can be different as per the DWARF spec. */
+ if (TREE_CODE (local_decl) != FUNCTION_DECL
+ && !DECL_EXTERNAL (local_decl))
+ set_decl_origin_self (local_decl);
}
{
}
}
\f
-/* Given a pointer to some BLOCK node, and a boolean value to set the
- "abstract" flags to, set that value into the BLOCK_ABSTRACT flag for
- the given block, and for all local decls and all local sub-blocks
- (recursively) which are contained therein. */
+/* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
+ and if it wasn't 1 before, push it to abstract_vec vector.
+ For all local decls and all local sub-blocks (recursively) do it
+ too. */
static void
-set_block_abstract_flags (tree stmt, int setting)
+set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
{
tree local_decl;
tree subblock;
unsigned int i;
- BLOCK_ABSTRACT (stmt) = setting;
+ if (!BLOCK_ABSTRACT (stmt))
+ {
+ abstract_vec.safe_push (stmt);
+ BLOCK_ABSTRACT (stmt) = 1;
+ }
for (local_decl = BLOCK_VARS (stmt);
local_decl != NULL_TREE;
local_decl = DECL_CHAIN (local_decl))
if (! DECL_EXTERNAL (local_decl))
- set_decl_abstract_flags (local_decl, setting);
+ set_decl_abstract_flags (local_decl, abstract_vec);
for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
{
local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
if ((TREE_CODE (local_decl) == VAR_DECL && !TREE_STATIC (local_decl))
|| TREE_CODE (local_decl) == PARM_DECL)
- set_decl_abstract_flags (local_decl, setting);
+ set_decl_abstract_flags (local_decl, abstract_vec);
}
for (subblock = BLOCK_SUBBLOCKS (stmt);
subblock != NULL_TREE;
subblock = BLOCK_CHAIN (subblock))
- set_block_abstract_flags (subblock, setting);
+ set_block_abstract_flags (subblock, abstract_vec);
}
-/* Given a pointer to some ..._DECL node, and a boolean value to set the
- "abstract" flags to, set that value into the DECL_ABSTRACT_P flag for the
- given decl, and (in the case where the decl is a FUNCTION_DECL) also
- set the abstract flags for all of the parameters, local vars, local
- blocks and sub-blocks (recursively) to the same setting. */
+/* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
+ to 1 and if it wasn't 1 before, push to abstract_vec vector.
+ In the case where the decl is a FUNCTION_DECL also set the abstract
+ flags for all of the parameters, local vars, local
+ blocks and sub-blocks (recursively). */
static void
-set_decl_abstract_flags (tree decl, int setting)
+set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
{
- DECL_ABSTRACT_P (decl) = setting;
+ if (!DECL_ABSTRACT_P (decl))
+ {
+ abstract_vec.safe_push (decl);
+ DECL_ABSTRACT_P (decl) = 1;
+ }
+
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree arg;
for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
- DECL_ABSTRACT_P (arg) = setting;
+ if (!DECL_ABSTRACT_P (arg))
+ {
+ abstract_vec.safe_push (arg);
+ DECL_ABSTRACT_P (arg) = 1;
+ }
if (DECL_INITIAL (decl) != NULL_TREE
&& DECL_INITIAL (decl) != error_mark_node)
- set_block_abstract_flags (DECL_INITIAL (decl), setting);
+ set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
}
}
/* Generate the DWARF2 info for the "abstract" instance of a function which we
- may later generate inlined and/or out-of-line instances of. */
+ may later generate inlined and/or out-of-line instances of.
+
+ FIXME: In the early-dwarf world, this function, and most of the
+ DECL_ABSTRACT code should be obsoleted. The early DIE _is_
+ the abstract instance. All we would need to do is annotate
+ the early DIE with the appropriate DW_AT_inline in late
+ dwarf (perhaps in gen_inlined_subroutine_die).
+
+ However, we can't do this yet, because LTO streaming of DIEs
+ has not been implemented yet. */
static void
dwarf2out_abstract_function (tree decl)
dw_die_ref old_die;
tree save_fn;
tree context;
- int was_abstract;
hash_table<decl_loc_hasher> *old_decl_loc_table;
hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
int old_call_site_count, old_tail_call_site_count;
save_fn = current_function_decl;
current_function_decl = decl;
- was_abstract = DECL_ABSTRACT_P (decl);
- set_decl_abstract_flags (decl, 1);
+ auto_vec<tree, 64> abstract_vec;
+ set_decl_abstract_flags (decl, abstract_vec);
dwarf2out_decl (decl);
- if (! was_abstract)
- set_decl_abstract_flags (decl, 0);
+ unsigned int i;
+ tree t;
+ FOR_EACH_VEC_ELT (abstract_vec, i, t)
+ if (TREE_CODE (t) == BLOCK)
+ BLOCK_ABSTRACT (t) = 0;
+ else
+ DECL_ABSTRACT_P (t) = 0;
current_function_decl = save_fn;
decl_loc_table = old_decl_loc_table;
&& block != DECL_INITIAL (decl)
&& TREE_CODE (block) == BLOCK)
{
- if (block_map.length () > BLOCK_NUMBER (block))
- stmt_die = block_map[BLOCK_NUMBER (block)];
+ stmt_die = BLOCK_DIE (block);
if (stmt_die)
break;
block = BLOCK_SUPERCONTEXT (block);
{
tree origin = decl_ultimate_origin (decl);
dw_die_ref subr_die;
- tree outer_scope;
dw_die_ref old_die = lookup_decl_die (decl);
+
+ /* This function gets called multiple times for different stages of
+ the debug process. For example, for func() in this code:
+
+ namespace S
+ {
+ void func() { ... }
+ }
+
+ ...we get called 4 times. Twice in early debug and twice in
+ late debug:
+
+ Early debug
+ -----------
+
+ 1. Once while generating func() within the namespace. This is
+ the declaration. The declaration bit below is set, as the
+ context is the namespace.
+
+ A new DIE will be generated with DW_AT_declaration set.
+
+ 2. Once for func() itself. This is the specification. The
+ declaration bit below is clear as the context is the CU.
+
+ We will use the cached DIE from (1) to create a new DIE with
+ DW_AT_specification pointing to the declaration in (1).
+
+ Late debug via rest_of_handle_final()
+ -------------------------------------
+
+ 3. Once generating func() within the namespace. This is also the
+ declaration, as in (1), but this time we will early exit below
+ as we have a cached DIE and a declaration needs no additional
+ annotations (no locations), as the source declaration line
+ info is enough.
+
+ 4. Once for func() itself. As in (2), this is the specification,
+ but this time we will re-use the cached DIE, and just annotate
+ it with the location information that should now be available.
+
+ For something without namespaces, but with abstract instances, we
+ are also called a multiple times:
+
+ class Base
+ {
+ public:
+ Base (); // constructor declaration (1)
+ };
+
+ Base::Base () { } // constructor specification (2)
+
+ Early debug
+ -----------
+
+ 1. Once for the Base() constructor by virtue of it being a
+ member of the Base class. This is done via
+ rest_of_type_compilation.
+
+ This is a declaration, so a new DIE will be created with
+ DW_AT_declaration.
+
+ 2. Once for the Base() constructor definition, but this time
+ while generating the abstract instance of the base
+ constructor (__base_ctor) which is being generated via early
+ debug of reachable functions.
+
+ Even though we have a cached version of the declaration (1),
+ we will create a DW_AT_specification of the declaration DIE
+ in (1).
+
+ 3. Once for the __base_ctor itself, but this time, we generate
+ an DW_AT_abstract_origin version of the DW_AT_specification in
+ (2).
+
+ Late debug via rest_of_handle_final
+ -----------------------------------
+
+ 4. One final time for the __base_ctor (which will have a cached
+ DIE with DW_AT_abstract_origin created in (3). This time,
+ we will just annotate the location information now
+ available.
+ */
int declaration = (current_function_decl != decl
|| class_or_namespace_scope_p (context_die));
premark_used_types (DECL_STRUCT_FUNCTION (decl));
- /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
- started to generate the abstract instance of an inline, decided to output
- its containing class, and proceeded to emit the declaration of the inline
- from the member list for the class. If so, DECLARATION takes priority;
- we'll get back to the abstract instance when done with the class. */
-
- /* The class-scope declaration DIE must be the primary DIE. */
- if (origin && declaration && class_or_namespace_scope_p (context_die))
- {
- origin = NULL;
- gcc_assert (!old_die);
- }
-
/* Now that the C++ front end lazily declares artificial member fns, we
might need to retrofit the declaration into its class. */
if (!declaration && !origin && !old_die
&& debug_info_level > DINFO_LEVEL_TERSE)
old_die = force_decl_die (decl);
+ /* An inlined instance, tag a new DIE with DW_AT_abstract_origin. */
if (origin != NULL)
{
gcc_assert (!declaration || local_scope_p (context_die));
if (old_die && old_die->die_parent == NULL)
add_child_die (context_die, old_die);
- subr_die = new_die (DW_TAG_subprogram, context_die, decl);
- add_abstract_origin_attribute (subr_die, origin);
- /* This is where the actual code for a cloned function is.
- Let's emit linkage name attribute for it. This helps
- debuggers to e.g, set breakpoints into
- constructors/destructors when the user asks "break
- K::K". */
- add_linkage_name (subr_die, decl);
+ if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+ {
+ /* If we have a DW_AT_abstract_origin we have a working
+ cached version. */
+ subr_die = old_die;
+ }
+ else
+ {
+ subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+ add_abstract_origin_attribute (subr_die, origin);
+ /* This is where the actual code for a cloned function is.
+ Let's emit linkage name attribute for it. This helps
+ debuggers to e.g, set breakpoints into
+ constructors/destructors when the user asks "break
+ K::K". */
+ add_linkage_name (subr_die, decl);
+ }
}
+ /* A cached copy, possibly from early dwarf generation. Reuse as
+ much as possible. */
else if (old_die)
{
- expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- struct dwarf_file_data * file_index = lookup_filename (s.file);
+ /* A declaration that has been previously dumped needs no
+ additional information. */
+ if (declaration)
+ return;
if (!get_AT_flag (old_die, DW_AT_declaration)
/* We can have a normal definition following an inline one in the
{
/* Detect and ignore this case, where we are trying to output
something we have already output. */
- return;
+ if (get_AT (old_die, DW_AT_low_pc)
+ || get_AT (old_die, DW_AT_ranges))
+ return;
+
+ /* If we have no location information, this must be a
+ partially generated DIE from early dwarf generation.
+ Fall through and generate it. */
}
/* If the definition comes from the same place as the declaration,
instances of inlines, since the spec requires the out-of-line copy
to have the same parent. For local class methods, this doesn't
apply; we just use the old DIE. */
- if ((is_cu_die (old_die->die_parent) || context_die == NULL)
- && (DECL_ARTIFICIAL (decl)
- || (get_AT_file (old_die, DW_AT_decl_file) == file_index
- && (get_AT_unsigned (old_die, DW_AT_decl_line)
- == (unsigned) s.line))))
+ 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)
+ && (DECL_ARTIFICIAL (decl)
+ || (get_AT_file (old_die, DW_AT_decl_file) == file_index
+ && (get_AT_unsigned (old_die, DW_AT_decl_line)
+ == (unsigned) s.line))))
{
subr_die = old_die;
- /* Clear out the declaration attribute and the formal parameters.
- Do not remove all children, because it is possible that this
- declaration die was forced using force_decl_die(). In such
- cases die that forced declaration die (e.g. TAG_imported_module)
- is one of the children that we do not want to remove. */
- remove_AT (subr_die, DW_AT_declaration);
- remove_AT (subr_die, DW_AT_object_pointer);
- remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+ /* Clear out the declaration attribute, but leave the
+ parameters so they can be augmented with location
+ information later. Unless this was a declaration, in
+ which case, wipe out the nameless parameters and recreate
+ them further down. */
+ if (remove_AT (subr_die, DW_AT_declaration))
+ {
+
+ remove_AT (subr_die, DW_AT_object_pointer);
+ remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+ }
}
+ /* Make a specification pointing to the previously built
+ declaration. */
else
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
}
}
}
+ /* Create a fresh DIE for anything else. */
else
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
if (DECL_ARTIFICIAL (decl))
add_AT_flag (subr_die, DW_AT_artificial, 1);
+ if (TREE_THIS_VOLATILE (decl) && (dwarf_version >= 5 || !dwarf_strict))
+ add_AT_flag (subr_die, DW_AT_noreturn, 1);
+
add_accessibility_attribute (subr_die, decl);
}
+ /* Unless we have an existing non-declaration DIE, equate the new
+ DIE. */
+ if (!old_die || is_declaration_die (old_die))
+ equate_decl_number_to_die (decl, subr_die);
+
if (declaration)
{
if (!old_die || !get_AT (old_die, DW_AT_inline))
if (lang_hooks.decls.function_decl_deleted_p (decl)
&& (! dwarf_strict))
add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
-
- /* The first time we see a member function, it is in the context of
- the class to which it belongs. We make sure of this by emitting
- the class first. The next time is the definition, which is
- handled above. The two may come from the same source text.
-
- Note that force_decl_die() forces function declaration die. It is
- later reused to represent definition. */
- equate_decl_number_to_die (decl, subr_die);
}
}
+ /* Tag abstract instances with DW_AT_inline. */
else if (DECL_ABSTRACT_P (decl))
{
if (DECL_DECLARED_INLINE_P (decl))
if (DECL_DECLARED_INLINE_P (decl)
&& lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
add_AT_flag (subr_die, DW_AT_artificial, 1);
-
- equate_decl_number_to_die (decl, subr_die);
}
- else if (!DECL_EXTERNAL (decl))
+ /* For non DECL_EXTERNALs, if range information is available, fill
+ the DIE with it. */
+ else if (!DECL_EXTERNAL (decl) && !early_dwarf)
{
HOST_WIDE_INT cfa_fb_offset;
- struct function *fun = DECL_STRUCT_FUNCTION (decl);
- if (!old_die || !get_AT (old_die, DW_AT_inline))
- equate_decl_number_to_die (decl, subr_die);
+ struct function *fun = DECL_STRUCT_FUNCTION (decl);
- gcc_checking_assert (fun);
if (!flag_reorder_blocks_and_partition)
{
dw_fde_ref fde = fun->fde;
compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
if (fun->static_chain_decl)
- add_AT_location_description (subr_die, DW_AT_static_link,
- loc_list_from_tree (fun->static_chain_decl, 2));
+ add_AT_location_description
+ (subr_die, DW_AT_static_link,
+ loc_list_from_tree (fun->static_chain_decl, 2, NULL));
}
/* Generate child dies for template paramaters. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
+ if (early_dwarf && debug_info_level > DINFO_LEVEL_TERSE)
gen_generic_params_dies (decl);
/* Now output descriptions of the arguments for this function. This gets
{
/* Generate DIEs to represent all known formal parameters. */
tree parm = DECL_ARGUMENTS (decl);
- tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+ tree generic_decl = early_dwarf
+ ? lang_hooks.decls.get_generic_function_decl (decl) : NULL;
tree generic_decl_parm = generic_decl
? DECL_ARGUMENTS (generic_decl)
: NULL;
gen_formal_parameter_pack_die (generic_decl_parm,
parm, subr_die,
&parm);
- else if (parm)
+ else if (parm && !POINTER_BOUNDS_P (parm))
{
dw_die_ref parm_die = gen_decl_die (parm, NULL, subr_die);
parm = DECL_CHAIN (parm);
}
+ else if (parm)
+ parm = DECL_CHAIN (parm);
if (generic_decl_parm)
generic_decl_parm = DECL_CHAIN (generic_decl_parm);
gen_unspecified_parameters_die (decl, subr_die);
}
+ if (subr_die != old_die)
+ /* Add the calling convention attribute if requested. */
+ add_calling_convention_attribute (subr_die, decl);
+
/* Output Dwarf info for all of the stuff within the body of the function
- (if it has one - it may be just a declaration). */
- outer_scope = DECL_INITIAL (decl);
+ (if it has one - it may be just a declaration).
- /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+ OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
a function. This BLOCK actually represents the outermost binding contour
for the function, i.e. the contour in which the function's formal
parameters and labels get declared. Curiously, it appears that the front
a BLOCK node representing the function's outermost pair of curly braces,
and any blocks used for the base and member initializers of a C++
constructor function. */
+ tree outer_scope = DECL_INITIAL (decl);
if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
{
int call_site_note_count = 0;
if (DECL_NAME (DECL_RESULT (decl)))
gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
- decls_for_scope (outer_scope, subr_die, 0);
+ /* The first time through decls_for_scope we will generate the
+ DIEs for the locals. The second time, we fill in the
+ location info. */
+ decls_for_scope (outer_scope, subr_die);
if (call_arg_locations && !dwarf_strict)
{
arg; arg = next_arg)
{
dw_loc_descr_ref reg, val;
- enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
+ machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
dw_die_ref cdie, tdie = NULL;
next_arg = XEXP (arg, 1);
call_site_count = -1;
tail_call_site_count = -1;
}
-
- if (subr_die != old_die)
- /* Add the calling convention attribute if requested. */
- add_calling_convention_attribute (subr_die, decl);
}
/* Returns a hash value for X (which really is a die_struct). */
return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
}
+/* Return TRUE if DECL, which may have been previously generated as
+ OLD_DIE, is a candidate for a DW_AT_specification. DECLARATION is
+ true if decl (or its origin) is either an extern declaration or a
+ class/namespace scoped declaration.
+
+ The declare_in_namespace support causes us to get two DIEs for one
+ variable, both of which are declarations. We want to avoid
+ considering one to be a specification, so we must test for
+ DECLARATION and DW_AT_declaration. */
+static inline bool
+decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration)
+{
+ return (old_die && TREE_STATIC (decl) && !declaration
+ && get_AT_flag (old_die, DW_AT_declaration) == 1);
+}
+
+/* Return true if DECL is a local static. */
+
+static inline bool
+local_function_static (tree decl)
+{
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ return TREE_STATIC (decl)
+ && DECL_CONTEXT (decl)
+ && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
/* Generate a DIE to represent a declared data object.
Either DECL or ORIGIN must be non-null. */
tree ultimate_origin;
dw_die_ref var_die;
dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
- dw_die_ref origin_die;
+ dw_die_ref origin_die = NULL;
bool declaration = (DECL_EXTERNAL (decl_or_origin)
|| class_or_namespace_scope_p (context_die));
bool specialization_p = false;
{
if (get_AT (var_die, DW_AT_location) == NULL)
{
- loc = loc_list_from_tree (com_decl, off ? 1 : 2);
+ loc = loc_list_from_tree (com_decl, off ? 1 : 2, NULL);
if (loc)
{
if (off)
com_die_arg.decl_id = DECL_UID (com_decl);
com_die_arg.die_parent = context_die;
com_die = common_block_die_table->find (&com_die_arg);
- loc = loc_list_from_tree (com_decl, 2);
+ loc = loc_list_from_tree (com_decl, 2, NULL);
if (com_die == NULL)
{
const char *cnam
add_AT_location_description (com_die, DW_AT_location, loc);
/* Avoid sharing the same loc descriptor between
DW_TAG_common_block and DW_TAG_variable. */
- loc = loc_list_from_tree (com_decl, 2);
+ loc = loc_list_from_tree (com_decl, 2, NULL);
}
else if (DECL_EXTERNAL (decl))
add_AT_flag (com_die, DW_AT_declaration, 1);
else if (get_AT (com_die, DW_AT_location) == NULL && loc)
{
add_AT_location_description (com_die, DW_AT_location, loc);
- loc = loc_list_from_tree (com_decl, 2);
+ loc = loc_list_from_tree (com_decl, 2, NULL);
remove_AT (com_die, DW_AT_declaration);
}
var_die = new_die (DW_TAG_variable, com_die, decl);
return;
}
- /* If the compiler emitted a definition for the DECL declaration
- and if we already emitted a DIE for it, don't emit a second
- DIE for it again. Allow re-declarations of DECLs that are
- inside functions, though. */
- if (old_die && declaration && !local_scope_p (context_die))
- return;
+ if (old_die)
+ {
+ if (declaration)
+ {
+ /* A declaration that has been previously dumped, needs no
+ further annotations, since it doesn't need location on
+ the second pass. */
+ return;
+ }
+ else if (decl_will_get_specification_p (old_die, decl, declaration)
+ && !get_AT (old_die, DW_AT_specification))
+ {
+ /* Fall-thru so we can make a new variable die along with a
+ DW_AT_specification. */
+ }
+ else if (origin && old_die->die_parent != context_die)
+ {
+ /* If we will be creating an inlined instance, we need a
+ new DIE that will get annotated with
+ DW_AT_abstract_origin. Clear things so we can get a
+ new DIE. */
+ gcc_assert (!DECL_ABSTRACT_P (decl));
+ old_die = NULL;
+ }
+ else
+ {
+ /* If a DIE was dumped early, it still needs location info.
+ Skip to where we fill the location bits. */
+ var_die = old_die;
+ goto gen_variable_die_location;
+ }
+ }
/* For static data members, the declaration in the class is supposed
to have DW_TAG_member tag; the specification should still be
else
var_die = new_die (DW_TAG_variable, context_die, decl);
- origin_die = NULL;
if (origin != NULL)
origin_die = add_abstract_origin_attribute (var_die, origin);
copy decls and set the DECL_ABSTRACT_P flag on them instead of
sharing them.
- ??? Duplicated blocks have been rewritten to use .debug_ranges.
-
- ??? The declare_in_namespace support causes us to get two DIEs for one
- variable, both of which are declarations. We want to avoid considering
- one to be a specification, so we must test that this DIE is not a
- declaration. */
- else if (old_die && TREE_STATIC (decl) && ! declaration
- && get_AT_flag (old_die, DW_AT_declaration) == 1)
+ ??? Duplicated blocks have been rewritten to use .debug_ranges. */
+ else if (decl_will_get_specification_p (old_die, decl, declaration))
{
/* This is a definition of a C++ class level static. */
add_AT_specification (var_die, old_die);
if (declaration)
add_AT_flag (var_die, DW_AT_declaration, 1);
- if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL))
+ if (decl && (DECL_ABSTRACT_P (decl)
+ || !old_die || is_declaration_die (old_die)))
equate_decl_number_to_die (decl, var_die);
+ gen_variable_die_location:
if (! declaration
&& (! DECL_ABSTRACT_P (decl_or_origin)
/* Local static vars are shared between all clones/inlines,
to add it again. */
&& (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
{
- if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
- && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
- defer_location (decl_or_origin, var_die);
+ if (early_dwarf)
+ add_pubname (decl_or_origin, var_die);
else
- add_location_or_const_value_attribute (var_die, decl_or_origin,
+ add_location_or_const_value_attribute (var_die, decl_or_origin,
decl == NULL, DW_AT_location);
- add_pubname (decl_or_origin, var_die);
}
else
tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
dw_die_ref const_die;
tree type = TREE_TYPE (decl);
+ const_die = lookup_decl_die (decl);
+ if (const_die)
+ return;
+
const_die = new_die (DW_TAG_constant, context_die, decl);
+ equate_decl_number_to_die (decl, const_die);
add_name_and_src_coords_attributes (const_die, decl);
add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
if (TREE_PUBLIC (decl))
gen_label_die (tree decl, dw_die_ref context_die)
{
tree origin = decl_ultimate_origin (decl);
- dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+ dw_die_ref lbl_die = lookup_decl_die (decl);
rtx insn;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (origin != NULL)
- add_abstract_origin_attribute (lbl_die, origin);
- else
- add_name_and_src_coords_attributes (lbl_die, decl);
+ if (!lbl_die)
+ {
+ lbl_die = new_die (DW_TAG_label, context_die, decl);
+ equate_decl_number_to_die (decl, lbl_die);
+
+ if (origin != NULL)
+ add_abstract_origin_attribute (lbl_die, origin);
+ else
+ add_name_and_src_coords_attributes (lbl_die, decl);
+ }
if (DECL_ABSTRACT_P (decl))
equate_decl_number_to_die (decl, lbl_die);
/* Generate a DIE for a lexical block. */
static void
-gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth)
+gen_lexical_block_die (tree stmt, dw_die_ref context_die)
{
- dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+ dw_die_ref old_die = 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;
+ }
- if (call_arg_locations)
+ if (BLOCK_ABSTRACT (stmt))
{
- if (block_map.length () <= BLOCK_NUMBER (stmt))
- block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
- block_map[BLOCK_NUMBER (stmt)] = stmt_die;
+ if (old_die)
+ {
+#ifdef ENABLE_CHECKING
+ /* This must have been generated early and it won't even
+ need location information since it's a DW_AT_inline
+ function. */
+ 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;
+ }
+#endif
+ 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;
+ }
}
- if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
- add_high_low_attributes (stmt, stmt_die);
+ if (old_die)
+ stmt_die = old_die;
- decls_for_scope (stmt, stmt_die, depth);
+ /* 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))
+ {
+ gcc_assert (stmt_die);
+ add_high_low_attributes (stmt, stmt_die);
+ }
+
+ decls_for_scope (stmt, stmt_die);
}
/* Generate a DIE for an inlined subprogram. */
static void
-gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth)
+gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
{
tree decl;
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
if (call_arg_locations)
- {
- if (block_map.length () <= BLOCK_NUMBER (stmt))
- block_map.safe_grow_cleared (BLOCK_NUMBER (stmt) + 1);
- block_map[BLOCK_NUMBER (stmt)] = subr_die;
- }
+ 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);
- decls_for_scope (stmt, subr_die, depth);
+ decls_for_scope (stmt, subr_die);
}
}
case OPT__sysroot_:
case OPT_nostdinc:
case OPT_nostdinc__:
+ case OPT_fpreprocessed:
+ case OPT_fltrans_output_list_:
+ case OPT_fresolution_:
/* Ignore these. */
continue;
default:
return producer;
}
+/* Given a C and/or C++ language/version string return the "highest".
+ C++ is assumed to be "higher" than C in this case. Used for merging
+ LTO translation unit languages. */
+static const char *
+highest_c_language (const char *lang1, const char *lang2)
+{
+ if (strcmp ("GNU C++14", lang1) == 0 || strcmp ("GNU C++14", lang2) == 0)
+ return "GNU C++14";
+ if (strcmp ("GNU C++11", lang1) == 0 || strcmp ("GNU C++11", lang2) == 0)
+ return "GNU C++11";
+ if (strcmp ("GNU C++98", lang1) == 0 || strcmp ("GNU C++98", lang2) == 0)
+ return "GNU C++98";
+
+ if (strcmp ("GNU C11", lang1) == 0 || strcmp ("GNU C11", lang2) == 0)
+ return "GNU C11";
+ if (strcmp ("GNU C99", lang1) == 0 || strcmp ("GNU C99", lang2) == 0)
+ return "GNU C99";
+ if (strcmp ("GNU C89", lang1) == 0 || strcmp ("GNU C89", lang2) == 0)
+ return "GNU C89";
+
+ gcc_unreachable ();
+}
+
+
/* Generate the DIE for the compilation unit. */
static dw_die_ref
else if (strncmp (common_lang, "GNU C", 5) == 0
&& strncmp (TRANSLATION_UNIT_LANGUAGE (t), "GNU C", 5) == 0)
/* Mixing C and C++ is ok, use C++ in that case. */
- common_lang = "GNU C++";
+ common_lang = highest_c_language (common_lang,
+ TRANSLATION_UNIT_LANGUAGE (t));
else
{
/* Fall back to C. */
language_string = common_lang;
}
- language = DW_LANG_C89;
- if (strcmp (language_string, "GNU C++") == 0)
- language = DW_LANG_C_plus_plus;
+ language = DW_LANG_C;
+ if (strncmp (language_string, "GNU C", 5) == 0
+ && ISDIGIT (language_string[5]))
+ {
+ language = DW_LANG_C89;
+ if (dwarf_version >= 3 || !dwarf_strict)
+ {
+ if (strcmp (language_string, "GNU C89") != 0)
+ language = DW_LANG_C99;
+
+ if (dwarf_version >= 5 /* || !dwarf_strict */)
+ if (strcmp (language_string, "GNU C11") == 0)
+ language = DW_LANG_C11;
+ }
+ }
+ else if (strncmp (language_string, "GNU C++", 7) == 0)
+ {
+ language = DW_LANG_C_plus_plus;
+ if (dwarf_version >= 5 /* || !dwarf_strict */)
+ {
+ if (strcmp (language_string, "GNU C++11") == 0)
+ language = DW_LANG_C_plus_plus_11;
+ else if (strcmp (language_string, "GNU C++14") == 0)
+ language = DW_LANG_C_plus_plus_14;
+ }
+ }
else if (strcmp (language_string, "GNU F77") == 0)
language = DW_LANG_Fortran77;
else if (strcmp (language_string, "GNU Pascal") == 0)
{
if (strcmp (language_string, "GNU Ada") == 0)
language = DW_LANG_Ada95;
- else if (strcmp (language_string, "GNU Fortran") == 0)
- language = DW_LANG_Fortran95;
+ else if (strncmp (language_string, "GNU Fortran", 11) == 0)
+ {
+ language = DW_LANG_Fortran95;
+ if (dwarf_version >= 5 /* || !dwarf_strict */)
+ {
+ if (strcmp (language_string, "GNU Fortran2003") == 0)
+ language = DW_LANG_Fortran03;
+ else if (strcmp (language_string, "GNU Fortran2008") == 0)
+ language = DW_LANG_Fortran08;
+ }
+ }
else if (strcmp (language_string, "GNU Java") == 0)
language = DW_LANG_Java;
else if (strcmp (language_string, "GNU Objective-C") == 0)
}
}
/* Use a degraded Fortran setting in strict DWARF2 so is_fortran works. */
- else if (strcmp (language_string, "GNU Fortran") == 0)
+ else if (strncmp (language_string, "GNU Fortran", 11) == 0)
language = DW_LANG_Fortran90;
add_AT_unsigned (die, DW_AT_language, language);
case DW_LANG_Fortran77:
case DW_LANG_Fortran90:
case DW_LANG_Fortran95:
+ case DW_LANG_Fortran03:
+ case DW_LANG_Fortran08:
/* Fortran has case insensitive identifiers and the front-end
lowercases everything. */
add_AT_unsigned (die, DW_AT_identifier_case, DW_ID_down_case);
/* If we thought we were generating minimal debug info for TYPE
and then changed our minds, some of the member declarations
may have already been defined. Don't define them again, but
- do put them in the right order. */
-
- child = lookup_decl_die (member);
- if (child)
- splice_child_die (context_die, child);
- else
- gen_decl_die (member, NULL, context_die);
- }
-
- /* Now output info about the function members (if any). */
- for (member = TYPE_METHODS (type); member; member = DECL_CHAIN (member))
- {
- /* Don't include clones in the member list. */
- if (DECL_ABSTRACT_ORIGIN (member))
- continue;
+ do put them in the right order. */
child = lookup_decl_die (member);
if (child)
else
gen_decl_die (member, NULL, context_die);
}
+
+ /* We do not keep type methods in type variants. */
+ gcc_assert (TYPE_MAIN_VARIANT (type) == type);
+ /* Now output info about the function members (if any). */
+ if (TYPE_METHODS (type) != error_mark_node)
+ for (member = TYPE_METHODS (type); member; member = DECL_CHAIN (member))
+ {
+ /* Don't include clones in the member list. */
+ if (DECL_ABSTRACT_ORIGIN (member))
+ continue;
+ /* Nor constructors for anonymous classes. */
+ if (DECL_ARTIFICIAL (member)
+ && dwarf2_name (member, 0) == NULL)
+ continue;
+
+ child = lookup_decl_die (member);
+ if (child)
+ splice_child_die (context_die, child);
+ else
+ gen_decl_die (member, NULL, context_die);
+ }
}
/* Generate a DIE for a structure or union type. If TYPE_DECL_SUPPRESS_DEBUG
gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
enum debug_info_usage usage)
{
+ if (TREE_ASM_WRITTEN (type))
+ {
+ /* Fill in the bound of variable-length fields in late dwarf if
+ still incomplete. */
+ if (!early_dwarf && variably_modified_type_p (type, NULL))
+ for (tree member = TYPE_FIELDS (type);
+ member;
+ member = DECL_CHAIN (member))
+ fill_variable_array_bounds (TREE_TYPE (member));
+ return;
+ }
+
dw_die_ref type_die = lookup_type_die (type);
dw_die_ref scope_die = 0;
int nested = 0;
tree origin;
if (TREE_ASM_WRITTEN (decl))
- return;
+ {
+ if (DECL_ORIGINAL_TYPE (decl))
+ fill_variable_array_bounds (DECL_ORIGINAL_TYPE (decl));
+ return;
+ }
TREE_ASM_WRITTEN (decl) = 1;
type_die = new_die (DW_TAG_typedef, context_die, decl);
{
type = DECL_ORIGINAL_TYPE (decl);
+ if (type == error_mark_node)
+ return;
+
gcc_assert (type != TREE_TYPE (decl));
equate_type_number_to_die (TREE_TYPE (decl), type_die);
}
{
type = TREE_TYPE (decl);
+ if (type == error_mark_node)
+ return;
+
if (is_naming_typedef_decl (TYPE_NAME (type)))
{
/* Here, we are in the case of decl being a typedef naming
|| !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
the containing class as they are generated. FIXME: This hurts the
idea of combining type decls from multiple TUs, since we can't predict
what set of template instantiations we'll get. */
- if (TYPE_CONTEXT (type)
+ else if (TYPE_CONTEXT (type)
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
{
if (type == NULL_TREE || type == error_mark_node)
return;
+#ifdef ENABLE_CHECKING
+ if (type)
+ verify_type (type);
+#endif
+
if (TYPE_NAME (type) != NULL_TREE
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& is_redundant_typedef (TYPE_NAME (type))
return;
}
- /* If this is an array type with hidden descriptor, handle it first. */
- if (!TREE_ASM_WRITTEN (type)
- && lang_hooks.types.get_array_descr_info
- && lang_hooks.types.get_array_descr_info (type, &info)
- && (dwarf_version >= 3 || !dwarf_strict))
- {
- gen_descr_array_type_die (type, &info, context_die);
- TREE_ASM_WRITTEN (type) = 1;
- return;
- }
-
/* We are going to output a DIE to represent the unqualified version
of this type (i.e. without any const or volatile qualifiers) so
get the main variant (i.e. the unqualified version) of this type
if (TREE_CODE (type) != VECTOR_TYPE)
type = type_main_variant (type);
+ /* If this is an array type with hidden descriptor, handle it first. */
+ if (!TREE_ASM_WRITTEN (type)
+ && lang_hooks.types.get_array_descr_info)
+ {
+ memset (&info, 0, sizeof (info));
+ if (lang_hooks.types.get_array_descr_info (type, &info))
+ {
+ gen_descr_array_type_die (type, &info, context_die);
+ TREE_ASM_WRITTEN (type) = 1;
+ return;
+ }
+ }
+
if (TREE_ASM_WRITTEN (type))
- return;
+ {
+ /* Variable-length types may be incomplete even if
+ TREE_ASM_WRITTEN. For such types, fall through to
+ gen_array_type_die() and possibly fill in
+ DW_AT_{upper,lower}_bound attributes. */
+ if ((TREE_CODE (type) != ARRAY_TYPE
+ && TREE_CODE (type) != RECORD_TYPE
+ && TREE_CODE (type) != UNION_TYPE
+ && TREE_CODE (type) != QUAL_UNION_TYPE)
+ || !variably_modified_type_p (type, NULL))
+ return;
+ }
switch (TREE_CODE (type))
{
break;
case ARRAY_TYPE:
- gen_array_type_die (type, context_die);
- break;
-
case VECTOR_TYPE:
gen_array_type_die (type, context_die);
break;
case FIXED_POINT_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
+ case POINTER_BOUNDS_TYPE:
/* No DIEs needed for fundamental types. */
break;
static void
gen_type_die (tree type, dw_die_ref context_die)
{
- gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE);
+ if (type != error_mark_node)
+ {
+ gen_type_die_with_usage (type, context_die, DINFO_USAGE_DIR_USE);
+#ifdef ENABLE_CHECKING
+ dw_die_ref die = lookup_type_die (type);
+ if (die)
+ check_die (die);
+#endif
+ }
}
/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
things which are local to the given block. */
static void
-gen_block_die (tree stmt, dw_die_ref context_die, int depth)
+gen_block_die (tree stmt, dw_die_ref context_die)
{
int must_output_die = 0;
bool inlined_func;
tree sub;
for (sub = BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
- gen_block_die (sub, context_die, depth + 1);
+ gen_block_die (sub, context_die);
return;
}
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, depth);
+ gen_inlined_subroutine_die (stmt, context_die);
}
else
- gen_lexical_block_die (stmt, context_die, depth);
+ gen_lexical_block_die (stmt, context_die);
}
else
- decls_for_scope (stmt, context_die, depth);
+ decls_for_scope (stmt, context_die);
}
/* Process variable DECL (or variable with origin ORIGIN) within
if (die != NULL && die->die_parent == NULL)
add_child_die (context_die, die);
else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
- dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
- stmt, context_die);
+ {
+ if (early_dwarf)
+ dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+ stmt, context_die);
+ }
else
gen_decl_die (decl, origin, context_die);
}
all of its sub-blocks. */
static void
-decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
+decls_for_scope (tree stmt, dw_die_ref context_die)
{
tree decl;
unsigned int i;
for (subblocks = BLOCK_SUBBLOCKS (stmt);
subblocks != NULL;
subblocks = BLOCK_CHAIN (subblocks))
- gen_block_die (subblocks, context_die, depth + 1);
+ gen_block_die (subblocks, context_die);
}
/* Is this a typedef we can avoid emitting? */
!= TYPE_NAME (TREE_TYPE (decl))));
}
+/* Looks up the DIE for a context. */
+
+static inline dw_die_ref
+lookup_context_die (tree context)
+{
+ if (context)
+ {
+ /* Find die that represents this context. */
+ if (TYPE_P (context))
+ {
+ context = TYPE_MAIN_VARIANT (context);
+ dw_die_ref ctx = lookup_type_die (context);
+ if (!ctx)
+ return NULL;
+ return strip_naming_typedef (context, ctx);
+ }
+ else
+ return lookup_decl_die (context);
+ }
+ return comp_unit_die ();
+}
+
/* Returns the DIE for a context. */
static inline dw_die_ref
type) within its namespace, if appropriate.
For compatibility with older debuggers, namespace DIEs only contain
- declarations; all definitions are emitted at CU scope. */
+ declarations; all definitions are emitted at CU scope, with
+ DW_AT_specification pointing to the declaration (like with class
+ members). */
static dw_die_ref
declare_in_namespace (tree thing, dw_die_ref context_die)
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:
return NULL;
}
\f
-/* Output debug information for global decl DECL. Called from toplev.c after
- compilation proper has finished. */
+/* Output initial debug information for global DECL. Called at the
+ end of the parsing process.
+
+ This is the initial debug generation process. As such, the DIEs
+ generated may be incomplete. A later debug generation pass
+ (dwarf2out_late_global_decl) will augment the information generated
+ in this pass (e.g., with complete location info). */
+
+static void
+dwarf2out_early_global_decl (tree decl)
+{
+ set_early_dwarf s;
+
+ /* gen_decl_die() will set DECL_ABSTRACT because
+ cgraph_function_possibly_inlined_p() returns true. This is in
+ turn will cause DW_AT_inline attributes to be set.
+
+ This happens because at early dwarf generation, there is no
+ cgraph information, causing cgraph_function_possibly_inlined_p()
+ to return true. Trick cgraph_function_possibly_inlined_p()
+ while we generate dwarf early. */
+ bool save = symtab->global_info_ready;
+ symtab->global_info_ready = true;
+
+ /* We don't handle TYPE_DECLs. If required, they'll be reached via
+ other DECLs and they can point to template types or other things
+ that dwarf2out can't handle when done via dwarf2out_decl. */
+ if (TREE_CODE (decl) != TYPE_DECL
+ && TREE_CODE (decl) != PARM_DECL)
+ {
+ tree save_fndecl = current_function_decl;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* No cfun means the symbol has no body, so there's nothing
+ to emit. */
+ if (!DECL_STRUCT_FUNCTION (decl))
+ goto early_decl_exit;
+
+ current_function_decl = decl;
+ }
+ dwarf2out_decl (decl);
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ current_function_decl = save_fndecl;
+ }
+ early_decl_exit:
+ symtab->global_info_ready = save;
+}
+
+/* Output debug information for global decl DECL. Called from
+ toplev.c after compilation proper has finished. */
static void
-dwarf2out_global_decl (tree decl)
+dwarf2out_late_global_decl (tree decl)
{
- /* Output DWARF2 information for file-scope tentative data object
- declarations, file-scope (extern) function declarations (which
- had no corresponding body) and file-scope tagged type declarations
- and definitions which have not yet been forced out. */
- if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
+ /* Output any global decls we missed or fill-in any location
+ information we were unable to determine on the first pass.
+
+ Skip over functions because they were handled by the
+ debug_hooks->function_decl() call in rest_of_handle_final. */
+ if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
+ && !POINTER_BOUNDS_P (decl))
dwarf2out_decl (decl);
}
dwarf2out_type_decl (tree decl, int local)
{
if (!local)
- dwarf2out_decl (decl);
+ {
+ set_early_dwarf s;
+ dwarf2out_decl (decl);
+ }
}
/* Output debug information for imported module or decl DECL.
gcc_assert (decl);
+ set_early_dwarf s;
+
/* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
We need decl DIE for reference and scope die. First, get DIE for the decl
itself. */
/* OK, now we have DIEs for decl as well as scope. Emit imported die. */
dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
-
}
/* Output debug information for namelists. */
}
-/* Write the debugging output for DECL. */
+/* Write the debugging output for DECL and return the DIE. */
static void
dwarf2out_decl (tree decl)
break;
case VAR_DECL:
- /* Ignore this VAR_DECL if it refers to a file-scope extern data object
- declaration and if the declaration was never even referenced from
- within this entire compilation unit. We suppress these DIEs in
- order to save space in the .debug section (by eliminating entries
- which are probably useless). Note that we must not suppress
- block-local extern declarations (whether used or not) because that
- would screw-up the debugger's name lookup mechanism and cause it to
- miss things which really ought to be in scope at a given point. */
- if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
- return;
-
/* For local statics lookup proper context die. */
- if (TREE_STATIC (decl)
- && DECL_CONTEXT (decl)
- && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+ if (local_function_static (decl))
context_die = lookup_decl_die (DECL_CONTEXT (decl));
/* If we are in terse mode, don't generate any DIEs to represent any
}
gen_decl_die (decl, NULL, context_die);
+
+#ifdef ENABLE_CHECKING
+ dw_die_ref die = lookup_decl_die (decl);
+ if (die)
+ check_die (die);
+#endif
}
/* Write the debugging output for DECL. */
call_arg_loc_last = NULL;
call_site_count = -1;
tail_call_site_count = -1;
- block_map.release ();
decl_loc_table->empty ();
cached_dw_loc_list_table->empty ();
}
section) and references to those files numbers (in the .debug_srcinfo
and.debug_macinfo sections). If the filename given as an argument is not
found in our current list, add it to the list and assign it the next
- available unique index number. In order to speed up searches, we remember
- the index of the filename was looked up last. This handles the majority of
- all searches. */
+ available unique index number. */
static struct dwarf_file_data *
lookup_filename (const char *file_name)
{
struct dwarf_file_data * created;
- /* Check to see if the file name that was searched on the previous
- call matches this file name. If so, return the index. */
- if (file_table_last_lookup
- && (file_name == file_table_last_lookup->filename
- || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
- return file_table_last_lookup;
+ if (!file_name)
+ return NULL;
- /* Didn't match the previous lookup, search the table. */
dwarf_file_data **slot
= file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
INSERT);
maybe_at_text_label_p = false;
}
+/* Temporary holder for dwarf2out_register_main_translation_unit. Used to let
+ front-ends register a translation unit even before dwarf2out_init is
+ called. */
+static tree main_translation_unit = NULL_TREE;
+
+/* Hook called by front-ends after they built their main translation unit.
+ Associate comp_unit_die to UNIT. */
+
+static void
+dwarf2out_register_main_translation_unit (tree unit)
+{
+ gcc_assert (TREE_CODE (unit) == TRANSLATION_UNIT_DECL
+ && main_translation_unit == NULL_TREE);
+ main_translation_unit = unit;
+ /* If dwarf2out_init has not been called yet, it will perform the association
+ itself looking at main_translation_unit. */
+ if (decl_die_table != NULL)
+ equate_decl_number_to_die (unit, comp_unit_die ());
+}
+
/* Add OPCODE+VAL as an entry at the end of the opcode array in TABLE. */
static void
/* Helpers to manipulate hash table of CUs. */
-struct macinfo_entry_hasher : typed_noop_remove <macinfo_entry>
+struct macinfo_entry_hasher : nofree_ptr_hash <macinfo_entry>
{
- typedef macinfo_entry value_type;
- typedef macinfo_entry compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const macinfo_entry *);
+ static inline bool equal (const macinfo_entry *, const macinfo_entry *);
};
inline hashval_t
-macinfo_entry_hasher::hash (const value_type *entry)
+macinfo_entry_hasher::hash (const macinfo_entry *entry)
{
return htab_hash_string (entry->info);
}
inline bool
-macinfo_entry_hasher::equal (const value_type *entry1,
- const compare_type *entry2)
+macinfo_entry_hasher::equal (const macinfo_entry *entry1,
+ const macinfo_entry *entry2)
{
return !strcmp (entry1->info, entry2->info);
}
static void
dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
{
+ /* This option is currently broken, see (PR53118 and PR46102). */
+ if (flag_eliminate_dwarf2_dups
+ && strstr (lang_hooks.name, "C++"))
+ {
+ warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
+ flag_eliminate_dwarf2_dups = 0;
+ }
+
/* Allocate the file_table. */
file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
/* Make sure the line number table for .text always exists. */
text_section_line_info = new_line_info_table ();
text_section_line_info->end_label = text_end_label;
+
+ /* If front-ends already registered a main translation unit but we were not
+ ready to perform the association, do this now. */
+ if (main_translation_unit != NULL_TREE)
+ equate_decl_number_to_die (main_translation_unit, comp_unit_die ());
}
/* Called before compile () starts outputtting functions, variables
if (skeleton_debug_str_hash)
skeleton_debug_str_hash->empty ();
prune_unused_types_prune (comp_unit_die ());
- for (node = limbo_die_list; node; node = node->next)
- prune_unused_types_prune (node->die);
+ for (limbo_die_node **pnode = &limbo_die_list; *pnode; )
+ {
+ node = *pnode;
+ if (!node->die->die_mark)
+ *pnode = node->next;
+ else
+ {
+ prune_unused_types_prune (node->die);
+ pnode = &node->next;
+ }
+ }
for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
prune_unused_types_prune (ctnode->root_die);
/* Helpers to manipulate hash table of comdat type units. */
-struct comdat_type_hasher : typed_noop_remove <comdat_type_node>
+struct comdat_type_hasher : nofree_ptr_hash <comdat_type_node>
{
- typedef comdat_type_node value_type;
- typedef comdat_type_node compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const comdat_type_node *);
+ static inline bool equal (const comdat_type_node *, const comdat_type_node *);
};
inline hashval_t
-comdat_type_hasher::hash (const value_type *type_node)
+comdat_type_hasher::hash (const comdat_type_node *type_node)
{
hashval_t h;
memcpy (&h, type_node->signature, sizeof (h));
}
inline bool
-comdat_type_hasher::equal (const value_type *type_node_1,
- const compare_type *type_node_2)
+comdat_type_hasher::equal (const comdat_type_node *type_node_1,
+ const comdat_type_node *type_node_2)
{
return (! memcmp (type_node_1->signature, type_node_2->signature,
DWARF_TYPE_SIGNATURE_SIZE));
{
tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr);
dw_die_ref tdie = lookup_decl_die (tdecl);
+ dw_die_ref cdie;
if (tdie == NULL
&& DECL_EXTERNAL (tdecl)
- && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE)
+ && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE
+ && (cdie = lookup_context_die (DECL_CONTEXT (tdecl))))
{
- force_decl_die (tdecl);
- tdie = lookup_decl_die (tdecl);
+ /* Creating a full DIE for tdecl is overly expensive and
+ at this point even wrong when in the LTO phase
+ as it can end up generating new type DIEs we didn't
+ output and thus optimize_external_refs will crash. */
+ tdie = new_die (DW_TAG_subprogram, cdie, NULL_TREE);
+ add_AT_flag (tdie, DW_AT_external, 1);
+ add_AT_flag (tdie, DW_AT_declaration, 1);
+ add_linkage_attr (tdie, tdecl);
+ add_name_and_src_coords_attributes (tdie, tdecl);
+ equate_decl_number_to_die (tdecl, tdie);
}
if (tdie)
{
hstate.add_object (val2->v.val_double.high);
break;
case dw_val_class_wide_int:
- hstate.add_object (*val2->v.val_wide);
+ hstate.add (val2->v.val_wide->get_val (),
+ get_full_len (*val2->v.val_wide)
+ * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
break;
case dw_val_class_addr:
inchash::add_rtx (val2->v.val_addr, hstate);
hstate.add_object (val2->v.val_double.high);
break;
case dw_val_class_wide_int:
- hstate.add_object (*val2->v.val_wide);
+ hstate.add (val2->v.val_wide->get_val (),
+ get_full_len (*val2->v.val_wide)
+ * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
break;
default:
gcc_unreachable ();
/* Hashtable helpers. */
-struct loc_list_hasher : typed_noop_remove <dw_loc_list_struct>
+struct loc_list_hasher : nofree_ptr_hash <dw_loc_list_struct>
{
- typedef dw_loc_list_struct value_type;
- typedef dw_loc_list_struct compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const dw_loc_list_struct *);
+ static inline bool equal (const dw_loc_list_struct *,
+ const dw_loc_list_struct *);
};
/* Return precomputed hash of location list X. */
inline hashval_t
-loc_list_hasher::hash (const value_type *x)
+loc_list_hasher::hash (const dw_loc_list_struct *x)
{
return x->hash;
}
/* Return true if location lists A and B are the same. */
inline bool
-loc_list_hasher::equal (const value_type *a, const compare_type *b)
+loc_list_hasher::equal (const dw_loc_list_struct *a,
+ const dw_loc_list_struct *b)
{
if (a == b)
return 1;
static void
dwarf2out_finish (const char *filename)
{
- limbo_die_node *node, *next_node;
comdat_type_node *ctnode;
- unsigned int i;
dw_die_ref main_comp_unit_die;
+ /* Flush out any latecomers to the limbo party. */
+ dwarf2out_early_finish ();
+
/* PCH might result in DW_AT_producer string being restored from the
header compilation, so always fill it with empty string initially
and overwrite only here. */
gen_remaining_tmpl_value_param_die_attribute ();
/* Add the name for the main input file now. We delayed this from
- dwarf2out_init to avoid complications with PCH. */
- add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
+ dwarf2out_init to avoid complications with PCH.
+ For LTO produced units use a fixed artificial name to avoid
+ leaking tempfile names into the dwarf. */
+ if (!in_lto_p)
+ add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
+ else
+ add_name_attribute (comp_unit_die (), "<artificial>");
if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
add_comp_dir_attribute (comp_unit_die ());
else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
add_comp_dir_attribute (comp_unit_die ());
}
- if (deferred_locations_list)
- for (i = 0; i < deferred_locations_list->length (); i++)
- {
- add_location_or_const_value_attribute (
- (*deferred_locations_list)[i].die,
- (*deferred_locations_list)[i].variable,
- false,
- DW_AT_location);
- }
-
- /* Traverse the limbo die list, and add parent/child links. The only
- dies without parents that should be here are concrete instances of
- inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
- For concrete instances, we can get the parent die from the abstract
- instance. */
- for (node = limbo_die_list; node; node = next_node)
- {
- dw_die_ref die = node->die;
- next_node = node->next;
-
- if (die->die_parent == NULL)
- {
- dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
-
- if (origin && origin->die_parent)
- add_child_die (origin->die_parent, die);
- else if (is_cu_die (die))
- ;
- else if (seen_error ())
- /* It's OK to be confused by errors in the input. */
- add_child_die (comp_unit_die (), die);
- else
- {
- /* In certain situations, the lexical block containing a
- nested function can be optimized away, which results
- in the nested function die being orphaned. Likewise
- with the return type of that nested function. Force
- this to be a child of the containing function.
-
- It may happen that even the containing function got fully
- inlined and optimized out. In that case we are lost and
- assign the empty child. This should not be big issue as
- the function is likely unreachable too. */
- gcc_assert (node->created_for);
-
- if (DECL_P (node->created_for))
- origin = get_context_die (DECL_CONTEXT (node->created_for));
- else if (TYPE_P (node->created_for))
- origin = scope_die_for (node->created_for, comp_unit_die ());
- else
- origin = comp_unit_die ();
-
- add_child_die (origin, die);
- }
- }
- }
-
- limbo_die_list = NULL;
-
#if ENABLE_ASSERT_CHECKING
{
dw_die_ref die = comp_unit_die (), c;
resolve_addr (comp_unit_die ());
move_marked_base_types ();
- for (node = deferred_asm_name; node; node = node->next)
- {
- tree decl = node->created_for;
- /* When generating LTO bytecode we can not generate new assembler
- names at this point and all important decls got theirs via
- free-lang-data. */
- if ((!flag_generate_lto || DECL_ASSEMBLER_NAME_SET_P (decl))
- && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
- {
- add_linkage_attr (node->die, decl);
- move_linkage_attr (node->die);
- }
- }
-
- deferred_asm_name = NULL;
-
/* Walk through the list of incomplete types again, trying once more to
emit full debugging info for them. */
retry_incomplete_types ();
/* Traverse the DIE's and add add sibling attributes to those DIE's
that have children. */
add_sibling_attributes (comp_unit_die ());
+ limbo_die_node *node;
for (node = limbo_die_list; node; node = node->next)
add_sibling_attributes (node->die);
for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
output_indirect_strings ();
}
+/* Perform any cleanups needed after the early debug generation pass
+ has run. */
+
+static void
+dwarf2out_early_finish (void)
+{
+ limbo_die_node *node, *next_node;
+
+ /* Add DW_AT_linkage_name for all deferred DIEs. */
+ for (node = deferred_asm_name; node; node = node->next)
+ {
+ tree decl = node->created_for;
+ if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+ /* A missing DECL_ASSEMBLER_NAME can be a constant DIE that
+ ended up in in deferred_asm_name before we knew it was
+ constant and never written to disk. */
+ && DECL_ASSEMBLER_NAME (decl))
+ {
+ add_linkage_attr (node->die, decl);
+ move_linkage_attr (node->die);
+ }
+ }
+ deferred_asm_name = NULL;
+
+ /* Traverse the limbo die list, and add parent/child links. The only
+ dies without parents that should be here are concrete instances of
+ inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
+ For concrete instances, we can get the parent die from the abstract
+ instance.
+
+ The point here is to flush out the limbo list so that it is empty
+ and we don't need to stream it for LTO. */
+ for (node = limbo_die_list; node; node = next_node)
+ {
+ dw_die_ref die = node->die;
+ next_node = node->next;
+
+ if (die->die_parent == NULL)
+ {
+ dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+ if (origin && origin->die_parent)
+ add_child_die (origin->die_parent, die);
+ else if (is_cu_die (die))
+ ;
+ else if (seen_error ())
+ /* It's OK to be confused by errors in the input. */
+ add_child_die (comp_unit_die (), die);
+ else
+ {
+ /* In certain situations, the lexical block containing a
+ nested function can be optimized away, which results
+ in the nested function die being orphaned. Likewise
+ with the return type of that nested function. Force
+ this to be a child of the containing function.
+
+ It may happen that even the containing function got fully
+ inlined and optimized out. In that case we are lost and
+ assign the empty child. This should not be big issue as
+ the function is likely unreachable too. */
+ gcc_assert (node->created_for);
+
+ if (DECL_P (node->created_for))
+ origin = get_context_die (DECL_CONTEXT (node->created_for));
+ else if (TYPE_P (node->created_for))
+ origin = scope_die_for (node->created_for, comp_unit_die ());
+ else
+ origin = comp_unit_die ();
+
+ add_child_die (origin, die);
+ }
+ }
+ }
+
+ limbo_die_list = NULL;
+}
+
/* Reset all state within dwarf2out.c so that we can rerun the compiler
within the same process. For use by toplev::finalize. */
cold_text_section = NULL;
current_unit_personality = NULL;
- deferred_locations_list = NULL;
-
next_die_offset = 0;
single_comp_unit_die = NULL;
comdat_type_list = NULL;
limbo_die_list = NULL;
- deferred_asm_name = NULL;
file_table = NULL;
decl_die_table = NULL;
common_block_die_table = NULL;
call_arg_loc_last = NULL;
call_site_count = -1;
tail_call_site_count = -1;
- //block_map = NULL;
cached_dw_loc_list_table = NULL;
abbrev_die_table = NULL;
abbrev_die_table_allocated = 0;
poc_label_num = 0;
last_emitted_file = NULL;
label_num = 0;
- file_table_last_lookup = NULL;
tmpl_value_parm_die_table = NULL;
generic_type_instances = NULL;
frame_pointer_fb_offset = 0;
frame_pointer_fb_offset_valid = false;
base_types.release ();
+ XDELETEVEC (producer_string);
+ producer_string = NULL;
}
#include "gt-dwarf2out.h"