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.
This commit is contained in:
Mark Wielaard 2020-08-25 15:33:00 +01:00 committed by Nick Clifton
parent b04aa1fc8c
commit c3757b583d
2 changed files with 136 additions and 2 deletions

View File

@ -1,3 +1,15 @@
2020-08-25 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-25 Alan Modra <amodra@gmail.com>
PR 26505

View File

@ -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)
{