Hi, With the introduction of early debug, we've added a phase in the compiler which produces information which is not visible, unless we run the compiler in the debugger and call debug_dwarf from dwarf2out_early_finish or some such.
This patch adds dumping of "early" and "final" debug info, into .earlydebug and .debug dump files, such that we can follow f.i. the upper bound of a vla type from early debug: ... DW_AT_upper_bound: location descriptor: (0x7f0d645b7550) DW_OP_GNU_variable_value , 0 ... to final debug: ... DW_AT_upper_bound: location descriptor: (0x7f0d645b7550) DW_OP_fbreg 18446744073709551592, 0 (0x7f0d645b7a00) DW_OP_deref 8, 0 ... to -dA annotated assembly file: ... .uleb128 0x3 # DW_AT_upper_bound .byte 0x91 # DW_OP_fbreg .sleb128 -24 .byte 0x6 # DW_OP_deref ... The .debug file shows the same information as the annotated assembly, but in the same format as the "early" debug info. Bootstrapped and reg-tested on x86_64. OK for trunk? Thanks, - Tom [debug] Add debug and earlydebug dumps 2018-08-13 Tom de Vries <tdevr...@suse.de> * cgraph.h (debuginfo_early_init, debuginfo_init, debuginfo_fini) (debuginfo_start, debuginfo_stop, debuginfo_early_start) (debuginfo_early_stop): Declare. * cgraphunit.c (debuginfo_early_init, debuginfo_init, debuginfo_fini) (debuginfo_start, debuginfo_stop, debuginfo_early_start) (debuginfo_early_stop): New function. (symbol_table::finalize_compilation_unit): Call debuginfo_early_start and debuginfo_early_stop. * dwarf2out.c (print_dw_val, print_loc_descr, print_die): Handle flag_dump_noaddr and flag_dump_unnumbered. (dwarf2out_finish, dwarf2out_early_finish): Dump dwarf. * toplev.c (compile_file): Call debuginfo_start and debuginfo_stop. (general_init): Call debuginfo_early_init. (finalize): Call debuginfo_fini. (do_compile): Call debuginfo_init. * lto.c (lto_main): Call debuginfo_early_start and debuginfo_early_stop. * gcc.c-torture/unsorted/dump-noaddr.x: Skip earlydebug and debug dumps. --- gcc/cgraph.h | 8 +++ gcc/cgraphunit.c | 66 ++++++++++++++++++++++ gcc/dwarf2out.c | 46 ++++++++++++--- gcc/lto/lto.c | 2 + gcc/testsuite/gcc.c-torture/unsorted/dump-noaddr.x | 7 +++ gcc/toplev.c | 5 ++ 6 files changed, 126 insertions(+), 8 deletions(-) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index a8b1b4cb3c3..2b00f0165fa 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -25,6 +25,14 @@ along with GCC; see the file COPYING3. If not see #include "ipa-ref.h" #include "plugin-api.h" +extern void debuginfo_early_init (void); +extern void debuginfo_init (void); +extern void debuginfo_fini (void); +extern void debuginfo_start (void); +extern void debuginfo_stop (void); +extern void debuginfo_early_start (void); +extern void debuginfo_early_stop (void); + class ipa_opt_pass_d; typedef ipa_opt_pass_d *ipa_opt_pass; diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 462e247328e..6649942c4fb 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -2636,6 +2636,70 @@ symbol_table::compile (void) } } +static int debuginfo_early_dump_nr; +static FILE *debuginfo_early_dump_file; +static dump_flags_t debuginfo_early_dump_flags; + +static int debuginfo_dump_nr; +static FILE *debuginfo_dump_file; +static dump_flags_t debuginfo_dump_flags; + +void +debuginfo_early_init (void) +{ + gcc::dump_manager *dumps = g->get_dumps (); + debuginfo_early_dump_nr = dumps->dump_register (".earlydebug", "earlydebug", + "earlydebug", DK_tree, + OPTGROUP_NONE, + false); + debuginfo_dump_nr = dumps->dump_register (".debug", "debug", + "debug", DK_tree, + OPTGROUP_NONE, + false); +} + +void +debuginfo_init (void) +{ + gcc::dump_manager *dumps = g->get_dumps (); + debuginfo_dump_file = dump_begin (debuginfo_dump_nr, NULL); + debuginfo_dump_flags = dumps->get_dump_file_info (debuginfo_dump_nr)->pflags; + debuginfo_early_dump_file = dump_begin (debuginfo_early_dump_nr, NULL); + debuginfo_early_dump_flags = dumps->get_dump_file_info (debuginfo_early_dump_nr)->pflags; +} + +void +debuginfo_fini (void) +{ + if (debuginfo_dump_file) + dump_end (debuginfo_dump_nr, debuginfo_dump_file); + if (debuginfo_early_dump_file) + dump_end (debuginfo_early_dump_nr, debuginfo_early_dump_file); +} + +void +debuginfo_start (void) +{ + set_dump_file (debuginfo_dump_file); +} + +void +debuginfo_stop (void) +{ + set_dump_file (NULL); +} + +void +debuginfo_early_start (void) +{ + set_dump_file (debuginfo_early_dump_file); +} + +void +debuginfo_early_stop (void) +{ + set_dump_file (NULL); +} /* Analyze the whole compilation unit once it is parsed completely. */ @@ -2691,7 +2755,9 @@ symbol_table::finalize_compilation_unit (void) /* Clean up anything that needs cleaning up after initial debug generation. */ + debuginfo_early_start (); (*debug_hooks->early_finish) (main_input_filename); + debuginfo_early_stop (); } /* Finally drive the pass manager. */ diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 9ed473088e7..4b63cbd8a1e 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -6455,7 +6455,12 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile) print_indent -= 4; } else - fprintf (outfile, " (%p)\n", (void *) val->v.val_loc); + { + if (flag_dump_noaddr || flag_dump_unnumbered) + fprintf (outfile, " #\n"); + else + fprintf (outfile, " (%p)\n", (void *) val->v.val_loc); + } break; case dw_val_class_loc_list: fprintf (outfile, "location list -> label:%s", @@ -6524,7 +6529,10 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile) } else fprintf (outfile, "die -> %ld", die->die_offset); - fprintf (outfile, " (%p)", (void *) die); + if (flag_dump_noaddr || flag_dump_unnumbered) + fprintf (outfile, " #"); + else + fprintf (outfile, " (%p)", (void *) die); } else fprintf (outfile, "die -> <null>"); @@ -6614,8 +6622,11 @@ print_loc_descr (dw_loc_descr_ref loc, FILE *outfile) for (l = loc; l != NULL; l = l->dw_loc_next) { print_spaces (outfile); - fprintf (outfile, "(%p) %s", - (void *) l, + if (flag_dump_noaddr || flag_dump_unnumbered) + fprintf (outfile, "#"); + else + fprintf (outfile, "(%p)", (void *) l); + fprintf (outfile, " %s", dwarf_stack_op_name (l->dw_loc_opc)); if (l->dw_loc_oprnd1.val_class != dw_val_class_none) { @@ -6642,9 +6653,12 @@ print_die (dw_die_ref die, FILE *outfile) unsigned ix; print_spaces (outfile); - fprintf (outfile, "DIE %4ld: %s (%p)\n", - die->die_offset, dwarf_tag_name (die->die_tag), - (void*) die); + fprintf (outfile, "DIE %4ld: %s ", + die->die_offset, dwarf_tag_name (die->die_tag)); + if (flag_dump_noaddr || flag_dump_unnumbered) + fprintf (outfile, "#\n"); + else + fprintf (outfile, "(%p)\n", (void*) die); print_spaces (outfile); fprintf (outfile, " abbrev id: %lu", die->die_abbrev); fprintf (outfile, " offset: %ld", die->die_offset); @@ -31088,7 +31102,7 @@ reset_dies (dw_die_ref die) and generate the DWARF-2 debugging info. */ static void -dwarf2out_finish (const char *) +dwarf2out_finish (const char *filename) { comdat_type_node *ctnode; dw_die_ref main_comp_unit_die; @@ -31169,6 +31183,12 @@ dwarf2out_finish (const char *) resolve_addr (comp_unit_die ()); move_marked_base_types (); + if (dump_file) + { + fprintf (dump_file, "DWARF for %s\n", filename); + print_die (comp_unit_die (), dump_file); + } + /* Initialize sections and labels used for actual assembler output. */ unsigned generation = init_sections_and_labels (false); @@ -31864,6 +31884,11 @@ dwarf2out_early_finish (const char *filename) if (in_lto_p) { early_dwarf_finished = true; + if (dump_file) + { + fprintf (dump_file, "LTO EARLY DWARF for %s\n", filename); + print_die (comp_unit_die (), dump_file); + } return; } @@ -31941,6 +31966,11 @@ dwarf2out_early_finish (const char *filename) /* The early debug phase is now finished. */ early_dwarf_finished = true; + if (dump_file) + { + fprintf (dump_file, "EARLY DWARF for %s\n", filename); + print_die (comp_unit_die (), dump_file); + } /* Do not generate DWARF assembler now when not producing LTO bytecode. */ if ((!flag_generate_lto && !flag_generate_offload) diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 8db280ecefc..10618896022 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -3419,7 +3419,9 @@ lto_main (void) lto_promote_statics_nonwpa (); /* Annotate the CU DIE and mark the early debug phase as finished. */ + debuginfo_early_start (); debug_hooks->early_finish ("<artificial>"); + debuginfo_early_stop (); /* Let the middle end know that we have read and merged all of the input files. */ diff --git a/gcc/testsuite/gcc.c-torture/unsorted/dump-noaddr.x b/gcc/testsuite/gcc.c-torture/unsorted/dump-noaddr.x index e86f36a1861..d2be9c001e0 100644 --- a/gcc/testsuite/gcc.c-torture/unsorted/dump-noaddr.x +++ b/gcc/testsuite/gcc.c-torture/unsorted/dump-noaddr.x @@ -19,6 +19,13 @@ proc dump_compare { src options } { set dump2 "$tmpdir/dump2/[file tail $dump1]" set dumptail "gcc.c-torture/unsorted/[file tail $dump1]" regsub {\.\d+((t|r|i)\.[^.]+)$} $dumptail {.*\1} dumptail + if { "$dumptail" == "gcc.c-torture/unsorted/dump-noaddr.c.*t.earlydebug" + || "$dumptail" == "gcc.c-torture/unsorted/dump-noaddr.c.*t.debug" } { + # The DW_AT_producer line contains the command line options so, this will + # fail on dump1 having '--param ggc-min-heapsize=1', and dump2 not. + untested "$dumptail, $option comparison" + continue + } set tmp [ diff "$dump1" "$dump2" ] if { $tmp == 0 } { untested "$dumptail, $option comparison" diff --git a/gcc/toplev.c b/gcc/toplev.c index aa943a8655e..d28bff01552 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -529,7 +529,9 @@ compile_file (void) dwarf2out_frame_finish (); #endif + debuginfo_start (); (*debug_hooks->finish) (main_input_filename); + debuginfo_stop (); timevar_pop (TV_SYMOUT); /* Output some stuff at end of file if nec. */ @@ -1185,6 +1187,7 @@ general_init (const char *argv0, bool init_signals) symtab = new (ggc_cleared_alloc <symbol_table> ()) symbol_table (); statistics_early_init (); + debuginfo_early_init (); finish_params (); } @@ -2079,6 +2082,7 @@ finalize (bool no_backend) if (!no_backend) { statistics_fini (); + debuginfo_fini (); g->get_passes ()->finish_optimization_passes (); @@ -2156,6 +2160,7 @@ do_compile () init_final (main_input_filename); coverage_init (aux_base_name); statistics_init (); + debuginfo_init (); invoke_plugin_callbacks (PLUGIN_START_UNIT, NULL); timevar_stop (TV_PHASE_SETUP);