From: Nick Clifton Date: Tue, 25 Aug 2020 14:39:00 +0000 (+0100) Subject: Backport patches from the mainline to fix the handling of DWARF-5 debug information: X-Git-Tag: binutils-2_35_1~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9fe8b9cc552b5af8b768b425b3207921ca95186;p=thirdparty%2Fbinutils-gdb.git Backport patches from the mainline to fix the handling of DWARF-5 debug information: binutils* testsuite/binutils-all/readelf.exp (readelf_wi_test): Also recognize DW_LANG_C11. bfd * 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. * dwarf2.c (read_attribute_value): Handle DW_FORM_data16. (read_formatted_entries): Likewise. And skip zero entry. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6d1d01a566a..4ad5aa840f1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,23 @@ +2020-08-25 Nick Clifton + + Backport from the mainline: + 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-24 Mark Wielaard + + * dwarf2.c (read_attribute_value): Handle DW_FORM_data16. + (read_formatted_entries): Likewise. And skip zero entry. + 2020-08-15 Alan Modra PR 26389 diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index 9ed4a4a2871..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, @@ -1329,6 +1337,17 @@ read_attribute_value (struct attribute * attr, attr->form = DW_FORM_sdata; attr->u.sval = implicit_const; break; + case DW_FORM_data16: + /* This is really a "constant", but there is no way to store that + so pretend it is a 16 byte block instead. */ + amt = sizeof (struct dwarf_block); + blk = (struct dwarf_block *) bfd_alloc (abfd, amt); + if (blk == NULL) + return NULL; + blk->size = 16; + info_ptr = read_n_bytes (info_ptr, info_ptr_end, blk); + attr->u.blk = blk; + break; default: _bfd_error_handler (_("DWARF error: invalid or unhandled FORM value: %#x"), form); @@ -2069,11 +2088,17 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, case DW_FORM_udata: *uintp = attr.u.val; break; + + case DW_FORM_data16: + /* MD5 data is in the attr.blk, but we are ignoring those. */ + break; } } - if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) - return FALSE; + /* Skip the first "zero entry", which is the compilation dir/file. */ + if (datai != 0) + if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) + return FALSE; } *bufp = buf; @@ -2617,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 @@ -3107,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; @@ -3153,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) { diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 8bfcfaa7a78..2e7fecee8ca 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,11 @@ +2020-08-25 Nick Clifton + + Backport from the mainline: + 2020-08-21 Mark Wielaard + + * testsuite/binutils-all/readelf.exp (readelf_wi_test): Also + recognize DW_LANG_C11. + 2020-08-12 Nick Clifton * po/sr.po: Updated Serbian translation. diff --git a/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp index 0ca27482229..8a62eeff582 100644 --- a/binutils/testsuite/binutils-all/readelf.exp +++ b/binutils/testsuite/binutils-all/readelf.exp @@ -188,7 +188,7 @@ proc readelf_wi_test {} { ".*DW_TAG_subprogram.*" ".*DW_TAG_base_type.*" ".*DW_AT_producer.*(GNU C|indirect string).*" - ".*DW_AT_language.*ANSI C.*" + ".*DW_AT_language.*(ANSI C|C11).*" ".*DW_AT_name.*(testprog.c|indirect string).*" ".*DW_AT_name.*fn.*" ".*DW_AT_name.*(main|indirect string).*"