From: Mark Wielaard Date: Tue, 25 Aug 2020 14:33:00 +0000 (+0100) Subject: Fix the linker's handling of DWARF-5 line number tables. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c3757b583d2448a5996e83e374fb96ac7938da35;p=binutils-gdb.git 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. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index fbdef4e5c75..1766a0850da 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2020-08-25 Mark Wielaard + + * 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 PR 26505 diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index d89a64b7fba..b8f0008a10d 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) {