Message ID | 20210312082047.GP745611@tucnak |
---|---|
State | New |
Headers | show |
Series | dwarf2out: Fix up ranges for -gdwarf-5 -gsplit-dwarf [PR99490] | expand |
On 3/12/21 3:20 AM, Jakub Jelinek wrote: > Hi! > > For -gdwarf-4 -gsplit-dwarf we used to emit .debug_ranges section > (so in the binaries/shared libraries) with DW_AT_ranges from skeleton > units as well as .debug_info.dwo pointing to it through DW_FORM_sec_offset > (and DW_AT_GNU_ranges_base pointing into section, not sure for what > reason exactly). > When DWARF5 support was being added, we've started using .debug_rnglists > section, added DW_AT_rnglists_base to the DW_TAG_skeleton_unit, kept > DW_AT_ranges with DW_FORM_sec_offset in the skeleton and switched > over to DW_FORM_rnglistx for DW_AT_ranges in .debug_info.dwo. > But the DWARF5 spec actually means for the ranges section (at least > everything for those DW_AT_ranges in .debug_info.dwo) to sit > in .debug_rnglists.dwo section next to the .debug_info.dwo, rather than > having consumers look it up in the binary/shared library instead. > Based on some discussions in the DWARF discuss mailing list: > http://lists.dwarfstd.org/pipermail/dwarf-discuss-dwarfstd.org/2021-March/thread.html#4765 > this patch mostly follows what LLVM emits for that right now: > 1) small .debug_rnglists section (when needed) just to cover the > skeleton DW_AT_ranges (if present); the content of the section > uses the Split DWARFy DW_RLE_* codes with addrx encodings where > possible > 2) DW_AT_ranges in the skeleton uses DW_FORM_sec_offset (difference > from LLVM which uses DW_FORM_rnglistx, which makes it larger > and ambiguous) > 3) DW_AT_rnglists_base attribute is gone from the skeleton (again, > unlike LLVM where it is just confusing what exactly it means because > it is inherited; it would make sense if we emitted DW_FORM_rnglistx > in non-split DWARF, but unless ranges are shared, I'm afraid we'd > make DWARF larger with fewer relocations by that) > 4) usually big .debug_rnglists.dwo section again with using DW_RLE_*x* > where possible > 5) DW_AT_ranges with DW_FORM_rnglistx from .debug_info.dwo referring to > that .debug_rnglists.dwo ranges > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2021-03-12 Jakub Jelinek <jakub@redhat.com> > > PR debug/99490 > * dwarf2out.c (debug_ranges_dwo_section): New variable. > (DW_RANGES_IDX_SKELETON): Define. > (struct dw_ranges): Add begin_entry and end_entry members. > (DEBUG_DWO_RNGLISTS_SECTION): Define. > (add_ranges_num): Adjust r initializer for addition of *_entry > members. > (add_ranges_by_labels): For -gsplit-dwarf and force_direct, > set idx to DW_RANGES_IDX_SKELETON. > (index_rnglists): Don't set r->idx if it is equal to > DW_RANGES_IDX_SKELETON. Initialize r->begin_entry and > r->end_entry for -gsplit-dwarf if those will be needed by > output_rnglists. > (output_rnglists): Add DWO argument. If true, switch to > debug_ranges_dwo_section rather than debug_ranges_section. > Adjust l1/l2 label indexes. Only output the offset table when > dwo is true and don't include in there the skeleton range > entry if present. For -gsplit-dwarf, skip ranges that belong > to the other rnglists section. Change return type from void > to bool and return true if there are any range entries for > the other section. For dwarf_split_debug_info use > DW_RLE_startx_endx, DW_RLE_startx_length and DW_RLE_base_addressx > entries instead of DW_RLE_start_end, DW_RLE_start_length and > DW_RLE_base_address. > (init_sections_and_labels): Initialize debug_ranges_dwo_section > if -gsplit-dwarf and DWARF >= 5. Adjust ranges_section_label > and range_base_label indexes. > (dwarf2out_finish): Call index_rnglists earlier before finalizing > .debug_addr. Never emit DW_AT_rnglists_base attribute. For > -gsplit-dwarf and DWARF >= 5 call output_rnglists up to twice > with different dwo arguments. > (dwarf2out_c_finalize): Clear debug_ranges_dwo_section. > > --- gcc/dwarf2out.c.jj 2021-03-10 17:36:37.037537129 +0100 > +++ gcc/dwarf2out.c 2021-03-11 12:50:00.402418873 +0100 > @@ -171,6 +171,7 @@ static GTY(()) section *debug_line_str_s > static GTY(()) section *debug_str_dwo_section; > static GTY(()) section *debug_str_offsets_section; > static GTY(()) section *debug_ranges_section; > +static GTY(()) section *debug_ranges_dwo_section; > static GTY(()) section *debug_frame_section; > > /* Maximum size (in bytes) of an artificially generated label. */ > @@ -3152,11 +3153,17 @@ struct GTY(()) dw_ranges { > /* If this is positive, it's a block number, otherwise it's a > bitwise-negated index into dw_ranges_by_label. */ > int num; > + /* If idx is equal to DW_RANGES_IDX_SKELETON, it should be emitted > + into .debug_rnglists section rather than .debug_rnglists.dwo > + for -gsplit-dwarf and DWARF >= 5. */ > +#define DW_RANGES_IDX_SKELETON ((1U << 31) - 1) > /* Index for the range list for DW_FORM_rnglistx. */ > unsigned int idx : 31; > /* True if this range might be possibly in a different section > from previous entry. */ > unsigned int maybe_new_sec : 1; > + addr_table_entry *begin_entry; > + addr_table_entry *end_entry; > }; > > /* A structure to hold a macinfo entry. */ > @@ -4099,6 +4106,9 @@ new_addr_loc_descr (rtx addr, enum dtpre > #ifndef DEBUG_RNGLISTS_SECTION > #define DEBUG_RNGLISTS_SECTION ".debug_rnglists" > #endif > +#ifndef DEBUG_DWO_RNGLISTS_SECTION > +#define DEBUG_DWO_RNGLISTS_SECTION ".debug_rnglists.dwo" > +#endif > #ifndef DEBUG_LINE_STR_SECTION > #define DEBUG_LINE_STR_SECTION ".debug_line_str" > #endif > @@ -11751,7 +11761,7 @@ output_aranges (void) > static unsigned int > add_ranges_num (int num, bool maybe_new_sec) > { > - dw_ranges r = { NULL, num, 0, maybe_new_sec }; > + dw_ranges r = { NULL, num, 0, maybe_new_sec, NULL, NULL }; > vec_safe_push (ranges_table, r); > return vec_safe_length (ranges_table) - 1; > } > @@ -11796,6 +11806,8 @@ add_ranges_by_labels (dw_die_ref die, co > add_AT_range_list (die, DW_AT_ranges, offset, force_direct); > *added = true; > note_rnglist_head (offset); > + if (dwarf_split_debug_info && force_direct) > + (*ranges_table)[offset].idx = DW_RANGES_IDX_SKELETON; > } > } > > @@ -11921,23 +11933,87 @@ asm_outputs_debug_line_str (void) > } > > > -/* Assign .debug_rnglists indexes. */ > +/* Assign .debug_rnglists indexes and unique indexes into the debug_addr > + section when needed. */ > > static void > index_rnglists (void) > { > unsigned i; > dw_ranges *r; > + bool base = false; > + unsigned int len = vec_safe_length (ranges_table); > > FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) > - if (r->label) > - r->idx = rnglist_idx++; > + { > + if (r->label && r->idx != DW_RANGES_IDX_SKELETON) > + r->idx = rnglist_idx++; > + > + if (!have_multiple_function_sections) > + continue; > + int block_num = r->num; > + if (HAVE_AS_LEB128 && (r->label || r->maybe_new_sec)) > + base = false; > + if (block_num > 0) > + { > + char blabel[MAX_ARTIFICIAL_LABEL_BYTES]; > + char elabel[MAX_ARTIFICIAL_LABEL_BYTES]; > + > + ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num); > + ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num); > + > + if (HAVE_AS_LEB128) > + { > + if (!base) > + { > + dw_ranges *r2 = NULL; > + if (i < len - 1) > + r2 = &(*ranges_table)[i + 1]; > + if (r2 > + && r2->num != 0 > + && r2->label == NULL > + && !r2->maybe_new_sec) Looks like this logic is copied from output_rnglists; can we factor it out? Say, range_needs_distinct_base_address (r2) or (i+1)? It would also be good to have a comment about why there's no end_entry in this case. > + { > + r->begin_entry > + = add_addr_table_entry (xstrdup (blabel), > + ate_kind_label); > + base = true; > + } > + } > + if (base) > + continue; > + r->begin_entry > + = add_addr_table_entry (xstrdup (blabel), ate_kind_label); > + } > + else > + { > + r->begin_entry > + = add_addr_table_entry (xstrdup (blabel), ate_kind_label); > + r->end_entry > + = add_addr_table_entry (xstrdup (elabel), ate_kind_label); > + } > + } > + > + /* Negative block_num stands for an index into ranges_by_label. */ > + else if (block_num < 0) > + { > + int lab_idx = - block_num - 1; > + const char *blabel = (*ranges_by_label)[lab_idx].begin; > + const char *elabel = (*ranges_by_label)[lab_idx].end; > + > + r->begin_entry > + = add_addr_table_entry (xstrdup (blabel), ate_kind_label); > + if (!HAVE_AS_LEB128) > + r->end_entry > + = add_addr_table_entry (xstrdup (elabel), ate_kind_label); > + } > + } > } > > -/* Emit .debug_rnglists section. */ > +/* Emit .debug_rnglists or (when DWO is true) .debug_rnglists.dwo section. */ > > -static void > -output_rnglists (unsigned generation) > +static bool > +output_rnglists (unsigned generation, bool dwo) > { > unsigned i; > dw_ranges *r; > @@ -11945,14 +12021,19 @@ output_rnglists (unsigned generation) > char l2[MAX_ARTIFICIAL_LABEL_BYTES]; > char basebuf[MAX_ARTIFICIAL_LABEL_BYTES]; > > - switch_to_section (debug_ranges_section); > - ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label); > + if (dwo) > + switch_to_section (debug_ranges_dwo_section); > + else > + { > + switch_to_section (debug_ranges_section); > + ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label); > + } > /* There are up to 4 unique ranges labels per generation. > See also init_sections_and_labels. */ > ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_RANGES_SECTION_LABEL, > - 2 + generation * 4); > + 2 + 2 * dwo + generation * 6); > ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_RANGES_SECTION_LABEL, > - 3 + generation * 4); > + 3 + 2 * dwo + generation * 6); > if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) > dw2_asm_output_data (4, 0xffffffff, > "Initial length escape value indicating " > @@ -11969,13 +12050,13 @@ output_rnglists (unsigned generation) > the offset table plus corresponding DW_FORM_rnglistx uleb128 indexes > into it are usually larger than just DW_FORM_sec_offset offsets > into the .debug_rnglists section. */ > - dw2_asm_output_data (4, dwarf_split_debug_info ? rnglist_idx : 0, > + dw2_asm_output_data (4, dwo ? rnglist_idx : 0, > "Offset Entry Count"); > - if (dwarf_split_debug_info) > + if (dwo) > { > ASM_OUTPUT_LABEL (asm_out_file, ranges_base_label); > FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) > - if (r->label) > + if (r->label && r->idx != DW_RANGES_IDX_SKELETON) > dw2_asm_output_delta (dwarf_offset_size, r->label, > ranges_base_label, NULL); > } > @@ -11983,15 +12064,32 @@ output_rnglists (unsigned generation) > const char *lab = ""; > unsigned int len = vec_safe_length (ranges_table); > const char *base = NULL; > + bool skipping = false; > + bool ret = false; > FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) > { > int block_num = r->num; > > if (r->label) > { > + if (dwarf_split_debug_info) > + { > + if ((r->idx == DW_RANGES_IDX_SKELETON) == dwo) These two ifs could be combined. > + { > + ret = true; > + skipping = true; > + continue; > + } > + } > ASM_OUTPUT_LABEL (asm_out_file, r->label); > lab = r->label; > } > + if (skipping) > + { > + if (block_num == 0) > + skipping = false; > + continue; > + } > if (HAVE_AS_LEB128 && (r->label || r->maybe_new_sec)) > base = NULL; > if (block_num > 0) > @@ -12027,10 +12125,23 @@ output_rnglists (unsigned generation) > && r2->label == NULL > && !r2->maybe_new_sec) > { > - dw2_asm_output_data (1, DW_RLE_base_address, > - "DW_RLE_base_address (%s)", lab); > - dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, > - "Base address (%s)", lab); > + if (dwarf_split_debug_info) > + { > + dw2_asm_output_data (1, DW_RLE_base_addressx, > + "DW_RLE_base_addressx (%s)", > + lab); > + dw2_asm_output_data_uleb128 (r->begin_entry->index, > + "Base address index " > + "(%s)", blabel); > + } > + else > + { > + dw2_asm_output_data (1, DW_RLE_base_address, > + "DW_RLE_base_address (%s)", > + lab); > + dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, > + "Base address (%s)", lab); > + } > strcpy (basebuf, blabel); > base = basebuf; > } > @@ -12045,13 +12156,35 @@ output_rnglists (unsigned generation) > "Range end address (%s)", lab); > continue; > } > - dw2_asm_output_data (1, DW_RLE_start_length, > - "DW_RLE_start_length (%s)", lab); > - dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, > - "Range begin address (%s)", lab); > + if (dwarf_split_debug_info) > + { > + dw2_asm_output_data (1, DW_RLE_startx_length, > + "DW_RLE_startx_length (%s)", lab); > + dw2_asm_output_data_uleb128 (r->begin_entry->index, > + "Range begin address index " > + "(%s)", blabel); > + } > + else > + { > + dw2_asm_output_data (1, DW_RLE_start_length, > + "DW_RLE_start_length (%s)", lab); > + dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, > + "Range begin address (%s)", lab); > + } > dw2_asm_output_delta_uleb128 (elabel, blabel, > "Range length (%s)", lab); > } > + else if (dwarf_split_debug_info) > + { > + dw2_asm_output_data (1, DW_RLE_startx_endx, > + "DW_RLE_startx_endx (%s)", lab); > + dw2_asm_output_data_uleb128 (r->begin_entry->index, > + "Range begin address index " > + "(%s)", blabel); > + dw2_asm_output_data_uleb128 (r->end_entry->index, > + "Range end address index " > + "(%s)", elabel); > + } > else > { > dw2_asm_output_data (1, DW_RLE_start_end, > @@ -12074,13 +12207,35 @@ output_rnglists (unsigned generation) > gcc_unreachable (); > if (HAVE_AS_LEB128) > { > - dw2_asm_output_data (1, DW_RLE_start_length, > - "DW_RLE_start_length (%s)", lab); > - dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, > - "Range begin address (%s)", lab); > + if (dwarf_split_debug_info) > + { > + dw2_asm_output_data (1, DW_RLE_startx_length, > + "DW_RLE_startx_length (%s)", lab); > + dw2_asm_output_data_uleb128 (r->begin_entry->index, > + "Range begin address index " > + "(%s)", blabel); > + } > + else > + { > + dw2_asm_output_data (1, DW_RLE_start_length, > + "DW_RLE_start_length (%s)", lab); > + dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, > + "Range begin address (%s)", lab); > + } > dw2_asm_output_delta_uleb128 (elabel, blabel, > "Range length (%s)", lab); > } > + else if (dwarf_split_debug_info) > + { > + dw2_asm_output_data (1, DW_RLE_startx_endx, > + "DW_RLE_startx_endx (%s)", lab); > + dw2_asm_output_data_uleb128 (r->begin_entry->index, > + "Range begin address index " > + "(%s)", blabel); > + dw2_asm_output_data_uleb128 (r->end_entry->index, > + "Range end address index " > + "(%s)", elabel); > + } > else > { > dw2_asm_output_data (1, DW_RLE_start_end, > @@ -12096,6 +12251,7 @@ output_rnglists (unsigned generation) > "DW_RLE_end_of_list (%s)", lab); > } > ASM_OUTPUT_LABEL (asm_out_file, l2); > + return ret; > } > > /* Data structure containing information about input files. */ > @@ -28823,6 +28979,10 @@ init_sections_and_labels (bool early_lto > debug_macinfo_section = get_section (debug_macinfo_section_name, > SECTION_DEBUG | SECTION_EXCLUDE, > NULL); > + if (dwarf_version >= 5) > + debug_ranges_dwo_section > + = get_section (DEBUG_DWO_RNGLISTS_SECTION, > + SECTION_DEBUG | SECTION_EXCLUDE, NULL); > } > debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, > SECTION_DEBUG, NULL); > @@ -28857,15 +29017,15 @@ init_sections_and_labels (bool early_lto > ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label, > DEBUG_LINE_SECTION_LABEL, > init_sections_and_labels_generation); > - /* There are up to 4 unique ranges labels per generation. > + /* There are up to 6 unique ranges labels per generation. > See also output_rnglists. */ > ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, > DEBUG_RANGES_SECTION_LABEL, > - init_sections_and_labels_generation * 4); > + init_sections_and_labels_generation * 6); > if (dwarf_version >= 5 && dwarf_split_debug_info) > ASM_GENERATE_INTERNAL_LABEL (ranges_base_label, > DEBUG_RANGES_SECTION_LABEL, > - 1 + init_sections_and_labels_generation * 4); > + 1 + init_sections_and_labels_generation * 6); > ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, > DEBUG_ADDR_SECTION_LABEL, > init_sections_and_labels_generation); > @@ -31665,6 +31825,9 @@ dwarf2out_finish (const char *filename) > index_location_lists (comp_unit_die ()); > } > > + if (dwarf_version >= 5 && !vec_safe_is_empty (ranges_table)) > + index_rnglists (); > + > if (addr_index_table != NULL) > { > unsigned int index = 0; > @@ -31730,9 +31893,6 @@ dwarf2out_finish (const char *filename) > int mark; > struct md5_ctx ctx; > > - if (dwarf_version >= 5 && !vec_safe_is_empty (ranges_table)) > - index_rnglists (); > - > /* Compute a checksum of the comp_unit to use as the dwo_id. */ > md5_init_ctx (&ctx); > mark = 0; > @@ -31752,10 +31912,7 @@ dwarf2out_finish (const char *filename) > comp-unit DIE. */ > if (!vec_safe_is_empty (ranges_table)) > { > - if (dwarf_version >= 5) > - add_AT_lineptr (main_comp_unit_die, DW_AT_rnglists_base, > - ranges_base_label); > - else > + if (dwarf_version < 5) > add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base, > ranges_section_label); > } > @@ -31833,7 +31990,26 @@ dwarf2out_finish (const char *filename) > if (!vec_safe_is_empty (ranges_table)) > { > if (dwarf_version >= 5) > - output_rnglists (generation); > + { > + if (dwarf_split_debug_info) > + { > + /* We don't know right now whether there are any > + ranges for .debug_rnglists and any for .debug_rnglists.dwo. > + Depending on into which of those two belongs the first > + ranges_table entry, emit that section first and that > + output_rnglists call will return if the other kind of Maybe "will return true if..." > + ranges needs to be emitted as well. */ > + if ((*ranges_table)[0].idx == DW_RANGES_IDX_SKELETON) > + { > + if (output_rnglists (generation, false)) > + output_rnglists (generation, true); > + } > + else if (output_rnglists (generation, true)) > + output_rnglists (generation, false); Maybe bool dwo = (*ranges_table)[0].idx != DW_RANGES_IDX_SKELETON; if (output_rnglists (generation, dwo)) output_rnglists (generation, !dwo); OK with these changes. Jason
--- gcc/dwarf2out.c.jj 2021-03-10 17:36:37.037537129 +0100 +++ gcc/dwarf2out.c 2021-03-11 12:50:00.402418873 +0100 @@ -171,6 +171,7 @@ static GTY(()) section *debug_line_str_s static GTY(()) section *debug_str_dwo_section; static GTY(()) section *debug_str_offsets_section; static GTY(()) section *debug_ranges_section; +static GTY(()) section *debug_ranges_dwo_section; static GTY(()) section *debug_frame_section; /* Maximum size (in bytes) of an artificially generated label. */ @@ -3152,11 +3153,17 @@ struct GTY(()) dw_ranges { /* If this is positive, it's a block number, otherwise it's a bitwise-negated index into dw_ranges_by_label. */ int num; + /* If idx is equal to DW_RANGES_IDX_SKELETON, it should be emitted + into .debug_rnglists section rather than .debug_rnglists.dwo + for -gsplit-dwarf and DWARF >= 5. */ +#define DW_RANGES_IDX_SKELETON ((1U << 31) - 1) /* Index for the range list for DW_FORM_rnglistx. */ unsigned int idx : 31; /* True if this range might be possibly in a different section from previous entry. */ unsigned int maybe_new_sec : 1; + addr_table_entry *begin_entry; + addr_table_entry *end_entry; }; /* A structure to hold a macinfo entry. */ @@ -4099,6 +4106,9 @@ new_addr_loc_descr (rtx addr, enum dtpre #ifndef DEBUG_RNGLISTS_SECTION #define DEBUG_RNGLISTS_SECTION ".debug_rnglists" #endif +#ifndef DEBUG_DWO_RNGLISTS_SECTION +#define DEBUG_DWO_RNGLISTS_SECTION ".debug_rnglists.dwo" +#endif #ifndef DEBUG_LINE_STR_SECTION #define DEBUG_LINE_STR_SECTION ".debug_line_str" #endif @@ -11751,7 +11761,7 @@ output_aranges (void) static unsigned int add_ranges_num (int num, bool maybe_new_sec) { - dw_ranges r = { NULL, num, 0, maybe_new_sec }; + dw_ranges r = { NULL, num, 0, maybe_new_sec, NULL, NULL }; vec_safe_push (ranges_table, r); return vec_safe_length (ranges_table) - 1; } @@ -11796,6 +11806,8 @@ add_ranges_by_labels (dw_die_ref die, co add_AT_range_list (die, DW_AT_ranges, offset, force_direct); *added = true; note_rnglist_head (offset); + if (dwarf_split_debug_info && force_direct) + (*ranges_table)[offset].idx = DW_RANGES_IDX_SKELETON; } } @@ -11921,23 +11933,87 @@ asm_outputs_debug_line_str (void) } -/* Assign .debug_rnglists indexes. */ +/* Assign .debug_rnglists indexes and unique indexes into the debug_addr + section when needed. */ static void index_rnglists (void) { unsigned i; dw_ranges *r; + bool base = false; + unsigned int len = vec_safe_length (ranges_table); FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) - if (r->label) - r->idx = rnglist_idx++; + { + if (r->label && r->idx != DW_RANGES_IDX_SKELETON) + r->idx = rnglist_idx++; + + if (!have_multiple_function_sections) + continue; + int block_num = r->num; + if (HAVE_AS_LEB128 && (r->label || r->maybe_new_sec)) + base = false; + if (block_num > 0) + { + char blabel[MAX_ARTIFICIAL_LABEL_BYTES]; + char elabel[MAX_ARTIFICIAL_LABEL_BYTES]; + + ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num); + ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num); + + if (HAVE_AS_LEB128) + { + if (!base) + { + dw_ranges *r2 = NULL; + if (i < len - 1) + r2 = &(*ranges_table)[i + 1]; + if (r2 + && r2->num != 0 + && r2->label == NULL + && !r2->maybe_new_sec) + { + r->begin_entry + = add_addr_table_entry (xstrdup (blabel), + ate_kind_label); + base = true; + } + } + if (base) + continue; + r->begin_entry + = add_addr_table_entry (xstrdup (blabel), ate_kind_label); + } + else + { + r->begin_entry + = add_addr_table_entry (xstrdup (blabel), ate_kind_label); + r->end_entry + = add_addr_table_entry (xstrdup (elabel), ate_kind_label); + } + } + + /* Negative block_num stands for an index into ranges_by_label. */ + else if (block_num < 0) + { + int lab_idx = - block_num - 1; + const char *blabel = (*ranges_by_label)[lab_idx].begin; + const char *elabel = (*ranges_by_label)[lab_idx].end; + + r->begin_entry + = add_addr_table_entry (xstrdup (blabel), ate_kind_label); + if (!HAVE_AS_LEB128) + r->end_entry + = add_addr_table_entry (xstrdup (elabel), ate_kind_label); + } + } } -/* Emit .debug_rnglists section. */ +/* Emit .debug_rnglists or (when DWO is true) .debug_rnglists.dwo section. */ -static void -output_rnglists (unsigned generation) +static bool +output_rnglists (unsigned generation, bool dwo) { unsigned i; dw_ranges *r; @@ -11945,14 +12021,19 @@ output_rnglists (unsigned generation) char l2[MAX_ARTIFICIAL_LABEL_BYTES]; char basebuf[MAX_ARTIFICIAL_LABEL_BYTES]; - switch_to_section (debug_ranges_section); - ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label); + if (dwo) + switch_to_section (debug_ranges_dwo_section); + else + { + switch_to_section (debug_ranges_section); + ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label); + } /* There are up to 4 unique ranges labels per generation. See also init_sections_and_labels. */ ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_RANGES_SECTION_LABEL, - 2 + generation * 4); + 2 + 2 * dwo + generation * 6); ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_RANGES_SECTION_LABEL, - 3 + generation * 4); + 3 + 2 * dwo + generation * 6); if (DWARF_INITIAL_LENGTH_SIZE - dwarf_offset_size == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating " @@ -11969,13 +12050,13 @@ output_rnglists (unsigned generation) the offset table plus corresponding DW_FORM_rnglistx uleb128 indexes into it are usually larger than just DW_FORM_sec_offset offsets into the .debug_rnglists section. */ - dw2_asm_output_data (4, dwarf_split_debug_info ? rnglist_idx : 0, + dw2_asm_output_data (4, dwo ? rnglist_idx : 0, "Offset Entry Count"); - if (dwarf_split_debug_info) + if (dwo) { ASM_OUTPUT_LABEL (asm_out_file, ranges_base_label); FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) - if (r->label) + if (r->label && r->idx != DW_RANGES_IDX_SKELETON) dw2_asm_output_delta (dwarf_offset_size, r->label, ranges_base_label, NULL); } @@ -11983,15 +12064,32 @@ output_rnglists (unsigned generation) const char *lab = ""; unsigned int len = vec_safe_length (ranges_table); const char *base = NULL; + bool skipping = false; + bool ret = false; FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r) { int block_num = r->num; if (r->label) { + if (dwarf_split_debug_info) + { + if ((r->idx == DW_RANGES_IDX_SKELETON) == dwo) + { + ret = true; + skipping = true; + continue; + } + } ASM_OUTPUT_LABEL (asm_out_file, r->label); lab = r->label; } + if (skipping) + { + if (block_num == 0) + skipping = false; + continue; + } if (HAVE_AS_LEB128 && (r->label || r->maybe_new_sec)) base = NULL; if (block_num > 0) @@ -12027,10 +12125,23 @@ output_rnglists (unsigned generation) && r2->label == NULL && !r2->maybe_new_sec) { - dw2_asm_output_data (1, DW_RLE_base_address, - "DW_RLE_base_address (%s)", lab); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, - "Base address (%s)", lab); + if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_RLE_base_addressx, + "DW_RLE_base_addressx (%s)", + lab); + dw2_asm_output_data_uleb128 (r->begin_entry->index, + "Base address index " + "(%s)", blabel); + } + else + { + dw2_asm_output_data (1, DW_RLE_base_address, + "DW_RLE_base_address (%s)", + lab); + dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, + "Base address (%s)", lab); + } strcpy (basebuf, blabel); base = basebuf; } @@ -12045,13 +12156,35 @@ output_rnglists (unsigned generation) "Range end address (%s)", lab); continue; } - dw2_asm_output_data (1, DW_RLE_start_length, - "DW_RLE_start_length (%s)", lab); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, - "Range begin address (%s)", lab); + if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_RLE_startx_length, + "DW_RLE_startx_length (%s)", lab); + dw2_asm_output_data_uleb128 (r->begin_entry->index, + "Range begin address index " + "(%s)", blabel); + } + else + { + dw2_asm_output_data (1, DW_RLE_start_length, + "DW_RLE_start_length (%s)", lab); + dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, + "Range begin address (%s)", lab); + } dw2_asm_output_delta_uleb128 (elabel, blabel, "Range length (%s)", lab); } + else if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_RLE_startx_endx, + "DW_RLE_startx_endx (%s)", lab); + dw2_asm_output_data_uleb128 (r->begin_entry->index, + "Range begin address index " + "(%s)", blabel); + dw2_asm_output_data_uleb128 (r->end_entry->index, + "Range end address index " + "(%s)", elabel); + } else { dw2_asm_output_data (1, DW_RLE_start_end, @@ -12074,13 +12207,35 @@ output_rnglists (unsigned generation) gcc_unreachable (); if (HAVE_AS_LEB128) { - dw2_asm_output_data (1, DW_RLE_start_length, - "DW_RLE_start_length (%s)", lab); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, - "Range begin address (%s)", lab); + if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_RLE_startx_length, + "DW_RLE_startx_length (%s)", lab); + dw2_asm_output_data_uleb128 (r->begin_entry->index, + "Range begin address index " + "(%s)", blabel); + } + else + { + dw2_asm_output_data (1, DW_RLE_start_length, + "DW_RLE_start_length (%s)", lab); + dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel, + "Range begin address (%s)", lab); + } dw2_asm_output_delta_uleb128 (elabel, blabel, "Range length (%s)", lab); } + else if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_RLE_startx_endx, + "DW_RLE_startx_endx (%s)", lab); + dw2_asm_output_data_uleb128 (r->begin_entry->index, + "Range begin address index " + "(%s)", blabel); + dw2_asm_output_data_uleb128 (r->end_entry->index, + "Range end address index " + "(%s)", elabel); + } else { dw2_asm_output_data (1, DW_RLE_start_end, @@ -12096,6 +12251,7 @@ output_rnglists (unsigned generation) "DW_RLE_end_of_list (%s)", lab); } ASM_OUTPUT_LABEL (asm_out_file, l2); + return ret; } /* Data structure containing information about input files. */ @@ -28823,6 +28979,10 @@ init_sections_and_labels (bool early_lto debug_macinfo_section = get_section (debug_macinfo_section_name, SECTION_DEBUG | SECTION_EXCLUDE, NULL); + if (dwarf_version >= 5) + debug_ranges_dwo_section + = get_section (DEBUG_DWO_RNGLISTS_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); } debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, SECTION_DEBUG, NULL); @@ -28857,15 +29017,15 @@ init_sections_and_labels (bool early_lto ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label, DEBUG_LINE_SECTION_LABEL, init_sections_and_labels_generation); - /* There are up to 4 unique ranges labels per generation. + /* There are up to 6 unique ranges labels per generation. See also output_rnglists. */ ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, DEBUG_RANGES_SECTION_LABEL, - init_sections_and_labels_generation * 4); + init_sections_and_labels_generation * 6); if (dwarf_version >= 5 && dwarf_split_debug_info) ASM_GENERATE_INTERNAL_LABEL (ranges_base_label, DEBUG_RANGES_SECTION_LABEL, - 1 + init_sections_and_labels_generation * 4); + 1 + init_sections_and_labels_generation * 6); ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, DEBUG_ADDR_SECTION_LABEL, init_sections_and_labels_generation); @@ -31665,6 +31825,9 @@ dwarf2out_finish (const char *filename) index_location_lists (comp_unit_die ()); } + if (dwarf_version >= 5 && !vec_safe_is_empty (ranges_table)) + index_rnglists (); + if (addr_index_table != NULL) { unsigned int index = 0; @@ -31730,9 +31893,6 @@ dwarf2out_finish (const char *filename) int mark; struct md5_ctx ctx; - if (dwarf_version >= 5 && !vec_safe_is_empty (ranges_table)) - index_rnglists (); - /* Compute a checksum of the comp_unit to use as the dwo_id. */ md5_init_ctx (&ctx); mark = 0; @@ -31752,10 +31912,7 @@ dwarf2out_finish (const char *filename) comp-unit DIE. */ if (!vec_safe_is_empty (ranges_table)) { - if (dwarf_version >= 5) - add_AT_lineptr (main_comp_unit_die, DW_AT_rnglists_base, - ranges_base_label); - else + if (dwarf_version < 5) add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base, ranges_section_label); } @@ -31833,7 +31990,26 @@ dwarf2out_finish (const char *filename) if (!vec_safe_is_empty (ranges_table)) { if (dwarf_version >= 5) - output_rnglists (generation); + { + if (dwarf_split_debug_info) + { + /* We don't know right now whether there are any + ranges for .debug_rnglists and any for .debug_rnglists.dwo. + Depending on into which of those two belongs the first + ranges_table entry, emit that section first and that + output_rnglists call will return if the other kind of + ranges needs to be emitted as well. */ + if ((*ranges_table)[0].idx == DW_RANGES_IDX_SKELETON) + { + if (output_rnglists (generation, false)) + output_rnglists (generation, true); + } + else if (output_rnglists (generation, true)) + output_rnglists (generation, false); + } + else + output_rnglists (generation, false); + } else output_ranges (); } @@ -32457,6 +32633,7 @@ dwarf2out_c_finalize (void) debug_str_dwo_section = NULL; debug_str_offsets_section = NULL; debug_ranges_section = NULL; + debug_ranges_dwo_section = NULL; debug_frame_section = NULL; fde_vec = NULL; debug_str_hash = NULL;