This is an archive of the discontinued LLVM Phabricator instance.

[LLDB] - Fix setting the breakpoints when -gsplit-dwarf and DWARF 5 were used for building the executable.
ClosedPublic

Authored by grimar on Nov 20 2018, 5:13 AM.

Details

Summary

Imagine the following code:

void baz() {
}

int main() {
  baz();
  return 0;
}

When compiling with with -gdwarf-4 -gsplit-dwarf LLDB is able to set the breakpoint correctly:

clang test.cc -g -fno-rtti -c -gdwarf-4 -gsplit-dwarf
clang test.o -g -fno-rtti -gdwarf-4 -o test -gsplit-dwarf
lldb test
(lldb) target create "test"
Current executable set to 'test' (x86_64).
(lldb) b baz
Breakpoint 1: where = test`baz() + 4 at test.cc:4:1, address = 0x0000000000400524

But not when -dwarf-5 is used. It thinks there are 2 locations:

clang test.cc -g -fno-rtti -c -gdwarf-5 -gsplit-dwarf
clang test.o -g -fno-rtti -gdwarf-5 -o test -gsplit-dwarf
lldb test
(lldb) target create "test"
Current executable set to 'test' (x86_64).
(lldb) b baz
Breakpoint 1: 2 locations.

The issue happens because starting from DWARF v5 DW_AT_addr_base attribute should be used
instead of DW_AT_GNU_addr_base. LLDB does not do that and we end up reading the
.debug_addr header as section content (as addresses) instead of skipping it and reading the real addresses.
Then LLDB is unable to match 2 similar locations and thinks they are different.

Diff Detail

Event Timeline

grimar created this revision.Nov 20 2018, 5:13 AM
grimar updated this revision to Diff 174755.Nov 20 2018, 5:47 AM
  • Added the test case forgotten.
grimar retitled this revision from [LLDB] - Fix setting the breakpoints when -gsplit-dwarf and DWARF 5 owere used for executable. to [LLDB] - Fix setting the breakpoints when -gsplit-dwarf and DWARF 5 were used for building the executable..Nov 20 2018, 7:42 AM
jankratochvil accepted this revision.Nov 26 2018, 2:26 AM
jankratochvil added a subscriber: jankratochvil.

I do not think my approval is sufficient but I agree with the patch.

This revision is now accepted and ready to land.Nov 26 2018, 2:26 AM
jankratochvil added inline comments.Nov 26 2018, 2:29 AM
source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
352

Here I would find good also a comment:

// pre-DWARF v5 attributes DW_AT_GNU_* applied only to the DWO unit while DWARF v5 attributes DW_AT_* apply also to the main unit

Based on a DebugFission comment:

Note the following difference between the current GCC implementation and the DWARF v5 specification: In the current GCC implementation (based on DWARF v4), if DW_AT_ranges is present, the offset into the ranges table is not relative to the value given by DW_AT_ranges_base (i.e., DW_AT_ranges_base is used only for references to the range table from the dwo sections). In DWARF v5, the DW_AT_ranges_base attribute is used for all references to the range table -- both from dwo sections and from skeleton compile units.

I was also thinking to fetch the attributes just once by some (m_version >= 5 ? DW_AT_addr_base : DW_AT_GNU_addr_base) but clang-7.0 does produce DWARF-5 still using DW_AT_GNU_addr_base.

grimar updated this revision to Diff 175222.Nov 26 2018, 3:09 AM
grimar marked an inline comment as done.

Thanks for looking at this, Jan!

  • Rewrote the comment.
source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
352

I rewrote the comment.

I was also thinking to fetch the attributes just once by some (m_version >= 5 ? DW_AT_addr_base : DW_AT_GNU_addr_base) but clang-7.0 does produce DWARF-5 still using DW_AT_GNU_addr_base.

Yeah, it would not be safe to do such check I think. But it should not be an issue, in practice, I believe it should be fine to check both the attributes in order.

clayborg requested changes to this revision.Nov 26 2018, 7:18 AM

See inlined comments.

source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
354
if (addr_base == LLDB_INVALID_ADDRESS)
This revision now requires changes to proceed.Nov 26 2018, 7:18 AM

Missed an inline comment on last comment

source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
311

Use LLDB_INVALID_ADDRESS instead of zero as zero could be a valid base address.

dw_addr_t addr_base = cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_addr_base, LLDB_INVALID_ADDRESS);
355–356
addr_base = cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_addr_base, LLDB_INVALID_ADDRESS);
grimar updated this revision to Diff 175456.Nov 27 2018, 4:59 AM
  • Addressed review comments.
clayborg added inline comments.Nov 27 2018, 9:59 AM
source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
355–356

Do we still want the addr_base to default to zero instead of LLDB_INVALID_ADDRESS here?

grimar marked an inline comment as done.Nov 28 2018, 1:35 AM
grimar added inline comments.
source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
355–356

I believe so. Setting the addr_base to default zero looks fine to me. That way the existent code does not
need to check for LLDB_INVALID_ADDRESS and can just call the GetAddrBase and add the result
to the offset calculation.
That is how things already work and I do not see any benefits from changing this behavior probably?

clayborg accepted this revision.Nov 28 2018, 10:07 AM
clayborg added inline comments.
source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
355–356

Sounds good, just wanted to check.

This revision is now accepted and ready to land.Nov 28 2018, 10:07 AM
This revision was automatically updated to reflect the committed changes.