Bug 23425 - unresolved symbol diagnostic ends up calling find_abstract_instance with relocations applied causing spurious 'DWARF error: invalid abstract instance DIE ref'
Summary: unresolved symbol diagnostic ends up calling find_abstract_instance with relo...
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: ---
Assignee: Alan Modra
URL: https://sourceware.org/ml/binutils/20...
Keywords:
Depends on:
Blocks:
 
Reported: 2018-07-18 07:27 UTC by Richard Biener
Modified: 2019-07-19 04:41 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
testcase (38.15 KB, application/octet-stream)
2018-07-18 07:30 UTC, Richard Biener
Details
A patch (1.84 KB, patch)
2018-09-03 14:23 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2018-07-18 07:27:35 UTC
Backtrace from the 2.31 branch:

#0  _bfd_error_handler (
    fmt=0x690150 "DWARF error: invalid abstract instance DIE ref")
    at /space/rguenther/src/binutils-gdb/bfd/bfd.c:1177
#1  0x00000000004c6214 in find_abstract_instance (unit=0x7056d8, 
    orig_info_ptr=0x76df90 "\004> ", attr_ptr=0x7fffffffcd10, pname=0x770f18, 
    is_linkage=0x770f14, filename_ptr=0x770f00, linenumber_ptr=0x770f0c)
    at /space/rguenther/src/binutils-gdb/bfd/dwarf2.c:2843
#2  0x00000000004c6cbe in scan_unit_for_symbols (unit=0x7056d8)
    at /space/rguenther/src/binutils-gdb/bfd/dwarf2.c:3169
#3  0x00000000004c789f in comp_unit_find_nearest_line (unit=0x7056d8, 
    addr=4198435, filename_ptr=0x7fffffffd018, function_ptr=0x7fffffffce70, 
    linenumber_ptr=0x7fffffffd00c, discriminator_ptr=0x0, stash=0x7054a0)
    at /space/rguenther/src/binutils-gdb/bfd/dwarf2.c:3616
#4  0x00000000004c9975 in _bfd_dwarf2_find_nearest_line (abfd=0x6fe880, 
    symbols=0x705270, symbol=0x0, section=0x700dd0, offset=35, 
    filename_ptr=0x7fffffffd018, functionname_ptr=0x7fffffffd010, 
    linenumber_ptr=0x7fffffffd00c, discriminator_ptr=0x0, 
    debug_sections=0x68f9a0 <dwarf_debug_sections>, addr_size=4, 
    pinfo=0x700090) at /space/rguenther/src/binutils-gdb/bfd/dwarf2.c:4807
#5  0x0000000000491807 in _bfd_elf_find_nearest_line (abfd=0x6fe880, 
    symbols=0x705270, section=0x700dd0, offset=35, 
    filename_ptr=0x7fffffffd018, functionname_ptr=0x7fffffffd010, 
    line_ptr=0x7fffffffd00c, discriminator_ptr=0x0)
    at /space/rguenther/src/binutils-gdb/bfd/elf.c:8752
#6  0x000000000042574f in vfinfo (fp=0x7ffff7bd2080 <_IO_2_1_stderr_>, 
    fmt=0x555b18 ": undefined reference to `%pT'\n", ap=0x7fffffffd208, 
    is_warning=1) at /space/rguenther/src/binutils-gdb/ld/ldmisc.c:350
#7  0x000000000042643f in einfo (
    fmt=0x555b10 "%X%P: %C: undefined reference to `%pT'\n")
    at /space/rguenther/src/binutils-gdb/ld/ldmisc.c:626
#8  0x000000000041fd50 in undefined_symbol (info=0x6ced80 <link_info>, 
    name=0x70506c "_ZNSsC1Ev", abfd=0x6fe880, section=0x700dd0, address=35, 
    error=1) at /space/rguenther/src/binutils-gdb/ld/ldmain.c:1346
#9  0x000000000046ad3d in elf_x86_64_relocate_section (output_bfd=0x6e7210, 
    info=0x6ced80 <link_info>, input_bfd=0x6fe880, input_section=0x700dd0, 
    contents=0x701f60 "UH\211", <incomplete sequence \345\270>, 
    relocs=0x7050f8, local_syms=0x6f32b0, local_sections=0x76dd60)
    at /space/rguenther/src/binutils-gdb/bfd/elf64-x86-64.c:2483

