On Thu, 3 Aug 2017, Jason Merrill wrote: > On Thu, Aug 3, 2017 at 6:51 AM, Richard Biener <rguent...@suse.de> wrote: > > On Wed, 2 Aug 2017, Jason Merrill wrote: > > > >> On Wed, Aug 2, 2017 at 6:35 AM, Richard Biener <rguent...@suse.de> wrote: > >> > On Wed, 2 Aug 2017, Jason Merrill wrote: > >> > > >> >> On 05/19/2017 06:42 AM, Richard Biener wrote: > >> >> > + /* ??? In some cases the C++ FE (at least) fails to > >> >> > + set DECL_CONTEXT properly. Simply globalize stuff > >> >> > + in this case. For example > >> >> > + __dso_handle created via iostream line 74 col 25. */ > >> >> > + parent = comp_unit_die (); > >> >> > >> >> I've now fixed __dso_handle, so that can be removed from the comment, > >> >> but it > >> >> still makes sense to have this fall-back for the (permitted) case of > >> >> null > >> >> DECL_CONTEXT. > >> > > >> > Adjusted the comment. > >> > > >> >> > + /* ??? LANG issue - DW_TAG_module for fortran. Either look > >> >> > + at the input language (if we have enough DECL_CONTEXT to follow) > >> >> > + or use a bit in tree_decl_with_vis to record the distinction. */ > >> >> > >> >> Sure, you should be able to look at TRANSLATION_UNIT_LANGUAGE. > >> > > >> > Yeah, the comment says we might be able to walk DECL_CONTEXT up to > >> > a TRANSLATION_UNIT_DECL. I've amended is_fortran similar to as I > >> > amended is_cxx, providing an overload for a decl, factoring out common > >> > code. So this is now if (is_fortran (decl)) ... = new_die > >> > (DW_TAG_module,...). > >> > > >> >> > ! /* ??? 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). > >> >> > >> >> As in our previous discussion, I think -feliminate-dwarf2-dups can go > >> >> away > >> >> now. But this is a more general issue: die_offset has meant the offset > >> >> from > >> >> the beginning of the CU, but if with_offset is set it means an offset > >> >> from > >> >> die_symbol. Since with_offset changes the meaning of die_symbol and > >> >> die_offset, having different code here depending on that flag makes > >> >> sense. > >> >> > >> >> It seems likely that when -fEDD goes away, we will never again want to > >> >> do > >> >> direct symbolic references to DIEs, in which case we could drop the > >> >> current > >> >> meaning of die_symbol, and so we wouldn't need the with_offset flag. > >> > > >> > Yeah, I've been playing with a patch to remove -fEDD but it has conflicts > >> > with the early LTO debug work and thus I wanted to postpone it until > >> > after that goes in to avoid further churn. I hope that's fine, it's > >> > sth I'll tackle soon after this patch lands on trunk. > >> > >> Sure. > >> > >> >> > ! /* 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)) > >> >> > >> >> I think this check should just be !with_offset; if that flag is set the > >> >> DIE > >> >> doesn't actually have its own symbol. > >> > > >> > with_offset is set only during LTRANS phase for the DIEs refering to > >> > the early DIEs via the CU label. But the above is guarding the > >> > early phase when we do not want to output that CU label twice. > >> > > >> > Can we revisit this check when -fEDD has gone away? > >> > >> Yes. > >> > >> >> > ! if (old_die > >> >> > ! && (c = get_AT_ref (old_die, DW_AT_abstract_origin)) > >> >> > ! /* ??? In LTO all origin DIEs still refer to the early > >> >> > ! debug copy. Detect that. */ > >> >> > ! && get_AT (c, DW_AT_inline)) > >> >> ... > >> >> > ! /* "Unwrap" the decls DIE which we put in the imported unit > >> >> > context. > >> >> > ! ??? If we finish dwarf2out_function_decl refactoring we > >> >> > can > >> >> > ! do this in a better way from the start and only lazily emit > >> >> > ! the early DIE references. */ > >> >> > >> >> It seems like in gen_subprogram_die you deliberately avoid reusing the > >> >> DIE > >> >> from dwarf2out_register_external_die (since it doesn't have > >> >> DW_AT_inline), and > >> >> then in add_abstract_origin_attribute you need to look through that > >> >> redundant > >> >> die. Why not reuse it? > >> > > >> > What we're doing here is dealing with the case of an inlined > >> > instance which is adjusted to point back to the early debug copy > >> > directly than to the wrapping DIE (supposed to eventually contain > >> > the concrete instance). > >> > >> But we enter this block when we're emitting the concrete out-of-line > >> instance, and the DW_AT_inline check prevents us from using the > >> wrapping DIE for the out-of-line instance. > >> > >> The comment should really change "inlined instance" to "concrete > >> instance"; inlined instances are handled in > >> gen_inlined_subroutine_die. > > > > You are right. I suspect I got confused by the comment when looking > > for a way to paper over the check_die ICE removing the check causes. > > We end up adding DW_AT_inline to the DIE which means check_die isn't > > happy with us using it for the concrete instance. > > > > That happens in two places, first add_abstract_origin_attribute > > calling dwarf2out_abstract_function for origin != FUNCTION_DECL/BLOCK > > and second from RTL expansion calling the same function via the > > debug hook. Both of this should be obsoleted by the early debug > > work on trunk. Then we do the same from gen_decl_die. I'm not sure > > that those cases are obsolete by now - the clone case should > > eventually be, but we can probably guard them with early_dwarf -- this > > exposes the issue that gen_subprogram_die happily re-uses the old_die > > even if DW_AT_inline is set, so the set_decl_origin_self must > > matter here. During early dwarf cgraph_function_possibly_inlined_p > > returns false. Not sure what is best here - either guarding > > gen_subprogram_die or doing set_decl_origin_self in > > dwarf2out_abstract_function? Doing the latter now with the idea > > this origin might be important elsewhere. For in_lto_p we also need to > > avoid dwarf2out_abstract_function, easiest by adding a > > || get_AT (old_die, DW_AT_abstract_origin) to the existing check > > for DW_AT_inline (that might have fixed all of the issues above, > > just in case you are hot happy with them). > > > > I've changed the comment in add_abstract_origin_attribute as the > > unwrapping is really because of the inlined subroutine case. It > > also ends up applying to the case of clones where I'm less sure > > if the abstract origin should point to the concrete instance or > > the abstract copy (without LTO it points at the abstract copy > > and thus matches what the patch ends up doing). > > > > So with the following I see the DIEs used for the concrete instance > > as intented and the abstract copy in the early object refered to > > by inline instances (and the concrete instance of course). > > > > Re-doing testing... > > OK if testing passes.
Thanks. Meanwhile testing passed. Bootstrapped and tested on x86_64-unknown-linux-gnu, LTO bootstrapped on x86_64-unknown-linux-gnu (both all languages). I've successfully built SPEC CPU 2006 with -flto -g (provides reasonable Fortran coverage). I've successfully ran the GCC testsuite with -flto -g which shows lots of FAILs but doesn't regress in any unexpected ways compared to before the patches. I'll ping Ian about the simple-object part again and will apply earliest at Aug 14th. Richard. 2017-08-04 Richard Biener <rguent...@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. Cleanups we can do (and need) when removing the "old" LTO path and add the early LTO path. (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). * 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. lto/ * 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. libstdc++/ * testsuite/libstdc++-prettyprinters/prettyprinters.exp: Run all tests with -flto as well if supported. * 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. Index: early-lto-debug/gcc/dwarf2out.c =================================================================== *** early-lto-debug.orig/gcc/dwarf2out.c 2017-08-02 10:20:42.693584645 +0200 --- early-lto-debug/gcc/dwarf2out.c 2017-08-03 12:44:13.545059174 +0200 *************** static GTY(()) section *debug_aranges_se *** 162,167 **** --- 162,168 ---- 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_begin_function (tr *** 2690,2695 **** --- 2691,2700 ---- 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. */ *************** const struct gcc_debug_hooks dwarf2_debu *** 2724,2729 **** --- 2729,2736 ---- 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 *************** const struct gcc_debug_hooks dwarf2_line *** 2765,2770 **** --- 2772,2779 ---- 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 */ *************** typedef struct GTY((chain_circular ("%h. *** 2893,2898 **** --- 2902,2910 ---- /* 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. */ *************** new_addr_loc_descr (rtx addr, enum dtpre *** 3696,3707 **** --- 3708,3731 ---- #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 *************** new_addr_loc_descr (rtx addr, enum dtpre *** 3714,3731 **** --- 3738,3770 ---- #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 *************** new_addr_loc_descr (rtx addr, enum dtpre *** 3754,3765 **** --- 3793,3813 ---- #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 *************** new_addr_loc_descr (rtx addr, enum dtpre *** 3784,3789 **** --- 3832,3841 ---- /* 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. */ *************** set_indirect_string (struct indirect_str *** 4372,4377 **** --- 4424,4447 ---- } } + /* 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. */ *************** get_AT_file (dw_die_ref die, enum dwarf_ *** 5017,5022 **** --- 5087,5107 ---- 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 *************** is_cxx (const_tree decl) *** 5035,5048 **** { 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); ! } if (context && TRANSLATION_UNIT_LANGUAGE (context)) return strncmp (TRANSLATION_UNIT_LANGUAGE (context), "GNU C++", 7) == 0; } --- 5120,5126 ---- { if (in_lto_p) { ! const_tree context = get_ultimate_context (decl); if (context && TRANSLATION_UNIT_LANGUAGE (context)) return strncmp (TRANSLATION_UNIT_LANGUAGE (context), "GNU C++", 7) == 0; } *************** is_fortran (void) *** 5063,5068 **** --- 5141,5161 ---- || 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 *************** lookup_decl_die (tree decl) *** 5407,5412 **** --- 5500,5683 ---- 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 *************** print_dw_val (dw_val_node *val, bool rec *** 5894,5900 **** die->die_id.die_type_node->signature); } else if (die->die_id.die_symbol) ! fprintf (outfile, "die -> label: %s", die->die_id.die_symbol); else fprintf (outfile, "die -> %ld", die->die_offset); fprintf (outfile, " (%p)", (void *) die); --- 6165,6175 ---- die->die_id.die_type_node->signature); } else if (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 const char *comdat_symbol_id; *** 7207,7216 **** 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. */ static void ! compute_section_prefix (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"; --- 7482,7491 ---- static unsigned int comdat_symbol_number; /* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its ! children, and set die_symbol. */ static void ! 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"; *************** compute_section_prefix (dw_die_ref unit_ *** 7229,7235 **** unmark_all_dies (unit_die); md5_finish_ctx (&ctx, checksum); ! sprintf (name, "%s.", base); clean_symbol_name (name); p = name + strlen (name); --- 7504,7514 ---- unmark_all_dies (unit_die); md5_finish_ctx (&ctx, checksum); ! /* 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); *************** compute_section_prefix (dw_die_ref unit_ *** 7239,7245 **** p += 2; } ! comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name); comdat_symbol_number = 0; } --- 7518,7532 ---- p += 2; } ! 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; } *************** output_die (dw_die_ref die) *** 9965,9971 **** /* 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) output_die_symbol (die); dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)", --- 10252,10262 ---- /* 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 ! /* 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)", *************** output_die (dw_die_ref die) *** 10158,10165 **** size = DWARF2_ADDR_SIZE; else size = DWARF_OFFSET_SIZE; ! dw2_asm_output_offset (size, sym, debug_info_section, "%s", ! name); } } else --- 10449,10468 ---- size = DWARF2_ADDR_SIZE; else size = DWARF_OFFSET_SIZE; ! /* ??? 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 *************** output_comp_unit (dw_die_ref die, int ou *** 10385,10391 **** calc_die_sizes (die); oldsym = die->die_id.die_symbol; ! if (oldsym) { tmp = XALLOCAVEC (char, strlen (oldsym) + 24); --- 10688,10694 ---- calc_die_sizes (die); oldsym = die->die_id.die_symbol; ! if (oldsym && die->comdat_type_p) { tmp = XALLOCAVEC (char, strlen (oldsym) + 24); *************** output_comp_unit (dw_die_ref die, int ou *** 10401,10406 **** --- 10704,10732 ---- 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); *************** parameter_ref_descriptor (rtx rtl) *** 14517,14522 **** --- 14843,14851 ---- 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) *************** add_abstract_origin_attribute (dw_die_re *** 20188,20214 **** { dw_die_ref origin_die = NULL; ! if (TREE_CODE (origin) != FUNCTION_DECL ! && TREE_CODE (origin) != BLOCK) { ! /* 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); } - - 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) --- 20517,20535 ---- { dw_die_ref origin_die = NULL; ! if (DECL_P (origin)) { ! dw_die_ref c; ! origin_die = lookup_decl_die (origin); ! /* "Unwrap" the decls DIE which we put in the imported unit context. ! We are looking for the abstract copy here. */ ! if (in_lto_p ! && origin_die ! && (c = get_AT_ref (origin_die, DW_AT_abstract_origin)) ! /* ??? Identify this better. */ ! && c->with_offset) ! origin_die = c; } else if (TYPE_P (origin)) origin_die = lookup_type_die (origin); else if (TREE_CODE (origin) == BLOCK) *************** gen_array_type_die (tree type, dw_die_re *** 20767,20773 **** 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 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE) { tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); --- 21088,21097 ---- size = int_size_in_bytes (type); if (size >= 0) add_AT_unsigned (array_die, DW_AT_byte_size, size); ! /* ??? 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)); *************** gen_formal_parameter_die (tree node, tre *** 21177,21184 **** parm_die = lookup_decl_die (node); /* If the contexts differ, we may not be talking about the same ! thing. */ ! if (parm_die && parm_die->die_parent != context_die) { if (!DECL_ABSTRACT_P (node)) { --- 21501,21511 ---- parm_die = lookup_decl_die (node); /* If the contexts differ, we may not be talking about the same ! 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)) { *************** gen_formal_parameter_die (tree node, tre *** 21188,21205 **** parm_die = NULL; } else ! { ! /* FIXME: Reuse DIE even with a differing context. ! ! This can happen when calling ! dwarf2out_abstract_function to build debug info for ! the abstract instance of a function for which we have ! already generated a DIE in ! dwarf2out_early_global_decl. ! ! Once we remove dwarf2out_abstract_function, we should ! have a call to gcc_unreachable here. */ ! } } if (parm_die && parm_die->die_parent == NULL) --- 21515,21521 ---- parm_die = NULL; } else ! gcc_unreachable (); } if (parm_die && parm_die->die_parent == NULL) *************** gen_type_die_for_member (tree type, tree *** 21454,21460 **** /* 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 --- 21770,21775 ---- *************** set_decl_origin_self (tree decl) *** 21527,21677 **** } } ! /* 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. */ 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); old_die = lookup_decl_die (decl); ! if (old_die && get_AT (old_die, DW_AT_inline)) /* 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) { ! context = decl_class_context (decl); ! if (context) ! gen_type_die_for_member ! (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ()); } ! /* Pretend we've just finished compiling this function. */ ! save_fn = current_function_decl; ! current_function_decl = decl; ! ! 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; } /* Helper function of premark_used_types() which gets called through --- 21842,21889 ---- } } ! /* Mark the early DIE for DECL as the abstract instance. */ static void dwarf2out_abstract_function (tree decl) { dw_die_ref old_die; /* 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); ! /* 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; ! /* 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 ! { ! 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); } ! if (DECL_DECLARED_INLINE_P (decl) ! && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl))) ! add_AT_flag (old_die, DW_AT_artificial, 1); ! set_decl_origin_self (decl); } /* Helper function of premark_used_types() which gets called through *************** gen_subprogram_die (tree decl, dw_die_re *** 21883,21889 **** && debug_info_level > DINFO_LEVEL_TERSE) old_die = force_decl_die (decl); ! /* An inlined instance, tag a new DIE with DW_AT_abstract_origin. */ if (origin != NULL) { gcc_assert (!declaration || local_scope_p (context_die)); --- 22095,22101 ---- && debug_info_level > DINFO_LEVEL_TERSE) old_die = force_decl_die (decl); ! /* A concrete instance, tag a new DIE with DW_AT_abstract_origin. */ if (origin != NULL) { gcc_assert (!declaration || local_scope_p (context_die)); *************** gen_subprogram_die (tree decl, dw_die_re *** 21962,21967 **** --- 22174,22183 ---- && 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) *************** gen_variable_die (tree decl, tree origin *** 22828,22833 **** --- 23044,23067 ---- /* 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; } } *************** gen_inlined_subroutine_die (tree stmt, d *** 23228,23239 **** 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 --- 23462,23467 ---- *************** process_scope_var (tree stmt, tree decl, *** 24819,24825 **** stmt, context_die); } else ! gen_decl_die (decl, origin, NULL, context_die); } /* Generate all of the decls declared within a given scope and (recursively) --- 25047,25068 ---- stmt, context_die); } else ! { ! 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) *************** gen_decl_die (tree decl, tree origin, st *** 25230,25243 **** /* This is only a declaration. */; #endif /* If we're emitting a clone, emit info for the abstract instance. */ ! 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. */ else if (cgraph_function_possibly_inlined_p (decl) && ! DECL_ABSTRACT_P (decl) && ! class_or_namespace_scope_p (context_die) --- 25473,25491 ---- /* 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. */ ! else if (origin || DECL_ORIGIN (decl) != decl) dwarf2out_abstract_function (origin ? DECL_ORIGIN (origin) : DECL_ABSTRACT_ORIGIN (decl)); ! /* 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) *************** gen_decl_die (tree decl, tree origin, st *** 25245,25254 **** 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); ! } /* Otherwise we're emitting the primary DIE for this decl. */ else if (debug_info_level > DINFO_LEVEL_TERSE) --- 25493,25499 ---- 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); /* Otherwise we're emitting the primary DIE for this decl. */ else if (debug_info_level > DINFO_LEVEL_TERSE) *************** gen_decl_die (tree decl, tree origin, st *** 25318,25337 **** 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); ! /* 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); /* Now output the DIE to represent the data object itself. This gets complicated because of the possibility that the VAR_DECL really --- 25563,25598 ---- if (debug_info_level <= DINFO_LEVEL_TERSE) break; ! /* 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); ! } ! 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); ! } /* Now output the DIE to represent the data object itself. This gets complicated because of the possibility that the VAR_DECL really *************** gen_decl_die (tree decl, tree origin, st *** 25361,25370 **** 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); return gen_formal_parameter_die (decl, origin, true /* Emit name attribute. */, context_die); --- 25622,25644 ---- break; case PARM_DECL: ! /* 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_early_global_decl (tree decl) *** 25436,25441 **** --- 25710,25725 ---- 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); *************** dwarf2out_late_global_decl (tree decl) *** 25457,25463 **** { dw_die_ref die = lookup_decl_die (decl); ! /* We have to generate early debug late for LTO. */ if (! die && in_lto_p) { dwarf2out_decl (decl); --- 25741,25749 ---- { dw_die_ref die = lookup_decl_die (decl); ! /* 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); *************** output_macinfo_op (macinfo_entry *ref) *** 26811,26817 **** case DW_MACRO_import: dw2_asm_output_data (1, ref->code, "Import"); ASM_GENERATE_INTERNAL_LABEL (label, ! DEBUG_MACRO_SECTION_LABEL, ref->lineno); dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL); break; default: --- 27097,27104 ---- case DW_MACRO_import: dw2_asm_output_data (1, ref->code, "Import"); ASM_GENERATE_INTERNAL_LABEL (label, ! DEBUG_MACRO_SECTION_LABEL, ! ref->lineno + macinfo_label_base); dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL); break; default: *************** save_macinfo_strings (void) *** 26985,26991 **** /* Output macinfo section(s). */ static void ! output_macinfo (void) { unsigned i; unsigned long length = vec_safe_length (macinfo_table); --- 27272,27278 ---- /* Output macinfo section(s). */ static void ! output_macinfo (const char *debug_line_label, bool early_lto_debug) { unsigned i; unsigned long length = vec_safe_length (macinfo_table); *************** output_macinfo (void) *** 27005,27011 **** /* AIX Assembler inserts the length, so adjust the reference to match the offset expected by debuggers. */ ! strcpy (dl_section_ref, debug_line_section_label); if (XCOFF_DEBUGGING_INFO) strcat (dl_section_ref, DWARF_INITIAL_LENGTH_SIZE_STR); --- 27292,27298 ---- /* AIX Assembler inserts the length, so adjust the reference to match the offset expected by debuggers. */ ! strcpy (dl_section_ref, debug_line_label); if (XCOFF_DEBUGGING_INFO) strcat (dl_section_ref, DWARF_INITIAL_LENGTH_SIZE_STR); *************** output_macinfo (void) *** 27018,27026 **** 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), debug_line_section, NULL); } --- 27305,27311 ---- 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, debug_line_label, debug_line_section, NULL); } *************** output_macinfo (void) *** 27074,27079 **** --- 27359,27368 ---- 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; *************** output_macinfo (void) *** 27093,27103 **** dw2_asm_output_data (1, 0, "End compilation unit"); targetm.asm_out.named_section (debug_macinfo_section_name, SECTION_DEBUG ! | SECTION_LINKONCE, comdat_key); ASM_GENERATE_INTERNAL_LABEL (label, DEBUG_MACRO_SECTION_LABEL, ! ref->lineno); ASM_OUTPUT_LABEL (asm_out_file, label); ref->code = 0; ref->info = NULL; --- 27382,27394 ---- dw2_asm_output_data (1, 0, "End compilation unit"); targetm.asm_out.named_section (debug_macinfo_section_name, SECTION_DEBUG ! | SECTION_LINKONCE ! | (early_lto_debug ! ? SECTION_EXCLUDE : 0), comdat_key); ASM_GENERATE_INTERNAL_LABEL (label, DEBUG_MACRO_SECTION_LABEL, ! ref->lineno + macinfo_label_base); ASM_OUTPUT_LABEL (asm_out_file, label); ref->code = 0; ref->info = NULL; *************** output_macinfo (void) *** 27118,27226 **** default: gcc_unreachable (); } } ! /* Initialize the various sections and labels for dwarf output. */ static void ! init_sections_and_labels (void) { ! 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 (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); } 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, 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, 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); ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label, ! DEBUG_ABBREV_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label, ! DEBUG_INFO_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label, ! DEBUG_LINE_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, ! DEBUG_RANGES_SECTION_LABEL, 0); if (dwarf_version >= 5 && dwarf_split_debug_info) ASM_GENERATE_INTERNAL_LABEL (ranges_base_label, ! DEBUG_RANGES_SECTION_LABEL, 1); ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, ! DEBUG_ADDR_SECTION_LABEL, 0); 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); } /* Set up for Dwarf output at the start of compilation. */ --- 27409,27600 ---- default: gcc_unreachable (); } + + macinfo_label_base += macinfo_label_base_adj; } ! /* Initialize the various sections and labels for dwarf output and prefix ! them with PREFIX if non-NULL. */ static void ! init_sections_and_labels (bool early_lto_debug) { ! /* As we may get called multiple times have a generation count for labels. */ ! static unsigned generation = 0; ! ! if (early_lto_debug) { ! 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 { ! 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_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_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, generation); ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label, ! DEBUG_INFO_SECTION_LABEL, generation); ! info_section_emitted = false; ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label, ! DEBUG_LINE_SECTION_LABEL, generation); ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, ! DEBUG_RANGES_SECTION_LABEL, generation); if (dwarf_version >= 5 && dwarf_split_debug_info) ASM_GENERATE_INTERNAL_LABEL (ranges_base_label, ! DEBUG_RANGES_SECTION_LABEL, 2 + generation); ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, ! 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, generation); ! ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, ! generation); ! ! ++generation; } /* Set up for Dwarf output at the start of compilation. */ *************** flush_limbo_die_list (void) *** 29567,29572 **** --- 29941,29962 ---- } } + /* 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. */ *************** dwarf2out_finish (const char *) *** 29594,29599 **** --- 29984,30029 ---- 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; *************** dwarf2out_finish (const char *) *** 29604,29610 **** move_marked_base_types (); /* Initialize sections and labels used for actual assembler output. */ ! init_sections_and_labels (); /* Traverse the DIE's and add sibling attributes to those DIE's that have children. */ --- 30034,30040 ---- move_marked_base_types (); /* Initialize sections and labels used for actual assembler output. */ ! init_sections_and_labels (false); /* Traverse the DIE's and add sibling attributes to those DIE's that have children. */ *************** dwarf2out_finish (const char *) *** 29705,29713 **** 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, macinfo_section_label); if (dwarf_split_debug_info) --- 30135,30141 ---- dl_section_ref); if (have_macinfo) ! add_AT_macptr (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE, macinfo_section_label); if (dwarf_split_debug_info) *************** dwarf2out_finish (const char *) *** 29912,29918 **** { switch_to_section (debug_macinfo_section); ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label); ! output_macinfo (); dw2_asm_output_data (1, 0, "End compilation unit"); } --- 30340,30347 ---- { switch_to_section (debug_macinfo_section); ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label); ! 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"); } *************** note_variable_value_in_expr (dw_die_ref *** 30133,30138 **** --- 30562,30581 ---- { 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; *************** dwarf2out_early_finish (const char *file *** 30343,30348 **** --- 30786,30904 ---- /* 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 Index: early-lto-debug/gcc/debug.h =================================================================== *** early-lto-debug.orig/gcc/debug.h 2017-08-02 10:21:25.118319347 +0200 --- early-lto-debug/gcc/debug.h 2017-08-02 10:21:39.142562230 +0200 *************** struct gcc_debug_hooks *** 148,153 **** --- 148,161 ---- 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 void debug_nothing_tree_tree_tree *** 212,217 **** --- 220,229 ---- 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; Index: early-lto-debug/gcc/debug.c =================================================================== *** early-lto-debug.orig/gcc/debug.c 2017-08-02 10:21:25.118319347 +0200 --- early-lto-debug/gcc/debug.c 2017-08-02 10:25:56.415019203 +0200 *************** const struct gcc_debug_hooks do_nothing_ *** 48,53 **** --- 48,55 ---- 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 */ *************** debug_nothing_tree_int (tree decl ATTRIB *** 147,149 **** --- 149,164 ---- 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) + { + } Index: early-lto-debug/gcc/dbxout.c =================================================================== *** early-lto-debug.orig/gcc/dbxout.c 2017-08-02 10:21:39.142562230 +0200 --- early-lto-debug/gcc/dbxout.c 2017-08-02 10:26:54.536026603 +0200 *************** const struct gcc_debug_hooks dbx_debug_h *** 372,377 **** --- 372,379 ---- 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 */ *************** const struct gcc_debug_hooks xcoff_debug *** 412,417 **** --- 414,421 ---- 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 */ Index: early-lto-debug/gcc/sdbout.c =================================================================== *** early-lto-debug.orig/gcc/sdbout.c 2017-08-02 10:21:39.146562299 +0200 --- early-lto-debug/gcc/sdbout.c 2017-08-02 10:27:32.172679470 +0200 *************** const struct gcc_debug_hooks sdb_debug_h *** 302,307 **** --- 302,309 ---- 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 */ Index: early-lto-debug/gcc/lto/lto.c =================================================================== *** early-lto-debug.orig/gcc/lto/lto.c 2017-08-02 10:21:25.146319831 +0200 --- early-lto-debug/gcc/lto/lto.c 2017-08-02 10:21:39.146562299 +0200 *************** unify_scc (struct data_in *data_in, unsi *** 1633,1638 **** --- 1633,1641 ---- free_node (scc->entries[i]); } + /* Drop DIE references. */ + dref_queue.truncate (0); + break; } *************** lto_read_decls (struct lto_file_decl_dat *** 1708,1715 **** from); if (len == 1 && (TREE_CODE (first) == IDENTIFIER_NODE ! || TREE_CODE (first) == INTEGER_CST ! || TREE_CODE (first) == TRANSLATION_UNIT_DECL)) continue; /* Try to unify the SCC with already existing ones. */ --- 1711,1717 ---- from); if (len == 1 && (TREE_CODE (first) == IDENTIFIER_NODE ! || TREE_CODE (first) == INTEGER_CST)) continue; /* Try to unify the SCC with already existing ones. */ *************** lto_read_decls (struct lto_file_decl_dat *** 1748,1763 **** 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 --- 1750,1755 ---- *************** lto_read_decls (struct lto_file_decl_dat *** 1773,1778 **** --- 1765,1778 ---- 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; } *************** lto_section_with_id (const char *name, u *** 1952,1958 **** 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; } /* Create file_data of each sub file id */ --- 1952,1963 ---- if (strncmp (name, section_name_prefix, strlen (section_name_prefix))) return 0; s = strrchr (name, '.'); ! 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 */ Index: early-lto-debug/gcc/lto-streamer-in.c =================================================================== *** early-lto-debug.orig/gcc/lto-streamer-in.c 2017-08-02 10:21:25.146319831 +0200 --- early-lto-debug/gcc/lto-streamer-in.c 2017-08-02 10:21:39.178562854 +0200 *************** along with GCC; see the file COPYING3. *** 41,46 **** --- 41,47 ---- #include "except.h" #include "cgraph.h" #include "cfgloop.h" + #include "debug.h" struct freeing_string_slot_hasher : string_slot_hasher *************** input_function (tree fn_decl, struct dat *** 1038,1043 **** --- 1039,1054 ---- 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); *************** lto_input_variable_constructor (struct l *** 1322,1327 **** --- 1333,1342 ---- } + /* 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. */ *************** lto_read_tree_1 (struct lto_input_block *** 1341,1346 **** --- 1356,1378 ---- && 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 *************** lto_input_tree (struct lto_input_block * *** 1486,1491 **** --- 1518,1530 ---- { 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); } Index: early-lto-debug/gcc/lto-streamer-out.c =================================================================== *** early-lto-debug.orig/gcc/lto-streamer-out.c 2017-08-02 10:21:25.150319901 +0200 --- early-lto-debug/gcc/lto-streamer-out.c 2017-08-02 10:21:39.178562854 +0200 *************** along with GCC; see the file COPYING3. *** 40,45 **** --- 40,46 ---- #include "cfgloop.h" #include "builtins.h" #include "gomp-constants.h" + #include "debug.h" static void lto_write_tree (struct output_block*, tree, bool); *************** lto_write_tree_1 (struct output_block *o *** 406,411 **** --- 407,432 ---- (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 *************** DFS::DFS_write_tree_body (struct output_ *** 745,751 **** ; else DFS_follow_tree_edge (DECL_NAME (expr)); ! DFS_follow_tree_edge (DECL_CONTEXT (expr)); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) --- 766,776 ---- ; else DFS_follow_tree_edge (DECL_NAME (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)) *************** DFS::DFS_write_tree_body (struct output_ *** 765,770 **** --- 790,796 ---- 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) *************** output_function (struct cgraph_node *nod *** 2061,2066 **** --- 2087,2103 ---- 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); Index: early-lto-debug/gcc/lto-streamer.h =================================================================== *** early-lto-debug.orig/gcc/lto-streamer.h 2017-08-02 10:21:25.150319901 +0200 --- early-lto-debug/gcc/lto-streamer.h 2017-08-02 10:21:39.182562923 +0200 *************** DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ *** 1212,1215 **** --- 1212,1225 ---- 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 */ Index: early-lto-debug/gcc/lto-wrapper.c =================================================================== *** early-lto-debug.orig/gcc/lto-wrapper.c 2017-08-02 10:21:25.150319901 +0200 --- early-lto-debug/gcc/lto-wrapper.c 2017-08-02 10:21:39.182562923 +0200 *************** static char **output_names; *** 70,75 **** --- 70,76 ---- static char **offload_names; static char *offload_objects_file_name; static char *makefile; + static char *debug_obj; const char tool_name[] = "lto-wrapper"; *************** tool_cleanup (bool) *** 88,93 **** --- 89,96 ---- 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]); *************** find_and_merge_options (int fd, off_t fi *** 960,965 **** --- 963,1029 ---- 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 *************** run_gcc (unsigned argc, char *argv[]) *** 984,991 **** int new_head_argc; bool have_lto = false; bool have_offload = false; ! unsigned lto_argc = 0; ! char **lto_argv; /* Get the driver and options. */ collect_gcc = getenv ("COLLECT_GCC"); --- 1048,1057 ---- int new_head_argc; bool have_lto = false; bool have_offload = false; ! 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"); *************** run_gcc (unsigned argc, char *argv[]) *** 1004,1009 **** --- 1070,1076 ---- /* 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) *************** run_gcc (unsigned argc, char *argv[]) *** 1046,1052 **** collect_gcc)) { have_lto = true; ! lto_argv[lto_argc++] = argv[i]; } close (fd); } --- 1113,1119 ---- collect_gcc)) { have_lto = true; ! ltoobj_argv[ltoobj_argc++] = argv[i]; } close (fd); } *************** run_gcc (unsigned argc, char *argv[]) *** 1107,1112 **** --- 1174,1190 ---- } } + /* 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; *************** cont1: *** 1296,1313 **** obstack_ptr_grow (&argv_obstack, "-fwpa"); } ! /* Append the input objects and possible preceding arguments. */ for (i = 0; i < lto_argc; ++i) obstack_ptr_grow (&argv_obstack, lto_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); if (lto_mode == LTO_MODE_LTO) { printf ("%s\n", flto_out); free (flto_out); flto_out = NULL; } --- 1374,1478 ---- obstack_ptr_grow (&argv_obstack, "-fwpa"); } ! /* 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; } *************** cont: *** 1456,1461 **** --- 1621,1632 ---- 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); Index: early-lto-debug/gcc/tree-streamer-in.c =================================================================== *** early-lto-debug.orig/gcc/tree-streamer-in.c 2017-08-02 10:21:25.150319901 +0200 --- early-lto-debug/gcc/tree-streamer-in.c 2017-08-02 10:21:39.182562923 +0200 *************** lto_input_ts_decl_common_tree_pointers ( *** 688,697 **** 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. */ if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (expr)) --- 688,694 ---- 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); ! 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)) Index: early-lto-debug/gcc/tree-streamer-out.c =================================================================== *** early-lto-debug.orig/gcc/tree-streamer-out.c 2017-08-02 10:21:25.154319970 +0200 --- early-lto-debug/gcc/tree-streamer-out.c 2017-08-02 10:21:39.182562923 +0200 *************** write_ts_decl_minimal_tree_pointers (str *** 566,572 **** 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); } --- 566,576 ---- stream_write_tree (ob, NULL_TREE, ref_p); else stream_write_tree (ob, DECL_NAME (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); } *************** write_ts_decl_common_tree_pointers (stru *** 585,594 **** 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. */ if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (expr)) --- 589,595 ---- special handling in LTO, it must be handled by streamer hooks. */ stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p); ! 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)) Index: early-lto-debug/gcc/config/darwin.c =================================================================== *** early-lto-debug.orig/gcc/config/darwin.c 2017-08-02 10:21:25.154319970 +0200 --- early-lto-debug/gcc/config/darwin.c 2017-08-02 10:21:39.182562923 +0200 *************** darwin_asm_lto_end (void) *** 1959,1965 **** } static void ! darwin_asm_dwarf_section (const char *name, unsigned int flags, tree decl); /* Called for the TARGET_ASM_NAMED_SECTION hook. */ --- 1959,1966 ---- } static void ! darwin_asm_dwarf_section (const char *name, unsigned int flags, ! tree decl, bool is_for_lto); /* Called for the TARGET_ASM_NAMED_SECTION hook. */ *************** darwin_asm_named_section (const char *na *** 2001,2007 **** vec_safe_push (lto_section_names, e); } else if (strncmp (name, "__DWARF,", 8) == 0) ! darwin_asm_dwarf_section (name, flags, decl); else fprintf (asm_out_file, "\t.section %s\n", name); } --- 2002,2010 ---- vec_safe_push (lto_section_names, e); } else if (strncmp (name, "__DWARF,", 8) == 0) ! 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 GTY (()) vec<dwarf_sect_used_entr *** 2783,2801 **** static void darwin_asm_dwarf_section (const char *name, unsigned int flags, ! tree ARG_UNUSED (decl)) { unsigned i; ! int namelen; ! const char * sname; 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); if (dwarf_sect_names_table == NULL) vec_alloc (dwarf_sect_names_table, 16); else --- 2786,2822 ---- static void darwin_asm_dwarf_section (const char *name, unsigned int flags, ! tree ARG_UNUSED (decl), bool is_for_lto) { unsigned i; ! int namelen, extra = 0; ! const char *sect, *lto_add = ""; ! char sname[64]; dwarf_sect_used_entry *ref; bool found = false; ! ! 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 *************** darwin_asm_dwarf_section (const char *na *** 2813,2819 **** } } - fprintf (asm_out_file, "\t.section %s\n", name); if (!found) { dwarf_sect_used_entry e; --- 2834,2839 ---- *************** darwin_asm_output_dwarf_offset (FILE *fi *** 2866,2879 **** HOST_WIDE_INT offset, section *base) { char sname[64]; ! int namelen; ! gcc_assert (base->common.flags & SECTION_NAMED); ! gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0); ! gcc_assert (strchr (base->named.name + 8, ',')); ! ! namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8); ! sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8); darwin_asm_output_dwarf_delta (file, size, lab, sname, offset); } --- 2886,2909 ---- HOST_WIDE_INT offset, section *base) { char sname[64]; ! int namelen, extra = 0; ! bool is_for_lto; ! const char *lto_add = ""; ! ! 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 (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); } Index: early-lto-debug/gcc/config/darwin.h =================================================================== *** early-lto-debug.orig/gcc/config/darwin.h 2017-08-02 10:21:25.154319970 +0200 --- early-lto-debug/gcc/config/darwin.h 2017-08-02 10:21:39.182562923 +0200 *************** extern GTY(()) int darwin_ms_struct; *** 445,451 **** #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 TARGET_WANT_DEBUG_PUB_SECTIONS true --- 445,458 ---- #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_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 Index: early-lto-debug/gcc/vmsdbgout.c =================================================================== *** early-lto-debug.orig/gcc/vmsdbgout.c 2017-08-02 10:21:39.186562992 +0200 --- early-lto-debug/gcc/vmsdbgout.c 2017-08-02 10:27:59.217149976 +0200 *************** const struct gcc_debug_hooks vmsdbg_debu *** 198,203 **** --- 198,205 ---- 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 */ Index: early-lto-debug/gcc/tree.c =================================================================== *** early-lto-debug.orig/gcc/tree.c 2017-08-02 10:21:25.158320039 +0200 --- early-lto-debug/gcc/tree.c 2017-08-02 10:21:39.186562992 +0200 *************** free_lang_data (void) *** 5980,5985 **** --- 5980,5989 ---- || (!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) Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/global-overflow-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/global-overflow-1.c 2017-08-02 10:21:25.158320039 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/global-overflow-1.c 2017-08-02 10:21:39.186562992 +0200 *************** int main() { *** 23,28 **** } /* { 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 "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)" } */ --- 23,28 ---- } /* { 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]*\\+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)" } */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/heap-overflow-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/heap-overflow-1.c 2017-08-02 10:21:25.158320039 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/heap-overflow-1.c 2017-08-02 10:21:39.190563062 +0200 *************** int main(int argc, char **argv) { *** 24,31 **** } /* { 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 "\[^\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)" } */ --- 24,31 ---- } /* { 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]*\\+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]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/misalign-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/misalign-1.c 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/misalign-1.c 2017-08-02 10:21:39.190563062 +0200 *************** main () *** 39,43 **** /* { 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)" } */ --- 39,43 ---- /* { 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]*\\+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)" } */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/misalign-2.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/misalign-2.c 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/misalign-2.c 2017-08-02 10:21:39.190563062 +0200 *************** main () *** 39,43 **** /* { 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)" } */ --- 39,43 ---- /* { 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]*\\+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)" } */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/null-deref-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/null-deref-1.c 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/null-deref-1.c 2017-08-02 10:21:39.190563062 +0200 *************** int main() *** 18,22 **** /* { 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)" } */ --- 18,22 ---- /* { 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]*\\+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)" } */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/stack-overflow-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/stack-overflow-1.c 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/stack-overflow-1.c 2017-08-02 10:21:39.190563062 +0200 *************** int main() { *** 18,23 **** } /* { 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 "\[^\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)" */ --- 18,23 ---- } /* { 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]*\\+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)" */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c 2017-08-02 10:21:39.190563062 +0200 *************** int main(int argc, char **argv) { *** 14,21 **** /* { 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 "\[^\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)" } */ --- 14,21 ---- /* { 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]*\\+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]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/use-after-free-1.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/use-after-free-1.c 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/use-after-free-1.c 2017-08-02 10:21:39.190563062 +0200 *************** int main() { *** 12,22 **** /* { 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 "\[^\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 "\[^\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)" } */ --- 12,22 ---- /* { 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]*\\+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]*\\+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]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */ Index: early-lto-debug/gcc/testsuite/g++.dg/asan/large-func-test-1.C =================================================================== *** early-lto-debug.orig/gcc/testsuite/g++.dg/asan/large-func-test-1.C 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/gcc/testsuite/g++.dg/asan/large-func-test-1.C 2017-08-02 10:21:39.190563062 +0200 *************** int main() { *** 38,44 **** // { 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 "\[^\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)" } --- 38,44 ---- // { 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]*\\+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)" } Index: early-lto-debug/libstdc++-v3/testsuite/libstdc++-prettyprinters/prettyprinters.exp =================================================================== *** early-lto-debug.orig/libstdc++-v3/testsuite/libstdc++-prettyprinters/prettyprinters.exp 2017-08-02 10:21:25.162320109 +0200 --- early-lto-debug/libstdc++-v3/testsuite/libstdc++-prettyprinters/prettyprinters.exp 2017-08-02 10:21:39.190563062 +0200 *************** *** 15,20 **** --- 15,21 ---- # <http://www.gnu.org/licenses/>. load_lib gdb-test.exp + load_lib target-supports.exp dg-init v3-build_support *************** global PCH_CXXFLAGS *** 46,51 **** --- 47,60 ---- 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 } Index: early-lto-debug/gcc/testsuite/gfortran.dg/save_6.f90 =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- early-lto-debug/gcc/testsuite/gfortran.dg/save_6.f90 2017-08-02 10:21:39.190563062 +0200 *************** *** 0 **** --- 1,54 ---- + ! { 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 Index: early-lto-debug/gcc/config/i386/i386.c =================================================================== *** early-lto-debug.orig/gcc/config/i386/i386.c 2017-08-02 10:21:25.174320316 +0200 --- early-lto-debug/gcc/config/i386/i386.c 2017-08-02 10:21:39.198563200 +0200 *************** make_resolver_func (const tree default_d *** 33898,33904 **** DECL_NAME (decl) = decl_name; TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; ! DECL_IGNORED_P (decl) = 0; /* IFUNC resolvers have to be externally visible. */ TREE_PUBLIC (decl) = 1; DECL_UNINLINABLE (decl) = 1; --- 33898,33904 ---- DECL_NAME (decl) = decl_name; TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; ! DECL_IGNORED_P (decl) = 1; /* IFUNC resolvers have to be externally visible. */ TREE_PUBLIC (decl) = 1; DECL_UNINLINABLE (decl) = 1; Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c 2017-07-17 09:52:30.728120381 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c 2017-08-03 09:41:02.010368309 +0200 *************** int main() { *** 17,22 **** } /* { 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 "\[^\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)" */ --- 17,22 ---- } /* { 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]*\\+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)" */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c 2017-07-17 09:52:30.728120381 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c 2017-08-03 09:41:48.967159382 +0200 *************** int main(int argc, char **argv) { *** 22,27 **** } /* { 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 "\[^\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)" */ --- 22,27 ---- } /* { 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]*\\+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)" */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c 2017-07-17 09:52:30.728120381 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c 2017-08-03 09:42:20.443689680 +0200 *************** int main(int argc, char **argv) { *** 17,22 **** } /* { 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 "\[^\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)" */ --- 17,22 ---- } /* { 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]*\\+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)" */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c 2017-07-17 09:52:30.732120446 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c 2017-08-03 09:42:53.304243311 +0200 *************** int main(int argc, char **argv) { *** 17,22 **** } /* { 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 "\[^\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)" */ --- 17,22 ---- } /* { 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]*\\+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)" */ Index: early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c =================================================================== *** early-lto-debug.orig/gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c 2017-07-17 09:52:30.732120446 +0200 --- early-lto-debug/gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c 2017-08-03 09:43:33.680923594 +0200 *************** int main(int argc, char **argv) { *** 17,22 **** } /* { 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 "\[^\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)" */ --- 17,22 ---- } /* { 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]*\\+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)" */ Index: early-lto-debug/gcc/cfgexpand.c =================================================================== *** early-lto-debug.orig/gcc/cfgexpand.c 2017-08-02 10:20:44.093608890 +0200 --- early-lto-debug/gcc/cfgexpand.c 2017-08-03 12:21:08.348962776 +0200 *************** pass_expand::execute (function *fun) *** 6527,6538 **** 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. */ --- 6527,6532 ----