Update unmatched and nested subprogram DIEs.

Summary:
readelf was showing some errors because we weren't updating DIEs that were not shallow
in the DIE tree, or DIEs of functions with addresses we don't recognize (mostly functions with
address 0, which could have been removed by the Linker Script but still have debugging information
there). These DIEs need to be updated because their abbreviations are patched.

(cherry picked from FBD3159335)
This commit is contained in:
Gabriel Poesia 2016-04-08 16:24:38 -07:00 committed by Maksim Panchenko
parent 665b03a464
commit 2694e58fa2
5 changed files with 63 additions and 18 deletions

View File

@ -95,6 +95,32 @@ void findLexicalBlocks(const DWARFCompileUnit *Unit,
}
}
// Recursively finds DWARF DW_TAG_subprogram DIEs and match them with
// BinaryFunctions. Record DIEs for unknown subprograms (mostly functions that
// are never called and removed from the binary) in Unknown.
void findSubprograms(const DWARFCompileUnit *Unit,
const DWARFDebugInfoEntryMinimal *DIE,
std::map<uint64_t, BinaryFunction> &BinaryFunctions,
BinaryContext::DIECompileUnitVector &Unknown) {
if (DIE->isSubprogramDIE()) {
uint64_t LowPC, HighPC;
if (DIE->getLowAndHighPC(Unit, LowPC, HighPC)) {
auto It = BinaryFunctions.find(LowPC);
if (It != BinaryFunctions.end()) {
It->second.addSubprocedureDIE(Unit, DIE);
} else {
Unknown.emplace_back(DIE, Unit);
}
}
}
for (auto ChildDIE = DIE->getFirstChild();
ChildDIE != nullptr && !ChildDIE->isNULL();
ChildDIE = ChildDIE->getSibling()) {
findSubprograms(Unit, ChildDIE, BinaryFunctions, Unknown);
}
}
} // namespace
namespace llvm {
@ -130,26 +156,11 @@ void BinaryContext::preprocessDebugInfo() {
void BinaryContext::preprocessFunctionDebugInfo(
std::map<uint64_t, BinaryFunction> &BinaryFunctions) {
// For each CU, iterate over its children DIEs and match subroutine DIEs to
// For each CU, iterate over its children DIEs and match subprogram DIEs to
// BinaryFunctions.
for (const auto &CU : DwCtx->compile_units()) {
const auto *UnitDIE = CU->getUnitDIE(false);
if (!UnitDIE->hasChildren())
continue;
for (auto ChildDIE = UnitDIE->getFirstChild();
ChildDIE != nullptr && !ChildDIE->isNULL();
ChildDIE = ChildDIE->getSibling()) {
if (ChildDIE->isSubprogramDIE()) {
uint64_t LowPC, HighPC;
if (ChildDIE->getLowAndHighPC(CU.get(), LowPC, HighPC)) {
auto It = BinaryFunctions.find(LowPC);
if (It != BinaryFunctions.end()) {
It->second.addSubprocedureDIE(CU.get(), ChildDIE);
}
}
}
}
findSubprograms(CU.get(), CU->getUnitDIE(false), BinaryFunctions,
UnknownFunctions);
}
// Iterate over DIE trees finding lexical blocks.

View File

@ -40,6 +40,9 @@
#include <vector>
namespace llvm {
class DWARFDebugInfoEntryMinimal;
namespace bolt {
class BinaryFunction;
@ -78,6 +81,14 @@ public:
/// List of DWARF location lists in .debug_loc.
std::vector<LocationList> LocationLists;
using DIECompileUnitVector =
std::vector<std::pair<const DWARFDebugInfoEntryMinimal *,
const DWARFCompileUnit *>> ;
/// List of subprocedure DIEs that have addresses that don't match any
/// function, along with their CU.
DIECompileUnitVector UnknownFunctions;
std::unique_ptr<MCContext> Ctx;
std::unique_ptr<DWARFContext> DwCtx;

View File

@ -65,6 +65,14 @@ void DebugRangesSectionsWriter::WriteRangesSection(MCObjectWriter *Writer) {
const auto &AddressRanges = BFAddressRangesPair.second;
SectionOffset += WriteAddressRanges(Writer, AddressRanges, false);
}
// Write an empty address list to be used for objects with unknown address
// ranges.
EmptyRangesListOffset = SectionOffset;
SectionOffset += WriteAddressRanges(
Writer,
std::vector<std::pair<uint64_t, uint64_t>>{},
false);
}
void

View File

@ -65,6 +65,10 @@ public:
return RangesSectionOffsetCUMap;
}
/// Returns an offset of an empty address ranges list that is always written
/// to .debug_ranges
uint32_t getEmptyRangesListOffset() const { return EmptyRangesListOffset; }
private:
// Map from compile unit offset to the list of address intervals that belong
// to that compile unit. Each interval is a pair
@ -77,6 +81,9 @@ private:
std::map<AddressRangesOwner *, std::vector<std::pair<uint64_t, uint64_t>>>
ObjectAddressRanges;
// Offset of an empty address ranges list.
uint32_t EmptyRangesListOffset;
/// When writing data to .debug_ranges remember offset per CU.
RangesCUMapType RangesSectionOffsetCUMap;
};

View File

@ -2182,6 +2182,14 @@ void RewriteInstance::updateDWARFAddressRanges() {
}
}
// Update address ranges of DIEs with addresses that don't match functions.
for (auto &DIECompileUnitPair : BC->UnknownFunctions) {
updateDWARFObjectAddressRanges(
RangesSectionsWriter.getEmptyRangesListOffset(),
DIECompileUnitPair.second,
DIECompileUnitPair.first);
}
// Update address ranges of lexical blocks.
for (const auto &LB : BC->LexicalBlocks) {
updateDWARFObjectAddressRanges(