aboutsummaryrefslogtreecommitdiff
path: root/bfd/dwarf2.c
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2020-08-25 15:33:00 +0100
committerNick Clifton <nickc@redhat.com>2020-08-25 15:33:00 +0100
commitc3757b583d2448a5996e83e374fb96ac7938da35 (patch)
treed4bb1bd641b824dea293b0e2052c9b3788b5bbf0 /bfd/dwarf2.c
parentb04aa1fc8c9d4a79e6293a3a1df7507052afedf3 (diff)
downloadgdb-c3757b583d2448a5996e83e374fb96ac7938da35.zip
gdb-c3757b583d2448a5996e83e374fb96ac7938da35.tar.gz
gdb-c3757b583d2448a5996e83e374fb96ac7938da35.tar.bz2
Fix the linker's handling of DWARF-5 line number tables.
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. * 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.
Diffstat (limited to 'bfd/dwarf2.c')
-rw-r--r--bfd/dwarf2.c126
1 files changed, 124 insertions, 2 deletions
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index d89a64b..b8f0008 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,
@@ -2634,6 +2642,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
@@ -3124,8 +3145,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;
@@ -3170,6 +3191,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)
{