[PATCH] bfd: Handle DWARF5 debug_rnglists

Mark Wielaard mark@klomp.org
Fri Aug 21 17:19:49 GMT 2020


When building with gcc with -gdwarf-5 ld tests (including ld-elf/dwarf.exp)
fail because they try to read the .debug_ranges section. But DWARF5
introduces a new .debug_rnglists section that encodes the address ranges
more efficiently. Implement reading the debug_rnglists in bfd/dwarf2.c.
Which makes all tests pass again and fixes several gcc testsuite tests
when defaulting to DWARF5.

bfd/ChangeLog:

	* dwarf2.c (struct dwarf2_debug_file): Add dwarf_rnglists_buffer
	and dwarf_rnglists_size fields.
	(dwarf_debug_sections): Add debug_rnglists.
	(dwarf_debug_section_enum): Likewise.
	(read_debug_rnglists): New function.
	(read_rangelist): New function to call either read_ranges or
	read_rnglists. Rename original function to...
	(read_ranges): ...this.
	(read_rnglists): New function.
---
 bfd/ChangeLog |  12 +++++
 bfd/dwarf2.c  | 126 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 62407f987aa..30c68a35cca 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,15 @@
+2020-08-21  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf2.c (struct dwarf2_debug_file): Add dwarf_rnglists_buffer
+	and dwarf_rnglists_size fields.
+	(dwarf_debug_sections): Add debug_rnglists.
+	(dwarf_debug_section_enum): Likewise.
+	(read_debug_rnglists): New function.
+	(read_rangelist): New function to call either read_ranges or
+	read_rnglists. Rename original function to...
+	(read_ranges): ...this.
+	(read_rnglists): New function.
+
 2020-08-21  Jan Beulich  <jbeulich@suse.com>
 
 	* peXXigen.c (_bfd_XX_bfd_copy_private_bfd_data_common): Check
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index 9ed4a4a2871..b8daa13c374 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -130,6 +130,12 @@ struct dwarf2_debug_file
   /* Length of the loaded .debug_ranges section.  */
   bfd_size_type dwarf_ranges_size;
 
+  /* Pointer to the .debug_rnglists section loaded into memory.  */
+  bfd_byte *dwarf_rnglists_buffer;
+
+  /* Length of the loaded .debug_rnglists section.  */
+  bfd_size_type dwarf_rnglists_size;
+
   /* A list of all previously read comp_units.  */
   struct comp_unit *all_comp_units;
 
@@ -327,6 +333,7 @@ const struct dwarf_debug_section dwarf_debug_sections[] =
   { ".debug_pubnames",		".zdebug_pubnames" },
   { ".debug_pubtypes",		".zdebug_pubtypes" },
   { ".debug_ranges",		".zdebug_ranges" },
+  { ".debug_rnglists",		".zdebug_rnglist" },
   { ".debug_static_func",	".zdebug_static_func" },
   { ".debug_static_vars",	".zdebug_static_vars" },
   { ".debug_str",		".zdebug_str", },
@@ -360,6 +367,7 @@ enum dwarf_debug_section_enum
   debug_pubnames,
   debug_pubtypes,
   debug_ranges,
+  debug_rnglists,
   debug_static_func,
   debug_static_vars,
   debug_str,
@@ -2617,6 +2625,19 @@ read_debug_ranges (struct comp_unit * unit)
 		       &file->dwarf_ranges_buffer, &file->dwarf_ranges_size);
 }
 
+/* Read in the .debug_rnglists section for future reference.  */
+
+static bfd_boolean
+read_debug_rnglists (struct comp_unit * unit)
+{
+  struct dwarf2_debug *stash = unit->stash;
+  struct dwarf2_debug_file *file = unit->file;
+
+  return read_section (unit->abfd, &stash->debug_sections[debug_rnglists],
+		       file->syms, 0,
+		       &file->dwarf_rnglists_buffer, &file->dwarf_rnglists_size);
+}
+
 /* Function table functions.  */
 
 static int
@@ -3107,8 +3128,8 @@ find_abstract_instance (struct comp_unit *unit,
 }
 
 static bfd_boolean
