Hi! This patch adds support for DWARF5 .debug_line{,_str} section format, though only if !DWARF2_ASM_LINE_DEBUG_INFO, because otherwise .debug_line is emitted by the assembler. For that we'll need some coordination with gas, dunno if we want a new as directive for that, or as command line switch, or perhaps key DWARF5 .debug_line on the presence of .debug_line_str section (though the last one probably isn't a good idea, because -gsplit-dwarf doesn't use .debug_line_str).
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-10-20 Jakub Jelinek <ja...@redhat.com> * dwarf2out.c (debug_line_str_section): New variable. (debug_line_str_hash): Likewise. (DEBUG_LINE_STR_SECTION): Define. (set_indirect_string): Handle DW_FORM_line_strp like DW_FORM_strp. (find_string_form): Fix up formatting. (size_of_die): Handle DW_FORM_line_strp like DW_FORM_strp. Fix up indentation. (output_die): Handle DW_FORM_line_strp. (output_file_names): Add -gdwarf-5 support. (output_line_info): Likewise. (init_sections_and_labels): Initialize debug_line_str_section. (output_indirect_string): Change 2nd argument from void * to enum dwarf_form form, compare with form rather than DW_FORM_strp. (output_indirect_strings): Pass DW_FORM_strp to output_indirect_string traversion. (dwarf2out_finish): Output .debug_line_str strings. (dwarf2out_c_finalize): Clear debug_line_str_section and debug_line_str_hash. --- gcc/dwarf2out.c.jj 2016-10-18 08:17:19.000000000 +0200 +++ gcc/dwarf2out.c 2016-10-19 14:37:23.945841924 +0200 @@ -167,6 +167,7 @@ static GTY(()) section *debug_loc_sectio static GTY(()) section *debug_pubnames_section; static GTY(()) section *debug_pubtypes_section; static GTY(()) section *debug_str_section; +static GTY(()) section *debug_line_str_section; static GTY(()) section *debug_str_dwo_section; static GTY(()) section *debug_str_offsets_section; static GTY(()) section *debug_ranges_section; @@ -225,6 +226,8 @@ struct indirect_string_hasher : ggc_ptr_ static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash; +static GTY (()) hash_table<indirect_string_hasher> *debug_line_str_hash; + /* With split_debug_info, both the comp_dir and dwo_name go in the main object file, rather than the dwo, similar to the force_direct parameter elsewhere but with additional complications: @@ -232,8 +235,8 @@ static GTY (()) hash_table<indirect_stri 1) The string is needed in both the main object file and the dwo. That is, the comp_dir and dwo_name will appear in both places. - 2) Strings can use three forms: DW_FORM_string, DW_FORM_strp or - DW_FORM_GNU_str_index. + 2) Strings can use four forms: DW_FORM_string, DW_FORM_strp, + DW_FORM_line_strp or DW_FORM_GNU_str_index. 3) GCC chooses the form to use late, depending on the size and reference count. @@ -3554,6 +3557,9 @@ new_addr_loc_descr (rtx addr, enum dtpre #ifndef DEBUG_RANGES_SECTION #define DEBUG_RANGES_SECTION ".debug_ranges" #endif +#ifndef DEBUG_LINE_STR_SECTION +#define DEBUG_LINE_STR_SECTION ".debug_line_str" +#endif /* Standard ELF section names for compiled code and data. */ #ifndef TEXT_SECTION_NAME @@ -4131,7 +4137,9 @@ set_indirect_string (struct indirect_str { char label[MAX_ARTIFICIAL_LABEL_BYTES]; /* Already indirect is a no op. */ - if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index) + if (node->form == DW_FORM_strp + || node->form == DW_FORM_line_strp + || node->form == DW_FORM_GNU_str_index) { gcc_assert (node->label); return; @@ -4175,7 +4183,7 @@ find_string_form (struct indirect_string single module. */ if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET || ((debug_str_section->common.flags & SECTION_MERGE) == 0 - && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)) + && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)) return node->form = DW_FORM_string; set_indirect_string (node); @@ -8500,10 +8508,10 @@ size_of_die (dw_die_ref die) break; case dw_val_class_str: form = AT_string_form (a); - if (form == DW_FORM_strp) + if (form == DW_FORM_strp || form == DW_FORM_line_strp) size += DWARF_OFFSET_SIZE; - else if (form == DW_FORM_GNU_str_index) - size += size_of_uleb128 (AT_index (a)); + else if (form == DW_FORM_GNU_str_index) + size += size_of_uleb128 (AT_index (a)); else size += strlen (a->dw_attr_val.v.val_str->str) + 1; break; @@ -9458,6 +9466,11 @@ output_die (dw_die_ref die) a->dw_attr_val.v.val_str->label, debug_str_section, "%s: \"%s\"", name, AT_string (a)); + else if (a->dw_attr_val.v.val_str->form == DW_FORM_line_strp) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, + a->dw_attr_val.v.val_str->label, + debug_line_str_section, + "%s: \"%s\"", name, AT_string (a)); else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index) dw2_asm_output_data_uleb128 (AT_index (a), "%s: \"%s\"", name, AT_string (a)); @@ -10429,8 +10442,18 @@ output_file_names (void) if (!last_emitted_file) { - dw2_asm_output_data (1, 0, "End directory table"); - dw2_asm_output_data (1, 0, "End file name table"); + if (dwarf_version >= 5) + { + dw2_asm_output_data (1, 0, "Directory entry format count"); + dw2_asm_output_data_uleb128 (0, "Directories count"); + dw2_asm_output_data (1, 0, "File name entry format count"); + dw2_asm_output_data_uleb128 (0, "File names count"); + } + else + { + dw2_asm_output_data (1, 0, "End directory table"); + dw2_asm_output_data (1, 0, "End file name table"); + } return; } @@ -10553,13 +10576,71 @@ output_file_names (void) /* Emit the directory name table. */ idx_offset = dirs[0].length > 0 ? 1 : 0; - for (i = 1 - idx_offset; i < ndirs; i++) - dw2_asm_output_nstring (dirs[i].path, - dirs[i].length - - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR, - "Directory Entry: %#x", i + idx_offset); + enum dwarf_form str_form = DW_FORM_string; + enum dwarf_form idx_form = DW_FORM_udata; + struct indirect_string_node *node; + if (dwarf_version >= 5) + { + const char *comp_dir = comp_dir_string (); + if (comp_dir == NULL) + comp_dir = ""; + str_form = DW_FORM_line_strp; + dw2_asm_output_data (1, 1, "Directory entry format count"); + if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET + || (debug_str_section->common.flags & SECTION_MERGE) == 0 + /* FIXME: For now. */ + || dwarf_split_debug_info) + str_form = DW_FORM_string; + dw2_asm_output_data_uleb128 (DW_LNCT_path, "DW_LNCT_path"); + dw2_asm_output_data_uleb128 (str_form, get_DW_FORM_name (str_form)); + dw2_asm_output_data_uleb128 (ndirs + idx_offset, "Directories count"); + if (str_form == DW_FORM_string) + { + dw2_asm_output_nstring (comp_dir, -1, "Directory Entry: %#x", 0); + for (i = 1 - idx_offset; i < ndirs; i++) + dw2_asm_output_nstring (dirs[i].path, + dirs[i].length + - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR, + "Directory Entry: %#x", i + idx_offset); + } + else + { + if (!debug_line_str_hash) + debug_line_str_hash + = hash_table<indirect_string_hasher>::create_ggc (10); + + node = find_AT_string_in_table (comp_dir, debug_line_str_hash); + set_indirect_string (node); + node->form = DW_FORM_line_strp; + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_line_str_section, + "Directory Entry: %#x: \"%s\"", 0, node->str); + for (i = 1 - idx_offset; i < ndirs; i++) + { + const char *str + = ggc_alloc_string (dirs[i].path, + dirs[i].length + - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR); + node = find_AT_string_in_table (str, debug_line_str_hash); + set_indirect_string (node); + node->form = DW_FORM_line_strp; + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_line_str_section, + "Directory Entry: %#x: \"%s\"", + i + idx_offset, node->str); + } + } + } + else + { + for (i = 1 - idx_offset; i < ndirs; i++) + dw2_asm_output_nstring (dirs[i].path, + dirs[i].length + - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR, + "Directory Entry: %#x", i + idx_offset); - dw2_asm_output_data (1, 0, "End directory table"); + dw2_asm_output_data (1, 0, "End directory table"); + } /* We have to emit them in the order of emitted_number since that's used in the debug info generation. To do this efficiently we @@ -10568,6 +10649,68 @@ output_file_names (void) for (i = 0; i < numfiles; i++) backmap[files[i].file_idx->emitted_number - 1] = i; + if (dwarf_version >= 5) + { + const char *filename0 = get_AT_string (comp_unit_die (), DW_AT_name); + if (filename0 == NULL) + filename0 = ""; + if (ndirs + idx_offset <= 256) + idx_form = DW_FORM_data1; + else if (ndirs + idx_offset <= 65536) + { + unsigned HOST_WIDE_INT sum = 1; + for (i = 0; i < numfiles; i++) + { + int file_idx = backmap[i]; + int dir_idx = dirs[files[file_idx].dir_idx].dir_idx; + sum += size_of_uleb128 (dir_idx); + } + if (sum >= HOST_WIDE_INT_UC (2) * (numfiles + 1)) + idx_form = DW_FORM_data2; + } +#ifdef VMS_DEBUGGING_INFO + dw2_asm_output_data (1, 4, "File name entry format count"); +#else + dw2_asm_output_data (1, 2, "File name entry format count"); +#endif + dw2_asm_output_data_uleb128 (DW_LNCT_path, "DW_LNCT_path"); + dw2_asm_output_data_uleb128 (str_form, get_DW_FORM_name (str_form)); + dw2_asm_output_data_uleb128 (DW_LNCT_directory_index, + "DW_LNCT_directory_index"); + dw2_asm_output_data_uleb128 (idx_form, get_DW_FORM_name (idx_form)); +#ifdef VMS_DEBUGGING_INFO + dw2_asm_output_data_uleb128 (DW_LNCT_timestamp, "DW_LNCT_timestamp"); + dw2_asm_output_data_uleb128 (DW_FORM_udata, "DW_FORM_udata"); + dw2_asm_output_data_uleb128 (DW_LNCT_size, "DW_LNCT_size"); + dw2_asm_output_data_uleb128 (DW_FORM_udata, "DW_FORM_udata"); +#endif + dw2_asm_output_data_uleb128 (numfiles + 1, "File names count"); + + if (dwarf_version >= 5 && str_form == DW_FORM_line_strp) + { + node = find_AT_string_in_table (filename0, debug_line_str_hash); + set_indirect_string (node); + node->form = DW_FORM_line_strp; + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_line_str_section, + "File Entry: %#x: \"%s\"", 0, node->str); + } + else + dw2_asm_output_nstring (filename0, -1, "File Entry: %#x", 0); + + /* Include directory index. */ + if (dwarf_version >= 5 && idx_form != DW_FORM_udata) + dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2, + 0, NULL); + else + dw2_asm_output_data_uleb128 (0, NULL); + +#ifdef VMS_DEBUGGING_INFO + dw2_asm_output_data_uleb128 (0, NULL); + dw2_asm_output_data_uleb128 (0, NULL); +#endif + } + /* Now write all the file names. */ for (i = 0; i < numfiles; i++) { @@ -10583,38 +10726,71 @@ output_file_names (void) int ver; long long cdt; long siz; - int maxfilelen = strlen (files[file_idx].path) - + dirs[dir_idx].length - + MAX_VMS_VERSION_LEN + 1; + int maxfilelen = (strlen (files[file_idx].path) + + dirs[dir_idx].length + + MAX_VMS_VERSION_LEN + 1); char *filebuf = XALLOCAVEC (char, maxfilelen); vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver); snprintf (filebuf, maxfilelen, "%s;%d", files[file_idx].path + dirs[dir_idx].length, ver); - dw2_asm_output_nstring - (filebuf, -1, "File Entry: %#x", (unsigned) i + 1); + if (dwarf_version >= 5 && str_form == DW_FORM_line_strp) + { + node = find_AT_string_in_table (filebuf, debug_line_str_hash); + set_indirect_string (node); + node->form = DW_FORM_line_strp; + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_line_str_section, + "File Entry: %#x: \"%s\"", (unsigned) i + 1, + node->str); + } + else + dw2_asm_output_nstring (filebuf, -1, "File Entry: %#x", + (unsigned) i + 1); /* Include directory index. */ - dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL); + if (dwarf_version >= 5 && idx_form != DW_FORM_udata) + dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2, + dir_idx + idx_offset, NULL); + else + dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL); /* Modification time. */ - dw2_asm_output_data_uleb128 - ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0) - ? cdt : 0, - NULL); + dw2_asm_output_data_uleb128 ((vms_file_stats_name (files[file_idx].path, + &cdt, 0, 0, 0) == 0) + ? cdt : 0, NULL); /* File length in bytes. */ - dw2_asm_output_data_uleb128 - ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0) - ? siz : 0, - NULL); + dw2_asm_output_data_uleb128 ((vms_file_stats_name (files[file_idx].path, + 0, &siz, 0, 0) == 0) + ? siz : 0, NULL); #else - dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1, - "File Entry: %#x", (unsigned) i + 1); + if (dwarf_version >= 5 && str_form == DW_FORM_line_strp) + { + node = find_AT_string_in_table (files[file_idx].path + + dirs[dir_idx].length, + debug_line_str_hash); + set_indirect_string (node); + node->form = DW_FORM_line_strp; + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_line_str_section, + "File Entry: %#x: \"%s\"", (unsigned) i + 1, + node->str); + } + else + dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, + -1, "File Entry: %#x", (unsigned) i + 1); /* Include directory index. */ - dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL); + if (dwarf_version >= 5 && idx_form != DW_FORM_udata) + dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2, + dir_idx + idx_offset, NULL); + else + dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL); + + if (dwarf_version >= 5) + continue; /* Modification time. */ dw2_asm_output_data_uleb128 (0, NULL); @@ -10624,7 +10800,8 @@ output_file_names (void) #endif /* VMS_DEBUGGING_INFO */ } - dw2_asm_output_data (1, 0, "End file name table"); + if (dwarf_version < 5) + dw2_asm_output_data (1, 0, "End file name table"); } @@ -10748,8 +10925,6 @@ output_line_info (bool prologue_only) static unsigned int generation; char l1[MAX_ARTIFICIAL_LABEL_BYTES], l2[MAX_ARTIFICIAL_LABEL_BYTES]; char p1[MAX_ARTIFICIAL_LABEL_BYTES], p2[MAX_ARTIFICIAL_LABEL_BYTES]; - /* We don't support DWARFv5 line tables yet. */ - int ver = dwarf_version < 5 ? dwarf_version : 4; bool saw_one = false; int opc; @@ -10769,7 +10944,12 @@ output_line_info (bool prologue_only) ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, ver, "DWARF Version"); + dw2_asm_output_data (2, dwarf_version, "DWARF Version"); + if (dwarf_version >= 5) + { + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size"); + dw2_asm_output_data (1, 0, "Segment Size"); + } dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); ASM_OUTPUT_LABEL (asm_out_file, p1); @@ -10783,7 +10963,7 @@ output_line_info (bool prologue_only) and don't let the target override. */ dw2_asm_output_data (1, 1, "Minimum Instruction Length"); - if (ver >= 4) + if (dwarf_version >= 4) dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN, "Maximum Operations Per Instruction"); dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START, @@ -25686,6 +25866,10 @@ init_sections_and_labels (void) 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 (DEBUG_RANGES_SECTION, SECTION_DEBUG, NULL); debug_frame_section = get_section (DEBUG_FRAME_SECTION, @@ -25862,12 +26046,12 @@ output_index_string (indirect_string_nod htab_traverse. Emit one queued .debug_str string. */ int -output_indirect_string (indirect_string_node **h, void *) +output_indirect_string (indirect_string_node **h, enum dwarf_form form) { struct indirect_string_node *node = *h; node->form = find_string_form (node); - if (node->form == DW_FORM_strp && node->refcount > 0) + if (node->form == form && node->refcount > 0) { ASM_OUTPUT_LABEL (asm_out_file, node->label); assemble_string (node->str, strlen (node->str) + 1); @@ -25883,13 +26067,15 @@ output_indirect_strings (void) { switch_to_section (debug_str_section); if (!dwarf_split_debug_info) - debug_str_hash->traverse<void *, output_indirect_string> (NULL); + debug_str_hash->traverse<enum dwarf_form, + output_indirect_string> (DW_FORM_strp); else { unsigned int offset = 0; unsigned int cur_idx = 0; - skeleton_debug_str_hash->traverse<void *, output_indirect_string> (NULL); + skeleton_debug_str_hash->traverse<enum dwarf_form, + output_indirect_string> (DW_FORM_strp); switch_to_section (debug_str_offsets_section); debug_str_hash->traverse_noresize @@ -28209,6 +28395,13 @@ dwarf2out_finish (const char *) /* If we emitted any indirect strings, output the string table too. */ if (debug_str_hash || skeleton_debug_str_hash) output_indirect_strings (); + if (debug_line_str_hash) + { + switch_to_section (debug_line_str_section); + const enum dwarf_form form = DW_FORM_line_strp; + debug_line_str_hash->traverse<enum dwarf_form, + output_indirect_string> (form); + } } /* Perform any cleanups needed after the early debug generation pass @@ -28240,6 +28433,37 @@ dwarf2out_early_finish (const char *file add_comp_dir_attribute (comp_unit_die ()); } + /* When emitting DWARF5 .debug_line_str, move DW_AT_name and + DW_AT_comp_dir into .debug_line_str section. */ + if (!DWARF2_ASM_LINE_DEBUG_INFO + && dwarf_version >= 5 + && !(DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET + || (DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0 + /* FIXME: For now. */ + || dwarf_split_debug_info)) + { + for (int i = 0; i < 2; i++) + { + dw_attr_node *a = get_AT (comp_unit_die (), + i ? DW_AT_comp_dir : DW_AT_name); + if (a == NULL + || AT_class (a) != dw_val_class_str + || strlen (AT_string (a)) + 1 <= DWARF_OFFSET_SIZE) + continue; + + if (! debug_line_str_hash) + debug_line_str_hash + = hash_table<indirect_string_hasher>::create_ggc (10); + + struct indirect_string_node *node + = find_AT_string_in_table (AT_string (a), debug_line_str_hash); + set_indirect_string (node); + node->form = DW_FORM_line_strp; + a->dw_attr_val.v.val_str->refcount--; + a->dw_attr_val.v.val_str = node; + } + } + /* With LTO early dwarf was really finished at compile-time, so make sure to adjust the phase after annotating the LTRANS CU DIE. */ if (in_lto_p) @@ -28345,12 +28569,14 @@ dwarf2out_c_finalize (void) debug_pubnames_section = NULL; debug_pubtypes_section = NULL; debug_str_section = NULL; + debug_line_str_section = NULL; debug_str_dwo_section = NULL; debug_str_offsets_section = NULL; debug_ranges_section = NULL; debug_frame_section = NULL; fde_vec = NULL; debug_str_hash = NULL; + debug_line_str_hash = NULL; skeleton_debug_str_hash = NULL; dw2_string_counter = 0; have_multiple_function_sections = false; Jakub