From 2694e58fa2a35ea42e3308e1b34da0cda8fb219a Mon Sep 17 00:00:00 2001 From: Gabriel Poesia Date: Fri, 8 Apr 2016 16:24:38 -0700 Subject: [PATCH] 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) --- bolt/BinaryContext.cpp | 47 ++++++++++++++++++------------ bolt/BinaryContext.h | 11 +++++++ bolt/DebugRangesSectionsWriter.cpp | 8 +++++ bolt/DebugRangesSectionsWriter.h | 7 +++++ bolt/RewriteInstance.cpp | 8 +++++ 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/bolt/BinaryContext.cpp b/bolt/BinaryContext.cpp index c3065e023f48..58ae61d1c891 100644 --- a/bolt/BinaryContext.cpp +++ b/bolt/BinaryContext.cpp @@ -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 &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 &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. diff --git a/bolt/BinaryContext.h b/bolt/BinaryContext.h index d93ecff598d1..bffdccb23413 100644 --- a/bolt/BinaryContext.h +++ b/bolt/BinaryContext.h @@ -40,6 +40,9 @@ #include namespace llvm { + +class DWARFDebugInfoEntryMinimal; + namespace bolt { class BinaryFunction; @@ -78,6 +81,14 @@ public: /// List of DWARF location lists in .debug_loc. std::vector LocationLists; + using DIECompileUnitVector = + std::vector> ; + + /// List of subprocedure DIEs that have addresses that don't match any + /// function, along with their CU. + DIECompileUnitVector UnknownFunctions; + std::unique_ptr Ctx; std::unique_ptr DwCtx; diff --git a/bolt/DebugRangesSectionsWriter.cpp b/bolt/DebugRangesSectionsWriter.cpp index 97838d47f00e..1e88b7038d27 100644 --- a/bolt/DebugRangesSectionsWriter.cpp +++ b/bolt/DebugRangesSectionsWriter.cpp @@ -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>{}, + false); } void diff --git a/bolt/DebugRangesSectionsWriter.h b/bolt/DebugRangesSectionsWriter.h index 9e3dacc8a4ff..b6331f71981d 100644 --- a/bolt/DebugRangesSectionsWriter.h +++ b/bolt/DebugRangesSectionsWriter.h @@ -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>> ObjectAddressRanges; + // Offset of an empty address ranges list. + uint32_t EmptyRangesListOffset; + /// When writing data to .debug_ranges remember offset per CU. RangesCUMapType RangesSectionOffsetCUMap; }; diff --git a/bolt/RewriteInstance.cpp b/bolt/RewriteInstance.cpp index 216f4bd72d93..5ca1f397df58 100644 --- a/bolt/RewriteInstance.cpp +++ b/bolt/RewriteInstance.cpp @@ -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(