diff mbox series

dwarf2out: Fix up ranges for -gdwarf-5 -gsplit-dwarf [PR99490]

Message ID 20210312082047.GP745611@tucnak
State New
Headers show
Series dwarf2out: Fix up ranges for -gdwarf-5 -gsplit-dwarf [PR99490] | expand

Commit Message

Jakub Jelinek March 12, 2021, 8:20 a.m. UTC
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.


	Jakub

Comments

Jason Merrill March 30, 2021, 8:53 p.m. UTC | #1
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
diff mbox series

Patch

--- 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;