diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h --- a/bolt/include/bolt/Core/DIEBuilder.h +++ b/bolt/include/bolt/Core/DIEBuilder.h @@ -60,6 +60,8 @@ 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 @@ 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 @@ 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 @@ /// 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 @@ /// 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 @@ 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 @@ 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 @@ 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 --- 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 @@ /// 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 @@ 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 @@ 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 @@ 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 @@ 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 --- a/bolt/include/bolt/Rewrite/DWARFRewriter.h +++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h @@ -105,6 +105,9 @@ /// 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 @@ 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 --- 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } 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 @@ // 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ "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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ if (isEmpty()) return; - for (DWARFUnit *DU : DUList) { + for (DWARFUnit *DU : getState().DUList) { DIE *UnitDIE = getUnitDIEbyUnit(*DU); generateUnitAbbrevs(UnitDIE); } @@ -734,14 +843,33 @@ 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 --- 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 @@ } } -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 @@ } } -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 @@ 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 @@ StrOffsetSectionWasModified = true; } -void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit) { +void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit, + DIEBuilder &DIEBldr) { if (IndexToAddressMap.empty()) return; @@ -888,8 +894,12 @@ 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 @@ 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 --- 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 @@ "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 @@ 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 @@ // 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 @@ } 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 @@ 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 @@ // 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 @@ RangesBase = RangesSectionWriter->getSectionOffset() + getDWARF5RngListLocListHeaderSize(); RangesSectionWriter->initSection(*Unit); - StrOffstsWriter->finalizeSection(*Unit); + StrOffstsWriter->finalizeSection(*Unit, *DIEBlder); } updateUnitDebugInfo(*Unit, *DIEBlder, *DebugLocWriter, *RangesSectionWriter, @@ -587,13 +636,33 @@ 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 @@ if (opts::WriteDWP) finalizeDWP(State); - CUOffsetMap OffsetMap = finalizeDebugSections(DIEBlder); + finalizeDebugSections(DIEBlder, *Streamer, *ObjOS, OffsetMap); updateGdbIndexSection(OffsetMap, CUIndex); } @@ -1225,7 +1294,69 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 --- /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 --- /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 --- 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 @@ .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 --- 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 @@ .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 --- /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 --- /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 --- 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 --- 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 --- 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 --- 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 --- 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