This is an archive of the discontinued LLVM Phabricator instance.

Fix FDE indexing while scan debug_info section
ClosedPublic

Authored by tatyana-krasnukha on May 24 2017, 9:48 AM.

Details

Summary

There are some differences between eh_frame and debug_frame formats that are not considered by DWARFCallFrameInfo::GetFDEIndex.
An FDE entry contains CIE_pointer in debug_frame in same place as cie_id in eh_frame. As described in dwarf standard (section 6.4.1), CIE_pointer is an "offset into the .debug_frame section". So, variable cie_offset should be equal cie_id for debug_frame.
FDE entries with zeroth CIE pointer (which is actually placed in cie_id variable) shouldn't be ignored also.

I had same issue as described here, and these changes have fixed it for me (with "m_is_eh_frame" set to false, of course).

I have also added a little change which allow to use debug_info section when eh_frame is absent. This case really can take place on some platforms.

Diff Detail

Repository
rL LLVM

Event Timeline

clayborg accepted this revision.May 24 2017, 9:58 AM
This revision is now accepted and ready to land.May 24 2017, 9:58 AM
abidh accepted this revision.May 25 2017, 1:51 AM
abidh closed this revision.May 25 2017, 3:23 AM

@tatyana-krasnukha Please make sure that patch is generated from the top level lldb directory.

Committed in r303847.

labath added a subscriber: labath.May 25 2017, 4:41 AM

Guys, this breaks a whole bunch of unwinding tests on android: http://lab.llvm.org:8011/builders/lldb-x86_64-ubuntu-14.04-android/builds/4243

I have reverted this commit, because we are still parsing debug_frame entries incorrectly. The first issue I ran into was parsing of CIE entries (which have a somewhat different layout in the debug_frame sections, and we're not taking that into account), but there may be others. We cannot enable debug_frame parsing until we can parse it properly. The issue is not android specific, as the earlier comment might have suggested, it just so happens that the android clang is the only compiler in our test cluster that produces debug_frame sections. Nonetheless, I can provide you with some example android binaries if you want to look at them more closely.

Yes, give those binaries, please.

Added support of DWARF <= 5. For unsupported versions GetUnwindPlan will return false and next behavior should be like without debug_frame at all. Checked it on binaries with v.2 and v.4 on x86-linux target, but have not a chance to run tests for arm-android and other. I'd appreciate it if someone, who has adjusted environment, would check it.

labath added a comment.Jun 5 2017, 6:23 AM

Thank you for adding the support for dwarf 4 CIE. I think it's a good start, but I believe the version check needs to be done in a smarter way.

On the flip side, I tried running this through the test suite on android, and I noticed only one test failing for arm64. I am going to try digging into this more later.

source/Symbol/DWARFCallFrameInfo.cpp
482

Unprintable character? Same thing two lines below.

source/Symbol/UnwindTable.cpp
70

So, this checks the version number of the *first* CIE in the debug_frame section right. That is incorrect, as the same section could have CIEs with different version numbers (In fact, that may be quite likely, as a module will usually contain some startup code, which will probably have been built with a different compiler than the user code). I think the "supported" decision should be made per-CIE, not for the whole section (or at the very least, check that *all* CIEs in the section have supported version numbers). This means the will need to be made in DWARFCallFrameInfo.cpp, which is good anyway, as the fact that you are reaching inside the section from UnwindTable.cpp was my other issue with this patch.

71

The spec says "This number is specific to the call frame information and is independent of the DWARF version number. ", so it's probably not right to call this "DwarfVersion"

source/Symbol/DWARFCallFrameInfo.cpp
482

Hm... It's strange, I formatted it with clang-format tool.

source/Symbol/UnwindTable.cpp
70

Not exactly true. This code checks DWARF version in debug_info section, if it exists. Its only purpose is to avoid extra actions if it is already known that the version is unsupported.

Version number of each CIE is checked in ParseCIE method.

71

It is not same, but it is not independent too. Look on comments for enum CFIVersion in DWARFCallFrameInfo.h

labath added inline comments.Jun 5 2017, 10:11 AM
source/Symbol/DWARFCallFrameInfo.cpp
482

clang-format does not remove non-ascii characters. You need to do that yourself.

source/Symbol/UnwindTable.cpp
70

Ok, so you're checking the version of the first compile unit. It still sounds wrong to me. What if the second compile unit has unsupported version?

If this is just an attempt at a performance optimization, then I say we just remove it. We can attempt to optimize performance differently if it ever becomes an issue.

71

I didn't notice that you are checking the debug_info section. You can ignore this comment.

tatyana-krasnukha added a reviewer: labath.

Removed non-printable characters from DWARFCallFrameInfo::GetFDEIndex and redundant version checks from UnwindTable::Initialize.

jasonmolenda edited edge metadata.Jun 7 2017, 9:32 PM

I don't have any comments on this - it seems like a good addition. We've almost entirely stopped using eh_frame/debug_frame on Darwin so I don't have any way to test this. When we were adding the eh_frame/debug_frame parser, clang (and I think gcc) were both generating the same thing for both sections, so there was no benefit to reading debug_frame. Greg wrote it with the idea that the code could process either source of information, but we never actually did that with it. I'm sure there are targets where a binary might have debug_frame but not eh_frame, and this change could be a big help there.

labath edited edge metadata.Jun 14 2017, 3:27 AM

I've looked into the other test failures I was seeing on arm64 after merging this in. I have a fix for this up in D34199.

As for the testing situation, theoretically we could claim this is tested, as android arm targets will use this code, but probably nobody except our bots will be able to exercise it. One possible way to test this in a more targeted way would be to go with something similar to https://reviews.llvm.org/D32434. I.e.,

  • build an tiny executable with a .debug_frame section
  • run obj2yaml on it
  • strip down the resulting yaml file (you probably only need the .text and .debug_frame section)
  • manually create a Module corresponding to the yaml file (as in the test)
  • construct a DWARFCallFrameInfo based on the Module
  • ask the call frame info for an unwind plan an verify it

I haven't tried constructing a DWARFCallFrameInfo in a unit test, but given that it only takes an ObjectFile in it's constructor, it looks like it should be possible to do it without having to instantiate the whole world.