From dcfa2ab534c8f1b4345012a02f130a0a07060bfd Mon Sep 17 00:00:00 2001 From: Alexander Yermolovich Date: Mon, 15 May 2023 14:23:21 -0700 Subject: [PATCH] [BOLT][DWARF] Change to process and write out TUs first then CUs in batches To reduce memory footprint changed so that we process and write out TUs first, reset DIEBuilder and process CUs. CUs are processed in buckets. First bucket contains all the CUs with cross CU references. Rest processd one at a time. clang-17 build in debug mode, by clang-17. before 8:25.81 real, 834.37 user, 86.03 sys, 0 amem, 79525064 mmem 8:02.20 real, 820.46 user, 81.81 sys, 0 amem, 79501616 mmem 7:52.69 real, 802.01 user, 83.99 sys, 0 amem, 79534392 mmem after 7:49.35 real, 822.04 user, 66.19 sys, 0 amem, 34934260 mmem 7:42.16 real, 825.46 user, 63.52 sys, 0 amem, 34951660 mmem 7:46.71 real, 821.11 user, 63.14 sys, 0 amem, 34981164 mmem Reviewed By: maksfb Differential Revision: https://reviews.llvm.org/D151909 --- bolt/include/bolt/Core/DIEBuilder.h | 116 ++++--- bolt/include/bolt/Core/DebugData.h | 33 +- bolt/include/bolt/Rewrite/DWARFRewriter.h | 14 +- bolt/lib/Core/DIEBuilder.cpp | 322 ++++++++++++------ bolt/lib/Core/DebugData.cpp | 296 ++++++++-------- bolt/lib/Rewrite/DWARFRewriter.cpp | 269 +++++++++------ ...rf4-cross-reference-different-abbrev-dst.s | 146 ++++++++ ...rf4-cross-reference-different-abbrev-src.s | 160 +++++++++ .../dwarf5-helper1-addr-section-reuse.s | 2 +- .../dwarf5-helper2-addr-section-reuse.s | 2 +- ...f4-cross-cu-backward-different-abbrev.test | 25 ++ ...rf4-cross-cu-forward-different-abbrev.test | 24 ++ bolt/test/X86/dwarf4-types-dwarf5-types.test | 98 +++--- ...5-gdb-index-types-gdb-generated-gdb11.test | 4 +- ...f5-gdb-index-types-gdb-generated-gdb9.test | 6 +- .../dwarf5-gdb-index-types-lld-generated.test | 2 +- bolt/test/X86/dwarf5-locexpr-referrence.test | 10 +- 17 files changed, 1075 insertions(+), 454 deletions(-) create mode 100644 bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-dst.s create mode 100644 bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-src.s create mode 100644 bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test create mode 100644 bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h index 8d08848d42f7a..e2da87662715c 100644 --- a/bolt/include/bolt/Core/DIEBuilder.h +++ b/bolt/include/bolt/Core/DIEBuilder.h @@ -60,6 +60,8 @@ class DIEBuilder { std::unordered_map DIEIDMap; }; + enum class ProcessingType { DWARF4TUs, DWARF5TUs, CUs }; + private: /// Contains information so that we we can update references in locexpr after /// we calculated all the final DIE offsets. @@ -83,41 +85,54 @@ class DIEBuilder { DWARFAbbreviationDeclaration::AttributeSpec AttrSpec; }; - /// A map of Units to Unit Index. - std::unordered_map UnitIDMap; - /// A map of Type Units to Type DIEs. - std::unordered_map TypeDIEMap; - std::vector DUList; - std::vector CloneUnitCtxMap; - std::vector> AddrReferences; + struct State { + /// A map of Units to Unit Index. + std::unordered_map UnitIDMap; + /// A map of Type Units to Type DIEs. + std::unordered_map TypeDIEMap; + std::list DUList; + std::vector CloneUnitCtxMap; + std::vector> AddrReferences; + std::vector DWARF4TUVector; + std::vector DWARF5TUVector; + std::vector DWARFCUVector; + std::vector LocWithReferencesToProcess; + BumpPtrAllocator DIEAlloc; + ProcessingType Type; + }; + + std::unique_ptr BuilderState; FoldingSet AbbreviationsSet; std::vector> Abbreviations; - std::vector DWARF4TUVector; - std::vector LocWithReferencesToProcess; - BumpPtrAllocator DIEAlloc; + DWARFContext *DwarfContext{nullptr}; + bool IsDWO{false}; + uint64_t UnitSize{0}; + llvm::DenseSet AllProcessed; + /// Returns current state of the DIEBuilder + State &getState() { return *BuilderState.get(); } /// Resolve the reference in DIE, if target is not loaded into IR, /// pre-allocate it. \p RefCU will be updated to the Unit specific by \p /// RefValue. - DWARFDie resolveDIEReference(const DWARFFormValue &RefValue, - DWARFUnit *&RefCU, - DWARFDebugInfoEntry &DwarfDebugInfoEntry, - const std::vector &DUOffsetList); + DWARFDie resolveDIEReference( + const DWARFFormValue &RefValue, + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + DWARFUnit *&RefCU, DWARFDebugInfoEntry &DwarfDebugInfoEntry); /// Resolve the reference in DIE, if target is not loaded into IR, /// pre-allocate it. \p RefCU will be updated to the Unit specific by \p /// RefValue. - DWARFDie resolveDIEReference(const uint64_t ReffOffset, DWARFUnit *&RefCU, - DWARFDebugInfoEntry &DwarfDebugInfoEntry, - const std::vector &DUOffsetList); + DWARFDie resolveDIEReference( + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const uint64_t ReffOffset, DWARFUnit *&RefCU, + DWARFDebugInfoEntry &DwarfDebugInfoEntry); /// Clone one attribute according to the format. \return the size of this /// attribute. void cloneAttribute(DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, const DWARFFormValue &Val, - const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, - const std::vector &DUOffsetList); + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec); /// Clone an attribute in string format. void cloneStringAttribute( @@ -129,7 +144,7 @@ class DIEBuilder { void cloneDieReferenceAttribute( DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE, const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, - const DWARFFormValue &Val, const std::vector &DUOffsetList); + const DWARFFormValue &Val); /// Clone an attribute in block format. void cloneBlockAttribute( @@ -175,23 +190,23 @@ class DIEBuilder { /// Update the Offset and Size of DIE. uint32_t computeDIEOffset(const DWARFUnit &CU, DIE &Die, uint32_t &CurOffset); - void registerUnit(DWARFUnit &DU); + void registerUnit(DWARFUnit &DU, bool NeedSort); /// \return the unique ID of \p U if it exists. std::optional getUnitId(const DWARFUnit &DU); DWARFUnitInfo &getUnitInfo(uint32_t UnitId) { - return CloneUnitCtxMap[UnitId]; + return getState().CloneUnitCtxMap[UnitId]; } DIEInfo &getDIEInfo(uint32_t UnitId, uint32_t DIEId) { - if (CloneUnitCtxMap[UnitId].DieInfoVector.size() > DIEId) - return *CloneUnitCtxMap[UnitId].DieInfoVector[DIEId].get(); + if (getState().CloneUnitCtxMap[UnitId].DieInfoVector.size() > DIEId) + return *getState().CloneUnitCtxMap[UnitId].DieInfoVector[DIEId].get(); errs() << "BOLT-WARNING: [internal-dwarf-error]: The DIE is not allocated " "before looking up, some" << "unexpected corner cases happened.\n"; - return *CloneUnitCtxMap[UnitId].DieInfoVector.front().get(); + return *getState().CloneUnitCtxMap[UnitId].DieInfoVector.front().get(); } std::optional getAllocDIEId(const DWARFUnit &DU, @@ -223,16 +238,28 @@ class DIEBuilder { /// Construct IR for \p DU. \p DUOffsetList specific the Unit in current /// Section. - void constructFromUnit(DWARFUnit &DU, std::vector &DUOffsetList); + void constructFromUnit(DWARFUnit &DU); /// Construct a DIE for \p DDie in \p U. \p DUOffsetList specific the Unit in /// current Section. - DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId, - std::vector &DUOffsetList); + DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId); public: DIEBuilder(DWARFContext *DwarfContext, bool IsDWO = false); + /// Returns enum to what we are currently processing. + ProcessingType getCurrentProcessingState() { return getState().Type; } + + /// Constructs IR for Type Units. + void buildTypeUnits(const bool Init = true); + /// Constructs IR for all the CUs. + void buildCompileUnits(const bool Init = true); + /// Constructs IR for CUs in a vector. + void buildCompileUnits(const std::vector &CUs); + /// Preventing implicit conversions. + template void buildCompileUnits(T) = delete; + void buildBoth(); + /// Returns DWARFUnitInfo for DWARFUnit DWARFUnitInfo &getUnitInfoByDwarfUnit(const DWARFUnit &DwarfUnit) { std::optional UnitId = getUnitId(DwarfUnit); @@ -247,16 +274,26 @@ class DIEBuilder { return Abbreviations; } DIE *getTypeDIE(DWARFUnit &DU) { - if (TypeDIEMap.count(&DU)) - return TypeDIEMap[&DU]; + if (getState().TypeDIEMap.count(&DU)) + return getState().TypeDIEMap[&DU]; errs() << "BOLT-ERROR: unable to find TypeUnit for Type Unit at offset 0x" << DU.getOffset() << "\n"; return nullptr; } - std::vector getDWARF4TUVector() { return DWARF4TUVector; } - bool isEmpty() { return CloneUnitCtxMap.empty(); } + std::vector &getDWARF4TUVector() { + return getState().DWARF4TUVector; + } + std::vector &getDWARF5TUVector() { + return getState().DWARF5TUVector; + } + std::vector &getDWARFCUVector() { + return getState().DWARFCUVector; + } + /// Returns list of CUs for which IR was build. + std::list &getProcessedCUs() { return getState().DUList; } + bool isEmpty() { return getState().CloneUnitCtxMap.empty(); } DIE *getUnitDIEbyUnit(const DWARFUnit &DU) { const DWARFUnitInfo &U = getUnitInfoByDwarfUnit(DU); @@ -272,23 +309,26 @@ class DIEBuilder { void finish(); // Interface to edit DIE - template T *allocateDIEValue() { return new (DIEAlloc) T; } + template T *allocateDIEValue() { + return new (getState().DIEAlloc) T; + } DIEValueList::value_iterator addValue(DIEValueList *Die, const DIEValue &V) { - return Die->addValue(DIEAlloc, V); + return Die->addValue(getState().DIEAlloc, V); } template DIEValueList::value_iterator addValue(DIEValueList *Die, dwarf::Attribute Attribute, dwarf::Form Form, T &&Value) { - return Die->addValue(DIEAlloc, Attribute, Form, std::forward(Value)); + return Die->addValue(getState().DIEAlloc, Attribute, Form, + std::forward(Value)); } template bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, dwarf::Form Form, T &&NewValue) { - return Die->replaceValue(DIEAlloc, Attribute, Form, + return Die->replaceValue(getState().DIEAlloc, Attribute, Form, std::forward(NewValue)); } @@ -296,13 +336,13 @@ class DIEBuilder { bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, dwarf::Attribute NewAttribute, dwarf::Form Form, T &&NewValue) { - return Die->replaceValue(DIEAlloc, Attribute, NewAttribute, Form, + return Die->replaceValue(getState().DIEAlloc, Attribute, NewAttribute, Form, std::forward(NewValue)); } bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, dwarf::Form Form, DIEValue &NewValue) { - return Die->replaceValue(DIEAlloc, Attribute, Form, NewValue); + return Die->replaceValue(getState().DIEAlloc, Attribute, Form, NewValue); } template diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h index 10b80c5e19f88..d4611e8f6ca4a 100644 --- a/bolt/include/bolt/Core/DebugData.h +++ b/bolt/include/bolt/Core/DebugData.h @@ -22,6 +22,7 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include #include #include #include @@ -315,17 +316,12 @@ class DebugAddrWriter { /// Adds {\p Address, \p Index} to \p CU. void addIndexAddress(uint64_t Address, uint32_t Index, DWARFUnit &CU); - /// Creates consolidated .debug_addr section, and builds DWOID to offset map. - virtual AddressSectionBuffer finalize(); + /// Write out entries in to .debug_addr section for CUs. + virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs); - /// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr - /// section. - virtual uint64_t getOffset(DWARFUnit &Unit); - - /// Returns True if CU exists in the DebugAddrWriter. - bool doesCUExist(DWARFUnit &Unit) { - return DWOIdToOffsetMap.count(getCUID(Unit)) > 0; - } + /// Return buffer with all the entries in .debug_addr already writen out using + /// update(...). + virtual AddressSectionBuffer &finalize() { return *Buffer; } /// Returns False if .debug_addr section was created.. bool isInitialized() const { return !AddressMaps.empty(); } @@ -387,10 +383,12 @@ class DebugAddrWriter { BinaryContext *BC; /// Maps DWOID to AddressForDWOCU. std::unordered_map AddressMaps; - /// Maps DWOID to offset within .debug_addr section. - std::unordered_map DWOIdToOffsetMap; /// Mutex used for parallel processing of debug info. std::mutex WriterMutex; + std::unique_ptr Buffer; + std::unique_ptr AddressStream; + /// Used to track sections that were not modified so that they can be re-used. + DenseMap UnmodifiedAddressOffsets; }; class DebugAddrWriterDwarf5 : public DebugAddrWriter { @@ -398,11 +396,8 @@ class DebugAddrWriterDwarf5 : public DebugAddrWriter { DebugAddrWriterDwarf5() = delete; DebugAddrWriterDwarf5(BinaryContext *BC) : DebugAddrWriter(BC) {} - /// Creates consolidated .debug_addr section, and builds DWOID to offset map. - AddressSectionBuffer finalize() override; - /// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr - /// section. - uint64_t getOffset(DWARFUnit &Unit) override; + /// Write out entries in to .debug_addr section for CUs. + virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs) override; protected: /// Given DWARFUnit \p Unit returns either DWO ID or it's offset within @@ -433,7 +428,7 @@ class DebugStrOffsetsWriter { void updateAddressMap(uint32_t Index, uint32_t Address); /// Writes out current sections entry into .debug_str_offsets. - void finalizeSection(DWARFUnit &Unit); + void finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr); /// Returns False if no strings were added to .debug_str. bool isFinalized() const { return !StrOffsetsBuffer->empty(); } @@ -447,7 +442,7 @@ class DebugStrOffsetsWriter { std::unique_ptr StrOffsetsBuffer; std::unique_ptr StrOffsetsStream; std::map IndexToAddressMap; - DenseSet ProcessedBaseOffsets; + std::unordered_map ProcessedBaseOffsets; // Section size not including header. uint32_t CurrentSectionSize{0}; bool StrOffsetSectionWasModified = false; diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h index 3962faed593bd..2de9c71398227 100644 --- a/bolt/include/bolt/Rewrite/DWARFRewriter.h +++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h @@ -105,6 +105,9 @@ class DWARFRewriter { /// DWARFLegacy is all DWARF versions before DWARF 5. enum class DWARFVersion { DWARFLegacy, DWARF5 }; + /// Used to track last CU offset for GDB Index. + uint32_t CUOffset{0}; + /// Update debug info for all DIEs in \p Unit. void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr, DebugLocWriter &DebugLocWriter, @@ -128,8 +131,17 @@ class DWARFRewriter { std::unique_ptr makeFinalLocListsSection(DWARFVersion Version); + /// Finalize type sections in the main binary. + CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer); + + /// Process and write out CUs that are passsed in. + void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEStreamer &Streamer, + CUOffsetMap &CUMap, + const std::list &CUs); + /// Finalize debug sections in the main binary. - CUOffsetMap finalizeDebugSections(DIEBuilder &DIEBlder); + void finalizeDebugSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer, + raw_svector_ostream &ObjOS, CUOffsetMap &CUMap); /// Patches the binary for DWARF address ranges (e.g. in functions and lexical /// blocks) to be updated. diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index f6a47f85c9bb8..582cf6cf96a86 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -31,9 +31,11 @@ #include #include #include +#include #include #include #include +#include #undef DEBUG_TYPE #define DEBUG_TYPE "bolt" @@ -41,7 +43,7 @@ namespace llvm { namespace bolt { void DIEBuilder::updateReferences() { - for (auto &[SrcDIEInfo, ReferenceInfo] : AddrReferences) { + for (auto &[SrcDIEInfo, ReferenceInfo] : getState().AddrReferences) { DIEInfo *DstDIEInfo = ReferenceInfo.Dst; DWARFUnitInfo &DstUnitInfo = getUnitInfo(DstDIEInfo->UnitId); dwarf::Attribute Attr = ReferenceInfo.AttrSpec.Attr; @@ -49,11 +51,12 @@ void DIEBuilder::updateReferences() { const uint64_t NewAddr = DstDIEInfo->Die->getOffset() + DstUnitInfo.UnitOffset; - SrcDIEInfo->Die->replaceValue(DIEAlloc, Attr, Form, DIEInteger(NewAddr)); + SrcDIEInfo->Die->replaceValue(getState().DIEAlloc, Attr, Form, + DIEInteger(NewAddr)); } // Handling referenes in location expressions. - for (LocWithReference &LocExpr : LocWithReferencesToProcess) { + for (LocWithReference &LocExpr : getState().LocWithReferencesToProcess) { SmallVector Buffer; DataExtractor Data(StringRef((const char *)LocExpr.BlockData.data(), LocExpr.BlockData.size()), @@ -65,16 +68,16 @@ void DIEBuilder::updateReferences() { DIEValueList *AttrVal; if (LocExpr.Form == dwarf::DW_FORM_exprloc) { - DIELoc *DL = new (DIEAlloc) DIELoc; + DIELoc *DL = new (getState().DIEAlloc) DIELoc; DL->setSize(Buffer.size()); AttrVal = static_cast(DL); } else { - DIEBlock *DBL = new (DIEAlloc) DIEBlock; + DIEBlock *DBL = new (getState().DIEAlloc) DIEBlock; DBL->setSize(Buffer.size()); AttrVal = static_cast(DBL); } for (auto Byte : Buffer) - AttrVal->addValue(DIEAlloc, static_cast(0), + AttrVal->addValue(getState().DIEAlloc, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(Byte)); DIEValue Value; @@ -87,7 +90,8 @@ void DIEBuilder::updateReferences() { DIEValue(dwarf::Attribute(LocExpr.Attr), dwarf::Form(LocExpr.Form), static_cast(AttrVal)); - LocExpr.Die.replaceValue(DIEAlloc, LocExpr.Attr, LocExpr.Form, Value); + LocExpr.Die.replaceValue(getState().DIEAlloc, LocExpr.Attr, LocExpr.Form, + Value); } return; @@ -108,8 +112,7 @@ uint32_t DIEBuilder::allocDIE(const DWARFUnit &DU, const DWARFDie &DDie, return DId; } -void DIEBuilder::constructFromUnit(DWARFUnit &DU, - std::vector &DUOffsetList) { +void DIEBuilder::constructFromUnit(DWARFUnit &DU) { std::optional UnitId = getUnitId(DU); if (!UnitId) { errs() << "BOLT-WARNING: [internal-dwarf-error]: " @@ -141,14 +144,14 @@ void DIEBuilder::constructFromUnit(DWARFUnit &DU, DIEEntry.getAbbreviationDeclarationPtr()) { DWARFDie DDie(&DU, &DIEEntry); - DIE *CurDIE = constructDIEFast(DDie, DU, *UnitId, DUOffsetList); + DIE *CurDIE = constructDIEFast(DDie, DU, *UnitId); DWARFUnitInfo &UI = getUnitInfo(*UnitId); // Can't rely on first element in DieVector due to cross CU forward // references. if (!UI.UnitDie) UI.UnitDie = CurDIE; if (IsTypeDIE) - TypeDIEMap[&DU] = CurDIE; + getState().TypeDIEMap[&DU] = CurDIE; if (!CurParentDIEStack.empty()) CurParentDIEStack.back()->addChild(CurDIE); @@ -161,36 +164,46 @@ void DIEBuilder::constructFromUnit(DWARFUnit &DU, } } while (CurParentDIEStack.size() > 0); - CloneUnitCtxMap[*UnitId].IsConstructed = true; + getState().CloneUnitCtxMap[*UnitId].IsConstructed = true; } -DIEBuilder::DIEBuilder(DWARFContext *DwarfContext, bool IsDWO) { - const DWARFUnitIndex &TUIndex = DwarfContext->getTUIndex(); - if (!TUIndex.getRows().empty()) { - for (auto &Row : TUIndex.getRows()) { - uint64_t Signature = Row.getSignature(); - // manually populate TypeUnit to UnitVector - DwarfContext->getTypeUnitForHash(DwarfContext->getMaxVersion(), Signature, - true); - } - } +DIEBuilder::DIEBuilder(DWARFContext *DwarfContext, bool IsDWO) + : DwarfContext(DwarfContext), IsDWO(IsDWO) {} +static unsigned int getCUNum(DWARFContext *DwarfContext, bool IsDWO) { unsigned int CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits() : DwarfContext->getNumCompileUnits(); CUNum += IsDWO ? DwarfContext->getNumDWOTypeUnits() : DwarfContext->getNumTypeUnits(); + return CUNum; +} - CloneUnitCtxMap.resize(CUNum); +void DIEBuilder::buildTypeUnits(const bool Init) { + if (Init) + BuilderState.reset(new State()); + + unsigned int CUNum = getCUNum(DwarfContext, IsDWO); + getState().CloneUnitCtxMap.resize(CUNum); DWARFContext::unit_iterator_range CU4TURanges = IsDWO ? DwarfContext->dwo_types_section_units() : DwarfContext->types_section_units(); - for (std::unique_ptr &DU : CU4TURanges) { - registerUnit(*DU.get()); - DWARF4TUVector.push_back(DU.get()); + const DWARFUnitIndex &TUIndex = DwarfContext->getTUIndex(); + if (!TUIndex.getRows().empty()) { + for (auto &Row : TUIndex.getRows()) { + uint64_t Signature = Row.getSignature(); + // manually populate TypeUnit to UnitVector + DwarfContext->getTypeUnitForHash(DwarfContext->getMaxVersion(), Signature, + true); + } } + + getState().Type = ProcessingType::DWARF4TUs; for (std::unique_ptr &DU : CU4TURanges) - constructFromUnit(*DU.get(), DWARF4TUVector); + registerUnit(*DU.get(), false); + + for (std::unique_ptr &DU : CU4TURanges) + constructFromUnit(*DU.get()); DWARFContext::unit_iterator_range CURanges = IsDWO ? DwarfContext->dwo_info_section_units() @@ -199,18 +212,70 @@ DIEBuilder::DIEBuilder(DWARFContext *DwarfContext, bool IsDWO) { // This handles DWARF4 CUs and DWARF5 CU/TUs. // Creating a vector so that for reference handling only DWARF5 CU/TUs are // used, and not DWARF4 TUs. - std::vector DWARF5CUTUVector; + getState().Type = ProcessingType::DWARF5TUs; for (std::unique_ptr &DU : CURanges) { - registerUnit(*DU.get()); - DWARF5CUTUVector.push_back(DU.get()); + if (!DU->isTypeUnit()) + continue; + registerUnit(*DU.get(), false); } - for (std::unique_ptr &DU : CURanges) - constructFromUnit(*DU.get(), DWARF5CUTUVector); + for (DWARFUnit *DU : getState().DWARF5TUVector) + constructFromUnit(*DU); } -DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId, - std::vector &DUOffsetList) { +void DIEBuilder::buildCompileUnits(const bool Init) { + if (Init) + BuilderState.reset(new State()); + + unsigned int CUNum = getCUNum(DwarfContext, IsDWO); + getState().CloneUnitCtxMap.resize(CUNum); + DWARFContext::unit_iterator_range CURanges = + IsDWO ? DwarfContext->dwo_info_section_units() + : DwarfContext->info_section_units(); + + // This handles DWARF4 CUs and DWARF5 CU/TUs. + // Creating a vector so that for reference handling only DWARF5 CU/TUs are + // used, and not DWARF4 TUs.getState().DUList + getState().Type = ProcessingType::CUs; + for (std::unique_ptr &DU : CURanges) { + if (DU->isTypeUnit()) + continue; + registerUnit(*DU.get(), false); + } + + // Using DULIst since it can be modified by cross CU refrence resolution. + for (DWARFUnit *DU : getState().DUList) { + if (DU->isTypeUnit()) + continue; + constructFromUnit(*DU); + } +} +void DIEBuilder::buildCompileUnits(const std::vector &CUs) { + BuilderState.reset(new State()); + // Initializing to full size because there could be cross CU references with + // different abbrev offsets. LLVM happens to output CUs that have cross CU + // references with the same abbrev table. So destinations end up in the first + // set, even if they themselves don't have src cross cu ref. We could have + // cases where this is not the case. In which case this container needs to be + // big enough for all. + getState().CloneUnitCtxMap.resize(DwarfContext->getNumCompileUnits()); + getState().Type = ProcessingType::CUs; + for (DWARFUnit *CU : CUs) + registerUnit(*CU, false); + + for (DWARFUnit *DU : getState().DUList) + constructFromUnit(*DU); +} + +void DIEBuilder::buildBoth() { + BuilderState.release(); + BuilderState = std::make_unique(); + buildTypeUnits(false); + buildCompileUnits(false); +} + +DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U, + uint32_t UnitId) { std::optional Idx = getAllocDIEId(U, DDie); if (Idx) { @@ -219,7 +284,7 @@ DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId, if (DWARFUnitInfo.IsConstructed && DieInfo.Die) return DieInfo.Die; } else { - Idx = allocDIE(U, DDie, DIEAlloc, UnitId); + Idx = allocDIE(U, DDie, getState().DIEAlloc, UnitId); } DIEInfo &DieInfo = getDIEInfo(UnitId, *Idx); @@ -245,18 +310,57 @@ DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId, for (const AttrSpec &AttrSpec : Abbrev->attributes()) { DWARFFormValue Val(AttrSpec.Form); Val.extractValue(Data, &AttrOffset, U.getFormParams(), &U); - cloneAttribute(*DieInfo.Die, DDie, U, Val, AttrSpec, DUOffsetList); + cloneAttribute(*DieInfo.Die, DDie, U, Val, AttrSpec); } return DieInfo.Die; } -static DWARFUnit *getUnitForOffset(const std::vector &Units, - const uint64_t Offset) { - auto CU = - llvm::upper_bound(Units, Offset, [](uint64_t LHS, const DWARFUnit *RHS) { - return LHS < RHS->getNextUnitOffset(); - }); - return CU != Units.end() ? *CU : nullptr; +static DWARFUnit * +getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx, + const uint64_t Offset, + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) { + auto findUnit = [&](std::vector &Units) -> DWARFUnit * { + auto CUIter = llvm::upper_bound(Units, Offset, + [](uint64_t LHS, const DWARFUnit *RHS) { + return LHS < RHS->getNextUnitOffset(); + }); + static std::vector CUOffsets; + static std::once_flag InitVectorFlag; + auto initCUVector = [&]() { + CUOffsets.reserve(DWCtx.getNumCompileUnits()); + for (const std::unique_ptr &CU : DWCtx.compile_units()) + CUOffsets.emplace_back(CU.get()); + }; + DWARFUnit *CU = CUIter != Units.end() ? *CUIter : nullptr; + // Above algorithm breaks when there is only one CU, and reference is + // outside of it. Fall through slower path, that searches all the CUs. + // For example when src and destination of cross CU references have + // different abbrev section. + if (!CU || + (CU && AttrSpec.Form == dwarf::DW_FORM_ref_addr && + !(CU->getOffset() < Offset && CU->getNextUnitOffset() > Offset))) { + // This is a work around for XCode clang. There is a build error when we + // pass DWCtx.compile_units() to llvm::upper_bound + std::call_once(InitVectorFlag, initCUVector); + auto CUIter = std::upper_bound(CUOffsets.begin(), CUOffsets.end(), Offset, + [](uint64_t LHS, const DWARFUnit *RHS) { + return LHS < RHS->getNextUnitOffset(); + }); + CU = CUIter != CUOffsets.end() ? (*CUIter) : nullptr; + } + return CU; + }; + + switch (Builder.getCurrentProcessingState()) { + case DIEBuilder::ProcessingType::DWARF4TUs: + return findUnit(Builder.getDWARF4TUVector()); + case DIEBuilder::ProcessingType::DWARF5TUs: + return findUnit(Builder.getDWARF5TUVector()); + case DIEBuilder::ProcessingType::CUs: + return findUnit(Builder.getDWARFCUVector()); + }; + + return nullptr; } uint32_t DIEBuilder::computeDIEOffset(const DWARFUnit &CU, DIE &Die, @@ -284,8 +388,8 @@ uint32_t DIEBuilder::computeDIEOffset(const DWARFUnit &CU, DIE &Die, } void DIEBuilder::finish() { - uint64_t UnitStartOffset = 0; - auto computeOffset = [&](const DWARFUnit &CU) -> void { + auto computeOffset = [&](const DWARFUnit &CU, + uint64_t &UnitStartOffset) -> void { DIE *UnitDIE = getUnitDIEbyUnit(CU); uint32_t HeaderSize = CU.getHeaderSize(); uint32_t CurOffset = HeaderSize; @@ -296,41 +400,44 @@ void DIEBuilder::finish() { CurUnitInfo.UnitLength = HeaderSize + UnitDIE->getSize(); UnitStartOffset += CurUnitInfo.UnitLength; }; - unsigned Index = 0; - unsigned Size = DUList.size(); // Computing offsets for .debug_types section. // It's processed first when CU is registered so will be at the begginnig of // the vector. - for (; Index < Size; ++Index) { - const DWARFUnit &CU = *DUList[Index]; - if (!(CU.getVersion() < 5 && CU.isTypeUnit())) + uint64_t TypeUnitStartOffset = 0; + for (const DWARFUnit *CU : getState().DUList) { + // We process DWARF$ types first. + if (!(CU->getVersion() < 5 && CU->isTypeUnit())) break; - computeOffset(CU); + computeOffset(*CU, TypeUnitStartOffset); } - UnitStartOffset = 0; - for (; Index < Size; ++Index) - computeOffset(*DUList[Index]); + for (const DWARFUnit *CU : getState().DUList) { + // Skipping DWARF4 types. + if (CU->getVersion() < 5 && CU->isTypeUnit()) + continue; + computeOffset(*CU, UnitSize); + } updateReferences(); } -DWARFDie -DIEBuilder::resolveDIEReference(const DWARFFormValue &RefValue, - DWARFUnit *&RefCU, - DWARFDebugInfoEntry &DwarfDebugInfoEntry, - const std::vector &DUOffsetList) { +DWARFDie DIEBuilder::resolveDIEReference( + const DWARFFormValue &RefValue, + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + DWARFUnit *&RefCU, DWARFDebugInfoEntry &DwarfDebugInfoEntry) { assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); uint64_t RefOffset = *RefValue.getAsReference(); - return resolveDIEReference(RefOffset, RefCU, DwarfDebugInfoEntry, - DUOffsetList); + return resolveDIEReference(AttrSpec, RefOffset, RefCU, DwarfDebugInfoEntry); } -DWARFDie -DIEBuilder::resolveDIEReference(const uint64_t RefOffset, DWARFUnit *&RefCU, - DWARFDebugInfoEntry &DwarfDebugInfoEntry, - const std::vector &DUOffsetList) { +DWARFDie DIEBuilder::resolveDIEReference( + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const uint64_t RefOffset, DWARFUnit *&RefCU, + DWARFDebugInfoEntry &DwarfDebugInfoEntry) { uint64_t TmpRefOffset = RefOffset; - if ((RefCU = getUnitForOffset(DUOffsetList, TmpRefOffset))) { + if ((RefCU = + getUnitForOffset(*this, *DwarfContext, TmpRefOffset, AttrSpec))) { + /// Trying to add to current working set in case it's cross CU reference. + registerUnit(*RefCU, true); DWARFDataExtractor DebugInfoData = RefCU->getDebugInfoExtractor(); if (DwarfDebugInfoEntry.extractFast(*RefCU, &TmpRefOffset, DebugInfoData, RefCU->getNextUnitOffset(), 0)) { @@ -341,9 +448,9 @@ DIEBuilder::resolveDIEReference(const uint64_t RefOffset, DWARFUnit *&RefCU, std::optional UnitId = getUnitId(*RefCU); // forward reference - if (UnitId && !CloneUnitCtxMap[*UnitId].IsConstructed && + if (UnitId && !getState().CloneUnitCtxMap[*UnitId].IsConstructed && !getAllocDIEId(*RefCU, RefDie)) - allocDIE(*RefCU, RefDie, DIEAlloc, *UnitId); + allocDIE(*RefCU, RefDie, getState().DIEAlloc, *UnitId); return RefDie; } } @@ -357,15 +464,14 @@ DIEBuilder::resolveDIEReference(const uint64_t RefOffset, DWARFUnit *&RefCU, void DIEBuilder::cloneDieReferenceAttribute( DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE, const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, - const DWARFFormValue &Val, const std::vector &DUOffsetList) { + const DWARFFormValue &Val) { const uint64_t Ref = *Val.getAsReference(); DIE *NewRefDie = nullptr; DWARFUnit *RefUnit = nullptr; DWARFDebugInfoEntry DDIEntry; - const DWARFDie RefDie = - resolveDIEReference(Val, RefUnit, DDIEntry, DUOffsetList); + const DWARFDie RefDie = resolveDIEReference(Val, AttrSpec, RefUnit, DDIEntry); if (!RefDie) return; @@ -382,7 +488,7 @@ void DIEBuilder::cloneDieReferenceAttribute( "unallocated DIE. Should be alloc!\n"; // We haven't cloned this DIE yet. Just create an empty one and // store it. It'll get really cloned when we process it. - DieInfo.Die = DIE::get(DIEAlloc, dwarf::Tag(RefDie.getTag())); + DieInfo.Die = DIE::get(getState().DIEAlloc, dwarf::Tag(RefDie.getTag())); } NewRefDie = DieInfo.Die; @@ -392,15 +498,16 @@ void DIEBuilder::cloneDieReferenceAttribute( // the DIE. DWARFDie CurDie = const_cast(InputDIE); DIEInfo *CurDieInfo = &getDIEInfoByDwarfDie(CurDie); - AddrReferences.push_back( + getState().AddrReferences.push_back( std::make_pair(CurDieInfo, AddrReferenceInfo(&DieInfo, AttrSpec))); - Die.addValue(DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_addr, + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_addr, DIEInteger(0xDEADBEEF)); return; } - Die.addValue(DIEAlloc, AttrSpec.Attr, AttrSpec.Form, DIEEntry(*NewRefDie)); + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form, + DIEEntry(*NewRefDie)); } void DIEBuilder::cloneStringAttribute( @@ -413,11 +520,12 @@ void DIEBuilder::cloneStringAttribute( consumeError(StrAddr.takeError()); return; } - Die.addValue(DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_string, - new (DIEAlloc) DIEInlineString(StrAddr.get(), DIEAlloc)); + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_string, + new (getState().DIEAlloc) + DIEInlineString(StrAddr.get(), getState().DIEAlloc)); } else { std::optional OffsetIndex = Val.getRawUValue(); - Die.addValue(DIEAlloc, AttrSpec.Attr, AttrSpec.Form, + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form, DIEInteger(*OffsetIndex)); } } @@ -507,10 +615,10 @@ void DIEBuilder::cloneBlockAttribute( DIEBlock *Block = nullptr; if (AttrSpec.Form == dwarf::DW_FORM_exprloc) { - Loc = new (DIEAlloc) DIELoc; + Loc = new (getState().DIEAlloc) DIELoc; } else if (doesFormBelongToClass(AttrSpec.Form, DWARFFormValue::FC_Block, U.getVersion())) { - Block = new (DIEAlloc) DIEBlock; + Block = new (getState().DIEAlloc) DIEBlock; } else { errs() << "BOLT-WARNING: [internal-dwarf-error]: Unexpected Form value in " "cloneBlockAttribute\n"; @@ -529,12 +637,12 @@ void DIEBuilder::cloneBlockAttribute( DWARFExpression Expr(Data, U.getAddressByteSize(), U.getFormParams().Format); if (cloneExpression(Data, Expr, U, Buffer, CloneExpressionStage::INIT)) - LocWithReferencesToProcess.emplace_back(Bytes.vec(), U, Die, - AttrSpec.Form, AttrSpec.Attr); + getState().LocWithReferencesToProcess.emplace_back( + Bytes.vec(), U, Die, AttrSpec.Form, AttrSpec.Attr); Bytes = Buffer; } for (auto Byte : Bytes) - Attr->addValue(DIEAlloc, static_cast(0), + Attr->addValue(getState().DIEAlloc, static_cast(0), dwarf::DW_FORM_data1, DIEInteger(Byte)); if (Loc) @@ -548,14 +656,14 @@ void DIEBuilder::cloneBlockAttribute( else Value = DIEValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), Block); - Die.addValue(DIEAlloc, Value); + Die.addValue(getState().DIEAlloc, Value); } void DIEBuilder::cloneAddressAttribute( DIE &Die, const DWARFUnit &U, const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, const DWARFFormValue &Val) { - Die.addValue(DIEAlloc, AttrSpec.Attr, AttrSpec.Form, + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form, DIEInteger(Val.getRawUValue())); } @@ -563,7 +671,7 @@ void DIEBuilder::cloneRefsigAttribute( DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, const DWARFFormValue &Val) { const std::optional SigVal = Val.getRawUValue(); - Die.addValue(DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_sig8, + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_sig8, DIEInteger(*SigVal)); } @@ -586,7 +694,8 @@ void DIEBuilder::cloneScalarAttribute( return; } - Die.addValue(DIEAlloc, AttrSpec.Attr, AttrSpec.Form, DIEInteger(Value)); + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form, + DIEInteger(Value)); } void DIEBuilder::cloneLoclistAttrubute( @@ -609,13 +718,13 @@ void DIEBuilder::cloneLoclistAttrubute( if (!Value.has_value()) return; - Die.addValue(DIEAlloc, AttrSpec.Attr, AttrSpec.Form, DIELocList(*Value)); + Die.addValue(getState().DIEAlloc, AttrSpec.Attr, AttrSpec.Form, + DIELocList(*Value)); } void DIEBuilder::cloneAttribute( DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, const DWARFFormValue &Val, - const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, - const std::vector &DUOffsetList) { + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) { switch (AttrSpec.Form) { case dwarf::DW_FORM_strp: case dwarf::DW_FORM_string: @@ -633,7 +742,7 @@ void DIEBuilder::cloneAttribute( case dwarf::DW_FORM_ref2: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_ref8: - cloneDieReferenceAttribute(Die, U, InputDIE, AttrSpec, Val, DUOffsetList); + cloneDieReferenceAttribute(Die, U, InputDIE, AttrSpec, Val); break; case dwarf::DW_FORM_block: case dwarf::DW_FORM_block1: @@ -701,7 +810,7 @@ void DIEBuilder::generateAbbrevs() { if (isEmpty()) return; - for (DWARFUnit *DU : DUList) { + for (DWARFUnit *DU : getState().DUList) { DIE *UnitDIE = getUnitDIEbyUnit(*DU); generateUnitAbbrevs(UnitDIE); } @@ -734,14 +843,33 @@ static uint64_t getHash(const DWARFUnit &DU) { return DU.getOffset(); } -void DIEBuilder::registerUnit(DWARFUnit &DU) { - UnitIDMap[getHash(DU)] = DUList.size(); - DUList.push_back(&DU); +void DIEBuilder::registerUnit(DWARFUnit &DU, bool NeedSort) { + auto IterGlobal = AllProcessed.insert(getHash(DU)); + // If DU is already in a current working set or was already processed we can + // skip it. + if (!IterGlobal.second) + return; + if (getState().Type == ProcessingType::DWARF4TUs) { + getState().DWARF4TUVector.push_back(&DU); + } else if (getState().Type == ProcessingType::DWARF5TUs) { + getState().DWARF5TUVector.push_back(&DU); + } else { + getState().DWARFCUVector.push_back(&DU); + /// Sorting for cross CU reference resolution. + if (NeedSort) + std::sort(getState().DWARFCUVector.begin(), + getState().DWARFCUVector.end(), + [](const DWARFUnit *A, const DWARFUnit *B) { + return A->getOffset() < B->getOffset(); + }); + } + getState().UnitIDMap[getHash(DU)] = getState().DUList.size(); + getState().DUList.push_back(&DU); } std::optional DIEBuilder::getUnitId(const DWARFUnit &DU) { - auto Iter = UnitIDMap.find(getHash(DU)); - if (Iter != UnitIDMap.end()) + auto Iter = getState().UnitIDMap.find(getHash(DU)); + if (Iter != getState().UnitIDMap.end()) return Iter->second; return std::nullopt; } diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp index ba67b162fae3f..5a9b4d1161e92 100644 --- a/bolt/lib/Core/DebugData.cpp +++ b/bolt/lib/Core/DebugData.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -385,7 +386,10 @@ void DebugARangesSectionWriter::writeARangesSection( } } -DebugAddrWriter::DebugAddrWriter(BinaryContext *Bc) { BC = Bc; } +DebugAddrWriter::DebugAddrWriter(BinaryContext *BC) : BC(BC) { + Buffer = std::make_unique(); + AddressStream = std::make_unique(*Buffer); +} void DebugAddrWriter::AddressForDWOCU::dump() { std::vector SortedMap(indexToAddressBegin(), @@ -429,61 +433,84 @@ void DebugAddrWriter::addIndexAddress(uint64_t Address, uint32_t Index, } } -AddressSectionBuffer DebugAddrWriter::finalize() { - // Need to layout all sections within .debug_addr - // Within each section sort Address by index. - AddressSectionBuffer Buffer; - raw_svector_ostream AddressStream(Buffer); - for (std::unique_ptr &CU : BC->DwCtx->compile_units()) { - // Handling the case wehre debug information is a mix of Debug fission and - // monolitic. - if (!CU->getDWOId()) - continue; - const uint64_t CUID = getCUID(*CU.get()); - auto AM = AddressMaps.find(CUID); - // Adding to map even if it did not contribute to .debug_addr. - // The Skeleton CU might still have DW_AT_GNU_addr_base. - DWOIdToOffsetMap[CUID] = Buffer.size(); - // If does not exist this CUs DWO section didn't contribute to .debug_addr. - if (AM == AddressMaps.end()) - continue; - std::vector SortedMap(AM->second.indexToAddressBegin(), - AM->second.indexToAdddessEnd()); - // Sorting address in increasing order of indices. - llvm::sort(SortedMap, llvm::less_first()); - - uint8_t AddrSize = CU->getAddressByteSize(); - uint32_t Counter = 0; - auto WriteAddress = [&](uint64_t Address) -> void { - ++Counter; - switch (AddrSize) { - default: - assert(false && "Address Size is invalid."); - break; - case 4: - support::endian::write(AddressStream, static_cast(Address), - support::little); - break; - case 8: - support::endian::write(AddressStream, Address, support::little); - break; - } - }; +static void updateAddressBase(DIEBuilder &DIEBlder, DebugAddrWriter &AddrWriter, + DWARFUnit &CU, const uint64_t Offset) { + DIE *Die = DIEBlder.getUnitDIEbyUnit(CU); + DIEValue GnuAddrBaseAttrInfo = Die->findAttribute(dwarf::DW_AT_GNU_addr_base); + DIEValue AddrBaseAttrInfo = Die->findAttribute(dwarf::DW_AT_addr_base); + dwarf::Form BaseAttrForm; + dwarf::Attribute BaseAttr; + // For cases where Skeleton CU does not have DW_AT_GNU_addr_base + if (!GnuAddrBaseAttrInfo && CU.getVersion() < 5) + return; - for (const IndexAddressPair &Val : SortedMap) { - while (Val.first > Counter) - WriteAddress(0); - WriteAddress(Val.second); - } + if (GnuAddrBaseAttrInfo) { + BaseAttrForm = GnuAddrBaseAttrInfo.getForm(); + BaseAttr = GnuAddrBaseAttrInfo.getAttribute(); + } + + if (AddrBaseAttrInfo) { + BaseAttrForm = AddrBaseAttrInfo.getForm(); + BaseAttr = AddrBaseAttrInfo.getAttribute(); } - return Buffer; + if (GnuAddrBaseAttrInfo || AddrBaseAttrInfo) { + DIEBlder.replaceValue(Die, BaseAttr, BaseAttrForm, DIEInteger(Offset)); + } else if (CU.getVersion() >= 5) { + // A case where we were not using .debug_addr section, but after update + // now using it. + DIEBlder.addValue(Die, dwarf::DW_AT_addr_base, dwarf::DW_FORM_sec_offset, + DIEInteger(Offset)); + } } -AddressSectionBuffer DebugAddrWriterDwarf5::finalize() { + +void DebugAddrWriter::update(DIEBuilder &DIEBlder, DWARFUnit &CU) { + // Handling the case wehre debug information is a mix of Debug fission and + // monolitic. + if (!CU.getDWOId()) + return; + const uint64_t CUID = getCUID(CU); + auto AM = AddressMaps.find(CUID); + // Adding to map even if it did not contribute to .debug_addr. + // The Skeleton CU might still have DW_AT_GNU_addr_base. + uint64_t Offset = Buffer->size(); + // If does not exist this CUs DWO section didn't contribute to .debug_addr. + if (AM == AddressMaps.end()) + return; + std::vector SortedMap(AM->second.indexToAddressBegin(), + AM->second.indexToAdddessEnd()); + // Sorting address in increasing order of indices. + llvm::sort(SortedMap, llvm::less_first()); + + uint8_t AddrSize = CU.getAddressByteSize(); + uint32_t Counter = 0; + auto WriteAddress = [&](uint64_t Address) -> void { + ++Counter; + switch (AddrSize) { + default: + assert(false && "Address Size is invalid."); + break; + case 4: + support::endian::write(*AddressStream, static_cast(Address), + support::little); + break; + case 8: + support::endian::write(*AddressStream, Address, support::little); + break; + } + }; + + for (const IndexAddressPair &Val : SortedMap) { + while (Val.first > Counter) + WriteAddress(0); + WriteAddress(Val.second); + } + updateAddressBase(DIEBlder, *this, CU, Offset); +} + +void DebugAddrWriterDwarf5::update(DIEBuilder &DIEBlder, DWARFUnit &CU) { // Need to layout all sections within .debug_addr // Within each section sort Address by index. - AddressSectionBuffer Buffer; - raw_svector_ostream AddressStream(Buffer); const endianness Endian = BC->DwCtx->isLittleEndian() ? support::little : support::big; const DWARFSection &AddrSec = BC->DwCtx->getDWARFObj().getAddrSection(); @@ -491,94 +518,72 @@ AddressSectionBuffer DebugAddrWriterDwarf5::finalize() { DWARFDebugAddrTable AddrTable; DIDumpOptions DumpOpts; constexpr uint32_t HeaderSize = 8; - DenseMap UnmodifiedAddressOffsets; - for (std::unique_ptr &CU : BC->DwCtx->compile_units()) { - const uint64_t CUID = getCUID(*CU.get()); - const uint8_t AddrSize = CU->getAddressByteSize(); - auto AMIter = AddressMaps.find(CUID); - // A case where CU has entry in .debug_addr, but we don't modify addresses - // for it. - if (AMIter == AddressMaps.end()) { - AMIter = AddressMaps.insert({CUID, AddressForDWOCU()}).first; - std::optional BaseOffset = CU->getAddrOffsetSectionBase(); - if (!BaseOffset) - continue; - // Address base offset is to the first entry. - // The size of header is 8 bytes. - uint64_t Offset = *BaseOffset - HeaderSize; - auto Iter = UnmodifiedAddressOffsets.find(Offset); - if (Iter != UnmodifiedAddressOffsets.end()) { - DWOIdToOffsetMap[CUID] = Iter->getSecond(); - continue; - } - UnmodifiedAddressOffsets[Offset] = Buffer.size() + HeaderSize; - if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddrSize, - DumpOpts.WarningHandler)) { - DumpOpts.RecoverableErrorHandler(std::move(Err)); - continue; - } - - uint32_t Index = 0; - for (uint64_t Addr : AddrTable.getAddressEntries()) - AMIter->second.insert(Addr, Index++); + const uint64_t CUID = getCUID(CU); + const uint8_t AddrSize = CU.getAddressByteSize(); + auto AMIter = AddressMaps.find(CUID); + // A case where CU has entry in .debug_addr, but we don't modify addresses + // for it. + if (AMIter == AddressMaps.end()) { + AMIter = AddressMaps.insert({CUID, AddressForDWOCU()}).first; + std::optional BaseOffset = CU.getAddrOffsetSectionBase(); + if (!BaseOffset) + return; + // Address base offset is to the first entry. + // The size of header is 8 bytes. + uint64_t Offset = *BaseOffset - HeaderSize; + auto Iter = UnmodifiedAddressOffsets.find(Offset); + if (Iter != UnmodifiedAddressOffsets.end()) { + updateAddressBase(DIEBlder, *this, CU, Iter->getSecond()); + return; } - - DWOIdToOffsetMap[CUID] = Buffer.size() + HeaderSize; - - std::vector SortedMap( - AMIter->second.indexToAddressBegin(), - AMIter->second.indexToAdddessEnd()); - // Sorting address in increasing order of indices. - llvm::sort(SortedMap, llvm::less_first()); - // Writing out Header - const uint32_t Length = SortedMap.size() * AddrSize + 4; - support::endian::write(AddressStream, Length, Endian); - support::endian::write(AddressStream, static_cast(5), Endian); - support::endian::write(AddressStream, static_cast(AddrSize), - Endian); - support::endian::write(AddressStream, static_cast(0), Endian); - - uint32_t Counter = 0; - auto writeAddress = [&](uint64_t Address) -> void { - ++Counter; - switch (AddrSize) { - default: - llvm_unreachable("Address Size is invalid."); - break; - case 4: - support::endian::write(AddressStream, static_cast(Address), - Endian); - break; - case 8: - support::endian::write(AddressStream, Address, Endian); - break; - } - }; - - for (const IndexAddressPair &Val : SortedMap) { - while (Val.first > Counter) - writeAddress(0); - writeAddress(Val.second); + UnmodifiedAddressOffsets[Offset] = Buffer->size() + HeaderSize; + if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddrSize, + DumpOpts.WarningHandler)) { + DumpOpts.RecoverableErrorHandler(std::move(Err)); + return; } + + uint32_t Index = 0; + for (uint64_t Addr : AddrTable.getAddressEntries()) + AMIter->second.insert(Addr, Index++); } - return Buffer; -} + updateAddressBase(DIEBlder, *this, CU, Buffer->size() + HeaderSize); -uint64_t DebugAddrWriter::getOffset(DWARFUnit &Unit) { - const uint64_t CUID = getCUID(Unit); - assert(CUID && "Can't get offset, not a skeleton CU."); - auto Iter = DWOIdToOffsetMap.find(CUID); - assert(Iter != DWOIdToOffsetMap.end() && - "Offset in to.debug_addr was not found for DWO ID."); - return Iter->second; -} + std::vector SortedMap(AMIter->second.indexToAddressBegin(), + AMIter->second.indexToAdddessEnd()); + // Sorting address in increasing order of indices. + llvm::sort(SortedMap, llvm::less_first()); + // Writing out Header + const uint32_t Length = SortedMap.size() * AddrSize + 4; + support::endian::write(*AddressStream, Length, Endian); + support::endian::write(*AddressStream, static_cast(5), Endian); + support::endian::write(*AddressStream, static_cast(AddrSize), + Endian); + support::endian::write(*AddressStream, static_cast(0), Endian); + + uint32_t Counter = 0; + auto writeAddress = [&](uint64_t Address) -> void { + ++Counter; + switch (AddrSize) { + default: + llvm_unreachable("Address Size is invalid."); + break; + case 4: + support::endian::write(*AddressStream, static_cast(Address), + Endian); + break; + case 8: + support::endian::write(*AddressStream, Address, Endian); + break; + } + }; -uint64_t DebugAddrWriterDwarf5::getOffset(DWARFUnit &Unit) { - auto Iter = DWOIdToOffsetMap.find(getCUID(Unit)); - assert(Iter != DWOIdToOffsetMap.end() && - "Offset in to.debug_addr was not found for CU ID."); - return Iter->second; + for (const IndexAddressPair &Val : SortedMap) { + while (Val.first > Counter) + writeAddress(0); + writeAddress(Val.second); + } } void DebugLocWriter::init() { @@ -879,7 +884,8 @@ void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address) { StrOffsetSectionWasModified = true; } -void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit) { +void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit, + DIEBuilder &DIEBldr) { if (IndexToAddressMap.empty()) return; @@ -888,8 +894,12 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit) { assert(AttrVal && "DW_AT_str_offsets_base not present."); std::optional Val = AttrVal->V.getAsSectionOffset(); assert(Val && "DW_AT_str_offsets_base Value not present."); - auto RetVal = ProcessedBaseOffsets.insert(*Val); - if (RetVal.second) { + DIE &Die = *DIEBldr.getUnitDIEbyUnit(Unit); + DIEValue StrListBaseAttrInfo = + Die.findAttribute(dwarf::DW_AT_str_offsets_base); + auto RetVal = ProcessedBaseOffsets.find(*Val); + // Handling re-use of str-offsets section. + if (RetVal == ProcessedBaseOffsets.end() || StrOffsetSectionWasModified) { // Writing out the header for each section. support::endian::write(*StrOffsetsStream, CurrentSectionSize + 4, support::little); @@ -897,14 +907,20 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit) { support::little); support::endian::write(*StrOffsetsStream, static_cast(0), support::little); + + uint64_t BaseOffset = StrOffsetsBuffer->size(); + ProcessedBaseOffsets[*Val] = BaseOffset; + if (StrListBaseAttrInfo.getType()) + DIEBldr.replaceValue(&Die, dwarf::DW_AT_str_offsets_base, + StrListBaseAttrInfo.getForm(), + DIEInteger(BaseOffset)); for (const auto &Entry : IndexToAddressMap) support::endian::write(*StrOffsetsStream, Entry.second, support::little); + } else { + DIEBldr.replaceValue(&Die, dwarf::DW_AT_str_offsets_base, + StrListBaseAttrInfo.getForm(), + DIEInteger(RetVal->second)); } - // Will print error if we already processed this contribution, and now - // skipping it, but it was modified. - if (!RetVal.second && StrOffsetSectionWasModified) - errs() << "BOLT-WARNING: skipping string offsets section for CU at offset " - << Twine::utohexstr(Unit.getOffset()) << ", but it was modified\n"; StrOffsetSectionWasModified = false; IndexToAddressMap.clear(); diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index a197ea3e5829c..f60d3111d863a 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/DIE.h" #include "llvm/DWARFLinker/DWARFStreamer.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" @@ -238,6 +239,13 @@ static cl::opt "Skeleton CUs that get patched."), cl::ZeroOrMore, cl::Hidden, cl::init(false), cl::cat(BoltCategory)); + +static cl::opt BatchSize( + "cu-processing-batch-size", + cl::desc( + "Specifies the size of batches for processing CUs. Higher number has " + "better performance, but more memory usage. Default value is 1."), + cl::Hidden, cl::init(1), cl::cat(BoltCategory)); } // namespace opts static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU, @@ -342,12 +350,11 @@ createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile, return Streamer; } -static DWARFRewriter::UnitMeta emitUnit(DIEBuilder &DIEBldr, - std::unique_ptr &Streamer, - DWARFUnit &Unit) { +static DWARFRewriter::UnitMeta +emitUnit(DIEBuilder &DIEBldr, DIEStreamer &Streamer, DWARFUnit &Unit) { DIE *UnitDIE = DIEBldr.getUnitDIEbyUnit(Unit); const DIEBuilder::DWARFUnitInfo &U = DIEBldr.getUnitInfoByDwarfUnit(Unit); - Streamer->emitUnit(Unit, *UnitDIE); + Streamer.emitUnit(Unit, *UnitDIE); uint64_t TypeHash = 0; if (DWARFTypeUnit *DTU = dyn_cast_or_null(&Unit)) TypeHash = DTU->getTypeHash(); @@ -377,7 +384,8 @@ static void emitDWOBuilder(const std::string &DWOName, // TUs for (std::unique_ptr &CU : SplitCU.getContext().dwo_info_section_units()) { - DWARFRewriter::UnitMeta MI = emitUnit(DWODIEBuilder, Streamer, *CU.get()); + DWARFRewriter::UnitMeta MI = + emitUnit(DWODIEBuilder, *Streamer, *CU.get()); if (CU->isTypeUnit()) TUMetaVector.emplace_back(MI); else @@ -386,11 +394,11 @@ static void emitDWOBuilder(const std::string &DWOName, } else { for (std::unique_ptr &CU : SplitCU.getContext().dwo_compile_units()) - emitUnit(DWODIEBuilder, Streamer, *CU.get()); + emitUnit(DWODIEBuilder, *Streamer, *CU.get()); // emit debug_types sections for dwarf4 for (DWARFUnit *CU : DWODIEBuilder.getDWARF4TUVector()) { - DWARFRewriter::UnitMeta MI = emitUnit(DWODIEBuilder, Streamer, *CU); + DWARFRewriter::UnitMeta MI = emitUnit(DWODIEBuilder, *Streamer, *CU); TUMetaVector.emplace_back(MI); } } @@ -439,6 +447,46 @@ void DWARFRewriter::addStringHelper(DIEBuilder &DIEBldr, DIE &Die, DIEInteger(NewOffset)); } +using DWARFUnitVec = std::vector; +using CUPartitionVector = std::vector; +/// Partitions CUs in to buckets. Bucket size is controlled by +/// cu-processing-batch-size. All the CUs that have cross CU reference reference +/// as a source are put in to the same initial bucket. +static CUPartitionVector partitionCUs(DWARFContext &DwCtx) { + CUPartitionVector Vec(2); + unsigned Counter = 0; + const DWARFDebugAbbrev *Abbr = DwCtx.getDebugAbbrev(); + for (std::unique_ptr &CU : DwCtx.compile_units()) { + Expected AbbrDeclSet = + Abbr->getAbbreviationDeclarationSet(CU->getAbbreviationsOffset()); + if (!AbbrDeclSet) { + consumeError(AbbrDeclSet.takeError()); + return Vec; + } + bool CrossCURefFound = false; + for (const DWARFAbbreviationDeclaration &Decl : *AbbrDeclSet.get()) { + for (const DWARFAbbreviationDeclaration::AttributeSpec &Attr : + Decl.attributes()) { + if (Attr.Form == dwarf::DW_FORM_ref_addr) { + CrossCURefFound = true; + break; + } + } + if (CrossCURefFound) + break; + } + if (CrossCURefFound) { + Vec[0].push_back(CU.get()); + } else { + ++Counter; + Vec.back().push_back(CU.get()); + } + if (Counter % opts::BatchSize == 0 && !Vec.back().empty()) + Vec.push_back({}); + } + return Vec; +} + void DWARFRewriter::updateDebugInfo() { ErrorOr DebugInfo = BC.getUniqueSectionByName(".debug_info"); if (!DebugInfo) @@ -541,6 +589,7 @@ void DWARFRewriter::updateDebugInfo() { // Skipping CUs that failed to load. if (SplitCU) { DIEBuilder DWODIEBuilder(&(*SplitCU)->getContext(), true); + DWODIEBuilder.buildBoth(); std::string DWOName = updateDWONameCompDir( *Unit, *DIEBlder, *DIEBlder->getUnitDIEbyUnit(*Unit)); @@ -579,7 +628,7 @@ void DWARFRewriter::updateDebugInfo() { RangesBase = RangesSectionWriter->getSectionOffset() + getDWARF5RngListLocListHeaderSize(); RangesSectionWriter->initSection(*Unit); - StrOffstsWriter->finalizeSection(*Unit); + StrOffstsWriter->finalizeSection(*Unit, *DIEBlder); } updateUnitDebugInfo(*Unit, *DIEBlder, *DebugLocWriter, *RangesSectionWriter, @@ -587,13 +636,33 @@ void DWARFRewriter::updateDebugInfo() { DebugLocWriter->finalize(*DIEBlder, *DIEBlder->getUnitDIEbyUnit(*Unit)); if (Unit->getVersion() >= 5) RangesSectionWriter->finalizeSection(); + AddrWriter->update(*DIEBlder, *Unit); }; CUIndex = 0; DIEBuilder DIEBlder(BC.DwCtx.get()); - if (opts::NoThreads || opts::DeterministicDebugInfo) { - for (std::unique_ptr &CU : BC.DwCtx->compile_units()) { - processUnitDIE(CUIndex++, CU.get(), &DIEBlder); + DIEBlder.buildTypeUnits(); + SmallVector OutBuffer; + std::unique_ptr ObjOS = + std::make_unique(OutBuffer); + const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); + auto TheTriple = std::make_unique(File->makeTriple()); + std::unique_ptr Streamer = + createDIEStreamer(*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, *this); + CUOffsetMap OffsetMap = finalizeTypeSections(DIEBlder, *Streamer); + + const bool SingleThreadedMode = + opts::NoThreads || opts::DeterministicDebugInfo; + if (!SingleThreadedMode) + DIEBlder.buildCompileUnits(); + if (SingleThreadedMode) { + CUPartitionVector PartVec = partitionCUs(*BC.DwCtx); + for (std::vector &Vec : PartVec) { + DIEBlder.buildCompileUnits(Vec); + for (DWARFUnit *CU : DIEBlder.getProcessedCUs()) + processUnitDIE(CUIndex++, CU, &DIEBlder); + finalizeCompileUnits(DIEBlder, *Streamer, OffsetMap, + DIEBlder.getProcessedCUs()); } } else { // Update unit debug info in parallel @@ -608,7 +677,7 @@ void DWARFRewriter::updateDebugInfo() { if (opts::WriteDWP) finalizeDWP(State); - CUOffsetMap OffsetMap = finalizeDebugSections(DIEBlder); + finalizeDebugSections(DIEBlder, *Streamer, *ObjOS, OffsetMap); updateGdbIndexSection(OffsetMap, CUIndex); } @@ -1225,7 +1294,69 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) { TypeInfoSection->setIsFinalized(); } -CUOffsetMap DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder) { +CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder, + DIEStreamer &Streamer) { + // update TypeUnit DW_AT_stmt_list with new .debug_line information. + for (const std::unique_ptr &TU : BC.DwCtx->types_section_units()) { + DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*TU.get()); + DIEValue StmtAttrInfo = UnitDIE->findAttribute(dwarf::DW_AT_stmt_list); + if (!StmtAttrInfo || !TypeUnitRelocMap.count(TU.get())) + continue; + DIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_stmt_list, + StmtAttrInfo.getForm(), + DIEInteger(TypeUnitRelocMap[TU.get()])); + } + + // generate and populate abbrevs here + DIEBlder.generateAbbrevs(); + DIEBlder.finish(); + SmallVector OutBuffer; + std::shared_ptr ObjOS = + std::make_shared(OutBuffer); + const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); + auto TheTriple = std::make_unique(File->makeTriple()); + std::unique_ptr TypeStreamer = + createDIEStreamer(*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, *this); + + // generate debug_info and CUMap + CUOffsetMap CUMap; + for (std::unique_ptr &CU : BC.DwCtx->info_section_units()) { + if (!CU->isTypeUnit()) + continue; + emitUnit(DIEBlder, Streamer, *CU.get()); + uint32_t StartOffset = CUOffset; + DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU.get()); + CUOffset += CU.get()->getHeaderSize(); + CUOffset += UnitDIE->getSize(); + CUMap[CU.get()->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; + } + + // Emit Type Unit of DWARF 4 to .debug_type section + for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) + emitUnit(DIEBlder, *TypeStreamer, *TU); + + TypeStreamer->finish(); + + std::unique_ptr ObjectMemBuffer = + MemoryBuffer::getMemBuffer(ObjOS->str(), "in-memory object file", false); + std::unique_ptr Obj = cantFail( + object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), + "error creating in-memory object"); + + for (const SectionRef &Section : Obj->sections()) { + StringRef Contents = cantFail(Section.getContents()); + StringRef Name = cantFail(Section.getName()); + if (Name.equals(".debug_types")) + BC.registerOrUpdateNoteSection(".debug_types", copyByteArray(Contents), + Contents.size()); + } + return CUMap; +} + +void DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder, + DIEStreamer &Streamer, + raw_svector_ostream &ObjOS, + CUOffsetMap &CUMap) { if (StrWriter->isInitialized()) { RewriteInstance::addToDebugSectionsToOverwrite(".debug_str"); std::unique_ptr DebugStrSectionContents = @@ -1285,89 +1416,13 @@ CUOffsetMap DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder) { BC.registerOrUpdateNoteSection(".debug_addr", copyByteArray(AddressSectionContents), AddressSectionContents.size()); - for (std::unique_ptr &CU : BC.DwCtx->compile_units()) { - DIE *Die = DIEBlder.getUnitDIEbyUnit(*CU.get()); - uint64_t Offset = 0; - DIEValue GnuAddrBaseAttrInfo = - Die->findAttribute(dwarf::DW_AT_GNU_addr_base); - DIEValue AddrBaseAttrInfo = Die->findAttribute(dwarf::DW_AT_addr_base); - dwarf::Form BaseAttrForm; - dwarf::Attribute BaseAttr; - // For cases where Skeleton CU does not have DW_AT_GNU_addr_base - if (!GnuAddrBaseAttrInfo && CU->getVersion() < 5) - continue; - - if (!AddrBaseAttrInfo && CU->getVersion() >= 5 && - !AddrWriter->doesCUExist(*CU)) - continue; - - Offset = AddrWriter->getOffset(*CU); - - if (GnuAddrBaseAttrInfo) { - BaseAttrForm = GnuAddrBaseAttrInfo.getForm(); - BaseAttr = GnuAddrBaseAttrInfo.getAttribute(); - } - - if (AddrBaseAttrInfo) { - BaseAttrForm = AddrBaseAttrInfo.getForm(); - BaseAttr = AddrBaseAttrInfo.getAttribute(); - } - - if (GnuAddrBaseAttrInfo || AddrBaseAttrInfo) { - DIEBlder.replaceValue(Die, BaseAttr, BaseAttrForm, DIEInteger(Offset)); - } else if (CU->getVersion() >= 5) { - // A case where we were not using .debug_addr section, but after update - // now using it. - DIEBlder.addValue(Die, dwarf::DW_AT_addr_base, - dwarf::DW_FORM_sec_offset, DIEInteger(Offset)); - } - } - } - - // update TypeUnit DW_AT_stmt_list with new .debug_line information. - for (const std::unique_ptr &TU : BC.DwCtx->types_section_units()) { - DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*TU.get()); - DIEValue StmtAttrInfo = UnitDIE->findAttribute(dwarf::DW_AT_stmt_list); - if (!StmtAttrInfo || !TypeUnitRelocMap.count(TU.get())) - continue; - DIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_stmt_list, - StmtAttrInfo.getForm(), - DIEInteger(TypeUnitRelocMap[TU.get()])); - } - - // generate and populate abbrevs here - DIEBlder.generateAbbrevs(); - DIEBlder.finish(); - SmallVector OutBuffer; - std::shared_ptr ObjOS = - std::make_shared(OutBuffer); - const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); - auto TheTriple = std::make_unique(File->makeTriple()); - std::unique_ptr Streamer = createDIEStreamer( - *TheTriple, *ObjOS, "AbbrevStreamerInitAug2", DIEBlder, *this); - - // generate debug_info and CUMap - CUOffsetMap CUMap; - uint32_t CUOffset = 0; - for (std::unique_ptr &CU : BC.DwCtx->info_section_units()) { - emitUnit(DIEBlder, Streamer, *CU.get()); - - uint32_t StartOffset = CUOffset; - DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU.get()); - CUOffset += CU.get()->getHeaderSize(); - CUOffset += UnitDIE->getSize(); - CUMap[CU.get()->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; } - // Emit Type Unit of DWARF 4 to .debug_type section - for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) - emitUnit(DIEBlder, Streamer, *TU); - - Streamer->emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion()); - Streamer->finish(); + Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion()); + Streamer.finish(); std::unique_ptr ObjectMemBuffer = - MemoryBuffer::getMemBuffer(ObjOS->str(), "in-memory object file", false); + MemoryBuffer::getMemBuffer(ObjOS.str(), "in-memory object file", false); std::unique_ptr Obj = cantFail( object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), "error creating in-memory object"); @@ -1381,9 +1436,6 @@ CUOffsetMap DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder) { } else if (Name.equals(".debug_info")) { BC.registerOrUpdateNoteSection(".debug_info", copyByteArray(Contents), Contents.size()); - } else if (Name.equals(".debug_types")) { - BC.registerOrUpdateNoteSection(".debug_types", copyByteArray(Contents), - Contents.size()); } } @@ -1402,7 +1454,23 @@ CUOffsetMap DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder) { copyByteArray(ARangesContents), ARangesContents.size()); } - return CUMap; +} + +void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder, + DIEStreamer &Streamer, + CUOffsetMap &CUMap, + const std::list &CUs) { + DIEBlder.generateAbbrevs(); + DIEBlder.finish(); + // generate debug_info and CUMap + for (DWARFUnit *CU : CUs) { + emitUnit(DIEBlder, Streamer, *CU); + const uint32_t StartOffset = CUOffset; + DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU); + CUOffset += CU->getHeaderSize(); + CUOffset += UnitDIE->getSize(); + CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; + } } // Creates all the data structures necessary for creating MCStreamer. @@ -1921,8 +1989,15 @@ void DWARFRewriter::updateGdbIndexSection(CUOffsetMap &CUMap, uint32_t NumCUs) { write32le(Buffer + 20, ConstantPoolOffset + Delta); Buffer += 24; + using MapEntry = std::pair; + std::vector CUVector(CUMap.begin(), CUMap.end()); + // Need to sort since we write out all of TUs in .debug_info before CUs. + std::sort(CUVector.begin(), CUVector.end(), + [](const MapEntry &E1, const MapEntry &E2) -> bool { + return E1.second.Offset < E2.second.Offset; + }); // Writing out CU List - for (auto &CUInfo : CUMap) { + for (auto &CUInfo : CUVector) { // Skipping TU for DWARF5 when they are not included in CU list. if (!OriginalOffsets.count(CUInfo.first)) continue; diff --git a/bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-dst.s b/bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-dst.s new file mode 100644 index 0000000000000..8fc19a084d190 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-dst.s @@ -0,0 +1,146 @@ + + .text + .file "inlinevar1.c" + .file 1 "" "./inlinevarother.h" + .globl main # -- Begin function main + .type main,@function +main: # @main +.Lfunc_begin1: + .file 2 "" "inlinevar1.c" + .loc 2 4 0 # inlinevar1.c:4:0 +.Ltmp2: + .file 3 "" "./inlinevar.h" + .loc 3 2 16 prologue_end # ./inlinevar.h:2:16 + movl $42, %eax + pushq %rax + .loc 3 3 10 # ./inlinevar.h:3:10 +.Ltmp3: + .loc 2 5 20 # inlinevar1.c:5:20 + callq other + popq %rcx + .loc 2 5 19 # inlinevar1.c:5:19 + addl %ecx, %eax + .loc 2 5 3 # inlinevar1.c:5:3 + retq +.Ltmp4: +.Lfunc_end1: + .size main, .Lfunc_end1-main + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 32 # DW_AT_inline + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 0xc # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + .quad .Lfunc_begin1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .globl debuginfo_func_inlined +debuginfo_func_inlined: +.Lfunc_inlined: + .byte 3 # Abbrev [3] DW_TAG_subprogram + .long .Linfo_string4 # DW_AT_name + .byte 3 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long .Ltype_int-.Lcu_begin0 # DW_AT_type + .byte 1 # DW_AT_inline + .globl debuginfo_var_var +debuginfo_var_var: +.Lvar_var: + .byte 4 # Abbrev [4] DW_TAG_variable + .long .Linfo_string6 # DW_AT_name + .byte 3 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long .Ltype_int-.Lcu_begin0 # DW_AT_type + .byte 0 # End Of Children Mark +.Ltype_int: + .byte 5 # Abbrev [5] DW_TAG_base_type + .long .Linfo_string5 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 11.0.0 + hand coding" +.Linfo_string1: + .asciz "inlinevar1.c" +.Linfo_string2: + .asciz "" +.Linfo_string4: + .asciz "inlined" +.Linfo_string5: + .asciz "int" +.Linfo_string6: + .asciz "var" + .section ".note.GNU-stack","",@progbits + .addrsig + .addrsig_sym other + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-src.s b/bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-src.s new file mode 100644 index 0000000000000..6a8dfa3eb63f3 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf4-cross-reference-different-abbrev-src.s @@ -0,0 +1,160 @@ + .text + .file "inlinevar2.c" + .globl other # -- Begin function other + .type other,@function +other: # @other +.Lfunc_begin0: + .file 1 "" "inlinevar2.c" + .loc 1 3 0 # inlinevar2.c:3:0 +.Ltmp0: + .file 2 "" "./inlinevar.h" + .loc 2 2 16 prologue_end # ./inlinevar.h:2:16 + movl $42, %eax + .loc 2 3 10 # ./inlinevar.h:3:10 + .loc 1 3 41 # inlinevar2.c:3:41 + retq +.Ltmp1: +.Ltmp2: +.Lfunc_end0: + .size other, .Lfunc_end0-other + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 0x10 # DW_FORM_ref_addr + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 0x10 # DW_FORM_ref_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 0xc # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc +.Ltype_int: + .byte 4 # Abbrev [4] DW_TAG_base_type + .long .Linfo_string5 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long .Linfo_string8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .long .Ltype_int-.Lcu_begin0 # DW_AT_type + # DW_AT_external + .byte 7 # Abbrev [7] DW_TAG_inlined_subroutine + .long debuginfo_func_inlined # DW_AT_abstract_origin + .quad .Ltmp0 # DW_AT_low_pc + .long .Ltmp1-.Ltmp0 # DW_AT_high_pc + .byte 1 # DW_AT_call_file + .byte 3 # DW_AT_call_line + .byte 48 # DW_AT_call_column + .byte 8 # Abbrev [8] DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long debuginfo_var_var # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 11.0.0 + hand coding" +.Linfo_string1: + .asciz "inlinevar2.c" +.Linfo_string2: + .asciz "" +.Linfo_string5: + .asciz "int" +.Linfo_string8: + .asciz "other" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf5-helper1-addr-section-reuse.s b/bolt/test/X86/Inputs/dwarf5-helper1-addr-section-reuse.s index 6227ebb1daeb2..d08ccd6079d28 100644 --- a/bolt/test/X86/Inputs/dwarf5-helper1-addr-section-reuse.s +++ b/bolt/test/X86/Inputs/dwarf5-helper1-addr-section-reuse.s @@ -104,7 +104,7 @@ _Z3foov: # @_Z3foov .byte 4 # DW_AT_name .byte 0 # DW_AT_decl_file .byte 1 # DW_AT_decl_line - .long 51 # DW_AT_type + .long 41 # DW_AT_type # DW_AT_external .byte 3 # Abbrev [3] 0x33:0x4 DW_TAG_base_type .byte 5 # DW_AT_name diff --git a/bolt/test/X86/Inputs/dwarf5-helper2-addr-section-reuse.s b/bolt/test/X86/Inputs/dwarf5-helper2-addr-section-reuse.s index 468cb82f00292..c804c2ea62514 100644 --- a/bolt/test/X86/Inputs/dwarf5-helper2-addr-section-reuse.s +++ b/bolt/test/X86/Inputs/dwarf5-helper2-addr-section-reuse.s @@ -104,7 +104,7 @@ _Z4foo2v: # @_Z4foo2v .byte 4 # DW_AT_name .byte 0 # DW_AT_decl_file .byte 1 # DW_AT_decl_line - .long 51 # DW_AT_type + .long 41 # DW_AT_type # DW_AT_external .byte 3 # Abbrev [3] 0x33:0x4 DW_TAG_base_type .byte 5 # DW_AT_name diff --git a/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test b/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test new file mode 100644 index 0000000000000..e609440696db4 --- /dev/null +++ b/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test @@ -0,0 +1,25 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-cross-reference-different-abbrev-dst.s -o %t.o +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-cross-reference-different-abbrev-src.s -o %t1.o +# RUN: %clang %cflags -gdwarf-4 %t.o %t1.o -o %t.exe +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s + +# This test checks that BOLT handles backward cross CU references for dwarf4 +# when CUs are have different abbrev tables. + +# PRECHECK: DW_TAG_compile_unit +# PRECHECK: DW_TAG_compile_unit +# PRECHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# PRECHECK-SAME: "inlined" +# PRECHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# PRECHECK-SAME: "var" + +# POSTCHECK: DW_TAG_compile_unit +# POSTCHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# POSTCHECK-SAME: "inlined" +# POSTCHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# POSTCHECK-SAME: "var" +# POSTCHECK: DW_TAG_compile_unit diff --git a/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test b/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test new file mode 100644 index 0000000000000..e73960e7251e6 --- /dev/null +++ b/bolt/test/X86/dwarf4-cross-cu-forward-different-abbrev.test @@ -0,0 +1,24 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-cross-reference-different-abbrev-dst.s -o %t.o +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-cross-reference-different-abbrev-src.s -o %t1.o +# RUN: %clang %cflags -gdwarf-4 %t1.o %t.o -o %t.exe +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s + +# This test checks that BOLT handles forward cross CU references for dwarf4 +# when CUs are have different abbrev tables. + +# PRECHECK: DW_TAG_compile_unit +# PRECHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# PRECHECK-SAME: "inlined" +# PRECHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# PRECHECK-SAME: "var" +# PRECHECK: DW_TAG_compile_unit + +# POSTCHECK: DW_TAG_compile_unit +# POSTCHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# POSTCHECK-SAME: "inlined" +# POSTCHECK: DW_AT_abstract_origin [DW_FORM_ref_addr] +# POSTCHECK-SAME: "var" diff --git a/bolt/test/X86/dwarf4-types-dwarf5-types.test b/bolt/test/X86/dwarf4-types-dwarf5-types.test index a3608cadeb688..dc45d0c3daa71 100644 --- a/bolt/test/X86/dwarf4-types-dwarf5-types.test +++ b/bolt/test/X86/dwarf4-types-dwarf5-types.test @@ -9,71 +9,71 @@ # Check BOLT handles DWARF4/5 with fdebug-types. -# POSTCHECK: version = 0x0004 -# POSTCHECK: DW_TAG_compile_unit [6] -# POSTCHECK: DW_TAG_subprogram [7] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x007c => {0x0000007c} "int") -# POSTCHECK: DW_TAG_formal_parameter [8] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x007c => {0x0000007c} "int") -# POSTCHECK: DW_TAG_formal_parameter [8] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0083 => {0x00000083} "char **") -# POSTCHECK: DW_TAG_variable [9] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0094 => {0x00000094} "Foo") -# POSTCHECK: DW_TAG_base_type [5] -# POSTCHECK: DW_TAG_pointer_type [4] - # POSTCHECK: version = 0x0005 -# POSTCHECK: DW_TAG_type_unit [11] -# POSTCHECK: DW_TAG_member [13] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0045 => {0x000000ec} "char *") +# POSTCHECK: DW_TAG_type_unit +# POSTCHECK: DW_TAG_member +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0045 => {0x{{[0-9a-f]+}}} "char *") # POSTCHECK: DW_TAG_pointer_type [4] -# POSTCHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x004a => {0x000000f1} "char") +# POSTCHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x004a => {0x{{[0-9a-f]+}}} "char") # POSTCHECK: version = 0x0005 -# POSTCHECK: DW_TAG_type_unit [11] -# POSTCHECK: DW_TAG_structure_type [12] -# POSTCHECK: DW_TAG_member [13] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x003c => {0x00000132} "char *") -# POSTCHECK: DW_TAG_member [13] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x003c => {0x00000132} "char *") +# POSTCHECK: DW_TAG_type_unit +# POSTCHECK: DW_TAG_structure_type +# POSTCHECK: DW_TAG_member +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x003c => {0x{{[0-9a-f]+}}} "char *") +# POSTCHECK: DW_TAG_member +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x003c => {0x{{[0-9a-f]+}}} "char *") # POSTCHECK: DW_TAG_pointer_type [4] -# POSTCHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x00000137} "char") +# POSTCHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0041 => {0x{{[0-9a-f]+}}} "char") + +# POSTCHECK: version = 0x0004 +# POSTCHECK: DW_TAG_compile_unit +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x007c => {0x{{[0-9a-f]+}}} "int") +# POSTCHECK: DW_TAG_formal_parameter +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x007c => {0x{{[0-9a-f]+}}} "int") +# POSTCHECK: DW_TAG_formal_parameter +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0083 => {0x{{[0-9a-f]+}}} "char **") +# POSTCHECK: DW_TAG_variable +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0094 => {0x{{[0-9a-f]+}}} "Foo") +# POSTCHECK: DW_TAG_base_type +# POSTCHECK: DW_TAG_pointer_type # POSTCHECK: version = 0x0005 -# POSTCHECK: DW_TAG_compile_unit [15] -# POSTCHECK: DW_TAG_subprogram [16] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0048 => {0x00000184} "int") -# POSTCHECK: DW_TAG_variable [17] -# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x004c => {0x00000188} "Foo2a") -# POSTCHECK: DW_TAG_base_type [14] -# POSTCHECK: DW_TAG_structure_type [10] +# POSTCHECK: DW_TAG_compile_unit +# POSTCHECK: DW_TAG_subprogram +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x0048 => {0x{{[0-9a-f]+}}} "int") +# POSTCHECK: DW_TAG_variable +# POSTCHECK: DW_AT_type [DW_FORM_ref4] (cu + 0x004c => {0x{{[0-9a-f]+}}} "Foo2a") +# POSTCHECK: DW_TAG_base_type +# POSTCHECK: DW_TAG_structure_type # POSTCHECK: DW_AT_signature [DW_FORM_ref_sig8] (0x104ec427d2ebea6f) -# POSTCHECK: DW_TAG_structure_type [10] +# POSTCHECK: DW_TAG_structure_type # POSTCHECK: DW_AT_signature [DW_FORM_ref_sig8] (0xb4580bc1535df1e4) # POSTCHECKTU: version = 0x0004 # POSTCHECKTU-SAME: type_signature = 0x675d23e4f33235f2 # POSTCHECKTU-SAME: type_offset = 0x001e -# POSTCHECKTU: DW_TAG_type_unit [1] -# POSTCHECKTU: DW_TAG_member [3] -# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x004c => {0x0000004c} "char *") -# POSTCHECKTU: DW_TAG_member [3] -# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x004c => {0x0000004c} "char *") -# POSTCHECKTU: DW_TAG_pointer_type [4] -# POSTCHECKTU-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0051 => {0x00000051} "char") -# POSTCHECKTU: DW_TAG_base_type [5] +# POSTCHECKTU: DW_TAG_type_unit +# POSTCHECKTU: DW_TAG_member +# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x004c => {0x{{[0-9a-f]+}}} "char *") +# POSTCHECKTU: DW_TAG_member +# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x004c => {0x{{[0-9a-f]+}}} "char *") +# POSTCHECKTU: DW_TAG_pointer_type +# POSTCHECKTU-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0051 => {0x{{[0-9a-f]+}}} "char") +# POSTCHECKTU: DW_TAG_base_type # POSTCHECKTU: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-f]+}}] = "char") # POSTCHECKTU: version = 0x0004 # POSTCHECKTU-SAME: type_signature = 0x49dc260088be7e56 # POSTCHECKTU-SAME: type_offset = 0x001e -# POSTCHECKTU: DW_TAG_type_unit [1] -# POSTCHECKTU: DW_TAG_structure_type [2] -# POSTCHECKTU: DW_TAG_member [3] -# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x0040 => {0x00000099} "char *") -# POSTCHECKTU: DW_TAG_member [3] -# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x0040 => {0x00000099} "char *") -# POSTCHECKTU: DW_TAG_pointer_type [4] -# POSTCHECKTU-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0045 => {0x0000009e} "char") -# POSTCHECKTU: DW_TAG_base_type [5] +# POSTCHECKTU: DW_TAG_type_unit +# POSTCHECKTU: DW_TAG_structure_type +# POSTCHECKTU: DW_TAG_member +# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x0040 => {0x{{[0-9a-f]+}}} "char *") +# POSTCHECKTU: DW_TAG_member +# POSTCHECKTU: DW_AT_type [DW_FORM_ref4] (cu + 0x0040 => {0x{{[0-9a-f]+}}} "char *") +# POSTCHECKTU: DW_TAG_pointer_type +# POSTCHECKTU-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0045 => {0x{{[0-9a-f]+}}} "char") +# POSTCHECKTU: DW_TAG_base_type # POSTCHECKTU-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-f]+}}] = "char") diff --git a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test index 0bb0bae26b24d..702f222723b45 100644 --- a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test +++ b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb11.test @@ -11,11 +11,11 @@ # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 2 entries -# POSTCHECK-NEXT: 0: Offset = 0x40, Length = 0x52 +# POSTCHECK-NEXT: 0: Offset = 0x80, Length = 0x52 # POSTCHECK-NEXT: 1: Offset = 0xd2, Length = 0x53 # POSTCHECK: Types CU list offset = 0x38, has 2 entries # POSTCHECK-NEXT: 0: offset = 0x00000000, type_offset = 0x00000023, type_signature = 0x418503b8111e9a7b -# POSTCHECK-NEXT: 1: offset = 0x00000092, type_offset = 0x00000023, type_signature = 0x00f6cca4e3a15118 +# POSTCHECK-NEXT: 1: offset = 0x00000040, type_offset = 0x00000023, type_signature = 0x00f6cca4e3a15118 # POSTCHECK: Address area offset = 0x68, has 2 entries # POSTCHECK-NEXT: Low/High address = [0x[[#%.4x,ADDR:]], # POSTCHECK-SAME: 0x[[#ADDR + 0xf]]) (Size: 0xf), CU id = 1 diff --git a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test index d424ec8549c46..e694a467bcd28 100644 --- a/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test +++ b/bolt/test/X86/dwarf5-gdb-index-types-gdb-generated-gdb9.test @@ -12,12 +12,12 @@ # POSTCHECK: Version = 8 # POSTCHECK: CU list offset = 0x18, has 4 entries # POSTCHECK-NEXT: 0: Offset = 0x0, Length = 0x40 -# POSTCHECK-NEXT: 1: Offset = 0x40, Length = 0x52 -# POSTCHECK-NEXT: 2: Offset = 0x92, Length = 0x40 +# POSTCHECK-NEXT: 1: Offset = 0x40, Length = 0x40 +# POSTCHECK-NEXT: 2: Offset = 0x80, Length = 0x52 # POSTCHECK-NEXT: 3: Offset = 0xd2, Length = 0x53 # POSTCHECK: Types CU list offset = 0x58, has 2 entries # POSTCHECK-NEXT: 0: offset = 0x00000000, type_offset = 0x00000023, type_signature = 0x418503b8111e9a7b -# POSTCHECK-NEXT: 1: offset = 0x00000092, type_offset = 0x00000023, type_signature = 0x00f6cca4e3a15118 +# POSTCHECK-NEXT: 1: offset = 0x00000040, type_offset = 0x00000023, type_signature = 0x00f6cca4e3a15118 # POSTCHECK: Address area offset = 0x88, has 2 entries # POSTCHECK-NEXT: Low/High address = [0x[[#%.4x,ADDR:]], # POSTCHECK-SAME: 0x[[#ADDR + 0xf]]) (Size: 0xf), CU id = 1 diff --git a/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test b/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test index e3288230e3a44..8f0043dd7609b 100644 --- a/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test +++ b/bolt/test/X86/dwarf5-gdb-index-types-lld-generated.test @@ -10,7 +10,7 @@ # POSTCHECK: Version = 7 # POSTCHECK: CU list offset = 0x18, has 2 entries -# POSTCHECK-NEXT: 0: Offset = 0x40, Length = 0x52 +# POSTCHECK-NEXT: 0: Offset = 0x80, Length = 0x52 # POSTCHECK-NEXT: 1: Offset = 0xd2, Length = 0x53 # POSTCHECK: Types CU list offset = 0x38, has 0 entries # POSTCHECK: Address area offset = 0x38, has 2 entries diff --git a/bolt/test/X86/dwarf5-locexpr-referrence.test b/bolt/test/X86/dwarf5-locexpr-referrence.test index 9953a6c3a8ab1..fe0f6a61514c2 100644 --- a/bolt/test/X86/dwarf5-locexpr-referrence.test +++ b/bolt/test/X86/dwarf5-locexpr-referrence.test @@ -8,14 +8,14 @@ # This test checks that we update relative DIE references with DW_OP_convert that are in locexpr. -# CHECK: version = 0x0005 # CHECK: version = 0x0005 # CHECK: DW_TAG_variable # CHECK-NEXT: DW_AT_location -# CHECK-SAME: DW_OP_convert (0x00000028 -> 0x0000005d) -# CHECK-SAME: DW_OP_convert (0x0000002c -> 0x00000061) +# CHECK-SAME: DW_OP_convert (0x00000028 -> 0x00000028) +# CHECK-SAME: DW_OP_convert (0x0000002c -> 0x0000002c) # CHECK: version = 0x0005 # CHECK: DW_TAG_variable # CHECK-NEXT: DW_AT_location -# CHECK-SAME: DW_OP_convert (0x00000028 -> 0x000000c4) -# CHECK-SAME: DW_OP_convert (0x0000002c -> 0x000000c8) +# CHECK-SAME: DW_OP_convert (0x00000028 -> 0x0000008f) +# CHECK-SAME: DW_OP_convert (0x0000002c -> 0x00000093) +# CHECK: version = 0x0005