+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and
+ register_external_die hooks.
+ (debug_false_tree_charstarstar_uhwistar): Declare.
+ (debug_nothing_tree_charstar_uhwi): Likewise.
+ * debug.c (do_nothing_debug_hooks): Adjust.
+ (debug_false_tree_charstarstar_uhwistar): New do nothing.
+ (debug_nothing_tree_charstar_uhwi): Likewise.
+ * dbxout.c (dbx_debug_hooks): Adjust.
+ (xcoff_debug_hooks): Likewise.
+ * sdbout.c (sdb_debug_hooks): Likewise.
+ * vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
+ * dwarf2out.c (macinfo_label_base): New global.
+ (dwarf2out_register_external_die): New function for the
+ register_external_die hook.
+ (dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl.
+ (dwarf2_debug_hooks): Use them.
+ (dwarf2_lineno_debug_hooks): Adjust.
+ (struct die_struct): Add with_offset flag.
+ (DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION,
+ DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION,
+ DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION,
+ DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION,
+ DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
+ DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros
+ defining section names for the early LTO debug variants.
+ (reset_indirect_string): New helper.
+ (add_AT_external_die_ref): Helper for dwarf2out_register_external_die.
+ (print_dw_val): Add support for offsetted symbol references.
+ (get_ultimate_context): Split out from is_cxx.
+ (is_cxx): Use get_ultimate_context.
+ (is_fortran): Add decl overload.
+ (compute_comp_unit_symbol): Split out worker from
+ compute_section_prefix.
+ (compute_section_prefix): Call compute_comp_unit_symbol and
+ set comdat_type_p here.
+ (output_die): Skip DIE symbol output for the LTO added one.
+ Handle DIE symbol references with offset.
+ (output_comp_unit): Guard section name mangling properly.
+ For LTO debug sections emit a symbol at the section beginning
+ which we use to refer to its DIEs.
+ (add_abstract_origin_attribute): For DIEs registered via
+ dwarf2out_register_external_die directly refer to the early
+ DIE rather than indirectly through the shadow one we created.
+ Remove obsolete call to dwarf2out_abstract_function for
+ non-function/block origins.
+ (gen_array_type_die): When generating early LTO debug do
+ not emit DW_AT_string_length.
+ (gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs
+ late when in LTO. As suggested place a gcc_unreachable for
+ the DECL_ABSTRACT_P case.
+ (gen_subprogram_die): Avoid another specification DIE
+ for early built declarations/definitions for the late LTO case.
+ (gen_variable_die): Add type references for late duplicated VLA dies
+ when in late LTO.
+ (gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function,
+ we have the abstract instance already.
+ (process_scope_var): Adjust decl DIE contexts in LTO which
+ first puts them in limbo.
+ (gen_decl_die): Do not generate type DIEs late apart from
+ types for VLAs or for decls we do not yet have a DIE. Do not
+ call dwarf2out_abstract_function late.
+ (dwarf2out_early_global_decl): Make sure to create DIEs
+ for abstract instances of a decl first.
+ (dwarf2out_late_global_decl): Adjust comment.
+ (output_macinfo_op): With multiple macro sections use
+ macinfo_label_base to distinguish labels.
+ (output_macinfo): Likewise. Update macinfo_label_base.
+ Pass in the line info label.
+ (note_variable_value_in_expr): When generating LTO resolve
+ all variable values here by generating DIEs as needed.
+ (init_sections_and_labels): Add early LTO debug flag parameter
+ and generate different sections and names if set. Add generation
+ counter for the labels so we can have multiple of them.
+ (reset_dies): Helper to allow DIEs to be output multiple times.
+ (dwarf2out_finish): When outputting DIEs to the fat part of an
+ LTO object first reset DIEs.
+ (dwarf2out_early_finish): Output early DIEs when generating LTO.
+ (modified_type_die): Check for decl_ultimate_origin being self
+ before recursing.
+ (gen_type_die_with_usage): Likewise.
+ (gen_typedef_die): Allow decl_ultimate_origin being self.
+ (set_decl_abstract_flags): Remove.
+ (set_block_abstract_flags): Likewise.
+ (dwarf2out_abstract_function): Treat the early generated DIEs
+ as the abstract copy and only add DW_AT_inline and
+ DW_AT_artificial here and call set_decl_origin_self.
+ If the DIE has an abstract origin don't do anything.
+ * tree.c (free_lang_data): Build a dummy TRANSLATION_UNIT_DECL
+ if we have none yet (Go fails to build one, PR78628).
+ (variably_modified_type_p): Prevent endless recursion for Ada
+ cyclic pointer types.
+ * lto-streamer-in.c: Include debug.h.
+ (dref_queue): New global.
+ (lto_read_tree_1): Stream in DIE references.
+ (lto_input_tree): Register DIE references.
+ (input_function): Stream DECL_DEBUG_ARGS.
+ * lto-streamer-out.c: Include debug.h.
+ (lto_write_tree_1): Output DIE references.
+ (DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN.
+ Force a TRANSLATION_UNIT_DECL DECL_CONTEXT for file-scope decls.
+ (output_function): Stream DECL_DEBUG_ARGS.
+ * tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers):
+ Stream DECL_ABSTRACT_ORIGIN.
+ * tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise.
+ (write_ts_decl_minimal_tree_pointers): Force a TRANSLATION_UNIT_DECL
+ DECL_CONTEXT for file-scope decls.
+ * lto-streamer.h (struct dref_entry): Declare.
+ (dref_queue): Likewise.
+ * cfgexpand.c (pass_expand::execute): Do not call the
+ outlining_inline_function hook here.
+ * lto-wrapper.c (debug_obj): New global.
+ (tool_cleanup): Unlink it if required.
+ (debug_objcopy): New function.
+ (run_gcc): Handle early debug sections in the IL files by
+ extracting them to separate files, partially linkin them and
+ feeding the result back as result to the linker.
+ * config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION,
+ DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION,
+ DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug
+ sections into a separate segment.
+ * config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO
+ segments.
+ (darwin_asm_dwarf_section): Likewise.
+ (darwin_asm_output_dwarf_offset): Likewise.
+ * config/i386/i386.c (make_resolver_func): Set DECL_IGNORED_P.
+
2017-08-21 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1;
}
- /* We are now committed to emitting code for this function. Do any
- preparation, such as emitting abstract debug info for the inline
- before it gets mangled by optimization. */
- if (cgraph_function_possibly_inlined_p (current_function_decl))
- (*debug_hooks->outlining_inline_function) (current_function_decl);
-
TREE_ASM_WRITTEN (current_function_decl) = 1;
/* After expanding, the return labels are no longer needed. */
}
static void
-darwin_asm_dwarf_section (const char *name, unsigned int flags, tree decl);
+darwin_asm_dwarf_section (const char *name, unsigned int flags,
+ tree decl, bool is_for_lto);
/* Called for the TARGET_ASM_NAMED_SECTION hook. */
vec_safe_push (lto_section_names, e);
}
else if (strncmp (name, "__DWARF,", 8) == 0)
- darwin_asm_dwarf_section (name, flags, decl);
+ darwin_asm_dwarf_section (name, flags, decl, false);
+ else if (strncmp (name, "__GNU_DWARF_LTO,", 16) == 0)
+ darwin_asm_dwarf_section (name, flags, decl, true);
else
fprintf (asm_out_file, "\t.section %s\n", name);
}
static void
darwin_asm_dwarf_section (const char *name, unsigned int flags,
- tree ARG_UNUSED (decl))
+ tree ARG_UNUSED (decl), bool is_for_lto)
{
unsigned i;
- int namelen;
- const char * sname;
+ int namelen, extra = 0;
+ const char *sect, *lto_add = "";
+ char sname[64];
dwarf_sect_used_entry *ref;
bool found = false;
- gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
- == (SECTION_DEBUG | SECTION_NAMED));
- /* We know that the name starts with __DWARF, */
- sname = name + 8;
- namelen = strchr (sname, ',') - sname;
- gcc_assert (namelen);
+
+ gcc_checking_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+ == (SECTION_DEBUG | SECTION_NAMED));
+
+ /* We know that the name starts with __DWARF, or __GNU_DAWRF_LTO */
+ sect = strchr (name, ',') + 1;
+ namelen = strchr (sect, ',') - sect;
+ gcc_checking_assert (namelen);
+
+ /* The section switch is output as written... */
+ fprintf (asm_out_file, "\t.section %s\n", name);
+
+ /* ... but the string we keep to make section start labels needs
+ adjustment for lto cases. */
+ if (is_for_lto)
+ {
+ lto_add = "_lto";
+ extra = 4;
+ }
+
+ snprintf (sname, 64, "%.*s%.*s", namelen, sect, extra, lto_add);
+ namelen += extra;
+
if (dwarf_sect_names_table == NULL)
vec_alloc (dwarf_sect_names_table, 16);
else
}
}
- fprintf (asm_out_file, "\t.section %s\n", name);
if (!found)
{
dwarf_sect_used_entry e;
HOST_WIDE_INT offset, section *base)
{
char sname[64];
- int namelen;
+ int namelen, extra = 0;
+ bool is_for_lto;
+ const char *lto_add = "";
- gcc_assert (base->common.flags & SECTION_NAMED);
- gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
- gcc_assert (strchr (base->named.name + 8, ','));
+ gcc_checking_assert (base->common.flags & SECTION_NAMED);
+ is_for_lto = strncmp (base->named.name, "__GNU_DWARF_LTO,", 16) == 0;
+ gcc_checking_assert (is_for_lto
+ || strncmp (base->named.name, "__DWARF,", 8) == 0);
+ const char *name = strchr (base->named.name, ',') + 1;
+ gcc_checking_assert (name);
- namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
- sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
+ namelen = strchr (name, ',') - (name);
+ if (is_for_lto)
+ {
+ lto_add = "_lto";
+ extra = 4;
+ }
+ snprintf (sname, 64, "*Lsection%.*s%.*s", namelen, name, extra, lto_add);
darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
}
#define DEBUG_PUBTYPES_SECTION "__DWARF,__debug_pubtypes,regular,debug"
#define DEBUG_STR_SECTION "__DWARF,__debug_str,regular,debug"
#define DEBUG_RANGES_SECTION "__DWARF,__debug_ranges,regular,debug"
-#define DEBUG_MACRO_SECTION "__DWARF,__debug_macro,regular,debug"
+#define DEBUG_MACRO_SECTION "__DWARF,__debug_macro,regular,debug"
+
+#define DEBUG_LTO_INFO_SECTION "__GNU_DWARF_LTO,__debug_info,regular,debug"
+#define DEBUG_LTO_ABBREV_SECTION "__GNU_DWARF_LTO,__debug_abbrev,regular,debug"
+#define DEBUG_LTO_MACINFO_SECTION "__GNU_DWARF_LTO,__debug_macinfo,regular,debug"
+#define DEBUG_LTO_LINE_SECTION "__GNU_DWARF_LTO,__debug_line,regular,debug"
+#define DEBUG_LTO_STR_SECTION "__GNU_DWARF_LTO,__debug_str,regular,debug"
+#define DEBUG_LTO_MACRO_SECTION "__GNU_DWARF_LTO,__debug_macro,regular,debug"
#define TARGET_WANT_DEBUG_PUB_SECTIONS true
DECL_NAME (decl) = decl_name;
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
- DECL_IGNORED_P (decl) = 0;
+ DECL_IGNORED_P (decl) = 1;
TREE_PUBLIC (decl) = 0;
DECL_UNINLINABLE (decl) = 1;
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
dbxout_late_global_decl, /* late_global_decl */
dbxout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
int local ATTRIBUTE_UNUSED)
{
}
+
+bool
+debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *)
+{
+ return false;
+}
+
+void
+debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT)
+{
+}
tree context, bool child,
bool implicit);
+ /* Return true if a DIE for the tree is available and return a symbol
+ and offset that can be used to refer to it externally. */
+ bool (* die_ref_for_decl) (tree, const char **, unsigned HOST_WIDE_INT *);
+
+ /* Early debug information for the tree is available at symbol plus
+ offset externally. */
+ void (* register_external_die) (tree, const char *, unsigned HOST_WIDE_INT);
+
/* DECL is an inline function, whose body is present, but which is
not being output at this point. */
void (* deferred_inline_function) (tree decl);
extern bool debug_true_const_tree (const_tree);
extern void debug_nothing_rtx_insn (rtx_insn *);
extern void debug_nothing_rtx_code_label (rtx_code_label *);
+extern bool debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ unsigned HOST_WIDE_INT *);
+extern void debug_nothing_tree_charstar_uhwi (tree, const char *,
+ unsigned HOST_WIDE_INT);
/* Hooks for various debug formats. */
extern const struct gcc_debug_hooks do_nothing_debug_hooks;
static GTY(()) section *debug_addr_section;
static GTY(()) section *debug_macinfo_section;
static const char *debug_macinfo_section_name;
+static unsigned macinfo_label_base = 1;
static GTY(()) section *debug_line_section;
static GTY(()) section *debug_skeleton_line_section;
static GTY(()) section *debug_loc_section;
static void dwarf2out_end_function (unsigned int);
static void dwarf2out_register_main_translation_unit (tree unit);
static void dwarf2out_set_name (tree, tree);
+static void dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off);
+static bool dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off);
/* The debug hooks structure. */
dwarf2out_late_global_decl,
dwarf2out_type_decl, /* type_decl */
dwarf2out_imported_module_or_decl,
+ dwarf2out_die_ref_for_decl,
+ dwarf2out_register_external_die,
debug_nothing_tree, /* deferred_inline_function */
/* The DWARF 2 backend tries to reduce debugging bloat by not
emitting the abstract description of inline functions until
debug_nothing_tree, /* late_global_decl */
debug_nothing_tree_int, /* type_decl */
debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
debug_nothing_rtx_code_label, /* label */
/* Die is used and must not be pruned as unused. */
BOOL_BITFIELD die_perennial_p : 1;
BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+ /* For an external ref to die_symbol if die_offset contains an extra
+ offset to that symbol. */
+ BOOL_BITFIELD with_offset : 1;
/* Whether this DIE was removed from the DIE tree, for example via
prune_unused_types. We don't consider those present from the
DIE lookup routines. */
#ifndef DEBUG_DWO_INFO_SECTION
#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_INFO_SECTION
+#define DEBUG_LTO_DWO_INFO_SECTION ".gnu.debuglto_.debug_info.dwo"
+#endif
+#ifndef DEBUG_LTO_INFO_SECTION
+#define DEBUG_LTO_INFO_SECTION ".gnu.debuglto_.debug_info"
+#endif
#ifndef DEBUG_ABBREV_SECTION
#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
#ifndef DEBUG_DWO_ABBREV_SECTION
#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_ABBREV_SECTION
+#define DEBUG_LTO_DWO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev.dwo"
+#endif
+#ifndef DEBUG_LTO_ABBREV_SECTION
+#define DEBUG_LTO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev"
+#endif
#ifndef DEBUG_ARANGES_SECTION
#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
#ifndef DEBUG_DWO_MACINFO_SECTION
#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_MACINFO_SECTION
+#define DEBUG_LTO_DWO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo.dwo"
+#endif
+#ifndef DEBUG_LTO_MACINFO_SECTION
+#define DEBUG_LTO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo"
+#endif
#ifndef DEBUG_DWO_MACRO_SECTION
#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo"
#endif
#ifndef DEBUG_MACRO_SECTION
#define DEBUG_MACRO_SECTION ".debug_macro"
#endif
+#ifndef DEBUG_LTO_DWO_MACRO_SECTION
+#define DEBUG_LTO_DWO_MACRO_SECTION ".gnu.debuglto_.debug_macro.dwo"
+#endif
+#ifndef DEBUG_LTO_MACRO_SECTION
+#define DEBUG_LTO_MACRO_SECTION ".gnu.debuglto_.debug_macro"
+#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
#ifndef DEBUG_DWO_LINE_SECTION
#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
#endif
+#ifndef DEBUG_LTO_LINE_SECTION
+#define DEBUG_LTO_LINE_SECTION ".gnu.debuglto_.debug_line.dwo"
+#endif
#ifndef DEBUG_LOC_SECTION
#define DEBUG_LOC_SECTION ".debug_loc"
#endif
#ifndef DEBUG_DWO_STR_OFFSETS_SECTION
#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
#endif
+#ifndef DEBUG_LTO_DWO_STR_OFFSETS_SECTION
+#define DEBUG_LTO_DWO_STR_OFFSETS_SECTION ".gnu.debuglto_.debug_str_offsets.dwo"
+#endif
#ifndef DEBUG_STR_DWO_SECTION
#define DEBUG_STR_DWO_SECTION ".debug_str.dwo"
#endif
+#ifndef DEBUG_LTO_STR_DWO_SECTION
+#define DEBUG_LTO_STR_DWO_SECTION ".gnu.debuglto_.debug_str.dwo"
+#endif
#ifndef DEBUG_STR_SECTION
#define DEBUG_STR_SECTION ".debug_str"
#endif
+#ifndef DEBUG_LTO_STR_SECTION
+#define DEBUG_LTO_STR_SECTION ".gnu.debuglto_.debug_str"
+#endif
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
#endif
/* Section flags for .debug_str.dwo section. */
#define DEBUG_STR_DWO_SECTION_FLAGS (SECTION_DEBUG | SECTION_EXCLUDE)
+/* Attribute used to refer to the macro section. */
+#define DEBUG_MACRO_ATTRIBUTE (dwarf_version >= 5 ? DW_AT_macros \
+ : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros)
+
/* Labels we insert at beginning sections we can reference instead of
the section names themselves. */
}
}
+/* A helper function for dwarf2out_finish, called to reset indirect
+ string decisions done for early LTO dwarf output before fat object
+ dwarf output. */
+
+int
+reset_indirect_string (indirect_string_node **h, void *)
+{
+ struct indirect_string_node *node = *h;
+ if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+ {
+ free (node->label);
+ node->label = NULL;
+ node->form = (dwarf_form) 0;
+ node->index = 0;
+ }
+ return 1;
+}
+
/* Find out whether a string should be output inline in DIE
or out-of-line in .debug_str section. */
return a ? AT_file (a) : NULL;
}
+/* Returns the ultimate TRANSLATION_UNIT_DECL context of DECL or NULL. */
+
+static const_tree
+get_ultimate_context (const_tree decl)
+{
+ while (decl && TREE_CODE (decl) != TRANSLATION_UNIT_DECL)
+ {
+ if (TREE_CODE (decl) == BLOCK)
+ decl = BLOCK_SUPERCONTEXT (decl);
+ else
+ decl = get_containing_scope (decl);
+ }
+ return decl;
+}
+
/* Return TRUE if the language is C++. */
static inline bool
{
if (in_lto_p)
{
- const_tree context = decl;
- while (context && TREE_CODE (context) != TRANSLATION_UNIT_DECL)
- {
- if (TREE_CODE (context) == BLOCK)
- context = BLOCK_SUPERCONTEXT (context);
- else
- context = get_containing_scope (context);
- }
+ const_tree context = get_ultimate_context (decl);
if (context && TRANSLATION_UNIT_LANGUAGE (context))
return strncmp (TRANSLATION_UNIT_LANGUAGE (context), "GNU C++", 7) == 0;
}
|| lang == DW_LANG_Fortran08);
}
+static inline bool
+is_fortran (const_tree decl)
+{
+ if (in_lto_p)
+ {
+ const_tree context = get_ultimate_context (decl);
+ if (context && TRANSLATION_UNIT_LANGUAGE (context))
+ return (strncmp (TRANSLATION_UNIT_LANGUAGE (context),
+ "GNU Fortran", 11) == 0
+ || strcmp (TRANSLATION_UNIT_LANGUAGE (context),
+ "GNU F77") == 0);
+ }
+ return is_fortran ();
+}
+
/* Return TRUE if the language is Ada. */
static inline bool
return *die;
}
+
+/* For DECL which might have early dwarf output query a SYMBOL + OFFSET
+ style reference. Return true if we found one refering to a DIE for
+ DECL, otherwise return false. */
+
+static bool
+dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ unsigned HOST_WIDE_INT *off)
+{
+ dw_die_ref die;
+
+ if (flag_wpa && !decl_die_table)
+ return false;
+
+ if (TREE_CODE (decl) == BLOCK)
+ die = BLOCK_DIE (decl);
+ else
+ die = lookup_decl_die (decl);
+ if (!die)
+ return false;
+
+ /* During WPA stage we currently use DIEs to store the
+ decl <-> label + offset map. That's quite inefficient but it
+ works for now. */
+ if (flag_wpa)
+ {
+ dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
+ if (!ref)
+ {
+ gcc_assert (die == comp_unit_die ());
+ return false;
+ }
+ *off = ref->die_offset;
+ *sym = ref->die_id.die_symbol;
+ return true;
+ }
+
+ /* Similar to get_ref_die_offset_label, but using the "correct"
+ label. */
+ *off = die->die_offset;
+ while (die->die_parent)
+ die = die->die_parent;
+ /* For the containing CU DIE we compute a die_symbol in
+ compute_section_prefix. */
+ gcc_assert (die->die_tag == DW_TAG_compile_unit
+ && die->die_id.die_symbol != NULL);
+ *sym = die->die_id.die_symbol;
+ return true;
+}
+
+/* Add a reference of kind ATTR_KIND to a DIE at SYMBOL + OFFSET to DIE. */
+
+static void
+add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *symbol, HOST_WIDE_INT offset)
+{
+ /* Create a fake DIE that contains the reference. Don't use
+ new_die because we don't want to end up in the limbo list. */
+ dw_die_ref ref = ggc_cleared_alloc<die_node> ();
+ ref->die_tag = die->die_tag;
+ ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
+ ref->die_offset = offset;
+ ref->with_offset = 1;
+ add_AT_die_ref (die, attr_kind, ref);
+}
+
+/* Create a DIE for DECL if required and add a reference to a DIE
+ at SYMBOL + OFFSET which contains attributes dumped early. */
+
+static void
+dwarf2out_register_external_die (tree decl, const char *sym,
+ unsigned HOST_WIDE_INT off)
+{
+ if (debug_info_level == DINFO_LEVEL_NONE)
+ return;
+
+ if (flag_wpa && !decl_die_table)
+ decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
+
+ dw_die_ref die
+ = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+ gcc_assert (!die);
+
+ tree ctx;
+ dw_die_ref parent = NULL;
+ /* Need to lookup a DIE for the decls context - the containing
+ function or translation unit. */
+ if (TREE_CODE (decl) == BLOCK)
+ {
+ ctx = BLOCK_SUPERCONTEXT (decl);
+ /* ??? We do not output DIEs for all scopes thus skip as
+ many DIEs as needed. */
+ while (TREE_CODE (ctx) == BLOCK
+ && !BLOCK_DIE (ctx))
+ ctx = BLOCK_SUPERCONTEXT (ctx);
+ }
+ else
+ ctx = DECL_CONTEXT (decl);
+ while (ctx && TYPE_P (ctx))
+ ctx = TYPE_CONTEXT (ctx);
+ if (ctx)
+ {
+ if (TREE_CODE (ctx) == BLOCK)
+ parent = BLOCK_DIE (ctx);
+ else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
+ /* Keep the 1:1 association during WPA. */
+ && !flag_wpa)
+ /* Otherwise all late annotations go to the main CU which
+ imports the original CUs. */
+ parent = comp_unit_die ();
+ else if (TREE_CODE (ctx) == FUNCTION_DECL
+ && TREE_CODE (decl) != PARM_DECL
+ && TREE_CODE (decl) != BLOCK)
+ /* Leave function local entities parent determination to when
+ we process scope vars. */
+ ;
+ else
+ parent = lookup_decl_die (ctx);
+ }
+ else
+ /* In some cases the FEs fail to set DECL_CONTEXT properly.
+ Handle this case gracefully by globalizing stuff. */
+ parent = comp_unit_die ();
+ /* Create a DIE "stub". */
+ switch (TREE_CODE (decl))
+ {
+ case TRANSLATION_UNIT_DECL:
+ if (! flag_wpa)
+ {
+ die = comp_unit_die ();
+ dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
+ add_AT_external_die_ref (import, DW_AT_import, sym, off);
+ /* We re-target all CU decls to the LTRANS CU DIE, so no need
+ to create a DIE for the original CUs. */
+ return;
+ }
+ /* Keep the 1:1 association during WPA. */
+ die = new_die (DW_TAG_compile_unit, NULL, decl);
+ break;
+ case NAMESPACE_DECL:
+ if (is_fortran (decl))
+ die = new_die (DW_TAG_module, parent, decl);
+ else
+ die = new_die (DW_TAG_namespace, parent, decl);
+ break;
+ case FUNCTION_DECL:
+ die = new_die (DW_TAG_subprogram, parent, decl);
+ break;
+ case VAR_DECL:
+ die = new_die (DW_TAG_variable, parent, decl);
+ break;
+ case RESULT_DECL:
+ die = new_die (DW_TAG_variable, parent, decl);
+ break;
+ case PARM_DECL:
+ die = new_die (DW_TAG_formal_parameter, parent, decl);
+ break;
+ case CONST_DECL:
+ die = new_die (DW_TAG_constant, parent, decl);
+ break;
+ case LABEL_DECL:
+ die = new_die (DW_TAG_label, parent, decl);
+ break;
+ case BLOCK:
+ die = new_die (DW_TAG_lexical_block, parent, decl);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (TREE_CODE (decl) == BLOCK)
+ BLOCK_DIE (decl) = die;
+ else
+ equate_decl_number_to_die (decl, die);
+
+ /* Add a reference to the DIE providing early debug at $sym + off. */
+ add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
+}
+
/* Returns a hash value for X (which really is a var_loc_list). */
inline hashval_t
die->die_id.die_type_node->signature);
}
else if (die->die_id.die_symbol)
- fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ {
+ fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+ if (die->with_offset)
+ fprintf (outfile, " + %ld", die->die_offset);
+ }
else
fprintf (outfile, "die -> %ld", die->die_offset);
fprintf (outfile, " (%p)", (void *) die);
static unsigned int comdat_symbol_number;
/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its
- children, and set comdat_symbol_id accordingly. */
+ children, and set die_symbol. */
static void
-compute_section_prefix (dw_die_ref unit_die)
+compute_comp_unit_symbol (dw_die_ref unit_die)
{
const char *die_name = get_AT_string (unit_die, DW_AT_name);
const char *base = die_name ? lbasename (die_name) : "anonymous";
unmark_all_dies (unit_die);
md5_finish_ctx (&ctx, checksum);
- sprintf (name, "%s.", base);
+ /* When we this for comp_unit_die () we have a DW_AT_name that might
+ not start with a letter but with anything valid for filenames and
+ clean_symbol_name doesn't fix that up. Prepend 'g' if the first
+ character is not a letter. */
+ sprintf (name, "%s%s.", ISALPHA (*base) ? "" : "g", base);
clean_symbol_name (name);
p = name + strlen (name);
p += 2;
}
- comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+ unit_die->die_id.die_symbol = xstrdup (name);
+}
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+ compute_comp_unit_symbol (unit_die);
+ unit_die->comdat_type_p = true;
+ comdat_symbol_id = unit_die->die_id.die_symbol;
comdat_symbol_number = 0;
}
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
- if (! die->comdat_type_p && die->die_id.die_symbol)
+ if (! die->comdat_type_p && die->die_id.die_symbol
+ /* Don't output the symbol twice. For LTO we want the label
+ on the section beginning, not on the actual DIE. */
+ && (!flag_generate_lto
+ || die->die_tag != DW_TAG_compile_unit))
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
size = DWARF2_ADDR_SIZE;
else
size = DWARF_OFFSET_SIZE;
- dw2_asm_output_offset (size, sym, debug_info_section, "%s",
- name);
+ /* ??? We cannot unconditionally output die_offset if
+ non-zero - at least -feliminate-dwarf2-dups will
+ create references to those DIEs via symbols. And we
+ do not clear its DIE offset after outputting it
+ (and the label refers to the actual DIEs, not the
+ DWARF CU unit header which is when using label + offset
+ would be the correct thing to do).
+ ??? This is the reason for the with_offset flag. */
+ if (AT_ref (a)->with_offset)
+ dw2_asm_output_offset (size, sym, AT_ref (a)->die_offset,
+ debug_info_section, "%s", name);
+ else
+ dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+ name);
}
}
else
calc_die_sizes (die);
oldsym = die->die_id.die_symbol;
- if (oldsym)
+ if (oldsym && die->comdat_type_p)
{
tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
info_section_emitted = true;
}
+ /* For LTO cross unit DIE refs we want a symbol on the start of the
+ debuginfo section, not on the CU DIE. */
+ if (flag_generate_lto && oldsym)
+ {
+ /* ??? No way to get visibility assembled without a decl. */
+ tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (oldsym), char_type_node);
+ TREE_PUBLIC (decl) = true;
+ TREE_STATIC (decl) = true;
+ DECL_ARTIFICIAL (decl) = true;
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = true;
+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+#ifdef ASM_WEAKEN_LABEL
+ /* We prefer a .weak because that handles duplicates from duplicate
+ archive members in a graceful way. */
+ ASM_WEAKEN_LABEL (asm_out_file, oldsym);
+#else
+ targetm.asm_out.globalize_label (asm_out_file, oldsym);
+#endif
+ ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+ }
+
/* Output debugging information. */
output_compilation_unit_header (dwo_id
? DW_UT_split_compile : DW_UT_compile);
/* Typedef variants that have an abstract origin don't get their own
type DIE (see gen_typedef_die), so fall back on the ultimate
abstract origin instead. */
- if (origin != NULL)
+ if (origin != NULL && origin != name)
return modified_type_die (TREE_TYPE (origin), cv_quals, reverse,
context_die);
if (dwarf_strict)
return NULL;
gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
+ /* With LTO during LTRANS we get the late DIE that refers to the early
+ DIE, thus we add another indirection here. This seems to confuse
+ gdb enough to make gcc.dg/guality/pr68860-1.c FAIL with LTO. */
ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
if (ref)
{
dw_die_ref origin_die = NULL;
- if (TREE_CODE (origin) != FUNCTION_DECL
- && TREE_CODE (origin) != BLOCK)
+ if (DECL_P (origin))
{
- /* We may have gotten separated from the block for the inlined
- function, if we're in an exception handler or some such; make
- sure that the abstract function has been written out.
-
- Doing this for nested functions is wrong, however; functions are
- distinct units, and our context might not even be inline. */
- tree fn = origin;
-
- if (TYPE_P (fn))
- fn = TYPE_STUB_DECL (fn);
-
- fn = decl_function_context (fn);
- if (fn)
- dwarf2out_abstract_function (fn);
+ dw_die_ref c;
+ origin_die = lookup_decl_die (origin);
+ /* "Unwrap" the decls DIE which we put in the imported unit context.
+ We are looking for the abstract copy here. */
+ if (in_lto_p
+ && origin_die
+ && (c = get_AT_ref (origin_die, DW_AT_abstract_origin))
+ /* ??? Identify this better. */
+ && c->with_offset)
+ origin_die = c;
}
-
- if (DECL_P (origin))
- origin_die = lookup_decl_die (origin);
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
else if (TREE_CODE (origin) == BLOCK)
size = int_size_in_bytes (type);
if (size >= 0)
add_AT_unsigned (array_die, DW_AT_byte_size, size);
- else if (TYPE_DOMAIN (type) != NULL_TREE
+ /* ??? We can't annotate types late, but for LTO we may not
+ generate a location early either (gfortran.dg/save_6.f90). */
+ else if (! (early_dwarf && flag_generate_lto)
+ && TYPE_DOMAIN (type) != NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE)
{
tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
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)
+ thing.
+ ??? When in LTO the DIE parent is the "abstract" copy and the
+ context_die is the specification "copy". But this whole block
+ should eventually be no longer needed. */
+ if (parm_die && parm_die->die_parent != context_die && !in_lto_p)
{
if (!DECL_ABSTRACT_P (node))
{
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. */
- }
+ gcc_unreachable ();
}
if (parm_die && parm_die->die_parent == NULL)
/* 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, 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
}
}
\f
-/* 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, vec<tree> &abstract_vec)
-{
- tree local_decl;
- tree subblock;
- unsigned int i;
-
- 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, abstract_vec);
-
- for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
- {
- local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
- if ((VAR_P (local_decl) && !TREE_STATIC (local_decl))
- || TREE_CODE (local_decl) == PARM_DECL)
- 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, abstract_vec);
-}
-
-/* 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, vec<tree> &abstract_vec)
-{
- 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))
- 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), 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.
-
- 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. */
+/* Mark the early DIE for DECL as the abstract instance. */
static void
dwarf2out_abstract_function (tree decl)
{
dw_die_ref old_die;
- tree save_fn;
- tree context;
- 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;
- struct call_arg_loc_node *old_call_arg_locations;
/* Make sure we have the actual abstract inline, not a clone. */
decl = DECL_ORIGIN (decl);
+ if (DECL_IGNORED_P (decl))
+ return;
+
old_die = lookup_decl_die (decl);
- if (old_die && get_AT (old_die, DW_AT_inline))
+ /* With early debug we always have an old DIE. */
+ gcc_assert (old_die != NULL);
+ if (get_AT (old_die, DW_AT_inline)
+ || get_AT (old_die, DW_AT_abstract_origin))
/* We've already generated the abstract instance. */
return;
- /* We can be called while recursively when seeing block defining inlined subroutine
- DIE. Be sure to not clobber the outer location table nor use it or we would
- get locations in abstract instantces. */
- old_decl_loc_table = decl_loc_table;
- decl_loc_table = NULL;
- old_cached_dw_loc_list_table = cached_dw_loc_list_table;
- cached_dw_loc_list_table = NULL;
- old_call_arg_locations = call_arg_locations;
- call_arg_locations = NULL;
- old_call_site_count = call_site_count;
- call_site_count = -1;
- old_tail_call_site_count = tail_call_site_count;
- tail_call_site_count = -1;
-
- /* Be sure we've emitted the in-class declaration DIE (if any) first, so
- we don't get confused by DECL_ABSTRACT_P. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
+ /* Go ahead and put DW_AT_inline on the DIE. */
+ if (DECL_DECLARED_INLINE_P (decl))
+ {
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_inlined);
+ else
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
+ }
+ else
{
- context = decl_class_context (decl);
- if (context)
- gen_type_die_for_member
- (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
+ if (cgraph_function_possibly_inlined_p (decl))
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_inlined);
+ else
+ add_AT_unsigned (old_die, DW_AT_inline, DW_INL_not_inlined);
}
- /* Pretend we've just finished compiling this function. */
- save_fn = current_function_decl;
- current_function_decl = decl;
+ if (DECL_DECLARED_INLINE_P (decl)
+ && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
+ add_AT_flag (old_die, DW_AT_artificial, 1);
- auto_vec<tree, 64> abstract_vec;
- set_decl_abstract_flags (decl, abstract_vec);
- dwarf2out_decl (decl);
- 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;
- cached_dw_loc_list_table = old_cached_dw_loc_list_table;
- call_arg_locations = old_call_arg_locations;
- call_site_count = old_call_site_count;
- tail_call_site_count = old_tail_call_site_count;
+ set_decl_origin_self (decl);
}
/* Helper function of premark_used_types() which gets called through
&& debug_info_level > DINFO_LEVEL_TERSE)
old_die = force_decl_die (decl);
- /* An inlined instance, tag a new DIE with DW_AT_abstract_origin. */
+ /* A concrete instance, tag a new DIE with DW_AT_abstract_origin. */
if (origin != NULL)
{
gcc_assert (!declaration || local_scope_p (context_die));
&& old_die->die_parent->die_tag == DW_TAG_module)
|| context_die == NULL)
&& (DECL_ARTIFICIAL (decl)
+ /* The location attributes may be in the abstract origin
+ which in the case of LTO might be not available to
+ look at. */
+ || get_AT (old_die, DW_AT_abstract_origin)
|| (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) s.line)
/* If a DIE was dumped early, it still needs location info.
Skip to where we fill the location bits. */
var_die = old_die;
+
+ /* ??? In LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Thus we dumped them again, also add a
+ reference to them. */
+ tree type = TREE_TYPE (decl_or_origin);
+ if (in_lto_p
+ && variably_modified_type_p
+ (type, decl_function_context (decl_or_origin)))
+ {
+ if (decl_by_reference_p (decl_or_origin))
+ add_type_attribute (var_die, TREE_TYPE (type),
+ TYPE_UNQUALIFIED, false, context_die);
+ else
+ add_type_attribute (var_die, type, decl_quals (decl_or_origin),
+ false, context_die);
+ }
+
goto gen_variable_die_location;
}
}
gcc_checking_assert (DECL_ABSTRACT_P (decl)
|| cgraph_function_possibly_inlined_p (decl));
- /* Emit info for the abstract instance first, if we haven't yet. We
- must emit this even if the block is abstract, otherwise when we
- emit the block below (or elsewhere), we may end up trying to emit
- a die whose origin die hasn't been emitted, and crashing. */
- dwarf2out_abstract_function (decl);
-
if (! BLOCK_ABSTRACT (stmt))
{
dw_die_ref subr_die
/* As we avoid creating DIEs for local typedefs (see decl_ultimate_origin
checks in process_scope_var and modified_type_die), this should be called
only for original types. */
- gcc_assert (decl_ultimate_origin (decl) == NULL);
+ gcc_assert (decl_ultimate_origin (decl) == NULL
+ || decl_ultimate_origin (decl) == decl);
TREE_ASM_WRITTEN (decl) = 1;
type_die = new_die (DW_TAG_typedef, context_die, decl);
tree name = TYPE_NAME (type);
tree origin = decl_ultimate_origin (name);
- if (origin != NULL)
+ if (origin != NULL && origin != name)
{
gen_decl_die (origin, NULL, NULL, context_die);
return;
stmt, context_die);
}
else
- gen_decl_die (decl, origin, NULL, context_die);
+ {
+ if (decl && DECL_P (decl))
+ {
+ die = lookup_decl_die (decl);
+
+ /* Early created DIEs do not have a parent as the decls refer
+ to the function as DECL_CONTEXT rather than the BLOCK. */
+ if (die && die->die_parent == NULL)
+ {
+ gcc_assert (in_lto_p);
+ add_child_die (context_die, die);
+ }
+ }
+
+ gen_decl_die (decl, origin, NULL, context_die);
+ }
}
/* Generate all of the decls declared within a given scope and (recursively)
/* This is only a declaration. */;
#endif
+ /* We should have abstract copies already and should not generate
+ stray type DIEs in late LTO dumping. */
+ if (! early_dwarf)
+ ;
+
/* If we're emitting a clone, emit info for the abstract instance. */
- if (origin || DECL_ORIGIN (decl) != decl)
+ else if (origin || DECL_ORIGIN (decl) != decl)
dwarf2out_abstract_function (origin
? DECL_ORIGIN (origin)
: DECL_ABSTRACT_ORIGIN (decl));
- /* If we're emitting an out-of-line copy of an inline function,
- emit info for the abstract instance and set up to refer to it. */
+ /* If we're emitting a possibly inlined function emit it as
+ abstract instance. */
else if (cgraph_function_possibly_inlined_p (decl)
&& ! DECL_ABSTRACT_P (decl)
&& ! class_or_namespace_scope_p (context_die)
a declaration. We must avoid setting DECL_ABSTRACT_ORIGIN in
that case, because that works only if we have a die. */
&& DECL_INITIAL (decl) != NULL_TREE)
- {
- dwarf2out_abstract_function (decl);
- set_decl_origin_self (decl);
- }
+ dwarf2out_abstract_function (decl);
/* Otherwise we're emitting the primary DIE for this decl. */
else if (debug_info_level > DINFO_LEVEL_TERSE)
if (debug_info_level <= DINFO_LEVEL_TERSE)
break;
- /* Output any DIEs that are needed to specify the type of this data
- object. */
- if (decl_by_reference_p (decl_or_origin))
- gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
- else
- gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ /* Avoid generating stray type DIEs during late dwarf dumping.
+ All types have been dumped early. */
+ if (early_dwarf
+ /* ??? But in LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Dump them again as happens for inlining
+ which copies both the decl and the types. */
+ /* ??? And even non-LTO needs to re-visit type DIEs to fill
+ in VLA bound information for example. */
+ || (decl && variably_modified_type_p (TREE_TYPE (decl),
+ current_function_decl)))
+ {
+ /* Output any DIEs that are needed to specify the type of this data
+ object. */
+ if (decl_by_reference_p (decl_or_origin))
+ gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+ else
+ gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ }
- /* And its containing type. */
- class_origin = decl_class_context (decl_or_origin);
- if (class_origin != NULL_TREE)
- gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+ if (early_dwarf)
+ {
+ /* And its containing type. */
+ class_origin = decl_class_context (decl_or_origin);
+ if (class_origin != NULL_TREE)
+ gen_type_die_for_member (class_origin, decl_or_origin, context_die);
- /* And its containing namespace. */
- context_die = declare_in_namespace (decl_or_origin, context_die);
+ /* And its containing namespace. */
+ context_die = declare_in_namespace (decl_or_origin, context_die);
+ }
/* Now output the DIE to represent the data object itself. This gets
complicated because of the possibility that the VAR_DECL really
break;
case PARM_DECL:
- if (DECL_BY_REFERENCE (decl_or_origin))
- gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
- else
- gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ /* Avoid generating stray type DIEs during late dwarf dumping.
+ All types have been dumped early. */
+ if (early_dwarf
+ /* ??? But in LTRANS we cannot annotate early created variably
+ modified type DIEs without copying them and adjusting all
+ references to them. Dump them again as happens for inlining
+ which copies both the decl and the types. */
+ /* ??? And even non-LTO needs to re-visit type DIEs to fill
+ in VLA bound information for example. */
+ || (decl && variably_modified_type_p (TREE_TYPE (decl),
+ current_function_decl)))
+ {
+ if (DECL_BY_REFERENCE (decl_or_origin))
+ gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+ else
+ gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+ }
return gen_formal_parameter_die (decl, origin,
true /* Emit name attribute. */,
context_die);
dwarf2out_decl (context);
}
+ /* Emit an abstract origin of a function first. This happens
+ with C++ constructor clones for example and makes
+ dwarf2out_abstract_function happy which requires the early
+ DIE of the abstract instance to be present. */
+ if (DECL_ABSTRACT_ORIGIN (decl))
+ {
+ current_function_decl = DECL_ABSTRACT_ORIGIN (decl);
+ dwarf2out_decl (DECL_ABSTRACT_ORIGIN (decl));
+ }
+
current_function_decl = decl;
}
dwarf2out_decl (decl);
{
dw_die_ref die = lookup_decl_die (decl);
- /* We have to generate early debug late for LTO. */
+ /* We may have to generate early debug late for LTO in case debug
+ was not enabled at compile-time or the target doesn't support
+ the LTO early debug scheme. */
if (! die && in_lto_p)
{
dwarf2out_decl (decl);
case DW_MACRO_import:
dw2_asm_output_data (1, ref->code, "Import");
ASM_GENERATE_INTERNAL_LABEL (label,
- DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+ DEBUG_MACRO_SECTION_LABEL,
+ ref->lineno + macinfo_label_base);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
break;
default:
/* Output macinfo section(s). */
static void
-output_macinfo (void)
+output_macinfo (const char *debug_line_label, bool early_lto_debug)
{
unsigned i;
unsigned long length = vec_safe_length (macinfo_table);
/* AIX Assembler inserts the length, so adjust the reference to match the
offset expected by debuggers. */
- strcpy (dl_section_ref, debug_line_section_label);
+ strcpy (dl_section_ref, debug_line_label);
if (XCOFF_DEBUGGING_INFO)
strcat (dl_section_ref, DWARF_INITIAL_LENGTH_SIZE_STR);
dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
else
dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
- dw2_asm_output_offset (DWARF_OFFSET_SIZE,
- (!dwarf_split_debug_info ? dl_section_ref
- : debug_skeleton_line_section_label),
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_label,
debug_line_section, NULL);
}
if (!macinfo_htab)
return;
+ /* Save the number of transparent includes so we can adjust the
+ label number for the fat LTO object DWARF. */
+ unsigned macinfo_label_base_adj = macinfo_htab->elements ();
+
delete macinfo_htab;
macinfo_htab = NULL;
dw2_asm_output_data (1, 0, "End compilation unit");
targetm.asm_out.named_section (debug_macinfo_section_name,
SECTION_DEBUG
- | SECTION_LINKONCE,
+ | SECTION_LINKONCE
+ | (early_lto_debug
+ ? SECTION_EXCLUDE : 0),
comdat_key);
ASM_GENERATE_INTERNAL_LABEL (label,
DEBUG_MACRO_SECTION_LABEL,
- ref->lineno);
+ ref->lineno + macinfo_label_base);
ASM_OUTPUT_LABEL (asm_out_file, label);
ref->code = 0;
ref->info = NULL;
default:
gcc_unreachable ();
}
+
+ macinfo_label_base += macinfo_label_base_adj;
}
-/* Initialize the various sections and labels for dwarf output. */
+/* Initialize the various sections and labels for dwarf output and prefix
+ them with PREFIX if non-NULL. */
static void
-init_sections_and_labels (void)
+init_sections_and_labels (bool early_lto_debug)
{
- if (!dwarf_split_debug_info)
+ /* As we may get called multiple times have a generation count for labels. */
+ static unsigned generation = 0;
+
+ if (early_lto_debug)
{
- debug_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- debug_loc_section = get_section (dwarf_version >= 5
- ? DEBUG_LOCLISTS_SECTION
- : DEBUG_LOC_SECTION,
- SECTION_DEBUG, NULL);
- debug_macinfo_section_name
- = (dwarf_strict && dwarf_version < 5)
- ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
- debug_macinfo_section = get_section (debug_macinfo_section_name,
- SECTION_DEBUG, NULL);
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_macinfo_section_name = ((dwarf_strict && dwarf_version < 5)
+ ? DEBUG_LTO_MACINFO_SECTION
+ : DEBUG_LTO_MACRO_SECTION);
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ /* For macro info we have to refer to a debug_line section, so similar
+ to split-dwarf emit a skeleton one for early debug. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ }
+ else
+ {
+ /* ??? Which of the following do we need early? */
+ debug_info_section = get_section (DEBUG_LTO_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_LTO_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_skeleton_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG
+ | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+ generation);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
+ the main .o, but the skeleton_line goes into the split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_LTO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ debug_str_offsets_section
+ = get_section (DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL,
+ generation);
+ debug_str_dwo_section = get_section (DEBUG_LTO_STR_DWO_SECTION,
+ DEBUG_STR_DWO_SECTION_FLAGS, NULL);
+ debug_macinfo_section_name
+ = (dwarf_strict
+ ? DEBUG_LTO_DWO_MACINFO_SECTION : DEBUG_LTO_DWO_MACRO_SECTION);
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ }
+ debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS
+ | SECTION_EXCLUDE, NULL);
}
else
{
- debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- debug_addr_section = get_section (DEBUG_ADDR_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
- SECTION_DEBUG, NULL);
- debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
- SECTION_DEBUG, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
- DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
-
- /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
- the main .o, but the skeleton_line goes into the split off dwo. */
- debug_skeleton_line_section
- = get_section (DEBUG_DWO_LINE_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
- DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
- debug_str_offsets_section = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE,
- NULL);
- ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
- DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
- debug_loc_section = get_section (dwarf_version >= 5
- ? DEBUG_DWO_LOCLISTS_SECTION
- : DEBUG_DWO_LOC_SECTION,
- SECTION_DEBUG | SECTION_EXCLUDE, NULL);
- debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
- DEBUG_STR_DWO_SECTION_FLAGS, NULL);
- debug_macinfo_section_name
- = (dwarf_strict && dwarf_version < 5)
- ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
- debug_macinfo_section = get_section (debug_macinfo_section_name,
+ if (!dwarf_split_debug_info)
+ {
+ debug_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_macinfo_section_name
+ = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG, NULL);
+ }
+ else
+ {
+ debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ debug_addr_section = get_section (DEBUG_ADDR_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+ DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+ generation);
+
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections
+ stay in the main .o, but the skeleton_line goes into the
+ split off dwo. */
+ debug_skeleton_line_section
+ = get_section (DEBUG_DWO_LINE_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+ DEBUG_SKELETON_LINE_SECTION_LABEL,
+ generation);
+ debug_str_offsets_section
+ = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+ ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+ DEBUG_SKELETON_INFO_SECTION_LABEL,
+ generation);
+ debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
- }
- debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_line_section = get_section (DEBUG_LINE_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
- SECTION_DEBUG, NULL);
- debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
+ DEBUG_STR_DWO_SECTION_FLAGS,
+ NULL);
+ debug_macinfo_section_name
+ = (dwarf_strict && dwarf_version < 5)
+ ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
+ debug_macinfo_section = get_section (debug_macinfo_section_name,
+ SECTION_DEBUG | SECTION_EXCLUDE,
+ NULL);
+ }
+ debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
- debug_str_section = get_section (DEBUG_STR_SECTION,
- DEBUG_STR_SECTION_FLAGS, NULL);
- if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
- debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
- DEBUG_STR_SECTION_FLAGS, NULL);
-
- debug_ranges_section = get_section (dwarf_version >= 5
- ? DEBUG_RNGLISTS_SECTION
- : DEBUG_RANGES_SECTION,
- SECTION_DEBUG, NULL);
- debug_frame_section = get_section (DEBUG_FRAME_SECTION,
- SECTION_DEBUG, NULL);
+ debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_str_section = get_section (DEBUG_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
+ debug_ranges_section = get_section (dwarf_version >= 5
+ ? DEBUG_RNGLISTS_SECTION
+ : DEBUG_RANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ }
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
- DEBUG_ABBREV_SECTION_LABEL, 0);
+ DEBUG_ABBREV_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
- DEBUG_INFO_SECTION_LABEL, 0);
+ DEBUG_INFO_SECTION_LABEL, generation);
+ info_section_emitted = false;
ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
- DEBUG_LINE_SECTION_LABEL, 0);
+ DEBUG_LINE_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
- DEBUG_RANGES_SECTION_LABEL, 0);
+ DEBUG_RANGES_SECTION_LABEL, generation);
if (dwarf_version >= 5 && dwarf_split_debug_info)
ASM_GENERATE_INTERNAL_LABEL (ranges_base_label,
- DEBUG_RANGES_SECTION_LABEL, 1);
+ DEBUG_RANGES_SECTION_LABEL, 2 + generation);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
- DEBUG_ADDR_SECTION_LABEL, 0);
+ DEBUG_ADDR_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
(dwarf_strict && dwarf_version < 5)
? DEBUG_MACINFO_SECTION_LABEL
- : DEBUG_MACRO_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
+ : DEBUG_MACRO_SECTION_LABEL, generation);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL,
+ generation);
+
+ ++generation;
}
/* Set up for Dwarf output at the start of compilation. */
}
}
+/* Reset DIEs so we can output them again. */
+
+static void
+reset_dies (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ /* Remove stuff we re-generate. */
+ die->die_mark = 0;
+ die->die_offset = 0;
+ die->die_abbrev = 0;
+ remove_AT (die, DW_AT_sibling);
+
+ FOR_EACH_CHILD (die, c, reset_dies (c));
+}
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
gen_remaining_tmpl_value_param_die_attribute ();
+ if (flag_generate_lto)
+ {
+ gcc_assert (flag_fat_lto_objects);
+
+ /* Prune stuff so that dwarf2out_finish runs successfully
+ for the fat part of the object. */
+ reset_dies (comp_unit_die ());
+ for (limbo_die_node *node = cu_die_list; node; node = node->next)
+ reset_dies (node->die);
+
+ hash_table<comdat_type_hasher> comdat_type_table (100);
+ for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+ {
+ comdat_type_node **slot
+ = comdat_type_table.find_slot (ctnode, INSERT);
+
+ /* Don't reset types twice. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ reset_dies (ctnode->root_die);
+
+ *slot = ctnode;
+ }
+
+ /* Reset die CU symbol so we don't output it twice. */
+ comp_unit_die ()->die_id.die_symbol = NULL;
+
+ /* Remove DW_AT_macro from the early output. */
+ if (have_macinfo)
+ remove_AT (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE);
+
+ /* Remove indirect string decisions. */
+ debug_str_hash->traverse<void *, reset_indirect_string> (NULL);
+ }
+
#if ENABLE_ASSERT_CHECKING
{
dw_die_ref die = comp_unit_die (), c;
move_marked_base_types ();
/* Initialize sections and labels used for actual assembler output. */
- init_sections_and_labels ();
+ init_sections_and_labels (false);
/* Traverse the DIE's and add sibling attributes to those DIE's that
have children. */
dl_section_ref);
if (have_macinfo)
- add_AT_macptr (comp_unit_die (),
- dwarf_version >= 5 ? DW_AT_macros
- : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+ add_AT_macptr (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE,
macinfo_section_label);
if (dwarf_split_debug_info)
{
switch_to_section (debug_macinfo_section);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
- output_macinfo ();
+ output_macinfo (!dwarf_split_debug_info ? debug_line_section_label
+ : debug_skeleton_line_section_label, false);
dw2_asm_output_data (1, 0, "End compilation unit");
}
{
tree decl = loc->dw_loc_oprnd1.v.val_decl_ref;
dw_die_ref ref = lookup_decl_die (decl);
+ if (! ref && flag_generate_lto)
+ {
+ /* ??? This is somewhat a hack because we do not create DIEs
+ for variables not in BLOCK trees early but when generating
+ early LTO output we need the dw_val_class_decl_ref to be
+ fully resolved. For fat LTO objects we'd also like to
+ undo this after LTO dwarf output. */
+ gcc_assert (DECL_CONTEXT (decl));
+ dw_die_ref ctx = lookup_decl_die (DECL_CONTEXT (decl));
+ gcc_assert (ctx != NULL);
+ gen_decl_die (decl, NULL_TREE, NULL, ctx);
+ ref = lookup_decl_die (decl);
+ gcc_assert (ref != NULL);
+ }
if (ref)
{
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
/* The early debug phase is now finished. */
early_dwarf_finished = true;
+
+ /* Do not generate DWARF assembler now when not producing LTO bytecode. */
+ if (!flag_generate_lto)
+ return;
+
+ /* Now as we are going to output for LTO initialize sections and labels
+ to the LTO variants. We don't need a random-seed postfix as other
+ LTO sections as linking the LTO debug sections into one in a partial
+ link is fine. */
+ init_sections_and_labels (true);
+
+ /* The output below is modeled after dwarf2out_finish with all
+ location related output removed and some LTO specific changes.
+ Some refactoring might make both smaller and easier to match up. */
+
+ /* Traverse the DIE's and add add sibling attributes to those DIE's
+ that have children. */
+ add_sibling_attributes (comp_unit_die ());
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ add_sibling_attributes (node->die);
+ for (comdat_type_node *ctnode = comdat_type_list;
+ ctnode != NULL; ctnode = ctnode->next)
+ add_sibling_attributes (ctnode->root_die);
+
+ if (have_macinfo)
+ add_AT_macptr (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE,
+ macinfo_section_label);
+
+ save_macinfo_strings ();
+
+ /* Output all of the compilation units. We put the main one last so that
+ the offsets are available to output_pubnames. */
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ output_comp_unit (node->die, 0, NULL);
+
+ hash_table<comdat_type_hasher> comdat_type_table (100);
+ for (comdat_type_node *ctnode = comdat_type_list;
+ ctnode != NULL; ctnode = ctnode->next)
+ {
+ comdat_type_node **slot = comdat_type_table.find_slot (ctnode, INSERT);
+
+ /* Don't output duplicate types. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_TERSE)
+ add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
+ (!dwarf_split_debug_info
+ ? debug_line_section_label
+ : debug_skeleton_line_section_label));
+
+ output_comdat_type_unit (ctnode);
+ *slot = ctnode;
+ }
+
+ /* The AT_pubnames attribute needs to go in all skeleton dies, including
+ both the main_cu and all skeleton TUs. Making this call unconditional
+ would end up either adding a second copy of the AT_pubnames attribute, or
+ requiring a special case in add_top_level_skeleton_die_attrs. */
+ if (!dwarf_split_debug_info)
+ add_AT_pubnames (comp_unit_die ());
+
+ /* Stick a unique symbol to the main debuginfo section. */
+ compute_comp_unit_symbol (comp_unit_die ());
+
+ /* Output the main compilation unit. We always need it if only for
+ the CU symbol. */
+ output_comp_unit (comp_unit_die (), true, NULL);
+
+ /* Output the abbreviation table. */
+ if (vec_safe_length (abbrev_die_table) != 1)
+ {
+ switch_to_section (debug_abbrev_section);
+ ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
+ output_abbrev_section ();
+ }
+
+ /* Have to end the macro section. */
+ if (have_macinfo)
+ {
+ /* We have to save macinfo state if we need to output it again
+ for the FAT part of the object. */
+ vec<macinfo_entry, va_gc> *saved_macinfo_table = macinfo_table;
+ if (flag_fat_lto_objects)
+ macinfo_table = macinfo_table->copy ();
+
+ switch_to_section (debug_macinfo_section);
+ ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+ output_macinfo (debug_skeleton_line_section_label, true);
+ dw2_asm_output_data (1, 0, "End compilation unit");
+
+ /* Emit a skeleton debug_line section. */
+ switch_to_section (debug_skeleton_line_section);
+ ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
+ output_line_info (true);
+
+ if (flag_fat_lto_objects)
+ {
+ vec_free (macinfo_table);
+ macinfo_table = saved_macinfo_table;
+ }
+ }
+
+
+ /* If we emitted any indirect strings, output the string table too. */
+ if (debug_str_hash || skeleton_debug_str_hash)
+ output_indirect_strings ();
+
+ /* Switch back to the text section. */
+ switch_to_section (text_section);
}
/* Reset all state within dwarf2out.c so that we can rerun the compiler
#include "except.h"
#include "cgraph.h"
#include "cfgloop.h"
+#include "debug.h"
struct freeing_string_slot_hasher : string_slot_hasher
DECL_RESULT (fn_decl) = stream_read_tree (ib, data_in);
DECL_ARGUMENTS (fn_decl) = streamer_read_chain (ib, data_in);
+ /* Read debug args if available. */
+ unsigned n_debugargs = streamer_read_uhwi (ib);
+ if (n_debugargs)
+ {
+ vec<tree, va_gc> **debugargs = decl_debug_args_insert (fn_decl);
+ vec_safe_grow (*debugargs, n_debugargs);
+ for (unsigned i = 0; i < n_debugargs; ++i)
+ (**debugargs)[i] = stream_read_tree (ib, data_in);
+ }
+
/* Read the tree of lexical scopes for the function. */
DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
unsigned block_leaf_count = streamer_read_uhwi (ib);
}
+/* Queue of acummulated decl -> DIE mappings. Similar to locations those
+ are only applied to prevailing tree nodes during tree merging. */
+vec<dref_entry> dref_queue;
+
/* Read the physical representation of a tree node EXPR from
input block IB using the per-file context in DATA_IN. */
&& TREE_CODE (expr) != FUNCTION_DECL
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_register_external_die. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *str = streamer_read_string (data_in, ib);
+ if (str)
+ {
+ unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+ dref_entry e = { expr, str, off };
+ dref_queue.safe_push (e);
+ }
+ }
}
/* Read the physical representation of a tree node with tag TAG from
{
unsigned len, entry_len;
lto_input_scc (ib, data_in, &len, &entry_len);
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
}
return lto_input_tree_1 (ib, data_in, tag, 0);
}
#include "cfgloop.h"
#include "builtins.h"
#include "gomp-constants.h"
+#include "debug.h"
static void lto_write_tree (struct output_block*, tree, bool);
(ob->decl_state->symtab_node_encoder, expr);
stream_write_tree (ob, initial, ref_p);
}
+
+ /* Stream references to early generated DIEs. Keep in sync with the
+ trees handled in dwarf2out_die_ref_for_decl. */
+ if ((DECL_P (expr)
+ && TREE_CODE (expr) != FIELD_DECL
+ && TREE_CODE (expr) != DEBUG_EXPR_DECL
+ && TREE_CODE (expr) != TYPE_DECL)
+ || TREE_CODE (expr) == BLOCK)
+ {
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+ if (debug_info_level > DINFO_LEVEL_NONE
+ && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+ {
+ streamer_write_string (ob, ob->main_stream, sym, true);
+ streamer_write_uhwi (ob, off);
+ }
+ else
+ streamer_write_string (ob, ob->main_stream, NULL, true);
+ }
}
/* Write a physical representation of tree node EXPR to output block
;
else
DFS_follow_tree_edge (DECL_NAME (expr));
- DFS_follow_tree_edge (DECL_CONTEXT (expr));
+ if (TREE_CODE (expr) != TRANSLATION_UNIT_DECL
+ && ! DECL_CONTEXT (expr))
+ DFS_follow_tree_edge ((*all_translation_units)[0]);
+ else
+ DFS_follow_tree_edge (DECL_CONTEXT (expr));
}
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
declarations which should be eliminated by decl merging. Be sure none
leaks to this point. */
gcc_assert (DECL_ABSTRACT_ORIGIN (expr) != error_mark_node);
+ DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
if ((VAR_P (expr)
|| TREE_CODE (expr) == PARM_DECL)
stream_write_tree (ob, DECL_RESULT (function), true);
streamer_write_chain (ob, DECL_ARGUMENTS (function), true);
+ /* Output debug args if available. */
+ vec<tree, va_gc> **debugargs = decl_debug_args_lookup (function);
+ if (! debugargs)
+ streamer_write_uhwi (ob, 0);
+ else
+ {
+ streamer_write_uhwi (ob, (*debugargs)->length ());
+ for (unsigned i = 0; i < (*debugargs)->length (); ++i)
+ stream_write_tree (ob, (**debugargs)[i], true);
+ }
+
/* Output DECL_INITIAL for the function, which contains the tree of
lexical scopes. */
stream_write_tree (ob, DECL_INITIAL (function), true);
DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
+/* Entry for the delayed registering of decl -> DIE references. */
+struct dref_entry {
+ tree decl;
+ const char *sym;
+ unsigned HOST_WIDE_INT off;
+};
+
+extern vec<dref_entry> dref_queue;
+
+
#endif /* GCC_LTO_STREAMER_H */
static char **offload_names;
static char *offload_objects_file_name;
static char *makefile;
+static char *debug_obj;
const char tool_name[] = "lto-wrapper";
maybe_unlink (offload_objects_file_name);
if (makefile)
maybe_unlink (makefile);
+ if (debug_obj)
+ maybe_unlink (debug_obj);
for (i = 0; i < nr; ++i)
{
maybe_unlink (input_names[i]);
return true;
}
+/* Copy early debug info sections from INFILE to a new file whose name
+ is returned. Return NULL on error. */
+
+const char *
+debug_objcopy (const char *infile)
+{
+ const char *outfile;
+ const char *errmsg;
+ int err;
+
+ const char *p;
+ off_t inoff = 0;
+ long loffset;
+ int consumed;
+ if ((p = strrchr (infile, '@'))
+ && p != infile
+ && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (p) == (unsigned int) consumed)
+ {
+ char *fname = xstrdup (infile);
+ fname[p - infile] = '\0';
+ infile = fname;
+ inoff = (off_t) loffset;
+ }
+ int infd = open (infile, O_RDONLY);
+ if (infd == -1)
+ return NULL;
+ simple_object_read *inobj = simple_object_start_read (infd, inoff,
+ "__GNU_LTO",
+ &errmsg, &err);
+ if (!inobj)
+ return NULL;
+
+ off_t off, len;
+ if (simple_object_find_section (inobj, ".gnu.debuglto_.debug_info",
+ &off, &len, &errmsg, &err) != 1)
+ {
+ if (errmsg)
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+
+ simple_object_release_read (inobj);
+ close (infd);
+ return NULL;
+ }
+
+ outfile = make_temp_file ("debugobjtem");
+ errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err);
+ if (errmsg)
+ {
+ unlink_if_ordinary (outfile);
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+ }
+
+ simple_object_release_read (inobj);
+ close (infd);
+
+ return outfile;
+}
+
+
+
/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
static void
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
- unsigned lto_argc = 0;
- char **lto_argv;
+ unsigned lto_argc = 0, ltoobj_argc = 0;
+ char **lto_argv, **ltoobj_argv;
+ bool skip_debug = false;
+ unsigned n_debugobj;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
/* Allocate array for input object files with LTO IL,
and for possible preceding arguments. */
lto_argv = XNEWVEC (char *, argc);
+ ltoobj_argv = XNEWVEC (char *, argc);
/* Look at saved options in the IL files. */
for (i = 1; i < argc; ++i)
collect_gcc))
{
have_lto = true;
- lto_argv[lto_argc++] = argv[i];
+ ltoobj_argv[ltoobj_argc++] = argv[i];
}
close (fd);
}
}
}
+ /* Output lto-wrapper invocation command. */
+ if (verbose)
+ {
+ for (i = 0; i < argc; ++i)
+ {
+ fputs (argv[i], stderr);
+ fputc (' ', stderr);
+ }
+ fputc ('\n', stderr);
+ }
+
if (no_partition)
{
lto_mode = LTO_MODE_LTO;
obstack_ptr_grow (&argv_obstack, "-fwpa");
}
- /* Append the input objects and possible preceding arguments. */
+ /* Append input arguments. */
for (i = 0; i < lto_argc; ++i)
obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+ /* Append the input objects. */
+ for (i = 0; i < ltoobj_argc; ++i)
+ obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
+ /* Handle early generated debug information. At compile-time
+ we output early DWARF debug info into .gnu.debuglto_ prefixed
+ sections. LTRANS object DWARF debug info refers to that.
+ So we need to transfer the .gnu.debuglto_ sections to the final
+ link. Ideally the linker plugin interface would allow us to
+ not claim those sections and instruct the linker to keep
+ them, renaming them in the process. For now we extract and
+ rename those sections via a simple-object interface to produce
+ regular objects containing only the early debug info. We
+ then partially link those to a single early debug info object
+ and pass that as additional output back to the linker plugin. */
+
+ /* Prepare the partial link to gather the compile-time generated
+ debug-info into a single input for the final link. */
+ debug_obj = make_temp_file ("debugobj");
+ obstack_ptr_grow (&argv_obstack, collect_gcc);
+ for (i = 1; i < decoded_options_count; ++i)
+ {
+ /* Retain linker choice and -B. */
+ if (decoded_options[i].opt_index == OPT_B
+ || decoded_options[i].opt_index == OPT_fuse_ld_bfd
+ || decoded_options[i].opt_index == OPT_fuse_ld_gold)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Retain all target options, this preserves -m32 for example. */
+ if (cl_options[decoded_options[i].opt_index].flags & CL_TARGET)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Recognize -g0. */
+ if (decoded_options[i].opt_index == OPT_g
+ && strcmp (decoded_options[i].arg, "0") == 0)
+ skip_debug = true;
+ }
+ obstack_ptr_grow (&argv_obstack, "-r");
+ obstack_ptr_grow (&argv_obstack, "-nostdlib");
+ obstack_ptr_grow (&argv_obstack, "-o");
+ obstack_ptr_grow (&argv_obstack, debug_obj);
+
+ /* Copy the early generated debug info from the objects to temporary
+ files and append those to the partial link commandline. */
+ n_debugobj = 0;
+ if (! skip_debug)
+ for (i = 0; i < ltoobj_argc; ++i)
+ {
+ const char *tem;
+ if ((tem = debug_objcopy (ltoobj_argv[i])))
+ {
+ obstack_ptr_grow (&argv_obstack, tem);
+ n_debugobj++;
+ }
+ }
+
+ /* Link them all into a single object. Ideally this would reduce
+ disk space usage mainly due to .debug_str merging but unfortunately
+ GNU ld doesn't perform this with -r. */
+ if (n_debugobj)
+ {
+ obstack_ptr_grow (&argv_obstack, NULL);
+ const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+ fork_execute (debug_link_argv[0],
+ CONST_CAST (char **, debug_link_argv), false);
+
+ /* And dispose the temporaries. */
+ for (i = 0; debug_link_argv[i]; ++i)
+ ;
+ for (--i; i > 0; --i)
+ {
+ if (strcmp (debug_link_argv[i], debug_obj) == 0)
+ break;
+ maybe_unlink (debug_link_argv[i]);
+ }
+ }
+ else
+ {
+ unlink_if_ordinary (debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ skip_debug = true;
+ }
+
if (lto_mode == LTO_MODE_LTO)
{
printf ("%s\n", flto_out);
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
free (flto_out);
flto_out = NULL;
}
for (i = 0; i < nr; ++i)
maybe_unlink (input_names[i]);
}
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
for (i = 0; i < nr; ++i)
{
fputs (output_names[i], stdout);
+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs.
+ (lto_read_decls): Process TRANSLATION_UNIT_DECLs. Remove
+ TYPE_DECL debug processing, register DIE references from
+ prevailing SCCs with the debug machinery.
+ (lto_section_with_id): Handle LTO debug sections.
+
2017-08-16 Nathan Sidwell <nathan@acm.org>
* lto.c (mentions_vars_p_type): Use TYPE_LANG_SLOT_1.
free_node (scc->entries[i]);
}
+ /* Drop DIE references. */
+ dref_queue.truncate (0);
+
break;
}
from);
if (len == 1
&& (TREE_CODE (first) == IDENTIFIER_NODE
- || TREE_CODE (first) == INTEGER_CST
- || TREE_CODE (first) == TRANSLATION_UNIT_DECL))
+ || TREE_CODE (first) == INTEGER_CST))
continue;
/* Try to unify the SCC with already existing ones. */
if (TREE_CODE (t) == INTEGER_CST
&& !TREE_OVERFLOW (t))
cache_integer_cst (t);
- /* Register TYPE_DECLs with the debuginfo machinery. */
- if (!flag_wpa
- && TREE_CODE (t) == TYPE_DECL)
- {
- /* Dwarf2out needs location information.
- TODO: Moving this out of the streamer loop may noticealy
- improve ltrans linemap memory use. */
- data_in->location_cache.apply_location_cache ();
- debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
- }
if (!flag_ltrans)
{
/* Register variables and functions with the
vec_safe_push (tree_with_vars, t);
}
}
+
+ /* Register DECLs with the debuginfo machinery. */
+ while (!dref_queue.is_empty ())
+ {
+ dref_entry e = dref_queue.pop ();
+ debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ }
+
if (seen_type)
num_type_scc_trees += len;
}
if (strncmp (name, section_name_prefix, strlen (section_name_prefix)))
return 0;
s = strrchr (name, '.');
- return s && sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
+ if (!s)
+ return 0;
+ /* If the section is not suffixed with an ID return. */
+ if ((size_t)(s - name) == strlen (section_name_prefix))
+ return 0;
+ return sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
}
/* Create file_data of each sub file id */
sdbout_late_global_decl, /* late_global_decl */
sdbout_symbol, /* type_decl */
debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
sdbout_label, /* label */
+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * c-c++-common/asan/global-overflow-1.c: Adjust diagnostic location
+ regex to handle the LTO case.
+ * c-c++-common/asan/heap-overflow-1.c: Likewise.
+ * c-c++-common/asan/misalign-1.c: Likewise.
+ * c-c++-common/asan/misalign-2.c: Likewise.
+ * c-c++-common/asan/null-deref-1.c: Likewise.
+ * c-c++-common/asan/stack-overflow-1.c: Likewise.
+ * c-c++-common/asan/strncpy-overflow-1.c: Likewise.
+ * c-c++-common/asan/use-after-free-1.c: Likewise.
+ * c-c++-common/asan/alloca_big_alignment.c: Likewise.
+ * c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
+ * c-c++-common/asan/alloca_overflow_partial.c: Likewise.
+ * c-c++-common/asan/alloca_overflow_right.c: Likewise.
+ * c-c++-common/asan/alloca_underflow_left.c: Likewise.
+ * g++.dg/asan/large-func-test-1.C: Likewise.
+ * gfortran.dg/save_6.f90: Add -flto -g variant of save_5.f90.
+
2017-08-21 Richard Biener <rguenther@suse.de>
PR middle-end/81884
}
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_big_alignment.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_big_alignment.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r\]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
/* { dg-output "\[^\n\r]*in foo.*alloca_big_alignment.c.*(\n|\r\n|\r)" */
}
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_detect_custom_size.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_detect_custom_size.c:16|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
/* { dg-output "\[^\n\r]*in foo.*alloca_detect_custom_size.c.*(\n|\r\n|\r)" */
}
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_partial.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_partial.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
/* { dg-output "\[^\n\r]*in foo.*alloca_overflow_partial.c.*(\n|\r\n|\r)" */
}
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_right.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_right.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
/* { dg-output "\[^\n\r]*in foo.*alloca_overflow_right.c.*(\n|\r\n|\r)" */
}
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_underflow_left.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_underflow_left.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
/* { dg-output "\[^\n\r]*in foo.*alloca_underflow_left.c.*(\n|\r\n|\r)" */
}
/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*global-overflow-1.c:20|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r).*" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*global-overflow-1.c:20|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r).*" } */
/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable" } */
/* { dg-output ".*YYY\[^\n\r]* of size 10\[^\n\r]*(\n|\r\n|\r)" } */
}
/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:21|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:21|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 0 bytes to the right of 10-byte region\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:19|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:19|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "ERROR: AddressSanitizer:\[^\n\r]*on address\[^\n\r]*" } */
/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*misalign-1.c:1\[01]|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-1.c:3\[45]|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*misalign-1.c:1\[01]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-1.c:3\[45]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "ERROR: AddressSanitizer:\[^\n\r]*on address\[^\n\r]*" } */
/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*baz(\[^\n\r]*misalign-2.c:2\[23]|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-2.c:3\[45]|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*baz(\[^\n\r]*misalign-2.c:2\[23]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-2.c:3\[45]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address\[^\n\r]*" } */
/* { dg-output "0x\[0-9a-f\]+ \[^\n\r]*pc 0x\[0-9a-f\]+.*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
}
/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*stack-overflow-1.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*stack-overflow-1.c:16|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
/* { dg-output "\[^\n\r]*in main.*stack-overflow-1.c.*(\n|\r\n|\r)" */
/* { dg-output "WRITE of size \[0-9\]* at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:10|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:9|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:9|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:8|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:8|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:7|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:7|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
// { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" }
// { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
// { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
-// { dg-output " #0 0x\[0-9a-f\]+ +(in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" }
+// { dg-output " #0 0x\[0-9a-f\]+ +(in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" }
// { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" }
// { dg-output "\[^\n\r]*allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" }
// { dg-output " #0( 0x\[0-9a-f\]+ +(in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
--- /dev/null
+! { dg-do run }
+! { dg-require-effective-target lto }
+! { dg-options "-fno-automatic -flto -g" }
+!
+! PR fortran/55733
+!
+! Check that -fno-automatic makes the local variable SAVEd
+! Check that -flto -g works
+!
+
+! Scalar allocatable
+subroutine foo(i)
+ integer :: i
+ integer, allocatable :: j
+ if (i == 1) j = 42
+ if (.not. allocated (j)) call abort ()
+ if (j /= 42) call abort ()
+end
+
+! Deferred-length string scalar
+subroutine bar()
+ logical, save :: first = .true.
+ character(len=:), allocatable :: str
+ if (first) then
+ first = .false.
+ if (allocated (str)) call abort ()
+ str = "ABCDEF"
+ end if
+ if (.not. allocated (str)) call abort ()
+ if (len (str) /= 6) call abort ()
+ if (str(1:6) /= "ABCDEF") call abort ()
+end subroutine bar
+
+! Deferred-length string array
+subroutine bar_array()
+ logical, save :: first = .true.
+ character(len=:), allocatable :: str
+ if (first) then
+ first = .false.
+ if (allocated (str)) call abort ()
+ str = "ABCDEF"
+ end if
+ if (.not. allocated (str)) call abort ()
+ if (len (str) /= 6) call abort ()
+ if (str(1:6) /= "ABCDEF") call abort ()
+end subroutine bar_array
+
+call foo(1)
+call foo(2)
+call bar()
+call bar_array()
+call bar()
+call bar_array()
+end
DECL_SIZE (expr) = stream_read_tree (ib, data_in);
DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
-
- /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
stream_write_tree (ob, NULL_TREE, ref_p);
else
stream_write_tree (ob, DECL_NAME (expr), ref_p);
- stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
+ if (TREE_CODE (expr) != TRANSLATION_UNIT_DECL
+ && ! DECL_CONTEXT (expr))
+ stream_write_tree (ob, (*all_translation_units)[0], ref_p);
+ else
+ stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
}
special handling in LTO, it must be handled by streamer hooks. */
stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
-
- /* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
- for early inlining so drop it on the floor instead of ICEing in
- dwarf2out.c. */
+ stream_write_tree (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
|| (!flag_generate_lto && !flag_generate_offload))
return 0;
+ /* Provide a dummy TRANSLATION_UNIT_DECL if the FE failed to provide one. */
+ if (vec_safe_is_empty (all_translation_units))
+ build_translation_unit_decl (NULL_TREE);
+
/* Allocate and assign alias sets to the standard integer types
while the slots are still in the way the frontends generated them. */
for (i = 0; i < itk_none; ++i)
case POINTER_TYPE:
case REFERENCE_TYPE:
case VECTOR_TYPE:
+ /* Ada can have pointer types refering to themselves indirectly. */
+ if (TREE_VISITED (type))
+ return false;
+ TREE_VISITED (type) = true;
if (variably_modified_type_p (TREE_TYPE (type), fn))
- return true;
+ {
+ TREE_VISITED (type) = false;
+ return true;
+ }
+ TREE_VISITED (type) = false;
break;
case FUNCTION_TYPE:
vmsdbgout_late_global_decl,
vmsdbgout_type_decl, /* type_decl */
debug_nothing_tree_tree_tree_bool_bool, /* imported_module_or_decl */
+ debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+ debug_nothing_tree_charstar_uhwi, /* register_external_die */
debug_nothing_tree, /* deferred_inline_function */
vmsdbgout_abstract_function,
debug_nothing_rtx_code_label, /* label */
+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * simple-object.h (simple_object_copy_lto_debug_sections): New
+ function.
+
2017-07-02 Jan Kratochvil <jan.kratochvil@redhat.com>
* dwarf2.def (DW_IDX_compile_unit, DW_IDX_type_unit, DW_IDX_die_offset)
extern void
simple_object_release_write (simple_object_write *);
+/* Copy LTO debug sections from SRC_OBJECT to DEST.
+ If an error occurs, return the errno value in ERR and an error string. */
+
+extern const char *
+simple_object_copy_lto_debug_sections (simple_object_read *src_object,
+ const char *dest,
+ int *err);
+
#ifdef __cplusplus
}
#endif
+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * simple-object-common.h (struct simple_object_functions): Add
+ copy_lto_debug_sections hook.
+ * simple-object.c: Include fcntl.h.
+ (handle_lto_debug_sections): New helper function.
+ (simple_object_copy_lto_debug_sections): New function copying
+ early LTO debug sections to regular debug sections in a new file.
+ (simple_object_start_write): Handle NULL segment_name.
+ * simple-object-coff.c (simple_object_coff_functions): Adjust
+ for not implemented copy_lto_debug_sections hook.
+ * simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
+ * simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
+ * simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
+ SHT_GROUP): Add various sectopn header types.
+ (SHF_EXCLUDE): Add flag.
+ (Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
+ (ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
+ (STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
+ (STV_DEFAULT): Add symbol visibility.
+ (SHN_COMMON): Add special section index name.
+ (struct simple_object_elf_write): New.
+ (simple_object_elf_start_write): Adjust for new private data.
+ (simple_object_elf_write_shdr): Pass in values for all fields
+ we write.
+ (simple_object_elf_write_to_file): Adjust. Copy from recorded
+ section headers if requested.
+ (simple_object_elf_release_write): Release private data.
+ (simple_object_elf_copy_lto_debug_sections): Copy and rename sections
+ as denoted by PFN and all their dependences, symbols and relocations
+ to the empty destination file.
+ (simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
+
2017-07-02 Jan Kratochvil <jan.kratochvil@redhat.com>
* dwarfnames.c (DW_FIRST_IDX, DW_END_IDX, DW_IDX, DW_IDX_DUP): New.
simple_object_coff_release_attributes,
simple_object_coff_start_write,
simple_object_coff_write_to_file,
- simple_object_coff_release_write
+ simple_object_coff_release_write,
+ NULL
};
/* Release the private data for an simple_object_write. */
void (*release_write) (void *);
+
+ /* Copy LTO debug sections. */
+ const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
+ simple_object_write *dobj,
+ int (*pfn) (const char **),
+ int *err);
};
/* The known object file formats. */
/* Special section index values. */
+#define SHN_UNDEF 0 /* Undefined section */
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
+#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
+
/* 32-bit ELF program header. */
typedef struct {
/* Values for sh_type field. */
+#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Link editing symbol table */
#define SHT_STRTAB 3 /* A string table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_GROUP 17 /* Section contains a section group */
+
+/* Values for sh_flags field. */
+
+#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude this
+ section from executable and
+ shared library that it builds
+ when those objects are not to be
+ further relocated. */
+/* Symbol table entry. */
+
+typedef struct
+{
+ unsigned char st_name[4]; /* Symbol name (string tbl index) */
+ unsigned char st_value[4]; /* Symbol value */
+ unsigned char st_size[4]; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ unsigned char st_shndx[2]; /* Section index */
+} Elf32_External_Sym;
+
+typedef struct
+{
+ unsigned char st_name[4]; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ unsigned char st_shndx[2]; /* Section index */
+ unsigned char st_value[8]; /* Symbol value */
+ unsigned char st_size[8]; /* Symbol size */
+} Elf64_External_Sym;
+
+#define ELF_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF_ST_TYPE(val) ((val) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_TLS 6 /* Thread local data object */
+#define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+
+#define STV_DEFAULT 0 /* Visibility is specified by binding type */
/* Functions to fetch and store different ELF types, depending on the
endianness and size. */
unsigned int flags;
};
+/* Private data for an simple_object_write. */
+
+struct simple_object_elf_write
+{
+ struct simple_object_elf_attributes attrs;
+ unsigned char *shdrs;
+};
+
/* See if we have an ELF file. */
static void *
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) attributes_data;
- struct simple_object_elf_attributes *ret;
+ struct simple_object_elf_write *ret;
/* We're just going to record the attributes, but we need to make a
copy because the user may delete them. */
- ret = XNEW (struct simple_object_elf_attributes);
- *ret = *attrs;
+ ret = XNEW (struct simple_object_elf_write);
+ ret->attrs = *attrs;
+ ret->shdrs = NULL;
return ret;
}
simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
off_t offset, unsigned int sh_name,
unsigned int sh_type, unsigned int sh_flags,
+ off_t sh_addr,
unsigned int sh_offset, unsigned int sh_size,
- unsigned int sh_link, unsigned int sh_addralign,
+ unsigned int sh_link, unsigned int sh_info,
+ unsigned int sh_addralign,
+ unsigned int sh_entsize,
const char **errmsg, int *err)
{
struct simple_object_elf_attributes *attrs =
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
- /* sh_info left as zero. */
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
- /* sh_entsize left as zero. */
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
return simple_object_internal_write (descriptor, offset, buf, shdr_size,
errmsg, err);
simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
int *err)
{
- struct simple_object_elf_attributes *attrs =
- (struct simple_object_elf_attributes *) sobj->data;
+ struct simple_object_elf_write *eow =
+ (struct simple_object_elf_write *) sobj->data;
+ struct simple_object_elf_attributes *attrs = &eow->attrs;
unsigned char cl;
size_t ehdr_size;
size_t shdr_size;
unsigned int first_sh_link;
size_t sh_name;
unsigned char zero;
+ unsigned secnum;
if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
return errmsg;
else
first_sh_link = shnum - 1;
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- 0, 0, 0, 0, first_sh_size, first_sh_link,
- 0, &errmsg, err))
+ 0, 0, 0, 0, 0, first_sh_size, first_sh_link,
+ 0, 0, 0, &errmsg, err))
return errmsg;
shdr_offset += shdr_size;
sh_name = 1;
+ secnum = 0;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t mask;
size_t new_sh_offset;
size_t sh_size;
struct simple_object_write_section_buffer *buffer;
+ unsigned int sh_type = SHT_PROGBITS;
+ unsigned int sh_flags = 0;
+ off_t sh_addr = 0;
+ unsigned int sh_link = 0;
+ unsigned int sh_info = 0;
+ unsigned int sh_addralign = 1U << section->align;
+ unsigned int sh_entsize = 0;
+ if (eow->shdrs)
+ {
+ sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_type, Elf_Word);
+ sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_flags, Elf_Addr);
+ sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_addr, Elf_Addr);
+ sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_link, Elf_Word);
+ sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_info, Elf_Word);
+ sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_addralign, Elf_Addr);
+ sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_entsize, Elf_Word);
+ secnum++;
+ }
- mask = (1U << section->align) - 1;
+ mask = sh_addralign - 1;
new_sh_offset = sh_offset + mask;
new_sh_offset &= ~ mask;
while (new_sh_offset > sh_offset)
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- sh_name, SHT_PROGBITS, 0, sh_offset,
- sh_size, 0, 1U << section->align,
+ sh_name, sh_type, sh_flags,
+ sh_addr, sh_offset,
+ sh_size, sh_link, sh_info,
+ sh_addralign, sh_entsize,
&errmsg, err))
return errmsg;
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- sh_name, SHT_STRTAB, 0, sh_offset,
- sh_name + strlen (".shstrtab") + 1, 0,
- 1, &errmsg, err))
+ sh_name, SHT_STRTAB, 0, 0, sh_offset,
+ sh_name + strlen (".shstrtab") + 1, 0, 0,
+ 1, 0, &errmsg, err))
return errmsg;
/* .shstrtab has a leading zero byte. */
static void
simple_object_elf_release_write (void *data)
{
+ struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+ if (eow->shdrs)
+ XDELETE (eow->shdrs);
XDELETE (data);
}
+/* Copy all sections in an ELF file. */
+
+static const char *
+simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+ simple_object_write *dobj,
+ int (*pfn) (const char **),
+ int *err)
+{
+ struct simple_object_elf_read *eor =
+ (struct simple_object_elf_read *) sobj->data;
+ const struct elf_type_functions *type_functions = eor->type_functions;
+ struct simple_object_elf_write *eow =
+ (struct simple_object_elf_write *) dobj->data;
+ unsigned char ei_class = eor->ei_class;
+ size_t shdr_size;
+ unsigned int shnum;
+ unsigned char *shdrs;
+ const char *errmsg;
+ unsigned char *shstrhdr;
+ size_t name_size;
+ off_t shstroff;
+ unsigned char *names;
+ unsigned int i;
+ int *pfnret;
+ const char **pfnname;
+
+ shdr_size = (ei_class == ELFCLASS32
+ ? sizeof (Elf32_External_Shdr)
+ : sizeof (Elf64_External_Shdr));
+
+ /* Read the section headers. We skip section 0, which is not a
+ useful section. */
+
+ shnum = eor->shnum;
+ shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + eor->shoff + shdr_size,
+ shdrs,
+ shdr_size * (shnum - 1),
+ &errmsg, err))
+ {
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* Read the section names. */
+
+ shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+ name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shstrhdr, sh_size, Elf_Addr);
+ shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shstrhdr, sh_offset, Elf_Addr);
+ names = XNEWVEC (unsigned char, name_size);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + shstroff,
+ names, name_size, &errmsg, err))
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+ pfnret = XNEWVEC (int, shnum);
+ pfnname = XNEWVEC (const char *, shnum);
+
+ /* First perform the callbacks to know which sections to preserve and
+ what name to use for those. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_name;
+ const char *name;
+ int ret;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_name, Elf_Word);
+ if (sh_name >= name_size)
+ {
+ *err = 0;
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return "ELF section name out of range";
+ }
+
+ name = (const char *) names + sh_name;
+
+ ret = (*pfn) (&name);
+ pfnret[i - 1] = ret == 1 ? 0 : -1;
+ pfnname[i - 1] = name;
+ }
+
+ /* Mark sections as preserved that are required by to be preserved
+ sections. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_type, sh_info, sh_link;
+ off_t offset;
+ off_t length;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+ sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_info, Elf_Word);
+ sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ if (sh_type == SHT_GROUP)
+ {
+ /* Mark groups containing copied sections. */
+ unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_entsize, Elf_Addr);
+ unsigned char *ent, *buf;
+ int keep = 0;
+ offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_offset, Elf_Addr);
+ length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_size, Elf_Addr);
+ buf = XNEWVEC (unsigned char, length);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + offset, buf,
+ (size_t) length, &errmsg, err))
+ {
+ XDELETEVEC (buf);
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+ for (ent = buf + entsize; ent < buf + length; ent += entsize)
+ {
+ unsigned sec = type_functions->fetch_Elf_Word (ent);
+ if (pfnret[sec - 1] == 0)
+ keep = 1;
+ }
+ if (keep)
+ {
+ pfnret[sh_link - 1] = 0;
+ pfnret[i - 1] = 0;
+ }
+ }
+ if (sh_type == SHT_RELA
+ || sh_type == SHT_REL)
+ {
+ /* Mark relocation sections and symtab of copied sections. */
+ if (pfnret[sh_info - 1] == 0)
+ {
+ pfnret[sh_link - 1] = 0;
+ pfnret[i - 1] = 0;
+ }
+ }
+ if (sh_type == SHT_SYMTAB)
+ {
+ /* Mark strings sections of copied symtabs. */
+ if (pfnret[i - 1] == 0)
+ pfnret[sh_link - 1] = 0;
+ }
+ }
+
+ /* Then perform the actual copying. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_name, sh_type;
+ const char *name;
+ off_t offset;
+ off_t length;
+ int ret;
+ const char *errmsg;
+ simple_object_write_section *dest;
+ off_t flags;
+ unsigned char *buf;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_name, Elf_Word);
+ if (sh_name >= name_size)
+ {
+ *err = 0;
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return "ELF section name out of range";
+ }
+
+ name = (const char *) names + sh_name;
+ offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_offset, Elf_Addr);
+ length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_size, Elf_Addr);
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+
+ ret = pfnret[i - 1];
+ name = ret == 0 ? pfnname[i - 1] : "";
+
+ dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
+ if (dest == NULL)
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* Record the SHDR of the source. */
+ memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
+ shdr = eow->shdrs + (i - 1) * shdr_size;
+
+ /* Copy the data.
+ ??? This is quite wasteful and ideally would be delayed until
+ write_to_file (). Thus it questions the interfacing
+ which eventually should contain destination creation plus
+ writing. */
+ /* Keep empty sections for sections we should discard. This avoids
+ the need to rewrite section indices in symtab and relocation
+ sections. */
+ if (ret == 0)
+ {
+ buf = XNEWVEC (unsigned char, length);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + offset, buf,
+ (size_t) length, &errmsg, err))
+ {
+ XDELETEVEC (buf);
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* If we are processing .symtab purge __gnu_lto_v1 and
+ __gnu_lto_slim symbols from it. */
+ if (sh_type == SHT_SYMTAB)
+ {
+ unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_entsize, Elf_Addr);
+ unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
+ off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ strshdr, sh_offset, Elf_Addr);
+ size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ strshdr, sh_size, Elf_Addr);
+ char *strings = XNEWVEC (char, strsz);
+ unsigned char *ent;
+ simple_object_internal_read (sobj->descriptor,
+ sobj->offset + stroff,
+ (unsigned char *)strings,
+ strsz, &errmsg, err);
+ for (ent = buf; ent < buf + length; ent += entsize)
+ {
+ unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+ Sym, ent,
+ st_shndx, Elf_Half);
+ unsigned char *st_info;
+ unsigned char *st_other;
+ int discard = 0;
+ if (ei_class == ELFCLASS32)
+ {
+ st_info = &((Elf32_External_Sym *)ent)->st_info;
+ st_other = &((Elf32_External_Sym *)ent)->st_other;
+ }
+ else
+ {
+ st_info = &((Elf64_External_Sym *)ent)->st_info;
+ st_other = &((Elf64_External_Sym *)ent)->st_other;
+ }
+ /* Eliminate all COMMONs - this includes __gnu_lto_v1
+ and __gnu_lto_slim which otherwise cause endless
+ LTO plugin invocation. */
+ if (st_shndx == SHN_COMMON)
+ /* Setting st_name to "" seems to work to purge
+ COMMON symbols (in addition to setting their
+ size to zero). */
+ discard = 1;
+ /* We also need to remove symbols refering to sections
+ we'll eventually remove as with fat LTO objects
+ we otherwise get duplicate symbols at final link
+ (with GNU ld, gold is fine and ignores symbols in
+ sections marked as EXCLUDE). ld/20513 */
+ else if (st_shndx != SHN_UNDEF
+ && st_shndx < shnum
+ && pfnret[st_shndx - 1] == -1)
+ discard = 1;
+
+ if (discard)
+ {
+ /* Make discarded symbols undefined and unnamed. */
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_name, Elf_Word, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_value, Elf_Addr, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_size, Elf_Word, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_shndx, Elf_Half, SHN_UNDEF);
+ *st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
+ STT_NOTYPE);
+ *st_other = STV_DEFAULT;
+ }
+ }
+ XDELETEVEC (strings);
+ }
+
+ errmsg = simple_object_write_add_data (dobj, dest,
+ buf, length, 1, err);
+ XDELETEVEC (buf);
+ if (errmsg)
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+ }
+ else
+ {
+ /* For deleted sections mark the section header table entry as
+ unused. That allows the link editor to remove it in a partial
+ link. */
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Addr, SHT_NULL);
+ }
+
+ flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_flags, Elf_Addr);
+ if (ret == 0)
+ flags &= ~SHF_EXCLUDE;
+ else if (ret == -1)
+ flags |= SHF_EXCLUDE;
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_flags, Elf_Addr, flags);
+ }
+
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (pfnret);
+ XDELETEVEC (pfnname);
+
+ return NULL;
+}
+
+
/* The ELF functions. */
const struct simple_object_functions simple_object_elf_functions =
simple_object_elf_release_attributes,
simple_object_elf_start_write,
simple_object_elf_write_to_file,
- simple_object_elf_release_write
+ simple_object_elf_release_write,
+ simple_object_elf_copy_lto_debug_sections
};
simple_object_mach_o_release_attributes,
simple_object_mach_o_start_write,
simple_object_mach_o_write_to_file,
- simple_object_mach_o_release_write
+ simple_object_mach_o_release_write,
+ NULL
};
simple_object_xcoff_release_attributes,
simple_object_xcoff_start_write,
simple_object_xcoff_write_to_file,
- simple_object_xcoff_release_write
+ simple_object_xcoff_release_write,
+ NULL
};
#include "simple-object.h"
#include <errno.h>
+#include <fcntl.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
return 1;
}
+/* Callback to identify and rename LTO debug sections by name.
+ Returns 1 if NAME is a LTO debug section, 0 if not. */
+
+static int
+handle_lto_debug_sections (const char **name)
+{
+ /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler
+ complains about bogus section flags. Which means we need to arrange
+ for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
+ fat lto object tooling work for the fat part). */
+ /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
+ sections. */
+ /* Copy LTO debug sections and rename them to their non-LTO name. */
+ if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
+ {
+ *name = *name + sizeof (".gnu.debuglto_") - 1;
+ return 1;
+ }
+ else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
+ {
+ *name = *name + sizeof (".gnu.lto_") - 1;
+ return 1;
+ }
+ return 0;
+}
+
+/* Copy LTO debug sections. */
+
+const char *
+simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+ const char *dest, int *err)
+{
+ const char *errmsg;
+ simple_object_write *dest_sobj;
+ simple_object_attributes *attrs;
+ int outfd;
+
+ if (! sobj->functions->copy_lto_debug_sections)
+ {
+ *err = EINVAL;
+ return "simple_object_copy_lto_debug_sections not implemented";
+ }
+
+ attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
+ if (! attrs)
+ return errmsg;
+ dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
+ simple_object_release_attributes (attrs);
+ if (! dest_sobj)
+ return errmsg;
+
+ errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
+ handle_lto_debug_sections,
+ err);
+ if (errmsg)
+ {
+ simple_object_release_write (dest_sobj);
+ return errmsg;
+ }
+
+ outfd = creat (dest, 00777);
+ if (outfd == -1)
+ {
+ *err = errno;
+ simple_object_release_write (dest_sobj);
+ return "open failed";
+ }
+
+ errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
+ close (outfd);
+ if (errmsg)
+ {
+ simple_object_release_write (dest_sobj);
+ return errmsg;
+ }
+
+ simple_object_release_write (dest_sobj);
+ return NULL;
+}
+
/* Fetch attributes. */
simple_object_attributes *
return NULL;
ret = XNEW (simple_object_write);
ret->functions = attrs->functions;
- ret->segment_name = xstrdup (segment_name);
+ ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
ret->sections = NULL;
ret->last_section = NULL;
ret->data = data;
+2017-08-21 Richard Biener <rguenther@suse.de>
+
+ * testsuite/libstdc++-prettyprinters/prettyprinters.exp: Run all
+ tests with -flto as well if supported.
+
2017-08-20 Martin Sebor <msebor@redhat.com>
PR c/81854
# <http://www.gnu.org/licenses/>.
load_lib gdb-test.exp
+load_lib target-supports.exp
dg-init
v3-build_support
gdb-dg-runtest [lsort [glob $srcdir/$subdir/*.cc]] \
"" "$DEFAULT_CXXFLAGS $PCH_CXXFLAGS"
+if { [check_effective_target_lto] } {
+ append cxxflags " -flto"
+ # work around sourceware.org 20882
+ regsub {^(.*)-Wl,--gc-sections(.*)$} $cxxldflags {\1\2} cxxldflags
+ gdb-dg-runtest [lsort [glob $srcdir/$subdir/*.cc]] \
+ "" "$DEFAULT_CXXFLAGS -flto $PCH_CXXFLAGS"
+}
+
if [info exists guality_gdb_name] {
unsetenv GUALITY_GDB_NAME
}