-read_rangelist (struct comp_unit *unit, struct arange *arange,
-		bfd_uint64_t offset)
+read_ranges (struct comp_unit *unit, struct arange *arange,
+	     bfd_uint64_t offset)
 {
   bfd_byte *ranges_ptr;
   bfd_byte *ranges_end;
@@ -3153,6 +3174,107 @@ read_rangelist (struct comp_unit *unit, struct arange *arange,
   return TRUE;
 }
 
+static bfd_boolean
+read_rnglists (struct comp_unit *unit, struct arange *arange,
+	       bfd_uint64_t offset)
+{
+  bfd_byte *rngs_ptr;
+  bfd_byte *rngs_end;
+  bfd_vma base_address = unit->base_address;
+  bfd_vma low_pc;
+  bfd_vma high_pc;
+  bfd *abfd = unit->abfd;
+
+  if (! unit->file->dwarf_rnglists_buffer)
+    {
+      if (! read_debug_rnglists (unit))
+	return FALSE;
+    }
+
+  rngs_ptr = unit->file->dwarf_rnglists_buffer + offset;
+  if (rngs_ptr < unit->file->dwarf_rnglists_buffer)
+    return FALSE;
+  rngs_end = unit->file->dwarf_rnglists_buffer;
+  rngs_end +=  unit->file->dwarf_rnglists_size;
+
+  for (;;)
+    {
+      enum dwarf_range_list_entry rlet;
+      unsigned int bytes_read;
+
+      if (rngs_ptr + 1 > rngs_end)
+	return FALSE;
+
+      rlet = read_1_byte (abfd, rngs_ptr, rngs_end);
+      rngs_ptr++;
+
+      switch (rlet)
+	{
+	case DW_RLE_end_of_list:
+	  return TRUE;
+
+	case DW_RLE_base_address:
+	  if (rngs_ptr + unit->addr_size > rngs_end)
+	    return FALSE;
+	  base_address = read_address (unit, rngs_ptr, rngs_end);
+	  rngs_ptr += unit->addr_size;
+	  continue;
+
+	case DW_RLE_start_length:
+	  if (rngs_ptr + unit->addr_size > rngs_end)
+	    return FALSE;
+	  low_pc = read_address (unit, rngs_ptr, rngs_end);
+	  rngs_ptr += unit->addr_size;
+	  high_pc = low_pc;
+	  high_pc += _bfd_safe_read_leb128 (abfd, rngs_ptr, &bytes_read,
+					    FALSE, rngs_end);
+	  rngs_ptr += bytes_read;
+	  break;
+
+	case DW_RLE_offset_pair:
+	  low_pc = base_address;
+	  low_pc += _bfd_safe_read_leb128 (abfd, rngs_ptr, &bytes_read,
+					   FALSE, rngs_end);
+	  high_pc = base_address;
+	  high_pc += _bfd_safe_read_leb128 (abfd, rngs_ptr, &bytes_read,
+					    FALSE, rngs_end);
+	  break;
+
+	case DW_RLE_start_end:
+	  if (rngs_ptr + 2 * unit->addr_size > rngs_end)
+	    return FALSE;
+	  low_pc = read_address (unit, rngs_ptr, rngs_end);
+	  rngs_ptr += unit->addr_size;
+	  high_pc = read_address (unit, rngs_ptr, rngs_end);
+	  rngs_ptr += unit->addr_size;
+	  break;
+
+	/* TODO x-variants need .debug_addr support used for split-dwarf.  */
+	case DW_RLE_base_addressx:
+	case DW_RLE_startx_endx:
+	case DW_RLE_startx_length:
+	default:
+	  return FALSE;
+	}
+
+      if ((low_pc == 0 && high_pc == 0) || low_pc == high_pc)
+	return FALSE;
+
+      if (!arange_add (unit, arange, low_pc, high_pc))
+	return FALSE;
+    }
+}
+
+static bfd_boolean
+read_rangelist (struct comp_unit *unit, struct arange *arange,
+		bfd_uint64_t offset)
+{
+  if (unit->version <= 4)
+    return read_ranges (unit, arange, offset);
+  else
+    return read_rnglists (unit, arange, offset);
+}
+
 static struct varinfo *
 lookup_var_by_offset (bfd_uint64_t offset, struct varinfo * table)
 {
-- 
2.18.4



More information about the Binutils mailing list