The code says it only handles refs within the same file but the guard
for this, a zero die_ref, doesn't work after applying relocations to
.debug_info and this function ends up being called from the unresolved
symbol diagnostic causing a spurious DWARF error to be reported.

      /* We only support DW_FORM_ref_addr within the same file, so
         any relocations should be resolved already.  Check this by
         testing for a zero die_ref;  There can't be a valid reference
         to the header of a .debug_info section.
         DW_FORM_ref_addr is an offset relative to .debug_info.
         Normally when using the GNU linker this is accomplished by
         emitting a symbolic reference to a label, because .debug_info
         sections are linked at zero.  When there are multiple section
         groups containing .debug_info, as there might be in a
         relocatable object file, it would be reasonable to assume that
         a symbolic reference to a label in any .debug_info section
         might be used.  Since we lay out multiple .debug_info
         sections at non-zero VMAs (see place_sections), and read
         them contiguously into stash->info_ptr_memory, that means
         the reference is relative to stash->info_ptr_memory.  */
      size_t total;

      info_ptr = unit->stash->info_ptr_memory;
      info_ptr_end = unit->stash->info_ptr_end;
      total = info_ptr_end - info_ptr;
      if (!die_ref || die_ref >= total)
        {
          _bfd_error_handler
            (_("DWARF error: invalid abstract instance DIE ref"));
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
Comment 1 Richard Biener 2018-07-18 07:30:01 UTC
Created attachment 11143 [details]
testcase

To reproduce do

> ./ld-new -o a.out ccELcIbzdebugobjtem cccLlhS9debugobjtem ccqD9BbN.ltrans0.ltrans.o
./ld-new: warning: cannot find entry symbol _start; defaulting to 0000000000401000
./ld-new: ./ld-new: DWARF error: invalid abstract instance DIE ref
ccqD9BbN.ltrans0.ltrans.o: in function `strerrno(int)':
<artificial>:(.text+0x23): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string()'
./ld-new: <artificial>:(.text+0x3b): undefined reference to `strerrno_s(char*, unsigned long, int)'
./ld-new: <artificial>:(.text+0x55): undefined reference to `std::string::operator=(char const*)'
./ld-new: <artificial>:(.text+0x68): undefined reference to `std::string::operator+=(char const*)'
./ld-new: <artificial>:(.text+0x7d): undefined reference to `std::string::operator=(char const*)'
./ld-new: <artificial>:(.text+0x8e): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
./ld-new: <artificial>:(.text+0x99): undefined reference to `_Unwind_Resume'
./ld-new: ccqD9BbN.ltrans0.ltrans.o:(.eh_frame+0x4b): undefined reference to `__gcc_personality_v0'
Comment 2 Richard Biener 2018-07-18 07:36:14 UTC
A similar issue seems to happen with .debug_str lookups:

/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Offset (1678049557) greater than or equal to .debug_str size (5846).
...
later undefined reference diagnostic

but I do not have a testcase to verify that.
Comment 3 Jonny Grant 2018-09-02 12:02:41 UTC
Hi
Could I ask if anyone is working on this?

If someone can work on it, I can probably create a test case for "/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Offset (1678049557) greater than or equal to .debug_str size (5846)."
Comment 4 H.J. Lu 2018-09-02 15:30:33 UTC
(In reply to Jon Grant from comment #3)
> Hi
> Could I ask if anyone is working on this?
> 
> If someone can work on it, I can probably create a test case for
> "/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Offset (1678049557) greater than
> or equal to .debug_str size (5846)."

Please provide a testcase.
Comment 5 Jonny Grant 2018-09-02 18:59:36 UTC
There's a testcase for the first attached. Can that be worked on first?
Comment 6 Jonny Grant 2018-09-02 19:43:56 UTC
/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Could not find abbrev number 113.


I get this output above as well. Could LD add a string to give more of a clue what 113 relates to? Just store the string with the 113 when it is added to the map etc..
Comment 7 Jonny Grant 2018-09-02 19:53:18 UTC
/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Offset (57611527) greater than or equal to .debug_str size (5853).
/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Invalid abstract instance DIE ref.

Can LD at least output the obj file causing the error in those messages please?
Comment 8 Jonny Grant 2018-09-02 22:11:05 UTC
Another type of message shows up. Maybe it could be updated to clarify what the info pointer was pointing to?

/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Info pointer extends beyond end of attributes
/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Could not find abbrev number 6285.
Comment 9 H.J. Lu 2018-09-03 14:10:53 UTC
(In reply to Jon Grant from comment #5)
> There's a testcase for the first attached. Can that be worked on first?

No, I need your testcase as well unless it is the same as the one here.
Comment 10 H.J. Lu 2018-09-03 14:23:49 UTC
Created attachment 11227 [details]
A patch

Please try this.
Comment 11 Jonny Grant 2018-09-03 18:00:01 UTC
(In reply to H.J. Lu from comment #10)
> Created attachment 11227 [details]
> A patch
> 
> Please try this.

Hi H.J.
Could you attach you Ld binary please? I'm on x64 Ubuntu
Comment 12 H.J. Lu 2018-09-04 13:31:52 UTC
(In reply to Jon Grant from comment #11)
> (In reply to H.J. Lu from comment #10)
> > Created attachment 11227 [details]
> > A patch
> > 
> > Please try this.
> 
> Hi H.J.
> Could you attach you Ld binary please? I'm on x64 Ubuntu

You need to build your own linker with my patch.
Comment 13 Sourceware Commits 2018-09-14 11:53:55 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a4cd947aca23d58966ead843e120f4c19db01030

commit a4cd947aca23d58966ead843e120f4c19db01030
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Sep 11 23:50:15 2018 +0930

    PR23425, unresolved symbol diagnostic
    
    dwarf2.c code reasonably assumes that debug info is local to a file,
    an assumption now violated by gcc, resulting in "DWARF error: invalid
    abstract instance DIE ref" or wrong details when attempting to print
    linker error messages with file, function and line reported.
    
    This is because find_abstract_instance is only prepared to handle
    DW_FORM_ref_addr when the .debug_info section referenced is in the
    current file.  When that isn't the case, relocations to access another
    file's .debug_info will typically be against a symbol defined at the
    start of that .debug_info section, plus an addend.  Since the dwarf2.c
    code only considers the current file's debug info, that symbol will be
    undefined, resolving to zero.  In effect the ref_addr will wrongly
    resolve to the current file's .debug_info.
    
    This patch avoids the problem by treating relocations in debug
    sections against undefined symbols in a similar manner to the way
    relocations against symbols defined in discarded sections are
    resolved.  They result in a zero value (except in .debug_ranges)
    regardless of the addend.
    
    	PR 23425
    	* reloc.c (bfd_generic_get_relocated_section_contents): Zero reloc
    	fields in debug sections when reloc is against an undefined symbol
    	and called from bfd_simple_get_relocated_section_contents or
    	similar.
    	* dwarf2.c (find_abstract_instance): Return true for zero offset
    	DW_FORM_ref_addr without returning values.
Comment 14 Alan Modra 2018-09-18 23:46:47 UTC
Fixed
Comment 15 Jonny Grant 2018-10-03 12:04:22 UTC
Many thanks

I built from git, and checked locally. The other "abrev" issue, and "Dwarf Error: Offset (1678049557) greater than or equal to .debug_str size (5846)." no longer visible.
Comment 16 Sourceware Commits 2018-10-13 13:26:11 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0930cb3021b8078b34cf216e79eb8608d017864f

commit 0930cb3021b8078b34cf216e79eb8608d017864f
Author: Alan Modra <amodra@gmail.com>
Date:   Sat Oct 13 22:03:02 2018 +1030

    _bfd_clear_contents bounds checking
    
    This PR shows a fuzzed binary triggering a segfault via a bad
    relocation in .debug_line.  It turns out that unlike normal
    relocations applied to a section, the linker applies those with
    symbols from discarded sections via _bfd_clear_contents without
    checking that the relocation is within the section bounds.  The same
    thing now happens when reading debug sections since commit
    a4cd947aca23, the PR23425 fix.
    
    	PR 23770
    	PR 23425
    	* reloc.c (_bfd_clear_contents): Replace "location" param with
    	"buf" and "off".  Bounds check "off".  Return status.
    	* cofflink.c (_bfd_coff_generic_relocate_section): Update
    	_bfd_clear_contents call.
    	* elf-bfd.h (RELOC_AGAINST_DISCARDED_SECTION): Likewise.
    	* elf32-arc.c (elf_arc_relocate_section): Likewise.
    	* elf32-i386.c (elf_i386_relocate_section): Likewise.
    	* elf32-metag.c (metag_final_link_relocate): Likewise.
    	* elf32-nds32.c (nds32_elf_get_relocated_section_contents): Likewise.
    	* elf32-ppc.c (ppc_elf_relocate_section): Likewise.
    	* elf32-visium.c (visium_elf_relocate_section): Likewise.
    	* elf64-ppc.c (ppc64_elf_relocate_section): Likewise.
    	* elf64-x86-64.c *(elf_x86_64_relocate_section): Likewise.
    	* libbfd-in.h (_bfd_clear_contents): Update prototype.
    	* libbfd.h: Regenerate.
Comment 17 Jonny Grant 2018-10-15 15:16:16 UTC
Could I ask if this message could be expanded to give more clues if ever it occurs again in a future build?

"/usr/bin/x86_64-linux-gnu-ld: Dwarf Error: Offset (1678049557) greater than or equal to .debug_str size (5846)."