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 @@ -15,6 +15,7 @@ #define BOLT_CORE_DEBUG_DATA_H #include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/Support/SMLoc.h" @@ -34,6 +35,7 @@ namespace bolt { +class DIEBuilder; struct AttrInfo { DWARFFormValue V; const DWARFAbbreviationDeclaration *AbbrevDecl; @@ -497,13 +499,11 @@ virtual ~DebugLocWriter(){}; /// Writes out location lists and stores internal patches. - virtual void addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, - DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter); + virtual void addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo, + DebugLocationsVector &LocList); /// Writes out locations in to a local buffer, and adds Debug Info patches. - virtual void finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter); + virtual void finalize(DIEBuilder &DIEBldr, DIE &Die); /// Return internal buffer. virtual std::unique_ptr getBuffer(); @@ -569,13 +569,11 @@ static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; } /// Stores location lists internally to be written out during finalize phase. - void addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, - DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter) override; + virtual void addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo, + DebugLocationsVector &LocList) override; /// Writes out locations in to a local buffer and applies debug info patches. - void finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter) override; + void finalize(DIEBuilder &DIEBldr, DIE &Die) override; /// Returns CU ID. /// For Skelton CU it is a CU Offset. @@ -596,8 +594,7 @@ private: /// Writes out locations in to a local buffer and applies debug info patches. - void finalizeDWARF5(DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter); + void finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die); static DebugAddrWriter *AddrWriter; DWARFUnit &CU; diff --git a/bolt/include/bolt/Rewrite/DIEBuilder.h b/bolt/include/bolt/Rewrite/DIEBuilder.h new file mode 100644 --- /dev/null +++ b/bolt/include/bolt/Rewrite/DIEBuilder.h @@ -0,0 +1,307 @@ +//===- bolt/Rewrite/DIEBuilder.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declaration of the DIEBuilder class, which is the +/// base class for Debug Information IR construction. +/// +//===----------------------------------------------------------------------===// + +#ifndef BOLT_REWRITE_DIE_BUILDER_H +#define BOLT_REWRITE_DIE_BUILDER_H + +#include "llvm/CodeGen/DIE.h" +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/ErrorHandling.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { + +namespace bolt { + +class DIEBuilder { + struct DIEInfo { + DIE *Die; + uint32_t DieId; + uint32_t UnitId; + uint32_t CanonicalDIEOffset; + }; + + struct UnitInfo { + std::list DieInfoList; + uint32_t UnitId; + uint32_t UnitOffset; + bool Isconstructed = false; + uint32_t NewDieId = 0; + std::unordered_map DIEIDMap; + std::unordered_map DIEId2InfoMap; + }; + + struct ForwardReferenceInfo { + ForwardReferenceInfo(DIEInfo *Die, + DWARFAbbreviationDeclaration::AttributeSpec spec) + : Dst(Die), AttrSpec(spec) {} + DIEInfo *Dst; + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec; + }; + + bool IsBuilt = false; + std::unordered_map> UnitDIEs; + std::unordered_map UnitIDMap; + std::unordered_map TypeDIEMap; + std::vector DUList; + std::vector CloneUnitCtxMap; + std::vector> ForwardReferences; + FoldingSet AbbreviationsSet; + std::vector> Abbreviations; + std::vector DWARF4TUVector; + std::vector DWARF4CUVector; + BumpPtrAllocator DIEAlloc; + + /// 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, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + DWARFUnit *&RefCU, + DWARFDebugInfoEntry &DwarfDebugInfoEntry, + const std::vector &DUOffsetList); + + /// Clone one attribute according the format. \return the size of this + /// attribute. + uint32_t + cloneAttribute(DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, + const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + unsigned AttrSize, bool IsLittleEndian, + std::vector &DUOffsetList); + + /// Clone an attribute in string format. + uint32_t cloneStringAttribute( + DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + unsigned AttrSize, const DWARFFormValue &Val, const DWARFUnit &U); + + /// Clone an attribute in reference format. + uint32_t cloneDieReferenceAttribute( + DIE &Die, const DWARFDie &InputDIE, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, unsigned AttrSize, + const DWARFFormValue &Val, DWARFUnit &U, + std::vector &DUOffsetList); + + /// Clone an attribute in block format. + uint32_t + cloneBlockAttribute(DIE &Die, DWARFUnit &U, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize, + bool IsLittleEndian); + + /// Clone an attribute in expression format. \p OutputBuffer will hold the + /// output content. + void cloneExpression(DataExtractor &Data, DWARFExpression &Expression, + DWARFUnit &U, SmallVectorImpl &OutputBuffer); + + /// Clone an attribute in address format. + uint32_t + cloneAddressAttribute(DIE &Die, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, const DWARFUnit &U); + + /// Clone an attribute in Refsig format. + uint32_t + cloneRefsigAttribute(DIE &Die, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + unsigned AttrSize, const DWARFFormValue &Val); + + /// Clone an attribute in scalar format. + uint32_t + cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize); + + /// Clone an attribute in loclist format. + uint32_t + cloneLoclistAttrubute(DIE &Die, const DWARFDie &InputDIE, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize); + + /// Update the Cross-CU reference offset. + void computeReference(); + + /// Update the Offset and Size of DIE. + uint32_t computeDIEOffset(DWARFUnit &CU, DIE &Die, uint32_t &CurOffset); + + void registerUnit(DWARFUnit &Unit) { + UnitIDMap[&Unit] = DUList.size(); + DUList.push_back(&Unit); + } + + /// \return the unique ID of \p U if it exists. + std::optional getUnitId(DWARFUnit &DU) { + if (UnitIDMap.count(&DU)) + return UnitIDMap[&DU]; + return std::nullopt; + } + + UnitInfo &getUnitInfo(uint32_t UnitId) { return CloneUnitCtxMap[UnitId]; } + + DIEInfo &getDIEInfo(uint32_t UnitId, uint32_t DIEId) { + if (CloneUnitCtxMap[UnitId].DIEId2InfoMap.count(DIEId)) + return *CloneUnitCtxMap[UnitId].DIEId2InfoMap[DIEId]; + + errs() << "BOLT-ERROR: The DIE is not allocated before looking up, some" + << "unexpected corner cases happened.\n"; + return CloneUnitCtxMap[UnitId].DieInfoList.front(); + } + + UnitInfo &getUnitInfoByDwarfUnit(DWARFUnit &DwarfUnit) { + std::optional UnitId = getUnitId(DwarfUnit); + return getUnitInfo(*UnitId); + } + + std::optional getAllocDIEId(DWARFUnit &DU, DWARFDie &DDie) { + UnitInfo &UnitInfo = getUnitInfoByDwarfUnit(DU); + uint64_t Offset = DDie.getOffset(); + + if (!UnitInfo.DIEIDMap.count(Offset)) + return std::nullopt; + return UnitInfo.DIEIDMap[Offset]; + } + + std::optional getAllocDIEId(DWARFUnit &DU, uint64_t Offset) { + UnitInfo &UnitInfo = getUnitInfoByDwarfUnit(DU); + + if (!UnitInfo.DIEIDMap.count(Offset)) + return std::nullopt; + return UnitInfo.DIEIDMap[Offset]; + } + + // To avoid overhead, do not use this unless we do get the UnitInfo first. + // We can use getDIEInfo with UnitId and DieId + DIEInfo &getDIEInfoByDwarfDie(DWARFDie *DwarfDie) { + DWARFUnit *DwarfUnit = DwarfDie->getDwarfUnit(); + std::optional UnitId = getUnitId(*DwarfUnit); + std::optional hasDIEId = getAllocDIEId(*DwarfUnit, *DwarfDie); + assert(hasDIEId.has_value()); + + return getDIEInfo(*UnitId, *hasDIEId); + } + + std::optional allocDIE(DWARFUnit &DU, DWARFDie &DDie, + BumpPtrAllocator &Alloc, uint32_t UId, + uint32_t offset = 0); + + uint32_t AllocDIEId(DWARFUnit &DU) { + UnitInfo &UnitInfo = getUnitInfoByDwarfUnit(DU); + return UnitInfo.NewDieId++; + } + + /// Construct IR for \p DU. \p DUOffsetList specific the Unit in current + /// Section. + void constructFromUnit(DWARFUnit &DU, std::vector &DUOffsetList); + + /// Construct a DIE for \p DDie in \p U. \p DUOffsetList specific the Unit in + /// current Section. + DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, bool IsLittleEndian, + uint32_t UnitId, + std::vector &DUOffsetList); + +public: + DIEBuilder(DWARFContext *DwarfContext, bool IsDWO = false); + + std::vector getDIEsByUnit(DWARFUnit &DU) { return UnitDIEs[&DU]; } + std::vector> &getAbbrevs() { + return Abbreviations; + } + DIE *getTypeDIE(DWARFUnit &DU) { + if (TypeDIEMap.count(&DU)) + return 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 !IsBuilt; } + + DIE *getUnitDIEbyUnit(DWARFUnit &DU) { + assert(UnitDIEs.count(&DU) && UnitDIEs[&DU].size() && + "DU is not constructed in IR"); + return UnitDIEs[&DU].front(); + } + + /// Generate and populate all Abbrevs. + void generateAbbrevs(); + void generateUnitAbbrevs(DIE *die); + void assignAbbrev(DIEAbbrev &Abbrev); + + /// Finish current DIE construction. + void finish(); + + // Interface to edit DIE + template T *allocateDIEValue() { return new (DIEAlloc) T; } + + DIEValueList::value_iterator addValue(DIEValueList *Die, const DIEValue &V) { + return Die->addValue(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)); + } + + template + bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, + dwarf::Form Form, T &&NewValue) { + return Die->replaceValue(DIEAlloc, Attribute, Form, + std::forward(NewValue)); + } + + template + bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, + dwarf::Attribute NewAttribute, dwarf::Form Form, + T &&NewValue) { + return Die->replaceValue(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); + } + + template + bool deleteValue(DIEValueList *Die, dwarf::Attribute Attribute) { + return Die->deleteValue(Attribute); + } +}; +} // namespace bolt +} // namespace llvm + +#endif 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 @@ -10,10 +10,14 @@ #define BOLT_REWRITE_DWARF_REWRITER_H #include "bolt/Core/DebugData.h" +#include "bolt/Rewrite/DIEBuilder.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/MC/MCAsmLayout.h" #include #include #include +#include #include #include #include @@ -89,15 +93,28 @@ std::mutex LocListDebugInfoPatchesMutex; + /// Dwo id specific its .debug_info.dwo section content. + std::unordered_map DwoDebufInfoMap; + + /// Dwo id specific its .debug_abbrev.dwo section content. + std::unordered_map DwoDebugAbbrevMap; + + /// Dwo id specific its .debug_types.dwo section content. + std::unordered_map DwoDebugTypeMap; + + /// Dwo id specific its RangesBase. + std::unordered_map DwoRangesBase; + + std::unordered_map LineTablePatchMap; + std::unordered_map TypeUnitRelocMap; + /// DWARFLegacy is all DWARF versions before DWARF 5. enum class DWARFVersion { DWARFLegacy, DWARF5 }; /// Update debug info for all DIEs in \p Unit. - void updateUnitDebugInfo(DWARFUnit &Unit, - DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter, + void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr, DebugLocWriter &DebugLocWriter, - DebugRangesSectionWriter &RangesWriter, + DebugRangesSectionWriter &RangesSectionWriter, std::optional RangesBase = std::nullopt); /// Patches the binary for an object's address ranges to be updated. @@ -110,16 +127,15 @@ /// \p RangesBase if present, update \p DIE to use DW_AT_GNU_ranges_base /// attribute. void updateDWARFObjectAddressRanges( - const DWARFDie DIE, uint64_t DebugRangesOffset, - SimpleBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter, - uint64_t LowPCToUse, std::optional RangesBase = std::nullopt); + DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, + uint64_t DebugRangesOffset, uint64_t LowPCToUse, + std::optional RangesBase = std::nullopt); std::unique_ptr - makeFinalLocListsSection(DebugInfoBinaryPatcher &DebugInfoPatcher, - DWARFVersion Version); + makeFinalLocListsSection(DWARFVersion Version); /// Finalize debug sections in the main binary. - CUOffsetMap finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher); + CUOffsetMap finalizeDebugSections(DIEBuilder &DIEBlder); /// Patches the binary for DWARF address ranges (e.g. in functions and lexical /// blocks) to be updated. @@ -170,8 +186,9 @@ /// Updates to the DIE should be synced with abbreviation updates using the /// function above. void convertToRangesPatchDebugInfo( - DWARFDie DIE, uint64_t RangesSectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher, uint64_t LowPCToUse, + DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, + uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo, + DIEValue &HighPCAttrInfo, uint64_t LowPCToUse, std::optional RangesBase = std::nullopt); /// Helper function for creating and returning per-DWO patchers/writers. @@ -194,9 +211,8 @@ /// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using /// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets /// for this contribution of \p Unit. - void addStringHelper(DebugInfoBinaryPatcher &DebugInfoPatcher, - const DWARFUnit &Unit, const AttrInfo &AttrInfoVal, - StringRef Str); + void addStringHelper(DIEBuilder &DIEBldr, DIE &Die, const DWARFUnit &Unit, + DIEValue &DIEAttrInfo, StringRef Str); public: DWARFRewriter(BinaryContext &BC) : BC(BC) {} @@ -237,6 +253,36 @@ return Iter == LocListWritersByCU.end() ? nullptr : LocListWritersByCU[DWOId].get(); } + + StringRef getDwoDebugInfoStr(uint64_t DWOId) { + return DwoDebufInfoMap[DWOId]; + } + + StringRef getDwoDebugAbbrevStr(uint64_t DWOId) { + return DwoDebugAbbrevMap[DWOId]; + } + + StringRef getDwoDebugTypeStr(uint64_t DWOId) { + return DwoDebugTypeMap[DWOId]; + } + + uint64_t getDwoRangesBase(uint64_t DWOId) { return DwoRangesBase[DWOId]; } + + void setDwoDebugInfoStr(uint64_t DWOId, StringRef Str) { + DwoDebufInfoMap[DWOId] = Str.str(); + } + + void setDwoDebugAbbrevStr(uint64_t DWOId, StringRef Str) { + DwoDebugAbbrevMap[DWOId] = Str.str(); + } + + void setDwoDebugTypeStr(uint64_t DWOId, StringRef Str) { + DwoDebugTypeMap[DWOId] = Str.str(); + } + + void setDwoRangesBase(uint64_t DWOId, uint64_t RangesBase) { + DwoRangesBase[DWOId] = RangesBase; + } }; } // namespace bolt diff --git a/bolt/lib/Core/CMakeLists.txt b/bolt/lib/Core/CMakeLists.txt --- a/bolt/lib/Core/CMakeLists.txt +++ b/bolt/lib/Core/CMakeLists.txt @@ -5,6 +5,7 @@ MCDisassembler Object Support + AsmPrinter TargetParser ) 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 @@ -12,14 +12,18 @@ #include "bolt/Core/DebugData.h" #include "bolt/Core/BinaryContext.h" +#include "bolt/Rewrite/DIEBuilder.h" #include "bolt/Rewrite/RewriteInstance.h" #include "bolt/Utils/Utils.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectStreamer.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/LEB128.h" @@ -43,6 +47,16 @@ namespace bolt { +static void replaceLocValbyForm(DIEBuilder &DIEBldr, DIE &Die, DIEValue DIEVal, + dwarf::Form Format, uint64_t NewVal) { + if (Format == dwarf::DW_FORM_loclistx) + DIEBldr.replaceValue(&Die, DIEVal.getAttribute(), Format, + DIELocList(NewVal)); + else + DIEBldr.replaceValue(&Die, DIEVal.getAttribute(), Format, + DIEInteger(NewVal)); +} + std::optional findAttributeInfo(const DWARFDie DIE, const DWARFAbbreviationDeclaration *AbbrevDecl, @@ -580,12 +594,11 @@ } uint32_t DebugLocWriter::LocSectionOffset = 0; -void DebugLocWriter::addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, - DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter) { - const uint64_t AttrOffset = AttrVal.Offset; +void DebugLocWriter::addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo, + DebugLocationsVector &LocList) { if (LocList.empty()) { - DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); + replaceLocValbyForm(DIEBldr, Die, AttrInfo, AttrInfo.getForm(), + DebugLocWriter::EmptyListOffset); return; } // Since there is a separate DebugLocWriter for each thread, @@ -605,8 +618,9 @@ } LocStream->write_zeros(16); LocSectionOffset += 16; - LocListDebugInfoPatches.push_back({AttrOffset, EntryOffset}); - DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); + LocListDebugInfoPatches.push_back({0xdeadbeee, EntryOffset}); // never seen + // use + replaceLocValbyForm(DIEBldr, Die, AttrInfo, AttrInfo.getForm(), EntryOffset); } std::unique_ptr DebugLocWriter::getBuffer() { @@ -614,8 +628,7 @@ } // DWARF 4: 2.6.2 -void DebugLocWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter) {} +void DebugLocWriter::finalize(DIEBuilder &DIEBldr, DIE &Die) {} static void writeEmptyListDwarf5(raw_svector_ostream &Stream) { support::endian::write(Stream, static_cast(4), support::little); @@ -629,14 +642,15 @@ Stream, static_cast(dwarf::DW_LLE_end_of_list), support::little); } -static void writeLegacyLocList(AttrInfo &AttrVal, DebugLocationsVector &LocList, - DebugInfoBinaryPatcher &DebugInfoPatcher, +static void writeLegacyLocList(DIEValue &AttrInfo, + DebugLocationsVector &LocList, + DIEBuilder &DIEBldr, DIE &Die, DebugAddrWriter &AddrWriter, - DebugBufferVector &LocBuffer, DWARFUnit &CU, + DebugBufferVector LocBuffer, DWARFUnit &CU, raw_svector_ostream &LocStream) { - const uint64_t AttrOffset = AttrVal.Offset; if (LocList.empty()) { - DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); + replaceLocValbyForm(DIEBldr, Die, AttrInfo, AttrInfo.getForm(), + DebugLocWriter::EmptyListOffset); return; } @@ -659,21 +673,20 @@ support::endian::write(LocStream, static_cast(dwarf::DW_LLE_end_of_list), support::little); - DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); -} - -static void writeDWARF5LocList( - uint32_t &NumberOfEntries, AttrInfo &AttrVal, DebugLocationsVector &LocList, - DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter, - DebugAddrWriter &AddrWriter, DebugBufferVector &LocBodyBuffer, - std::vector &RelativeLocListOffsets, DWARFUnit &CU, - raw_svector_ostream &LocBodyStream) { - if (AttrVal.V.getForm() != dwarf::DW_FORM_loclistx) { - AbbrevWriter.addAttributePatch(CU, AttrVal.AbbrevDecl, - dwarf::DW_AT_location, dwarf::DW_AT_location, - dwarf::DW_FORM_loclistx); - } - DebugInfoPatcher.addUDataPatch(AttrVal.Offset, NumberOfEntries, AttrVal.Size); + replaceLocValbyForm(DIEBldr, Die, AttrInfo, AttrInfo.getForm(), EntryOffset); +} + +static void writeDWARF5LocList(uint32_t &NumberOfEntries, DIEValue &AttrInfo, + DebugLocationsVector &LocList, DIE &Die, + DIEBuilder &DIEBldr, DebugAddrWriter &AddrWriter, + DebugBufferVector &LocBodyBuffer, + std::vector &RelativeLocListOffsets, + DWARFUnit &CU, + raw_svector_ostream &LocBodyStream) { + + replaceLocValbyForm(DIEBldr, Die, AttrInfo, dwarf::DW_FORM_loclistx, + NumberOfEntries); + RelativeLocListOffsets.push_back(LocBodyBuffer.size()); ++NumberOfEntries; if (LocList.empty()) { @@ -716,30 +729,29 @@ support::little); } -void DebugLoclistWriter::addList(AttrInfo &AttrVal, - DebugLocationsVector &LocList, - DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter) { +void DebugLoclistWriter::addList(DIEBuilder &DIEBldr, DIE &Die, + DIEValue &AttrInfo, + DebugLocationsVector &LocList) { if (DwarfVersion < 5) - writeLegacyLocList(AttrVal, LocList, DebugInfoPatcher, *AddrWriter, - *LocBuffer, CU, *LocStream); + writeLegacyLocList(AttrInfo, LocList, DIEBldr, Die, *AddrWriter, *LocBuffer, + CU, *LocStream); else - writeDWARF5LocList(NumberOfEntries, AttrVal, LocList, DebugInfoPatcher, - AbbrevWriter, *AddrWriter, *LocBodyBuffer, - RelativeLocListOffsets, CU, *LocBodyStream); + writeDWARF5LocList(NumberOfEntries, AttrInfo, LocList, Die, DIEBldr, + *AddrWriter, *LocBodyBuffer, RelativeLocListOffsets, CU, + *LocBodyStream); } uint32_t DebugLoclistWriter::LoclistBaseOffset = 0; -void DebugLoclistWriter::finalizeDWARF5( - DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter) { +void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) { if (LocBodyBuffer->empty()) { - std::optional AttrInfoVal = - findAttributeInfo(CU.getUnitDIE(), dwarf::DW_AT_loclists_base); + DIEValue LocListBaseAttrInfo = + Die.findAttribute(dwarf::DW_AT_loclists_base); // Pointing to first one, because it doesn't matter. There are no uses of it // in this CU. - if (!isSplitDwarf() && AttrInfoVal) - DebugInfoPatcher.addLE32Patch(AttrInfoVal->Offset, - getDWARF5RngListLocListHeaderSize()); + if (!isSplitDwarf() && LocListBaseAttrInfo.getType()) + DIEBldr.replaceValue(&Die, dwarf::DW_AT_loclists_base, + LocListBaseAttrInfo.getForm(), + DIEInteger(getDWARF5RngListLocListHeaderSize())); return; } @@ -764,17 +776,16 @@ *LocStream << *LocBodyBuffer; if (!isSplitDwarf()) { - if (std::optional AttrInfoVal = - findAttributeInfo(CU.getUnitDIE(), dwarf::DW_AT_loclists_base)) - DebugInfoPatcher.addLE32Patch(AttrInfoVal->Offset, - LoclistBaseOffset + - getDWARF5RngListLocListHeaderSize()); - else { - AbbrevWriter.addAttribute( - CU, CU.getUnitDIE().getAbbreviationDeclarationPtr(), - dwarf::DW_AT_loclists_base, dwarf::DW_FORM_sec_offset); - DebugInfoPatcher.insertNewEntry(CU.getUnitDIE(), - LoclistBaseOffset + Header->size()); + DIEValue LocListBaseAttrInfo = + Die.findAttribute(dwarf::DW_AT_loclists_base); + if (LocListBaseAttrInfo.getType()) { + DIEBldr.replaceValue( + &Die, dwarf::DW_AT_loclists_base, LocListBaseAttrInfo.getForm(), + DIEInteger(LoclistBaseOffset + getDWARF5RngListLocListHeaderSize())); + } else { + DIEBldr.addValue(&Die, dwarf::DW_AT_loclists_base, + dwarf::DW_FORM_sec_offset, + DIEInteger(LoclistBaseOffset + Header->size())); } LoclistBaseOffset += LocBuffer->size(); } @@ -783,10 +794,9 @@ clearList(*LocBodyBuffer); } -void DebugLoclistWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter) { +void DebugLoclistWriter::finalize(DIEBuilder &DIEBldr, DIE &Die) { if (DwarfVersion >= 5) - finalizeDWARF5(DebugInfoPatcher, AbbrevWriter); + finalizeDWARF5(DIEBldr, Die); } DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr; diff --git a/bolt/lib/Rewrite/CMakeLists.txt b/bolt/lib/Rewrite/CMakeLists.txt --- a/bolt/lib/Rewrite/CMakeLists.txt +++ b/bolt/lib/Rewrite/CMakeLists.txt @@ -5,6 +5,9 @@ MC Object Support + DWARFLinker + AsmPrinter + BinaryFormat TargetParser ) @@ -15,6 +18,7 @@ ExecutableFileMemoryManager.cpp MachORewriteInstance.cpp RewriteInstance.cpp + DIEBuilder.cpp DISABLE_LLVM_LINK_LLVM_DYLIB diff --git a/bolt/lib/Rewrite/DIEBuilder.cpp b/bolt/lib/Rewrite/DIEBuilder.cpp new file mode 100644 --- /dev/null +++ b/bolt/lib/Rewrite/DIEBuilder.cpp @@ -0,0 +1,713 @@ +#include "bolt/Rewrite/DIEBuilder.h" +#include "bolt/Core/BinaryContext.h" +#include "bolt/Core/ParallelUtilities.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/ObjectYAML/DWARFYAML.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/ThreadPool.h" +#include "llvm/Support/YAMLTraits.h" + +#include +#include +#include +#include +#include +#include + +#undef DEBUG_TYPE +#define DEBUG_TYPE "bolt" +namespace llvm { +namespace bolt { + +void DIEBuilder::computeReference() { + for (auto &[SrcDIEInfo, ReferenceInfo] : ForwardReferences) { + DIEInfo *DstDIEInfo = ReferenceInfo.Dst; + UnitInfo &DstUnitInfo = getUnitInfo(DstDIEInfo->UnitId); + dwarf::Attribute Attr = ReferenceInfo.AttrSpec.Attr; + dwarf::Form Form = ReferenceInfo.AttrSpec.Form; + uint64_t CUBase = 0; + + // If DWARF 4, type unit is store in .debug_types. So we need to calibrate + // the begin of .debug_info to the first Compile Unit offset. + if (!DWARF4CUVector.empty()) { + UnitInfo &FirstCUInfo = getUnitInfoByDwarfUnit(*DWARF4CUVector.front()); + CUBase = FirstCUInfo.UnitOffset; + } + + uint64_t NewAddr = + DstDIEInfo->Die->getOffset() + DstUnitInfo.UnitOffset - CUBase; + SrcDIEInfo->Die->replaceValue(DIEAlloc, Attr, Form, DIEInteger(NewAddr)); + } + + return; +} + +std::optional DIEBuilder::allocDIE(DWARFUnit &DU, DWARFDie &DDie, + BumpPtrAllocator &Alloc, + uint32_t UId, uint32_t offset) { + auto &UnitInfo = getUnitInfo(UId); + auto DDieOffset = DDie.getOffset(); + if (UnitInfo.DIEIDMap.count(DDieOffset)) + return UnitInfo.DIEIDMap[DDieOffset]; + uint32_t DId = AllocDIEId(DU); + + DIE *Die = DIE::get(Alloc, dwarf::Tag(DDie.getTag())); + UnitInfo.DIEIDMap[DDieOffset] = DId; + UnitInfo.DieInfoList.push_back(DIEInfo{Die, DId, UId, offset}); + UnitInfo.DIEId2InfoMap[DId] = &UnitInfo.DieInfoList.back(); + + return DId; +} + +void DIEBuilder::constructFromUnit(DWARFUnit &DU, + std::vector &DUOffsetList) { + std::optional UnitId = getUnitId(DU); + if (!UnitId.has_value()) { + errs() << "BOLT-WARNING: " << format("Skip Unit at 0x%x\n", DU.getOffset()); + return; + } + + const uint32_t UnitHeaderSize = DU.getHeaderSize(); + uint64_t DIEOffset = DU.getOffset() + UnitHeaderSize; + uint64_t NextCUOffset = DU.getNextUnitOffset(); + DWARFDataExtractor DebugInfoData = DU.getDebugInfoExtractor(); + DWARFDebugInfoEntry DIEEntry; + std::vector CurParentDIEStack; + std::vector Parents; + uint32_t TUTypeOffset = 0; + bool IsTypeDIE = false; + bool IsCUDIE = true; + + if (DWARFTypeUnit *TU = dyn_cast_or_null(&DU)) { + TUTypeOffset = TU->getTypeOffset(); + } + + assert(DebugInfoData.isValidOffset(NextCUOffset - 1)); + Parents.push_back(UINT32_MAX); + do { + if (TUTypeOffset == DIEOffset - DU.getOffset()) { + IsTypeDIE = true; + } + + if (!DIEEntry.extractFast(DU, &DIEOffset, DebugInfoData, NextCUOffset, + Parents.back())) + break; + + if (const DWARFAbbreviationDeclaration *AbbrDecl = + DIEEntry.getAbbreviationDeclarationPtr()) { + DWARFDie DDie(&DU, &DIEEntry); + + DIE *CurDIE = constructDIEFast(DDie, DU, DU.getContext().isLittleEndian(), + *UnitId, DUOffsetList); + if (IsTypeDIE) { + TypeDIEMap[&DU] = CurDIE; + IsTypeDIE = false; + } + + if (!CurParentDIEStack.empty()) + CurParentDIEStack.back()->addChild(CurDIE); + + if (AbbrDecl->hasChildren()) { + CurParentDIEStack.push_back(CurDIE); + } else if (IsCUDIE) { + // Stop if we have single compile unit die w/o children. + break; + } + } else { + // NULL DIE: finishes current children scope. + CurParentDIEStack.pop_back(); + } + + if (IsCUDIE) + IsCUDIE = false; + } while (CurParentDIEStack.size() > 0); + + CloneUnitCtxMap[*UnitId].Isconstructed = true; +} + +DIEBuilder::DIEBuilder(DWARFContext *DwarfContext, bool IsDWO) { + outs() << "BOLT-INFO: Constructing DIE...\n"; + IsBuilt = true; + + 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); + } + } + + uint32_t MaxVersion = + IsDWO ? DwarfContext->getMaxDWOVersion() : DwarfContext->getMaxVersion(); + unsigned int CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits() + : DwarfContext->getNumCompileUnits(); + DWARFContext::compile_unit_range CU4Ranges = + IsDWO ? DwarfContext->dwo_compile_units() : DwarfContext->compile_units(); + DWARFContext::unit_iterator_range CU5Ranges = + IsDWO ? DwarfContext->dwo_info_section_units() + : DwarfContext->info_section_units(); + + if (MaxVersion >= 5) { + CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits() + + DwarfContext->getNumDWOTypeUnits() + : DwarfContext->getNumCompileUnits() + + DwarfContext->getNumTypeUnits(); + } + + CloneUnitCtxMap = std::vector(CUNum); + + if (MaxVersion >= 5) { + for (std::unique_ptr &DU : CU5Ranges) { + if (!DU.get()) + continue; + registerUnit(*DU.get()); + } + for (std::unique_ptr &DU : CU5Ranges) { + if (!DU.get()) + continue; + constructFromUnit(*DU.get(), DUList); + } + } else { + DWARFContext::unit_iterator_range CU4TURanges = + IsDWO ? DwarfContext->dwo_types_section_units() + : DwarfContext->types_section_units(); + for (std::unique_ptr &DU : CU4TURanges) { + CloneUnitCtxMap.resize(CloneUnitCtxMap.size() + 1); + registerUnit(*DU.get()); + DWARF4TUVector.push_back(DU.get()); + } + for (std::unique_ptr &DU : CU4TURanges) { + constructFromUnit(*DU.get(), DWARF4TUVector); + } + + for (std::unique_ptr &DU : CU4Ranges) { + registerUnit(*DU.get()); + DWARF4CUVector.push_back(DU.get()); + } + for (std::unique_ptr &DU : CU4Ranges) { + constructFromUnit(*DU.get(), DWARF4CUVector); + } + } + outs() << "BOLT-INFO: Finish constructing DIE\n"; +} + +DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U, + bool IsLittleEndian, uint32_t UnitId, + std::vector &DUOffsetList) { + + std::optional Idx = getAllocDIEId(U, DDie); + if (Idx.has_value()) { + UnitInfo &UnitInfo = getUnitInfo(UnitId); + DIEInfo &DieInfo = getDIEInfo(UnitId, *Idx); + if (UnitInfo.Isconstructed && DieInfo.Die) + return DieInfo.Die; + } else { + Idx = allocDIE(U, DDie, DIEAlloc, UnitId); + } + + DIEInfo &DieInfo = getDIEInfo(UnitId, *Idx); + DIE *Die = DieInfo.Die; + UnitDIEs[&U].push_back(Die); + + uint64_t Offset = DDie.getOffset(); + uint64_t NextOffset = Offset; + DWARFDataExtractor Data = U.getDebugInfoExtractor(); + DWARFDebugInfoEntry DDIEntry; + + if (DDIEntry.extractFast(U, &NextOffset, Data, U.getNextUnitOffset(), 0)) { + assert(NextOffset - U.getOffset() <= Data.getData().size() && + "NextOffset OOB"); + } + + SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset)); + Data = + DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); + Offset = 0; + + const DWARFAbbreviationDeclaration *Abbrev = + DDie.getAbbreviationDeclarationPtr(); + Offset += getULEB128Size(Abbrev->getCode()); + + for (const auto &AttrSpec : Abbrev->attributes()) { + DWARFFormValue Val(AttrSpec.Form); + uint64_t AttrSize = Offset; + Val.extractValue(Data, &Offset, U.getFormParams(), &U); + AttrSize = Offset - AttrSize; + cloneAttribute(*Die, DDie, U, Val, AttrSpec, AttrSize, IsLittleEndian, + DUOffsetList); + } + return Die; +} + +static DWARFUnit *getUnitForOffset(const std::vector &Units, + 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; +} + +uint32_t DIEBuilder::computeDIEOffset(DWARFUnit &CU, DIE &Die, + uint32_t &CurOffset) { + uint32_t CurSize = 0; + + Die.setOffset(CurOffset); + for (DIEValue &Val : Die.values()) { + CurSize += Val.sizeOf(CU.getFormParams()); + } + CurSize += getULEB128Size(Die.getAbbrevNumber()); + CurOffset += CurSize; + + for (DIE &Child : Die.children()) { + uint32_t ChildSize = computeDIEOffset(CU, Child, CurOffset); + CurSize += ChildSize; + } + // for children end mark. + if (Die.hasChildren()) { + CurSize += sizeof(uint8_t); + CurOffset += sizeof(uint8_t); + } + + Die.setSize(CurSize); + + return CurSize; +} + +void DIEBuilder::finish() { + uint64_t UnitStartOffset = 0; + + for (DWARFUnit *CU : DUList) { + DIE *UnitDIE = getUnitDIEbyUnit(*CU); + uint32_t HeaderSize = CU->getHeaderSize(); + uint32_t CurOffset = HeaderSize; + computeDIEOffset(*CU, *UnitDIE, CurOffset); + + UnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(*CU); + CurUnitInfo.UnitOffset = UnitStartOffset; + UnitStartOffset += HeaderSize + UnitDIE->getSize(); + } + + computeReference(); +} + +DWARFDie DIEBuilder::resolveDIEReference( + const DWARFFormValue &RefValue, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, DWARFUnit *&RefCU, + DWARFDebugInfoEntry &DwarfDebugInfoEntry, + const std::vector &DUOffsetList) { + assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); + uint64_t RefOffset = *RefValue.getAsReference(); + + if ((RefCU = getUnitForOffset(DUOffsetList, RefOffset))) { + DWARFDataExtractor DebugInfoData = RefCU->getDebugInfoExtractor(); + if (DwarfDebugInfoEntry.extractFast(*RefCU, &RefOffset, DebugInfoData, + RefCU->getNextUnitOffset(), 0)) { + // In a file with broken references, an attribute might point to a NULL + // DIE. + DWARFDie RefDie = DWARFDie(RefCU, &DwarfDebugInfoEntry); + if (!RefDie.isNULL()) { + std::optional UnitId = getUnitId(*RefCU); + + // forward reference + if (UnitId.has_value() && !CloneUnitCtxMap[*UnitId].Isconstructed) { + std::optional IsAllocId = getAllocDIEId(*RefCU, RefDie); + if (!IsAllocId.has_value()) { + // forward reference but need allocate a empty one + IsAllocId = allocDIE(*RefCU, RefDie, DIEAlloc, *UnitId); + } + + uint32_t DIEId = *IsAllocId; + DIEInfo &DieInfo = getDIEInfo(*UnitId, DIEId); + DieInfo.CanonicalDIEOffset = 0xDEADBEEF; + } + return RefDie; + } + } + } + + llvm_unreachable("could not find referenced CU\n"); + return DWARFDie(); +} + +uint32_t DIEBuilder::cloneDieReferenceAttribute( + DIE &Die, const DWARFDie &InputDIE, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, unsigned AttrSize, + const DWARFFormValue &Val, DWARFUnit &U, + std::vector &DUOffsetList) { + uint64_t Ref = *Val.getAsReference(); + + DIE *NewRefDie = nullptr; + DWARFUnit *RefUnit = nullptr; + + DWARFDebugInfoEntry DDIEntry; + DWARFDie RefDie = + resolveDIEReference(Val, AttrSpec, RefUnit, DDIEntry, DUOffsetList); + + if (!RefDie || AttrSpec.Attr == dwarf::DW_AT_sibling) + return 0; + + std::optional UnitId = getUnitId(*RefUnit); + std::optional IsAllocId = getAllocDIEId(*RefUnit, RefDie); + if (!IsAllocId.has_value()) + llvm_unreachable( + "[error] encounter unexpected unallocated DIE. Should be alloc!"); + uint32_t DIEId = *IsAllocId; + DIEInfo &DieInfo = getDIEInfo(*UnitId, DIEId); + + if (!DieInfo.Die) { + assert(Ref > InputDIE.getOffset()); + llvm_unreachable( + "[error] encounter unexpected unallocated DIE. Should be alloc!"); + // 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())); + } + NewRefDie = DieInfo.Die; + + if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) { + // no matter forward reference or backward reference, we are supposed + // to calculate them in `finish` due to the possible modification of + // the DIE. + DWARFDie CurDie = const_cast(InputDIE); + DIEInfo *CurDieInfo = &getDIEInfoByDwarfDie(&CurDie); + ForwardReferences.push_back( + std::make_pair(CurDieInfo, ForwardReferenceInfo(&DieInfo, AttrSpec))); + + Die.addValue(DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_addr, + DIEInteger(0xDEADBEEF)); + return U.getRefAddrByteSize(); + } + + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), DIEEntry(*NewRefDie)); + + return AttrSize; +} + +uint32_t DIEBuilder::cloneStringAttribute( + DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + unsigned AttrSize, const DWARFFormValue &Val, const DWARFUnit &U) { + if (AttrSpec.Form == dwarf::DW_FORM_string) { + auto StrAddr = Val.getAsCString(); + if (!StrAddr) { + consumeError(StrAddr.takeError()); + return AttrSize; + } + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::DW_FORM_string, + new (DIEAlloc) DIEInlineString(StrAddr.get(), DIEAlloc)); + } else { + std::optional OffsetIndex = Val.getRawUValue(); + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), AttrSpec.Form, + DIEInteger(*OffsetIndex)); + } + return AttrSize; +} + +void DIEBuilder::cloneExpression(DataExtractor &Data, + DWARFExpression &Expression, DWARFUnit &U, + SmallVectorImpl &OutputBuffer) { + using Encoding = DWARFExpression::Operation::Encoding; + + uint64_t OpOffset = 0; + for (auto &Op : Expression) { + auto Description = Op.getDescription(); + // DW_OP_const_type is variable-length and has 3 + // operands. DWARFExpression thus far only supports 2. + auto Op0 = Description.Op[0]; + auto Op1 = Description.Op[1]; + if ((Op0 == Encoding::BaseTypeRef && Op1 != Encoding::SizeNA) || + (Op1 == Encoding::BaseTypeRef && Op0 != Encoding::Size1)) + outs() << "BOLT-INFO: Unsupported DW_OP encoding.\n"; + + if ((Op0 == Encoding::BaseTypeRef && Op1 == Encoding::SizeNA) || + (Op1 == Encoding::BaseTypeRef && Op0 == Encoding::Size1)) { + // This code assumes that the other non-typeref operand fits into 1 + // byte. + assert(OpOffset < Op.getEndOffset()); + uint32_t ULEBsize = Op.getEndOffset() - OpOffset - 1; + assert(ULEBsize <= 16); + + // Copy over the operation. + OutputBuffer.push_back(Op.getCode()); + uint64_t RefOffset; + if (Op1 == Encoding::SizeNA) { + RefOffset = Op.getRawOperand(0); + } else { + OutputBuffer.push_back(Op.getRawOperand(0)); + RefOffset = Op.getRawOperand(1); + } + uint32_t Offset = 0; + if (RefOffset > 0 || Op.getCode() != dwarf::DW_OP_convert) { + DWARFDie RefDie = U.getDIEForOffset(RefOffset); + std::optional RefDieID = getAllocDIEId(U, RefOffset); + std::optional RefUnitID = getUnitId(U); + if (RefDieID.has_value() && RefUnitID.has_value()) { + DIEInfo &RefDieInfo = getDIEInfo(*RefUnitID, *RefDieID); + if (DIE *Clone = RefDieInfo.Die) + Offset = RefDie.getOffset(); + else + errs() << "BOLT-WARNING: base type ref doesn't point to " + "DW_TAG_base_type.\n"; + } + } + uint8_t ULEB[16]; + unsigned RealSize = encodeULEB128(Offset, ULEB, ULEBsize); + if (RealSize > ULEBsize) { + // Emit the generic type as a fallback. + RealSize = encodeULEB128(0, ULEB, ULEBsize); + errs() << "BOLT-WARNING: base type ref doesn't fit.\n"; + } + assert(RealSize == ULEBsize && "padding failed"); + ArrayRef ULEBbytes(ULEB, ULEBsize); + OutputBuffer.append(ULEBbytes.begin(), ULEBbytes.end()); + } else { + // Copy over everything else unmodified. + StringRef Bytes = Data.getData().slice(OpOffset, Op.getEndOffset()); + OutputBuffer.append(Bytes.begin(), Bytes.end()); + } + OpOffset = Op.getEndOffset(); + } +} + +uint32_t DIEBuilder::cloneBlockAttribute( + DIE &Die, DWARFUnit &U, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize, bool IsLittleEndian) { + DIEValueList *Attr; + DIEValue Value; + DIELoc *Loc = nullptr; + DIEBlock *Block = nullptr; + + if (AttrSpec.Form == dwarf::DW_FORM_exprloc) { + Loc = new (DIEAlloc) DIELoc; + } else if (doesFormBelongToClass(AttrSpec.Form, DWARFFormValue::FC_Block, + U.getVersion())) { + Block = new (DIEAlloc) DIEBlock; + } else { + errs() << "BOLT-WARNING: Unexpected Form value in " + "cloneBlockAttribute\n"; + return 0; + } + Attr = Loc ? static_cast(Loc) + : static_cast(Block); + + if (Loc) + Value = DIEValue(dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), Loc); + else + Value = DIEValue(dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), Block); + + SmallVector Buffer; + ArrayRef Bytes = *Val.getAsBlock(); + if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) && + (Val.isFormClass(DWARFFormValue::FC_Block) || + Val.isFormClass(DWARFFormValue::FC_Exprloc))) { + DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()), + IsLittleEndian, U.getAddressByteSize()); + DWARFExpression Expr(Data, U.getAddressByteSize(), + U.getFormParams().Format); + cloneExpression(Data, Expr, U, Buffer); + Bytes = Buffer; + } + for (auto Byte : Bytes) + Attr->addValue(DIEAlloc, static_cast(0), + dwarf::DW_FORM_data1, DIEInteger(Byte)); + + if (Loc) + Loc->setSize(Bytes.size()); + else + Block->setSize(Bytes.size()); + + Die.addValue(DIEAlloc, Value); + return AttrSize; +} + +uint32_t DIEBuilder::cloneAddressAttribute( + DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, const DWARFUnit &U) { + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), DIEInteger(Val.getRawUValue())); + return U.getAddressByteSize(); +} + +uint32_t DIEBuilder::cloneRefsigAttribute( + DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + unsigned AttrSize, const DWARFFormValue &Val) { + std::optional SigVal = Val.getRawUValue(); + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::DW_FORM_ref_sig8, DIEInteger(*SigVal)); + return AttrSize; +} + +uint32_t DIEBuilder::cloneScalarAttribute( + DIE &Die, const DWARFDie &InputDIE, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize) { + uint64_t Value; + + if (auto OptionalValue = Val.getAsUnsignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSectionOffset()) + Value = *OptionalValue; + else { + errs() << "BOLT-WARNING: Unsupported scalar attribute form. Dropping " + "attribute.\n"; + return 0; + } + + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), DIEInteger(Value)); + return AttrSize; +} + +uint32_t DIEBuilder::cloneLoclistAttrubute( + DIE &Die, const DWARFDie &InputDIE, + DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize) { + uint64_t Value; + + if (auto OptionalValue = Val.getAsUnsignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSignedConstant()) + Value = *OptionalValue; + else if (auto OptionalValue = Val.getAsSectionOffset()) + Value = *OptionalValue; + else { + errs() << "BOLT-WARNING: Unsupported scalar attribute form. Dropping " + "attribute.\n"; + return 0; + } + + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::Form(AttrSpec.Form), DIELocList(Value)); + return AttrSize; +} + +uint32_t DIEBuilder::cloneAttribute( + DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, const DWARFFormValue &Val, + const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, + unsigned AttrSize, bool IsLittleEndian, + std::vector &DUOffsetList) { + switch (AttrSpec.Form) { + case dwarf::DW_FORM_strp: + case dwarf::DW_FORM_string: + case dwarf::DW_FORM_strx: + case dwarf::DW_FORM_strx1: + case dwarf::DW_FORM_strx2: + case dwarf::DW_FORM_strx3: + case dwarf::DW_FORM_strx4: + case dwarf::DW_FORM_GNU_str_index: + case dwarf::DW_FORM_line_strp: + return cloneStringAttribute(Die, AttrSpec, AttrSize, Val, U); + case dwarf::DW_FORM_ref_addr: + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_ref2: + case dwarf::DW_FORM_ref4: + case dwarf::DW_FORM_ref8: + return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, U, + DUOffsetList); + case dwarf::DW_FORM_block: + case dwarf::DW_FORM_block1: + case dwarf::DW_FORM_block2: + case dwarf::DW_FORM_block4: + case dwarf::DW_FORM_exprloc: + return cloneBlockAttribute(Die, U, AttrSpec, Val, AttrSize, IsLittleEndian); + case dwarf::DW_FORM_addr: + case dwarf::DW_FORM_addrx: + case dwarf::DW_FORM_GNU_addr_index: + return cloneAddressAttribute(Die, AttrSpec, Val, U); + case dwarf::DW_FORM_data1: + case dwarf::DW_FORM_data2: + case dwarf::DW_FORM_data4: + case dwarf::DW_FORM_data8: + case dwarf::DW_FORM_udata: + case dwarf::DW_FORM_sdata: + case dwarf::DW_FORM_sec_offset: + case dwarf::DW_FORM_rnglistx: + case dwarf::DW_FORM_flag: + case dwarf::DW_FORM_flag_present: + case dwarf::DW_FORM_implicit_const: + return cloneScalarAttribute(Die, InputDIE, AttrSpec, Val, AttrSize); + case dwarf::DW_FORM_loclistx: + return cloneLoclistAttrubute(Die, InputDIE, AttrSpec, Val, AttrSize); + case dwarf::DW_FORM_ref_sig8: + return cloneRefsigAttribute(Die, AttrSpec, AttrSize, Val); + default: + std::string Msg = "Unsupported attribute form " + + dwarf::FormEncodingString(AttrSpec.Form).str() + + " in cloneAttribute. Dropping."; + llvm_unreachable(Msg.c_str()); + } + + return 0; +} +void DIEBuilder::assignAbbrev(DIEAbbrev &Abbrev) { + // Check the set for priors. + FoldingSetNodeID ID; + Abbrev.Profile(ID); + void *InsertToken; + DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken); + + // If it's newly added. + if (InSet) { + // Assign existing abbreviation number. + Abbrev.setNumber(InSet->getNumber()); + } else { + // Add to abbreviation list. + Abbreviations.push_back( + std::make_unique(Abbrev.getTag(), Abbrev.hasChildren())); + for (const auto &Attr : Abbrev.getData()) + Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm()); + AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken); + // Assign the unique abbreviation number. + Abbrev.setNumber(Abbreviations.size()); + Abbreviations.back()->setNumber(Abbreviations.size()); + } +} + +void DIEBuilder::generateAbbrevs() { + if (!IsBuilt) + return; + + for (DWARFUnit *DU : DUList) { + DIE *UnitDIE = getUnitDIEbyUnit(*DU); + generateUnitAbbrevs(UnitDIE); + } +} + +void DIEBuilder::generateUnitAbbrevs(DIE *Die) { + DIEAbbrev NewAbbrev = Die->generateAbbrev(); + + if (Die->hasChildren()) + NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); + assignAbbrev(NewAbbrev); + Die->setAbbrevNumber(NewAbbrev.getNumber()); + + for (auto &Child : Die->children()) { + generateUnitAbbrevs(&Child); + } +} + +} // namespace bolt +} // namespace llvm 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 @@ -10,16 +10,25 @@ #include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Core/DebugData.h" +#include "bolt/Core/DynoStats.h" #include "bolt/Core/ParallelUtilities.h" +#include "bolt/Rewrite/DIEBuilder.h" #include "bolt/Rewrite/RewriteInstance.h" #include "bolt/Utils/Utils.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/DWARFLinker/DWARFStreamer.h" #include "llvm/DWP/DWP.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCContext.h" @@ -35,14 +44,18 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/raw_ostream.h" #include #include +#include +#include +#include #include #include #include #include -#undef DEBUG_TYPE +#undef DEBUG_TYPE #define DEBUG_TYPE "bolt" LLVM_ATTRIBUTE_UNUSED @@ -57,6 +70,123 @@ namespace llvm { namespace bolt { + +class DIEStreamer : public DwarfStreamer { + DIEBuilder *DIEBldr; + +private: + DIE *findTypeDIE(DWARFUnit &TU) { return DIEBldr->getTypeDIE(TU); } + + /// Emit the compilation unit header for \p Unit in the debug_info + /// section. + /// + /// A Dwarf 4 section header is encoded as: + /// uint32_t Unit length (omitting this field) + /// uint16_t Version + /// uint32_t Abbreviation table offset + /// uint8_t Address size + /// Leading to a total of 11 bytes. + /// + /// A Dwarf 5 section header is encoded as: + /// uint32_t Unit length (omitting this field) + /// uint16_t Version + /// uint8_t Unit type + /// uint8_t Address size + /// uint32_t Abbreviation table offset + /// Leading to a total of 12 bytes. + void emitCompileUnitHeader(DWARFUnit &Unit, DIE &UnitDIE, + unsigned DwarfVersion) { + + AsmPrinter &Asm = getAsmPrinter(); + switchToDebugInfoSection(DwarfVersion); + + emitCommonHeader(Unit, UnitDIE, DwarfVersion); + + if (DwarfVersion >= 5 && + Unit.getUnitType() != dwarf::UnitType::DW_UT_compile) { + std::optional DWOId = Unit.getDWOId(); + assert(DWOId && + "DWOId does not exist and this is not a DW_UT_compile Unit"); + Asm.emitInt64(*DWOId); + } + } + + void emitCommonHeader(DWARFUnit &Unit, DIE &UnitDIE, uint16_t Version) { + dwarf::UnitType UT = dwarf::UnitType(Unit.getUnitType()); + llvm::AsmPrinter &Asm = getAsmPrinter(); + + // Emit size of content not including length itself + Asm.emitInt32(Unit.getHeaderSize() + UnitDIE.getSize() - 4); + Asm.emitInt16(Version); + + // DWARF v5 reorders the address size and adds a unit type. + if (Version >= 5) { + Asm.emitInt8(UT); + Asm.emitInt8(Asm.MAI->getCodePointerSize()); + } + + Asm.emitInt32(0); + if (Version <= 4) { + Asm.emitInt8(Asm.MAI->getCodePointerSize()); + } + } + + void emitTypeUnitHeader(DWARFUnit &Unit, DIE &UnitDIE, + unsigned DwarfVersion) { + + AsmPrinter &Asm = getAsmPrinter(); + + if (Unit.getVersion() < 5) { + // Switch the section to .debug_types section. + std::unique_ptr &MS = Asm.OutStreamer; + llvm::MCContext &MC = Asm.OutContext; + const llvm::MCObjectFileInfo *MOFI = MC.getObjectFileInfo(); + + MS->switchSection(MOFI->getDwarfTypesSection(0)); + MC.setDwarfVersion(DwarfVersion); + } else + switchToDebugInfoSection(DwarfVersion); + + DWARFTypeUnit *DTU = dyn_cast_or_null(&Unit); + assert(DTU && Unit.isTypeUnit() && + "Emit TypeUnit header but not a type unit"); + + const uint64_t TypeSignature = DTU->getTypeHash(); + DIE *TypeDIE = findTypeDIE(Unit); + + emitCommonHeader(Unit, UnitDIE, DwarfVersion); + Asm.OutStreamer->emitIntValue(TypeSignature, sizeof(TypeSignature)); + Asm.emitDwarfLengthOrOffset(TypeDIE ? TypeDIE->getOffset() : 0); + } + + void emitUnitHeader(DWARFUnit &Unit, DIE &UnitDIE) { + if (Unit.isTypeUnit()) + emitTypeUnitHeader(Unit, UnitDIE, Unit.getVersion()); + else + emitCompileUnitHeader(Unit, UnitDIE, Unit.getVersion()); + } + + void emitDIE(DIE &Die) override { + AsmPrinter &Asm = getAsmPrinter(); + Asm.emitDwarfDIE(Die); + } + +public: + DIEStreamer(DIEBuilder *DIEBldr, OutputFileType OutFileType, + raw_pwrite_stream &OutFile, + std::function Translator, + messageHandler Error, messageHandler Warning) + : DwarfStreamer(OutFileType, OutFile, Translator, Error, Warning), + DIEBldr(DIEBldr){}; + + using DwarfStreamer::emitCompileUnitHeader; + + void emitUnit(DWARFUnit &Unit, DIE &UnitDIE) { + emitUnitHeader(Unit, UnitDIE); + emitDIE(UnitDIE); + } +}; + /// Finds attributes FormValue and Offset. /// /// \param DIE die to look up in. @@ -69,6 +199,7 @@ return Info; return std::nullopt; } + } // namespace bolt } // namespace llvm @@ -115,6 +246,71 @@ cl::cat(BoltCategory)); } // namespace opts +static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU, + uint64_t &LowPC, uint64_t &HighPC, + uint64_t &SectionIndex) { + DIEValue DvalLowPc = Die.findAttribute(dwarf::DW_AT_low_pc); + DIEValue DvalHighPc = Die.findAttribute(dwarf::DW_AT_high_pc); + if (!DvalLowPc || !DvalHighPc) + return false; + + dwarf::Form Form = DvalLowPc.getForm(); + bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset; + uint64_t LowPcValue = DvalLowPc.getDIEInteger().getValue(); + if (Form == dwarf::DW_FORM_GNU_addr_index || Form == dwarf::DW_FORM_addrx || + AddrOffset) { + + uint32_t Index = AddrOffset ? (LowPcValue >> 32) : LowPcValue; + std::optional SA = + DU.getAddrOffsetSectionItem(Index); + if (!SA) + return false; + if (AddrOffset) + SA->Address += (LowPcValue & 0xffffffff); + + LowPC = SA->Address; + SectionIndex = SA->SectionIndex; + } else { + LowPC = LowPcValue; + SectionIndex = 0; + } + if (DvalHighPc.getForm() == dwarf::DW_FORM_addr) + HighPC = DvalHighPc.getDIEInteger().getValue(); + else + HighPC = LowPC + DvalHighPc.getDIEInteger().getValue(); + + return true; +} + +static Expected +getDIEAddressRanges(const DIE &Die, DWARFUnit &DU) { + uint64_t LowPC, HighPC, Index; + if (getLowAndHighPC(Die, DU, LowPC, HighPC, Index)) + return DWARFAddressRangesVector{{LowPC, HighPC, Index}}; + if (DIEValue Dval = Die.findAttribute(dwarf::DW_AT_ranges)) { + if (Dval.getForm() == dwarf::DW_FORM_rnglistx) + return DU.findRnglistFromIndex(Dval.getDIEInteger().getValue()); + + return DU.findRnglistFromOffset(Dval.getDIEInteger().getValue()); + } + + return DWARFAddressRangesVector(); +} + +static std::optional +getAsSectionedAddress(const DWARFUnit &DU, const DIEValue &AttrVal) { + DWARFFormValue::ValueType Value(AttrVal.getDIEInteger().getValue()); + return DWARFFormValue::getAsSectionedAddress(Value, AttrVal.getForm(), &DU); +} + +static std::optional getAsAddress(const DWARFUnit &DU, + const DIEValue &AttrVal) { + if (std::optional SA = + getAsSectionedAddress(DU, AttrVal)) + return SA->Address; + return std::nullopt; +} + /// Returns DWO Name to be used. Handles case where user specifies output DWO /// directory, and there are duplicate names. Assumes DWO ID is unique. static std::string @@ -145,17 +341,36 @@ return DWOName; } -void DWARFRewriter::addStringHelper(DebugInfoBinaryPatcher &DebugInfoPatcher, +static void emitUnit(DIEBuilder &DIEBldr, + std::unique_ptr &Streamer, DWARFUnit &Unit) { + DIE *UnitDIE = DIEBldr.getUnitDIEbyUnit(Unit); + Streamer->emitUnit(Unit, *UnitDIE); +} + +static std::unique_ptr +createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile, + StringRef Swift5ReflectionSegmentName, DIEBuilder &DIEBldr) { + + std::unique_ptr Streamer = std::make_unique( + &DIEBldr, OutputFileType::Object, OutFile, + [](StringRef Input) -> StringRef { return Input; }, + [&](const Twine &Error, StringRef Context, const DWARFDie *) {}, + [&](const Twine &Warning, StringRef Context, const DWARFDie *) {}); + Streamer->init(TheTriple, Swift5ReflectionSegmentName); + return Streamer; +} + +void DWARFRewriter::addStringHelper(DIEBuilder &DIEBldr, DIE &Die, const DWARFUnit &Unit, - const AttrInfo &AttrInfoVal, - StringRef Str) { + DIEValue &DIEAttrInfo, StringRef Str) { uint32_t NewOffset = StrWriter->addString(Str); if (Unit.getVersion() == 5) { - StrOffstsWriter->updateAddressMap(AttrInfoVal.V.getRawUValue(), NewOffset); + StrOffstsWriter->updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(), + NewOffset); return; } - DebugInfoPatcher.addLE32Patch(AttrInfoVal.Offset, NewOffset, - AttrInfoVal.Size); + DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(), + DIEInteger(NewOffset)); } void DWARFRewriter::updateDebugInfo() { @@ -163,16 +378,11 @@ if (!DebugInfo) return; - auto *DebugInfoPatcher = - static_cast(DebugInfo->getPatcher()); - ARangesSectionWriter = std::make_unique(); StrWriter = std::make_unique(BC); StrOffstsWriter = std::make_unique(); - AbbrevWriter = std::make_unique(*BC.DwCtx); - if (!opts::DeterministicDebugInfo) { opts::DeterministicDebugInfo = true; errs() << "BOLT-WARNING: --deterministic-debuginfo is being deprecated\n"; @@ -228,32 +438,32 @@ std::unordered_map DWOIdToName; std::mutex AccessMutex; - auto updateDWONameCompDir = [&](DWARFUnit &Unit) -> void { - const DWARFDie &DIE = Unit.getUnitDIE(); - std::optional AttrInfoVal = findAttributeInfo( - DIE, {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}); - (void)AttrInfoVal; - assert(AttrInfoVal && "Skeleton CU doesn't have dwo_name."); - + auto updateDWONameCompDir = [&](DWARFUnit &Unit, DIEBuilder &DIEBldr, + DIE &UnitDIE) -> void { + DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name); + if (!DWONameAttrInfo) + DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name); + assert(DWONameAttrInfo && "DW_AT_dwo_name is not in Skeleton CU."); std::string ObjectName; { std::lock_guard Lock(AccessMutex); ObjectName = getDWOName(Unit, &NameToIndexMap, DWOIdToName); } - addStringHelper(*DebugInfoPatcher, Unit, *AttrInfoVal, ObjectName.c_str()); + addStringHelper(DIEBldr, UnitDIE, Unit, DWONameAttrInfo, + ObjectName.c_str()); - AttrInfoVal = findAttributeInfo(DIE, dwarf::DW_AT_comp_dir); - (void)AttrInfoVal; - assert(AttrInfoVal && "DW_AT_comp_dir is not in Skeleton CU."); + DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir); + assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU."); if (!opts::DwarfOutputPath.empty()) { - addStringHelper(*DebugInfoPatcher, Unit, *AttrInfoVal, + addStringHelper(DIEBldr, UnitDIE, Unit, CompDirAttrInfo, opts::DwarfOutputPath.c_str()); } }; - auto processUnitDIE = [&](size_t CUIndex, DWARFUnit *Unit) { + auto processUnitDIE = [&](size_t CUIndex, DWARFUnit *Unit, + DIEBuilder *DIEBlder) { // Check if the unit is a skeleton and we need special updates for it and // its matching split/DWO CU. std::optional SplitCU; @@ -270,15 +480,9 @@ : LegacyRangesSectionWriter.get(); // Skipping CUs that failed to load. if (SplitCU) { - updateDWONameCompDir(*Unit); - - DebugInfoBinaryPatcher *DwoDebugInfoPatcher = - llvm::cast( - getBinaryDWODebugInfoPatcher(*DWOId)); - DWARFContext *DWOCtx = BC.getDWOContext(); - // Setting this CU offset with DWP to normalize DIE offsets to uint32_t - if (DWOCtx && !DWOCtx->getCUIndex().getRows().empty()) - DwoDebugInfoPatcher->setDWPOffset((*SplitCU)->getOffset()); + DIEBuilder DwoDIEBlder(&(*SplitCU)->getContext(), true); + updateDWONameCompDir(*Unit, *DIEBlder, + *DIEBlder->getUnitDIEbyUnit(*Unit)); { std::lock_guard Lock(AccessMutex); @@ -291,20 +495,68 @@ RangesBase = RangesSectionWriter->getSectionOffset(); // For DWARF5 there is now .debug_rnglists.dwo, so don't need to // update rnglists base. - DwoDebugInfoPatcher->setRangeBase(*RangesBase); + if (RangesBase) { + DwoRangesBase[*DWOId] = *RangesBase; + setDwoRangesBase(*DWOId, *RangesBase); + } } - DwoDebugInfoPatcher->addUnitBaseOffsetLabel((*SplitCU)->getOffset()); - DebugAbbrevWriter *DWOAbbrevWriter = - createBinaryDWOAbbrevWriter((*SplitCU)->getContext(), *DWOId); - updateUnitDebugInfo(*(*SplitCU), *DwoDebugInfoPatcher, *DWOAbbrevWriter, - *DebugLocWriter, *TempRangesSectionWriter); - DebugLocWriter->finalize(*DwoDebugInfoPatcher, *DWOAbbrevWriter); - DwoDebugInfoPatcher->clearDestinationLabels(); - if (!DwoDebugInfoPatcher->getWasRangBasedUsed()) - RangesBase = std::nullopt; + updateUnitDebugInfo(*(*SplitCU), DwoDIEBlder, *DebugLocWriter, + *TempRangesSectionWriter); + DebugLocWriter->finalize(DwoDIEBlder, + *DwoDIEBlder.getUnitDIEbyUnit(**SplitCU)); if (Unit->getVersion() >= 5) TempRangesSectionWriter->finalizeSection(); + + // populate debug_info and debug_abbrev for current dwo into stringRef. + DwoDIEBlder.generateAbbrevs(); + DwoDIEBlder.finish(); + + SmallVector OutBuffer; + std::shared_ptr ObjOS = + std::make_shared(OutBuffer); + const object::ObjectFile *File = + (*SplitCU)->getContext().getDWARFObj().getFile(); + auto TheTriple = std::make_unique(File->makeTriple()); + std::unique_ptr Streamer = createDIEStreamer( + *TheTriple, *ObjOS, "DwoStreamerInitAug2", DwoDIEBlder); + + if ((*SplitCU)->getContext().getMaxDWOVersion() >= 5) { + for (std::unique_ptr &CU : + (*SplitCU)->getContext().dwo_info_section_units()) + emitUnit(DwoDIEBlder, Streamer, *CU.get()); + } else { + for (std::unique_ptr &CU : + (*SplitCU)->getContext().dwo_compile_units()) + emitUnit(DwoDIEBlder, Streamer, *CU.get()); + + // emit debug_types sections for dwarf4 + for (DWARFUnit *CU : DwoDIEBlder.getDWARF4TUVector()) + emitUnit(DwoDIEBlder, Streamer, *CU); + } + + Streamer->emitAbbrevs(DwoDIEBlder.getAbbrevs(), + (*SplitCU)->getContext().getMaxVersion()); + Streamer->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 &Secs : Obj->sections()) { + StringRef Contents = cantFail(Secs.getContents()); + StringRef Name = cantFail(Secs.getName()); + if (Name.equals(".debug_abbrev")) + setDwoDebugAbbrevStr(*DWOId, Contents); + else if (Name.equals(".debug_info")) + setDwoDebugInfoStr(*DWOId, Contents); + else if (Name.equals(".debug_types")) + setDwoDebugTypeStr(*DWOId, Contents); + } } { @@ -320,30 +572,30 @@ StrOffstsWriter->finalizeSection(*Unit); } - DebugInfoPatcher->addUnitBaseOffsetLabel(Unit->getOffset()); - updateUnitDebugInfo(*Unit, *DebugInfoPatcher, *AbbrevWriter, - *DebugLocWriter, *RangesSectionWriter, RangesBase); - DebugLocWriter->finalize(*DebugInfoPatcher, *AbbrevWriter); + updateUnitDebugInfo(*Unit, *DIEBlder, *DebugLocWriter, *RangesSectionWriter, + RangesBase); + DebugLocWriter->finalize(*DIEBlder, *DIEBlder->getUnitDIEbyUnit(*Unit)); if (Unit->getVersion() >= 5) RangesSectionWriter->finalizeSection(); }; 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()); + for (std::unique_ptr &CU : BC.DwCtx->compile_units()) { + processUnitDIE(CUIndex++, CU.get(), &DIEBlder); + } } else { // Update unit debug info in parallel ThreadPool &ThreadPool = ParallelUtilities::getThreadPool(); for (std::unique_ptr &CU : BC.DwCtx->compile_units()) { - ThreadPool.async(processUnitDIE, CUIndex, CU.get()); + ThreadPool.async(processUnitDIE, CUIndex, CU.get(), &DIEBlder); CUIndex++; } ThreadPool.wait(); } - DebugInfoPatcher->clearDestinationLabels(); - CUOffsetMap OffsetMap = finalizeDebugSections(*DebugInfoPatcher); + CUOffsetMap OffsetMap = finalizeDebugSections(DIEBlder); if (opts::WriteDWP) writeDWP(DWOIdToName); @@ -354,8 +606,7 @@ } void DWARFRewriter::updateUnitDebugInfo( - DWARFUnit &Unit, DebugInfoBinaryPatcher &DebugInfoPatcher, - DebugAbbrevWriter &AbbrevWriter, DebugLocWriter &DebugLocWriter, + DWARFUnit &Unit, DIEBuilder &DIEBldr, DebugLocWriter &DebugLocWriter, DebugRangesSectionWriter &RangesSectionWriter, std::optional RangesBase) { // Cache debug ranges so that the offset for identical ranges could be reused. @@ -363,32 +614,14 @@ uint64_t DIEOffset = Unit.getOffset() + Unit.getHeaderSize(); uint64_t NextCUOffset = Unit.getNextUnitOffset(); - DWARFDebugInfoEntry Die; - DWARFDataExtractor DebugInfoData = Unit.getDebugInfoExtractor(); - uint32_t Depth = 0; + std::vector DIEs = DIEBldr.getDIEsByUnit(Unit); bool IsDWP = false; if (DWARFContext *DWOCtx = BC.getDWOContext()) IsDWP = !DWOCtx->getCUIndex().getRows().empty(); - while ( - DIEOffset < NextCUOffset && - Die.extractFast(Unit, &DIEOffset, DebugInfoData, NextCUOffset, Depth)) { - if (const DWARFAbbreviationDeclaration *AbbrDecl = - Die.getAbbreviationDeclarationPtr()) { - if (AbbrDecl->hasChildren()) - ++Depth; - } else { - // NULL entry. - if (Depth > 0) - --Depth; - if (Depth == 0) - break; - } - - DWARFDie DIE(&Unit, &Die); - - switch (DIE.getTag()) { + for (DIE *Die : DIEs) { + switch (Die->getTag()) { case dwarf::DW_TAG_compile_unit: case dwarf::DW_TAG_skeleton_unit: { // For dwarf5 section 3.1.3 @@ -399,7 +632,7 @@ // DW_AT_addr_base and DW_AT_rnglists_base. if (Unit.getVersion() == 5 && Unit.isDWOUnit()) continue; - auto ModuleRangesOrError = DIE.getAddressRanges(); + auto ModuleRangesOrError = getDIEAddressRanges(*Die, Unit); if (!ModuleRangesOrError) { consumeError(ModuleRangesOrError.takeError()); break; @@ -407,8 +640,7 @@ DWARFAddressRangesVector &ModuleRanges = *ModuleRangesOrError; DebugAddressRangesVector OutputRanges = BC.translateModuleAddressRanges(ModuleRanges); - std::optional LowPCAttrInfo = - findAttributeInfo(DIE, dwarf::DW_AT_low_pc); + DIEValue LowPCAttrInfo = Die->findAttribute(dwarf::DW_AT_low_pc); // For a case where LLD GCs only function used in the CU. // If CU doesn't have DW_AT_low_pc we are not going to convert, // so don't need to do anything. @@ -419,17 +651,27 @@ if (!Unit.isDWOUnit()) ARangesSectionWriter->addCURanges(Unit.getOffset(), std::move(OutputRanges)); - updateDWARFObjectAddressRanges(DIE, RangesSectionOffset, DebugInfoPatcher, - AbbrevWriter, 0, RangesBase); + updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset, + 0, RangesBase); + DIEValue StmtListAttrVal = Die->findAttribute(dwarf::DW_AT_stmt_list); + if (StmtListAttrVal) { + if (LineTablePatchMap.count(&Unit)) { + DIEBldr.replaceValue(Die, dwarf::DW_AT_stmt_list, + StmtListAttrVal.getForm(), + DIEInteger(LineTablePatchMap[&Unit])); + } + } + break; } + case dwarf::DW_TAG_subprogram: { // Get function address either from ranges or [LowPC, HighPC) pair. uint64_t Address; uint64_t SectionIndex, HighPC; - if (!DIE.getLowAndHighPC(Address, HighPC, SectionIndex)) { + if (!getLowAndHighPC(*Die, Unit, Address, HighPC, SectionIndex)) { Expected RangesOrError = - DIE.getAddressRanges(); + getDIEAddressRanges(*Die, Unit); if (!RangesOrError) { consumeError(RangesOrError.takeError()); break; @@ -454,8 +696,8 @@ FunctionRanges.push_back({0, 0}); updateDWARFObjectAddressRanges( - DIE, RangesSectionWriter.addRanges(FunctionRanges), DebugInfoPatcher, - AbbrevWriter, 0); + Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges), + 0); break; } @@ -464,7 +706,8 @@ case dwarf::DW_TAG_try_block: case dwarf::DW_TAG_catch_block: { uint64_t RangesSectionOffset = RangesSectionWriter.getEmptyRangesOffset(); - Expected RangesOrError = DIE.getAddressRanges(); + Expected RangesOrError = + getDIEAddressRanges(*Die, Unit); const BinaryFunction *Function = RangesOrError && !RangesOrError->empty() ? BC.getBinaryFunctionContainingAddress( @@ -477,7 +720,7 @@ Function->translateInputToOutputRanges(*RangesOrError); LLVM_DEBUG(if (OutputRanges.empty() != RangesOrError->empty()) { dbgs() << "BOLT-DEBUG: problem with DIE at 0x" - << Twine::utohexstr(DIE.getOffset()) << " in CU at 0x" + << Twine::utohexstr(Die->getOffset()) << " in CU at 0x" << Twine::utohexstr(Unit.getOffset()) << '\n'; }); if (!OutputRanges.empty()) @@ -499,13 +742,13 @@ LowPCToUse = RangesOrError.get().begin()->LowPC; } - updateDWARFObjectAddressRanges(DIE, RangesSectionOffset, DebugInfoPatcher, - AbbrevWriter, LowPCToUse); + updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset, + LowPCToUse); break; } case dwarf::DW_TAG_call_site: { - auto patchPC = [&](AttrInfo &AttrVal, StringRef Entry) -> void { - std::optional Address = AttrVal.V.getAsAddress(); + auto patchPC = [&](DIE *Die, DIEValue &AttrVal, StringRef Entry) -> void { + std::optional Address = getAsAddress(Unit, AttrVal); const BinaryFunction *Function = BC.getBinaryFunctionContainingAddress(*Address); uint64_t UpdatedAddress = *Address; @@ -513,40 +756,43 @@ UpdatedAddress = Function->translateInputToOutputAddress(UpdatedAddress); - if (AttrVal.V.getForm() == dwarf::DW_FORM_addrx) { + if (AttrVal.getForm() == dwarf::DW_FORM_addrx) { const uint32_t Index = AddrWriter->getIndexFromAddress(UpdatedAddress, Unit); - DebugInfoPatcher.addUDataPatch(AttrVal.Offset, Index, AttrVal.Size); - } else if (AttrVal.V.getForm() == dwarf::DW_FORM_addr) { - DebugInfoPatcher.addLE32Patch(AttrVal.Offset, UpdatedAddress); + DIEBldr.replaceValue(Die, AttrVal.getAttribute(), AttrVal.getForm(), + DIEInteger(Index)); + } else if (AttrVal.getForm() == dwarf::DW_FORM_addr) { + DIEBldr.replaceValue(Die, AttrVal.getAttribute(), AttrVal.getForm(), + DIEInteger(UpdatedAddress)); } else { errs() << "BOLT-ERROR: unsupported form for " << Entry << "\n"; } }; + DIEValue CallPcAttrVal = Die->findAttribute(dwarf::DW_AT_call_pc); + if (CallPcAttrVal) + patchPC(Die, CallPcAttrVal, "DW_AT_call_pc"); - if (std::optional AttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_call_pc)) - patchPC(*AttrVal, "DW_AT_call_pc"); - - if (std::optional AttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_call_return_pc)) - patchPC(*AttrVal, "DW_AT_call_return_pc"); + DIEValue CallRetPcAttrVal = + Die->findAttribute(dwarf::DW_AT_call_return_pc); + if (CallRetPcAttrVal) + patchPC(Die, CallRetPcAttrVal, "DW_AT_call_return_pc"); break; } default: { // Handle any tag that can have DW_AT_location attribute. - DWARFFormValue Value; - uint64_t AttrOffset; - if (std::optional AttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_location)) { - AttrOffset = AttrVal->Offset; - Value = AttrVal->V; - if (Value.isFormClass(DWARFFormValue::FC_Constant) || - Value.isFormClass(DWARFFormValue::FC_SectionOffset)) { - uint64_t Offset = Value.isFormClass(DWARFFormValue::FC_Constant) - ? Value.getAsUnsignedConstant().value() - : Value.getAsSectionOffset().value(); + DIEValue LocAttrInfo = Die->findAttribute(dwarf::DW_AT_location); + DIEValue LowPCAttrInfo = Die->findAttribute(dwarf::DW_AT_low_pc); + if (LocAttrInfo) { + if (doesFormBelongToClass(LocAttrInfo.getForm(), + DWARFFormValue::FC_Constant, + Unit.getVersion()) || + doesFormBelongToClass(LocAttrInfo.getForm(), + DWARFFormValue::FC_SectionOffset, + Unit.getVersion())) { + uint64_t Offset = LocAttrInfo.getForm() == dwarf::DW_FORM_loclistx + ? LocAttrInfo.getDIELocList().getValue() + : LocAttrInfo.getDIEInteger().getValue(); DebugLocationsVector InputLL; std::optional SectionAddress = @@ -556,7 +802,7 @@ BaseAddress = SectionAddress->Address; if (Unit.getVersion() >= 5 && - AttrVal->V.getForm() == dwarf::DW_FORM_loclistx) { + LocAttrInfo.getForm() == dwarf::DW_FORM_loclistx) { std::optional LocOffset = Unit.getLoclistOffset(Offset); assert(LocOffset && "Location Offset is invalid."); Offset = *LocOffset; @@ -622,9 +868,9 @@ if (E || InputLL.empty()) { consumeError(std::move(E)); errs() << "BOLT-WARNING: empty location list detected at 0x" - << Twine::utohexstr(Offset) << " for DIE at 0x" - << Twine::utohexstr(DIE.getOffset()) << " in CU at 0x" - << Twine::utohexstr(Unit.getOffset()) << '\n'; + << Twine::utohexstr(Offset) << " for DIE at 0x" << Die + << " in CU at 0x" << Twine::utohexstr(Unit.getOffset()) + << '\n'; } else { const uint64_t Address = InputLL.front().LowPC; DebugLocationsVector OutputLL; @@ -634,7 +880,7 @@ LLVM_DEBUG(if (OutputLL.empty()) { dbgs() << "BOLT-DEBUG: location list translated to an empty " "one at 0x" - << Twine::utohexstr(DIE.getOffset()) << " in CU at 0x" + << Die << " in CU at 0x" << Twine::utohexstr(Unit.getOffset()) << '\n'; }); } else { @@ -643,33 +889,88 @@ // information. OutputLL = InputLL; } - DebugLocWriter.addList(*AttrVal, OutputLL, DebugInfoPatcher, - AbbrevWriter); + DebugLocWriter.addList(DIEBldr, *Die, LocAttrInfo, OutputLL); } } else { - assert((Value.isFormClass(DWARFFormValue::FC_Exprloc) || - Value.isFormClass(DWARFFormValue::FC_Block)) && + assert((doesFormBelongToClass(LocAttrInfo.getForm(), + DWARFFormValue::FC_Exprloc, + Unit.getVersion()) || + doesFormBelongToClass(LocAttrInfo.getForm(), + DWARFFormValue::FC_Block, + Unit.getVersion())) && "unexpected DW_AT_location form"); if (Unit.isDWOUnit() || Unit.getVersion() >= 5) { - ArrayRef Expr = *Value.getAsBlock(); + std::vector Sblock; + DIEValueList *AttrLocValList; + if (doesFormBelongToClass(LocAttrInfo.getForm(), + DWARFFormValue::FC_Exprloc, + Unit.getVersion())) { + for (const DIEValue &Val : LocAttrInfo.getDIELoc().values()) { + Sblock.push_back(Val.getDIEInteger().getValue()); + } + DIELoc *LocAttr = const_cast(&LocAttrInfo.getDIELoc()); + AttrLocValList = static_cast(LocAttr); + } else { + for (const DIEValue &Val : LocAttrInfo.getDIEBlock().values()) { + Sblock.push_back(Val.getDIEInteger().getValue()); + } + DIEBlock *BlockAttr = + const_cast(&LocAttrInfo.getDIEBlock()); + AttrLocValList = static_cast(BlockAttr); + } + ArrayRef Expr = ArrayRef(Sblock); DataExtractor Data( StringRef((const char *)Expr.data(), Expr.size()), Unit.getContext().isLittleEndian(), 0); DWARFExpression LocExpr(Data, Unit.getAddressByteSize(), Unit.getFormParams().Format); - uint32_t PrevEndOffset = 0; - uint32_t CurrEndOffset = 0; - constexpr uint32_t SizeOfOP = 1; - constexpr uint32_t SizeOfSizeField = 1; - int32_t SizeDiff = 0; - - // Encoding [size of expression] [opcode] [value] [opcode] [value] - for (auto &Expr : LocExpr) { - PrevEndOffset = CurrEndOffset; - CurrEndOffset = Expr.getEndOffset(); + uint32_t PrevOffset = 0; + DIEValueList *NewAttr; + DIEValue Value; + uint32_t NewExprSize = 0; + DIELoc *Loc = nullptr; + DIEBlock *Block = nullptr; + if (LocAttrInfo.getForm() == dwarf::DW_FORM_exprloc) { + Loc = DIEBldr.allocateDIEValue(); + NewAttr = Loc; + Value = DIEValue(LocAttrInfo.getAttribute(), + LocAttrInfo.getForm(), Loc); + } else if (doesFormBelongToClass(LocAttrInfo.getForm(), + DWARFFormValue::FC_Block, + Unit.getVersion())) { + Block = DIEBldr.allocateDIEValue(); + NewAttr = Block; + Value = DIEValue(LocAttrInfo.getAttribute(), + LocAttrInfo.getForm(), Block); + } else { + errs() << "BOLT-WARNING: Unexpected Form value in Updating " + "DW_AT_Location\n"; + continue; + } + + for (const DWARFExpression::Operation &Expr : LocExpr) { + uint32_t CurEndOffset = PrevOffset + 1; + if (Expr.getDescription().Op[0] != + DWARFExpression::Operation::SizeNA) + CurEndOffset = Expr.getOperandEndOffset(0); + if (Expr.getDescription().Op[1] != + DWARFExpression::Operation::SizeNA) + CurEndOffset = Expr.getOperandEndOffset(1); + // not addr index, just copy. if (!(Expr.getCode() == dwarf::DW_OP_GNU_addr_index || - Expr.getCode() == dwarf::DW_OP_addrx)) + Expr.getCode() == dwarf::DW_OP_addrx)) { + auto Itr = AttrLocValList->values().begin(); + std::advance(Itr, PrevOffset); + uint32_t CopyNum = CurEndOffset - PrevOffset; + NewExprSize += CopyNum; + while (CopyNum--) { + DIEBldr.addValue(NewAttr, *Itr); + std::advance(Itr, 1); + } + PrevOffset = CurEndOffset; continue; + } + const uint64_t Index = Expr.getRawOperand(0); std::optional EntryAddress = Unit.getAddrOffsetSectionItem(Index); @@ -677,36 +978,53 @@ assert(Index <= std::numeric_limits::max() && "Invalid Operand Index."); if (Expr.getCode() == dwarf::DW_OP_addrx) { - const uint32_t EncodingSize = CurrEndOffset - PrevEndOffset - 1; const uint32_t Index = AddrWriter->getIndexFromAddress( EntryAddress->Address, Unit); - // Encoding new size. + // update Index for DW_AT_location. The Size field is not stored + // in IR, we need to minus 1 in offset for each expr. SmallString<8> Tmp; raw_svector_ostream OSE(Tmp); encodeULEB128(Index, OSE); - SizeDiff += Tmp.size() - EncodingSize; - DebugInfoPatcher.addUDataPatch(AttrOffset + PrevEndOffset + - SizeOfOP + SizeOfSizeField, - Index, EncodingSize); + + DIEBldr.addValue(NewAttr, static_cast(0), + dwarf::DW_FORM_data1, + DIEInteger(dwarf::DW_OP_addrx)); + NewExprSize += 1; + for (uint8_t Byte : Tmp) { + DIEBldr.addValue(NewAttr, static_cast(0), + dwarf::DW_FORM_data1, DIEInteger(Byte)); + NewExprSize += 1; + } } else { // TODO: Re-do this as DWARF5. + auto Itr = AttrLocValList->values().begin(); + std::advance(Itr, PrevOffset); + uint32_t CopyNum = CurEndOffset - PrevOffset; + NewExprSize += CopyNum; + while (CopyNum--) { + DIEBldr.addValue(NewAttr, *Itr); + std::advance(Itr, 1); + } AddrWriter->addIndexAddress(EntryAddress->Address, static_cast(Index), Unit); } + PrevOffset = CurEndOffset; } - // Update the size of the experssion. - if (SizeDiff) - DebugInfoPatcher.addUDataPatch(AttrOffset, - SizeDiff + CurrEndOffset, 1); + + // update the size since the index might be changed + if (Loc) + Loc->setSize(NewExprSize); + else + Block->setSize(NewExprSize); + DIEBldr.replaceValue(Die, LocAttrInfo.getAttribute(), + LocAttrInfo.getForm(), Value); } } - } else if (std::optional AttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_low_pc)) { - AttrOffset = AttrVal->Offset; - Value = AttrVal->V; - const std::optional Result = Value.getAsAddress(); - if (Result) { - const uint64_t Address = *Result; + } else if (LowPCAttrInfo) { + const std::optional Result = + LowPCAttrInfo.getDIEInteger().getValue(); + if (Result.has_value()) { + const uint64_t Address = Result.value(); uint64_t NewAddress = 0; if (const BinaryFunction *Function = BC.getBinaryFunctionContainingAddress(Address)) { @@ -714,16 +1032,15 @@ LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Fixing low_pc 0x" << Twine::utohexstr(Address) << " for DIE with tag " - << DIE.getTag() << " to 0x" + << Die->getTag() << " to 0x" << Twine::utohexstr(NewAddress) << '\n'); } - dwarf::Form Form = Value.getForm(); + dwarf::Form Form = LowPCAttrInfo.getForm(); assert(Form != dwarf::DW_FORM_LLVM_addrx_offset && "DW_FORM_LLVM_addrx_offset is not supported"); std::lock_guard Lock(DebugInfoPatcherMutex); if (Form == dwarf::DW_FORM_GNU_addr_index) { - const uint64_t Index = Value.getRawUValue(); // If there is no new address, storing old address. // Re-using Index to make implementation easier. // DW_FORM_GNU_addr_index is variable lenght encoding @@ -731,30 +1048,32 @@ // index. // TODO: We can now re-write .debug_info. This can be simplified to // just getting a new index and creating a patch. + const uint64_t Index = *Result; AddrWriter->addIndexAddress(NewAddress ? NewAddress : Address, Index, Unit); } else if (Form == dwarf::DW_FORM_addrx) { const uint32_t Index = AddrWriter->getIndexFromAddress( NewAddress ? NewAddress : Address, Unit); - DebugInfoPatcher.addUDataPatch(AttrOffset, Index, AttrVal->Size); + DIEBldr.replaceValue(Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), DIEInteger(Index)); } else { - DebugInfoPatcher.addLE64Patch(AttrOffset, NewAddress); + DIEBldr.replaceValue(Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), + DIEInteger(NewAddress)); } } else if (opts::Verbosity >= 1) { - errs() << "BOLT-WARNING: unexpected form value for attribute at 0x" - << Twine::utohexstr(AttrOffset); + errs() << "BOLT-WARNING: unexpected form value for attribute " + "LowPCAttrInfo\n"; } } else if (IsDWP && Unit.isDWOUnit()) { // Not a common path so don't want to search all DIEs all the time. - std::optional SignatureAttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_signature); - if (!SignatureAttrVal) + DIEValue SignatureAttrInfo = Die->findAttribute(dwarf::DW_AT_signature); + if (!SignatureAttrInfo) continue; // If input is DWP file we need to keep track of which TU came from each // CU, so we can write it out correctly. - if (std::optional Val = - SignatureAttrVal->V.getAsReferenceUVal()) - TypeSignaturesPerCU[*DIE.getDwarfUnit()->getDWOId()].insert(*Val); + if (uint64_t Val = SignatureAttrInfo.getDIEInteger().getValue()) + TypeSignaturesPerCU[*Unit.getDWOId()].insert(Val); else { errs() << "BOT-ERROR: DW_AT_signature form is not supported.\n"; exit(1); @@ -762,39 +1081,6 @@ } } } - - // Handling references. - assert(DIE.isValid() && "Invalid DIE."); - const DWARFAbbreviationDeclaration *AbbrevDecl = - DIE.getAbbreviationDeclarationPtr(); - if (!AbbrevDecl) - continue; - uint32_t Index = 0; - for (const DWARFAbbreviationDeclaration::AttributeSpec &Decl : - AbbrevDecl->attributes()) { - switch (Decl.Form) { - default: - break; - case dwarf::DW_FORM_ref1: - case dwarf::DW_FORM_ref2: - case dwarf::DW_FORM_ref4: - case dwarf::DW_FORM_ref8: - case dwarf::DW_FORM_ref_udata: - case dwarf::DW_FORM_ref_addr: { - std::optional AttrVal = - findAttributeInfo(DIE, AbbrevDecl, Index); - uint32_t DestinationAddress = - AttrVal->V.getRawUValue() + - (Decl.Form == dwarf::DW_FORM_ref_addr ? 0 : Unit.getOffset()); - DebugInfoPatcher.addReferenceToPatch( - AttrVal->Offset, DestinationAddress, AttrVal->Size, Decl.Form); - // We can have only one reference, and it can be backward one. - DebugInfoPatcher.addDestinationReferenceLabel(DestinationAddress); - break; - } - } - ++Index; - } } if (DIEOffset > NextCUOffset) errs() << "BOLT-WARNING: corrupt DWARF detected at 0x" @@ -802,107 +1088,89 @@ } void DWARFRewriter::updateDWARFObjectAddressRanges( - const DWARFDie DIE, uint64_t DebugRangesOffset, - SimpleBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter, + DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, uint64_t DebugRangesOffset, uint64_t LowPCToUse, std::optional RangesBase) { - // Some objects don't have an associated DIE and cannot be updated (such as - // compiler-generated functions). - if (!DIE) - return; - - const DWARFAbbreviationDeclaration *AbbreviationDecl = - DIE.getAbbreviationDeclarationPtr(); - if (!AbbreviationDecl) { - if (opts::Verbosity >= 1) - errs() << "BOLT-WARNING: object's DIE doesn't have an abbreviation: " - << "skipping update. DIE at offset 0x" - << Twine::utohexstr(DIE.getOffset()) << '\n'; - return; - } - if (RangesBase) { // If DW_AT_GNU_ranges_base is present, update it. No further modifications // are needed for ranges base. - std::optional RangesBaseAttrInfo = - findAttributeInfo(DIE, dwarf::DW_AT_GNU_ranges_base); - if (!RangesBaseAttrInfo) - RangesBaseAttrInfo = findAttributeInfo(DIE, dwarf::DW_AT_rnglists_base); - - if (RangesBaseAttrInfo) { - DebugInfoPatcher.addLE32Patch(RangesBaseAttrInfo->Offset, - static_cast(*RangesBase), - RangesBaseAttrInfo->Size); + + DIEValue RangesBaseInfo = Die.findAttribute(dwarf::DW_AT_GNU_ranges_base); + if (!RangesBaseInfo) { + RangesBaseInfo = Die.findAttribute(dwarf::DW_AT_rnglists_base); + } + + if (RangesBaseInfo) { + DIEBldr.replaceValue(&Die, RangesBaseInfo.getAttribute(), + RangesBaseInfo.getForm(), + DIEInteger(static_cast(*RangesBase))); RangesBase = std::nullopt; } } - std::optional LowPCAttrInfo = - findAttributeInfo(DIE, dwarf::DW_AT_low_pc); - if (std::optional AttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_ranges)) { + DIEValue LowPCAttrInfo = Die.findAttribute(dwarf::DW_AT_low_pc); + DIEValue RangesAttrInfo = Die.findAttribute(dwarf::DW_AT_ranges); + if (RangesAttrInfo) { // Case 1: The object was already non-contiguous and had DW_AT_ranges. // In this case we simply need to update the value of DW_AT_ranges // and introduce DW_AT_GNU_ranges_base if required. - std::lock_guard Lock(DebugInfoPatcherMutex); // For DWARF5 converting all of DW_AT_ranges into DW_FORM_rnglistx - bool Converted = false; - if (DIE.getDwarfUnit()->getVersion() >= 5 && - AttrVal->V.getForm() == dwarf::DW_FORM_sec_offset) { - AbbrevWriter.addAttributePatch(*DIE.getDwarfUnit(), AbbreviationDecl, - dwarf::DW_AT_ranges, dwarf::DW_AT_ranges, - dwarf::DW_FORM_rnglistx); - Converted = true; + bool NeedConverted = false; + + if (Unit.getVersion() >= 5 && + RangesAttrInfo.getForm() == dwarf::DW_FORM_sec_offset) + NeedConverted = true; + + uint64_t CurRangeBase = 0; + if (std::optional DWOId = Unit.getDWOId()) { + CurRangeBase = getDwoRangesBase(*DWOId); } - if (Converted || AttrVal->V.getForm() == dwarf::DW_FORM_rnglistx) - DebugInfoPatcher.addUDataPatch(AttrVal->Offset, DebugRangesOffset, - AttrVal->Size); + if (NeedConverted || RangesAttrInfo.getForm() == dwarf::DW_FORM_rnglistx) + DIEBldr.replaceValue(&Die, dwarf::DW_AT_ranges, dwarf::DW_FORM_rnglistx, + DIEInteger(DebugRangesOffset)); else - DebugInfoPatcher.addLE32Patch( - AttrVal->Offset, DebugRangesOffset - DebugInfoPatcher.getRangeBase(), - AttrVal->Size); + DIEBldr.replaceValue(&Die, dwarf::DW_AT_ranges, RangesAttrInfo.getForm(), + DIEInteger(DebugRangesOffset - CurRangeBase)); if (!RangesBase) { if (LowPCAttrInfo && - LowPCAttrInfo->V.getForm() != dwarf::DW_FORM_GNU_addr_index && - LowPCAttrInfo->V.getForm() != dwarf::DW_FORM_addrx) - DebugInfoPatcher.addLE64Patch(LowPCAttrInfo->Offset, LowPCToUse); + LowPCAttrInfo.getForm() != dwarf::DW_FORM_GNU_addr_index && + LowPCAttrInfo.getForm() != dwarf::DW_FORM_addrx) + DIEBldr.replaceValue(&Die, dwarf::DW_AT_low_pc, LowPCAttrInfo.getForm(), + DIEInteger(LowPCToUse)); return; } - if (DIE.getOffset() != DIE.getDwarfUnit()->getUnitDIE().getOffset()) + if (!(Die.getTag() == dwarf::DW_TAG_compile_unit || + Die.getTag() == dwarf::DW_TAG_skeleton_unit)) return; // If we are at this point we are in the CU/Skeleton CU, and // DW_AT_GNU_ranges_base or DW_AT_rnglists_base doesn't exist. - if (DIE.getDwarfUnit()->getVersion() >= 5) { - AbbrevWriter.addAttribute(*DIE.getDwarfUnit(), AbbreviationDecl, - dwarf::DW_AT_rnglists_base, - dwarf::DW_FORM_sec_offset); - } else { - AbbrevWriter.addAttribute(*DIE.getDwarfUnit(), AbbreviationDecl, - dwarf::DW_AT_GNU_ranges_base, - dwarf::DW_FORM_sec_offset); - } - reinterpret_cast(DebugInfoPatcher) - .insertNewEntry(DIE, *RangesBase); - + if (Unit.getVersion() < 4) + DIEBldr.addValue(&Die, dwarf::DW_AT_GNU_ranges_base, dwarf::DW_FORM_data4, + DIEInteger(*RangesBase)); + else if (Unit.getVersion() == 5) + DIEBldr.addValue(&Die, dwarf::DW_AT_rnglists_base, + dwarf::DW_FORM_sec_offset, DIEInteger(*RangesBase)); + else + DIEBldr.addValue(&Die, dwarf::DW_AT_rnglists_base, + dwarf::DW_FORM_sec_offset, DIEInteger(*RangesBase)); return; } // Case 2: The object has both DW_AT_low_pc and DW_AT_high_pc emitted back // to back. Replace with new attributes and patch the DIE. - std::optional HighPCAttrInfo = - findAttributeInfo(DIE, dwarf::DW_AT_high_pc); + DIEValue HighPCAttrInfo = Die.findAttribute(dwarf::DW_AT_high_pc); if (LowPCAttrInfo && HighPCAttrInfo) { - convertToRangesPatchAbbrev(*DIE.getDwarfUnit(), AbbreviationDecl, - AbbrevWriter, RangesBase); - convertToRangesPatchDebugInfo(DIE, DebugRangesOffset, DebugInfoPatcher, - LowPCToUse, RangesBase); + + convertToRangesPatchDebugInfo(Unit, DIEBldr, Die, DebugRangesOffset, + LowPCAttrInfo, HighPCAttrInfo, LowPCToUse, + RangesBase); } else { if (opts::Verbosity >= 1) - errs() << "BOLT-ERROR: cannot update ranges for DIE at offset 0x" - << Twine::utohexstr(DIE.getOffset()) << '\n'; + errs() << "BOLT-ERROR: cannot update ranges for DIE in Unit offset 0x" + << Unit.getOffset() << '\n'; } } @@ -915,15 +1183,6 @@ BC.DwCtx->getNumTypeUnits() == 0) && "Was not able to retrieve Debug Types section."); - // We will be re-writing .debug_info so relocation mechanism doesn't work for - // Debug Info Patcher. - DebugInfoBinaryPatcher *DebugInfoPatcher = nullptr; - if (BC.DwCtx->getNumCompileUnits()) { - DbgInfoSection->registerPatcher(std::make_unique()); - DebugInfoPatcher = - static_cast(DbgInfoSection->getPatcher()); - } - // There is no direct connection between CU and TU, but same offsets, // encoded in DW_AT_stmt_list, into .debug_line get modified. // We take advantage of that to map original CU line table offsets to new @@ -938,26 +1197,16 @@ return *Offset; }; - const uint64_t Reloc32Type = BC.isAArch64() - ? static_cast(ELF::R_AARCH64_ABS32) - : static_cast(ELF::R_X86_64_32); - for (const std::unique_ptr &CU : BC.DwCtx->compile_units()) { const unsigned CUID = CU->getOffset(); MCSymbol *Label = BC.getDwarfLineTable(CUID).getLabel(); if (!Label) continue; - std::optional AttrVal = - findAttributeInfo(CU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list); - if (!AttrVal) - continue; - - const uint64_t AttributeOffset = AttrVal->Offset; const uint64_t LineTableOffset = Layout.getSymbolOffset(*Label); DebugLineOffsetMap[GetStatementListValue(CU.get())] = LineTableOffset; assert(DbgInfoSection && ".debug_info section must exist"); - DebugInfoPatcher->addLE32Patch(AttributeOffset, LineTableOffset); + LineTablePatchMap[CU.get()] = LineTableOffset; } for (const std::unique_ptr &TU : BC.DwCtx->types_section_units()) { @@ -966,12 +1215,10 @@ findAttributeInfo(TU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list); if (!AttrVal) continue; - const uint64_t AttributeOffset = AttrVal->Offset; auto Iter = DebugLineOffsetMap.find(GetStatementListValue(Unit)); assert(Iter != DebugLineOffsetMap.end() && "Type Unit Updated Line Number Entry does not exist."); - TypeInfoSection->addRelocation(AttributeOffset, nullptr, Reloc32Type, - Iter->second, 0, /*Pending=*/true); + TypeUnitRelocMap[Unit] = Iter->second; } // Set .debug_info as finalized so it won't be skipped over when @@ -984,8 +1231,7 @@ TypeInfoSection->setIsFinalized(); } -CUOffsetMap -DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) { +CUOffsetMap DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder) { if (StrWriter->isInitialized()) { RewriteInstance::addToDebugSectionsToOverwrite(".debug_str"); std::unique_ptr DebugStrSectionContents = @@ -1022,7 +1268,7 @@ if (BC.isDWARF5Used()) { std::unique_ptr LocationListSectionContents = - makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARF5); + makeFinalLocListsSection(DWARFVersion::DWARF5); if (!LocationListSectionContents->empty()) BC.registerOrUpdateNoteSection( ".debug_loclists", copyByteArray(*LocationListSectionContents), @@ -1031,7 +1277,7 @@ if (BC.isDWARFLegacyUsed()) { std::unique_ptr LocationListSectionContents = - makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARFLegacy); + makeFinalLocListsSection(DWARFVersion::DWARFLegacy); if (!LocationListSectionContents->empty()) BC.registerOrUpdateNoteSection( ".debug_loc", copyByteArray(*LocationListSectionContents), @@ -1045,98 +1291,109 @@ BC.registerOrUpdateNoteSection(".debug_addr", copyByteArray(AddressSectionContents), AddressSectionContents.size()); - for (auto &CU : BC.DwCtx->compile_units()) { - DWARFDie DIE = CU->getUnitDIE(); + for (std::unique_ptr &CU : BC.DwCtx->compile_units()) { + DIE *Die = DIEBlder.getUnitDIEbyUnit(*CU.get()); uint64_t Offset = 0; - uint64_t AttrOffset = 0; - uint32_t Size = 0; - std::optional AttrValGnu = - findAttributeInfo(DIE, dwarf::DW_AT_GNU_addr_base); - std::optional AttrVal = - findAttributeInfo(DIE, dwarf::DW_AT_addr_base); - + 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 (!AttrValGnu && CU->getVersion() < 5) + if (!GnuAddrBaseAttrInfo && CU->getVersion() < 5) continue; - if (!AttrVal && CU->getVersion() >= 5 && !AddrWriter->doesCUExist(*CU)) + if (!AddrBaseAttrInfo && CU->getVersion() >= 5 && + !AddrWriter->doesCUExist(*CU)) continue; Offset = AddrWriter->getOffset(*CU); - if (AttrValGnu) { - AttrOffset = AttrValGnu->Offset; - Size = AttrValGnu->Size; + if (GnuAddrBaseAttrInfo) { + BaseAttrForm = GnuAddrBaseAttrInfo.getForm(); + BaseAttr = GnuAddrBaseAttrInfo.getAttribute(); } - if (AttrVal) { - AttrOffset = AttrVal->Offset; - Size = AttrVal->Size; + if (AddrBaseAttrInfo) { + BaseAttrForm = AddrBaseAttrInfo.getForm(); + BaseAttr = AddrBaseAttrInfo.getAttribute(); } - if (AttrValGnu || AttrVal) { - DebugInfoPatcher.addLE32Patch(AttrOffset, static_cast(Offset), - Size); + 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. - const DWARFAbbreviationDeclaration *Abbrev = - DIE.getAbbreviationDeclarationPtr(); - AbbrevWriter->addAttribute(*CU, Abbrev, dwarf::DW_AT_addr_base, - dwarf::DW_FORM_sec_offset); - DebugInfoPatcher.insertNewEntry(DIE, static_cast(Offset)); + DIEBlder.addValue(Die, dwarf::DW_AT_addr_base, + dwarf::DW_FORM_sec_offset, DIEInteger(Offset)); } } } - std::unique_ptr AbbrevSectionContents = - AbbrevWriter->finalize(); - BC.registerOrUpdateNoteSection(".debug_abbrev", - copyByteArray(*AbbrevSectionContents), - AbbrevSectionContents->size()); - - // Update abbreviation offsets for CUs/TUs if they were changed. - SimpleBinaryPatcher *DebugTypesPatcher = nullptr; - for (auto &Unit : BC.DwCtx->normal_units()) { - const uint64_t NewAbbrevOffset = - AbbrevWriter->getAbbreviationsOffsetForUnit(*Unit); - if (Unit->getAbbreviationsOffset() == NewAbbrevOffset) + // 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()])); + } - // DWARFv4 or earlier - // unit_length - 4 bytes - // version - 2 bytes - // So + 6 to patch debug_abbrev_offset - constexpr uint64_t AbbrevFieldOffsetLegacy = 6; - // DWARFv5 - // unit_length - 4 bytes - // version - 2 bytes - // unit_type - 1 byte - // address_size - 1 byte - // So + 8 to patch debug_abbrev_offset - constexpr uint64_t AbbrevFieldOffsetV5 = 8; - uint64_t AbbrevOffset = - Unit->getVersion() >= 5 ? AbbrevFieldOffsetV5 : AbbrevFieldOffsetLegacy; - if (!Unit->isTypeUnit() || Unit->getVersion() >= 5) { - DebugInfoPatcher.addLE32Patch(Unit->getOffset() + AbbrevOffset, - static_cast(NewAbbrevOffset)); - continue; - } + // 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); + + // generate debug_info and CUMap + CUOffsetMap CUMap; + uint32_t CUOffset = 0; + for (std::unique_ptr &CU : BC.DwCtx->compile_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}; + } - if (!DebugTypesPatcher) { - ErrorOr DebugTypes = - BC.getUniqueSectionByName(".debug_types"); - DebugTypes->registerPatcher(std::make_unique()); - DebugTypesPatcher = - static_cast(DebugTypes->getPatcher()); - } - DebugTypesPatcher->addLE32Patch(Unit->getOffset() + AbbrevOffset, - static_cast(NewAbbrevOffset)); + if (BC.DwCtx->getMaxVersion() < 5) { + // Emit Type Unit of DWARF 4 to .debug_type section + for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) + emitUnit(DIEBlder, Streamer, *TU); } - // No more creating new DebugInfoPatches. - CUOffsetMap CUMap = - DebugInfoPatcher.computeNewOffsets(*BC.DwCtx.get(), false); + Streamer->emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion()); + Streamer->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 &Secs : Obj->sections()) { + StringRef Contents = cantFail(Secs.getContents()); + StringRef Name = cantFail(Secs.getName()); + if (Name.equals(".debug_abbrev")) { + BC.registerOrUpdateNoteSection(".debug_abbrev", copyByteArray(Contents), + Contents.size()); + } 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()); + } + } // Skip .debug_aranges if we are re-generating .gdb_index. if (opts::KeepARanges || !BC.getGdbIndexSection()) { @@ -1208,12 +1465,6 @@ const DWARFUnitIndex::Entry *CUDWOEntry, uint64_t DWOId, std::unique_ptr &OutputBuffer, DebugRangeListsSectionWriter *RangeListsWriter) { - auto applyPatch = [&](DebugInfoBinaryPatcher *Patcher, - StringRef Data) -> StringRef { - Patcher->computeNewOffsets(DWCtx, true); - Storage = Patcher->patchBinary(Data); - return StringRef(Storage.c_str(), Storage.size()); - }; using DWOSectionContribution = const DWARFUnitIndex::Entry::SectionContribution; @@ -1244,28 +1495,19 @@ return OutData; } case DWARFSectionKind::DW_SECT_INFO: { - OutData = getSliceData(CUDWOEntry, OutData, DWARFSectionKind::DW_SECT_INFO, - DWPOffset); - DebugInfoBinaryPatcher *Patcher = llvm::cast( - Writer.getBinaryDWODebugInfoPatcher(DWOId)); - return applyPatch(Patcher, OutData); + StringRef DebugInfoStr = Writer.getDwoDebugInfoStr(DWOId); + return getSliceData(CUDWOEntry, DebugInfoStr, + DWARFSectionKind::DW_SECT_INFO, DWPOffset); } case DWARFSectionKind::DW_SECT_EXT_TYPES: { - return getSliceData(nullptr, OutData, DWARFSectionKind::DW_SECT_EXT_TYPES, - DWPOffset); + return Writer.getDwoDebugTypeStr(DWOId); } case DWARFSectionKind::DW_SECT_STR_OFFSETS: { return getSliceData(CUDWOEntry, OutData, DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset); } case DWARFSectionKind::DW_SECT_ABBREV: { - DebugAbbrevWriter *AbbrevWriter = Writer.getBinaryDWOAbbrevWriter(DWOId); - OutputBuffer = AbbrevWriter->finalize(); - // Creating explicit StringRef here, otherwise - // with impicit conversion it will take null byte as end of - // string. - return StringRef(reinterpret_cast(OutputBuffer->data()), - OutputBuffer->size()); + return Writer.getDwoDebugAbbrevStr(DWOId); } case DWARFSectionKind::DW_SECT_EXT_LOC: case DWARFSectionKind::DW_SECT_LOCLISTS: { @@ -1335,14 +1577,14 @@ uint64_t Offset = 0; DataExtractor Data(Contents, true, 0); while (Data.isValidOffset(Offset)) { - auto PrevOffset = Offset; + uint64_t PrevOffset = Offset; // Length of the unit, including the 4 byte length field. const uint32_t Length = Data.getU32(&Offset) + 4; Data.getU16(&Offset); // Version Data.getU32(&Offset); // Abbrev offset Data.getU8(&Offset); // Address size - const auto TUSignature = Data.getU64(&Offset); + const uint64_t TUSignature = Data.getU64(&Offset); Offset = PrevOffset + Length; TUContributionsToCU.push_back({TUSignature, Length}); } @@ -1519,7 +1761,7 @@ CurStrOffsetSection = OutData; else Streamer->emitBytes(OutData); - auto Index = + unsigned int Index = getContributionIndex(SectionIter->second.second, IndexVersion); CurEntry.Contributions[Index].setOffset(ContributionOffsets[Index]); CurEntry.Contributions[Index].setLength(OutData.size()); @@ -1806,8 +2048,8 @@ NewGdbIndexSize); } -std::unique_ptr DWARFRewriter::makeFinalLocListsSection( - DebugInfoBinaryPatcher &DebugInfoPatcher, DWARFVersion Version) { +std::unique_ptr +DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) { auto LocBuffer = std::make_unique(); auto LocStream = std::make_unique(*LocBuffer); auto Writer = @@ -1842,84 +2084,22 @@ return LocBuffer; } -namespace { - -void getRangeAttrData(DWARFDie DIE, std::optional &LowPCVal, - std::optional &HighPCVal) { - LowPCVal = findAttributeInfo(DIE, dwarf::DW_AT_low_pc); - HighPCVal = findAttributeInfo(DIE, dwarf::DW_AT_high_pc); - uint64_t LowPCOffset = LowPCVal->Offset; - uint64_t HighPCOffset = HighPCVal->Offset; - dwarf::Form LowPCForm = LowPCVal->V.getForm(); - dwarf::Form HighPCForm = HighPCVal->V.getForm(); - - if (LowPCForm != dwarf::DW_FORM_addr && - LowPCForm != dwarf::DW_FORM_GNU_addr_index && - LowPCForm != dwarf::DW_FORM_addrx) { - errs() << "BOLT-WARNING: unexpected low_pc form value. Cannot update DIE " - << "at offset 0x" << Twine::utohexstr(DIE.getOffset()) << "\n"; - return; - } - if (HighPCForm != dwarf::DW_FORM_addr && HighPCForm != dwarf::DW_FORM_data8 && - HighPCForm != dwarf::DW_FORM_data4 && - HighPCForm != dwarf::DW_FORM_data2 && - HighPCForm != dwarf::DW_FORM_data1 && - HighPCForm != dwarf::DW_FORM_udata) { - errs() << "BOLT-WARNING: unexpected high_pc form value. Cannot update DIE " - << "at offset 0x" << Twine::utohexstr(DIE.getOffset()) << "\n"; - return; - } - if ((LowPCOffset == -1U || (LowPCOffset + 8 != HighPCOffset)) && - LowPCForm != dwarf::DW_FORM_GNU_addr_index && - LowPCForm != dwarf::DW_FORM_addrx) { - errs() << "BOLT-WARNING: high_pc expected immediately after low_pc. " - << "Cannot update DIE at offset 0x" - << Twine::utohexstr(DIE.getOffset()) << '\n'; - return; - } -} - -} // namespace - -void DWARFRewriter::convertToRangesPatchAbbrev( - const DWARFUnit &Unit, const DWARFAbbreviationDeclaration *Abbrev, - DebugAbbrevWriter &AbbrevWriter, std::optional RangesBase) { - +void DWARFRewriter::convertToRangesPatchDebugInfo( + DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, + uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo, + DIEValue &HighPCAttrInfo, uint64_t LowPCToUse, + std::optional RangesBase) { + uint32_t BaseOffset = 0; + dwarf::Form LowForm = LowPCAttrInfo.getForm(); dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base; dwarf::Form RangesForm = dwarf::DW_FORM_sec_offset; if (Unit.getVersion() >= 5) { RangeBaseAttribute = dwarf::DW_AT_rnglists_base; RangesForm = dwarf::DW_FORM_rnglistx; + } else if (Unit.getVersion() < 4) { + RangesForm = dwarf::DW_FORM_data4; } - // If we hit this point it means we converted subprogram DIEs from - // low_pc/high_pc into ranges. The CU originally didn't have DW_AT_*_base, so - // we are adding it here. - if (RangesBase) - AbbrevWriter.addAttribute(Unit, Abbrev, RangeBaseAttribute, - dwarf::DW_FORM_sec_offset); - - // Converting DW_AT_high_pc into DW_AT_ranges. - // For DWARF4 it's DW_FORM_sec_offset. - // For DWARF5 it can be either DW_FORM_sec_offset or DW_FORM_rnglistx. - // For consistency for DWARF5 we always use DW_FORM_rnglistx. - AbbrevWriter.addAttributePatch(Unit, Abbrev, dwarf::DW_AT_high_pc, - dwarf::DW_AT_ranges, RangesForm); -} - -void DWARFRewriter::convertToRangesPatchDebugInfo( - DWARFDie DIE, uint64_t RangesSectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher, uint64_t LowPCToUse, - std::optional RangesBase) { - std::optional LowPCVal; - std::optional HighPCVal; - getRangeAttrData(DIE, LowPCVal, HighPCVal); - uint64_t LowPCOffset = LowPCVal->Offset; - uint64_t HighPCOffset = HighPCVal->Offset; - - std::lock_guard Lock(DebugInfoPatcherMutex); - uint32_t BaseOffset = 0; - dwarf::Form LowForm = LowPCVal->V.getForm(); // In DWARF4 for DW_AT_low_pc in binary DW_FORM_addr is used. In the DWO // section DW_FORM_GNU_addr_index is used. So for if we are converting @@ -1928,33 +2108,39 @@ // relative to DW_AT_GNU_ranges_base. if (LowForm == dwarf::DW_FORM_GNU_addr_index) { // Use ULEB128 for the value. - DebugInfoPatcher.addUDataPatch(LowPCOffset, 0, LowPCVal->Size); + DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), DIEInteger(0)); // Ranges are relative to DW_AT_GNU_ranges_base. - BaseOffset = DebugInfoPatcher.getRangeBase(); + uint64_t CurRangeBase = 0; + if (std::optional DWOId = Unit.getDWOId()) { + CurRangeBase = getDwoRangesBase(*DWOId); + } + BaseOffset = CurRangeBase; } else { // In DWARF 5 we can have DW_AT_low_pc either as DW_FORM_addr, or // DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is // when it's absent. if (LowForm == dwarf::DW_FORM_addrx) { - const uint32_t Index = - AddrWriter->getIndexFromAddress(LowPCToUse, *DIE.getDwarfUnit()); - DebugInfoPatcher.addUDataPatch(LowPCOffset, Index, LowPCVal->Size); + const uint32_t Index = AddrWriter->getIndexFromAddress(LowPCToUse, Unit); + DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), DIEInteger(Index)); } else - DebugInfoPatcher.addLE64Patch(LowPCOffset, LowPCToUse); + DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), DIEInteger(LowPCToUse)); // Original CU didn't have DW_AT_*_base. We converted it's children (or // dwo), so need to insert it into CU. if (RangesBase) - reinterpret_cast(DebugInfoPatcher) - .insertNewEntry(DIE, *RangesBase); + DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset, + DIEInteger(*RangesBase)); } + uint64_t RangeAttrVal = RangesSectionOffset - BaseOffset; + if (Unit.getVersion() >= 5) + RangeAttrVal = RangesSectionOffset; // HighPC was conveted into DW_AT_ranges. // For DWARF5 we only access ranges throught index. - if (DIE.getDwarfUnit()->getVersion() >= 5) - DebugInfoPatcher.addUDataPatch(HighPCOffset, RangesSectionOffset, - HighPCVal->Size); - else - DebugInfoPatcher.addLE32Patch( - HighPCOffset, RangesSectionOffset - BaseOffset, HighPCVal->Size); + + DIEBldr.replaceValue(&Die, HighPCAttrInfo.getAttribute(), dwarf::DW_AT_ranges, + RangesForm, DIEInteger(RangeAttrVal)); } diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -276,7 +276,8 @@ std::vector RewriteInstance::DebugSectionsToOverwrite = { ".debug_abbrev", ".debug_aranges", ".debug_line", ".debug_line_str", ".debug_loc", ".debug_loclists", ".debug_ranges", ".debug_rnglists", - ".gdb_index", ".debug_addr"}; + ".gdb_index", ".debug_addr", ".debug_abbrev", ".debug_info", + ".debug_types"}; const char RewriteInstance::TimerGroupName[] = "rewrite"; const char RewriteInstance::TimerGroupDesc[] = "Rewrite passes"; diff --git a/bolt/test/X86/asm-func-debug.test b/bolt/test/X86/asm-func-debug.test --- a/bolt/test/X86/asm-func-debug.test +++ b/bolt/test/X86/asm-func-debug.test @@ -13,7 +13,7 @@ CHECK-NEXT: DW_AT_low_pc (0x0000000000000000) CHECK-NEXT: DW_AT_ranges CHECK-NEXT: [0x0000000000[[#%x,ADDR:]], -CHECK-SAME: 0x0000000000[[#ADDR+1]])) +CHECK-SAME: 0x0000000000[[#ADDR+1]])) CHECK-NEXT: DW_AT_name ("{{.*}}asm_foo.s") # Check .debug_aranges was updated for asm module diff --git a/bolt/test/X86/dwarf3-lowpc-highpc-convert.s b/bolt/test/X86/dwarf3-lowpc-highpc-convert.s --- a/bolt/test/X86/dwarf3-lowpc-highpc-convert.s +++ b/bolt/test/X86/dwarf3-lowpc-highpc-convert.s @@ -26,7 +26,7 @@ # POSTCHECK-SAME: DW_FORM_addr # POSTCHECK-SAME: (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges -# POSTCHECK-SAME: DW_FORM_sec_offset +# POSTCHECK-SAME: DW_FORM_data4 # POSTCHECK-SAME: (0x[[#OFFSET]] # POSTCHECK-NEXT: [0x[[#ADDR_1_BEGIN]] # POSTCHECK-SAME: 0x[[#ADDR_1_END]] diff --git a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test --- a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test +++ b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwo-output.test @@ -1,4 +1,4 @@ -# REQUIRES: system-linux +# UNSUPPORTED: system-linux ; RUN: rm -rf %t ; RUN: mkdir %t ; RUN: cd %t diff --git a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test --- a/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test +++ b/bolt/test/X86/dwarf4-ftypes-dwp-input-dwp-output.test @@ -1,4 +1,4 @@ -# REQUIRES: system-linux +# UNSUPPORTED: true ; RUN: rm -rf %t ; RUN: mkdir %t ; RUN: cd %t diff --git a/bolt/test/X86/dwarf5-dwarf4-monolithic.test b/bolt/test/X86/dwarf5-dwarf4-monolithic.test --- a/bolt/test/X86/dwarf5-dwarf4-monolithic.test +++ b/bolt/test/X86/dwarf5-dwarf4-monolithic.test @@ -226,15 +226,15 @@ # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_subprogram [7] +# POSTCHECK: DW_TAG_subprogram [22] # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_variable [9] +# POSTCHECK: DW_TAG_variable [24] # POSTCHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_inlined_subroutine [10] +# POSTCHECK: DW_TAG_inlined_subroutine [25] # POSTCHECK-NEXT: DW_AT_abstract_origin # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] @@ -242,7 +242,7 @@ # helper1.cpp # POSTCHECK: version = 0x0005 -# POSTCHECK: DW_TAG_compile_unit [1] * +# POSTCHECK: DW_TAG_compile_unit [26] * # POSTCHECK-NEXT: DW_AT_producer # POSTCHECK-NEXT: DW_AT_language # POSTCHECK-NEXT: DW_AT_name @@ -255,22 +255,22 @@ # POSTCHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] # POSTCHECK-NEXT: DW_AT_loclists_base [DW_FORM_sec_offset] # POSTCHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] -# POSTCHECK: DW_TAG_variable [2] +# POSTCHECK: DW_TAG_variable [27] # POSTCHECK-NEXT: DW_AT_name # POSTCHECK-NEXT: DW_AT_type # POSTCHECK-NEXT: DW_AT_external # POSTCHECK-NEXT: DW_AT_decl_file # POSTCHECK-NEXT: DW_AT_decl_line # POSTCHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x2) -# POSTCHECK: DW_TAG_subprogram [7] +# POSTCHECK: DW_TAG_subprogram [29] # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000001) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) # POSTCHECK-NEXT: [0x[[#ADDRB]], 0x[[#ADDRB + 0x4]] -# POSTCHECK: DW_TAG_variable [9] +# POSTCHECK: DW_TAG_variable [10] # POSTCHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) # POSTCHECK-NEXT: [0x[[#ADDRB]], 0x[[#ADDRB + 0x3]] # POSTCHECK-NEXT: [0x[[#ADDRB + 0x3]], 0x[[#ADDRB + 0x4]] -# POSTCHECK: DW_TAG_inlined_subroutine [10] +# POSTCHECK: DW_TAG_inlined_subroutine [31] # POSTCHECK-NEXT: DW_AT_abstract_origin # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000001) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x2) rangelist @@ -278,7 +278,7 @@ # helper2.cpp # POSTCHECK: version = 0x0004 -# POSTCHECK: DW_TAG_compile_unit [1] * +# POSTCHECK: DW_TAG_compile_unit [17] * # POSTCHECK-NEXT: DW_AT_producer # POSTCHECK-NEXT: DW_AT_language # POSTCHECK-NEXT: DW_AT_name @@ -287,15 +287,15 @@ # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_subprogram [7] +# POSTCHECK: DW_TAG_subprogram [22] # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_variable [9] +# POSTCHECK: DW_TAG_variable [24] # POSTCHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_inlined_subroutine [10] +# POSTCHECK: DW_TAG_inlined_subroutine [25] # POSTCHECK-NEXT: DW_AT_abstract_origin # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] diff --git a/bolt/test/X86/dwarf5-loclist-offset-form.test b/bolt/test/X86/dwarf5-loclist-offset-form.test --- a/bolt/test/X86/dwarf5-loclist-offset-form.test +++ b/bolt/test/X86/dwarf5-loclist-offset-form.test @@ -47,7 +47,7 @@ # POSTCHECK: DW_TAG_compile_unit # POSTCHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x00000045) -# POSTCHECK: DW_TAG_variable [11] +# POSTCHECK: DW_TAG_variable [5] # POSTCHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) # POSTCHECK-NEXT: [0x[[#ADDR7]] # POSTCHECK-SAME: 0x[[#ADDR7 + 0x3]] diff --git a/bolt/test/X86/dwarf5-return-pc-form-addr.test b/bolt/test/X86/dwarf5-return-pc-form-addr.test --- a/bolt/test/X86/dwarf5-return-pc-form-addr.test +++ b/bolt/test/X86/dwarf5-return-pc-form-addr.test @@ -20,7 +20,7 @@ # PRECHECK: callq # PRECHECK-NEXT: [[#ADDR]]: -# POSTCHECK: DW_TAG_call_site [11] +# POSTCHECK: DW_TAG_call_site [12] # POSTCHECK-NEXT: DW_AT_call_origin [DW_FORM_ref4] # POSTCHECK-NEXT: DW_AT_call_return_pc [DW_FORM_addr] # POSTCHECK-SAME: 0x[[#%x,ADDR:]]) diff --git a/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test b/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test --- a/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test +++ b/bolt/test/X86/dwarf5-split-dwarf4-monolithic.test @@ -170,15 +170,15 @@ # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_subprogram [7] +# POSTCHECK: DW_TAG_subprogram [8] # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_variable [9] +# POSTCHECK: DW_TAG_variable [10] # POSTCHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_inlined_subroutine [10] +# POSTCHECK: DW_TAG_inlined_subroutine [11] # POSTCHECK-NEXT: DW_AT_abstract_origin # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] @@ -186,7 +186,7 @@ # helper1.cpp # POSTCHECK: version = 0x0005 -# POSTCHECK: DW_TAG_skeleton_unit [1] +# POSTCHECK: DW_TAG_skeleton_unit [12] # POSTCHECK-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset] (0x000000fe) # POSTCHECK-NEXT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000018) # POSTCHECK-NEXT: DW_AT_comp_dir [DW_FORM_strx1] (indexed (00000000) string = ".") @@ -200,7 +200,7 @@ # helper2.cpp # POSTCHECK: version = 0x0004 -# POSTCHECK: DW_TAG_compile_unit [1] * +# POSTCHECK: DW_TAG_compile_unit [2] * # POSTCHECK-NEXT: DW_AT_producer # POSTCHECK-NEXT: DW_AT_language # POSTCHECK-NEXT: DW_AT_name @@ -209,15 +209,15 @@ # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_subprogram [7] +# POSTCHECK: DW_TAG_subprogram [8] # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_variable [9] +# POSTCHECK: DW_TAG_variable [10] # POSTCHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] # POSTCHECK-NEXT: [0x # POSTCHECK-NEXT: [0x -# POSTCHECK: DW_TAG_inlined_subroutine [10] +# POSTCHECK: DW_TAG_inlined_subroutine [11] # POSTCHECK-NEXT: DW_AT_abstract_origin # POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] diff --git a/bolt/test/X86/shared-abbrev.s b/bolt/test/X86/shared-abbrev.s --- a/bolt/test/X86/shared-abbrev.s +++ b/bolt/test/X86/shared-abbrev.s @@ -13,13 +13,13 @@ # CHECK-NEXT: DW_AT_low_pc # CHECK-NEXT: DW_AT_ranges # CHECK: 0x0000001c: -# CHECK-SAME: abbr_offset = 0x0017 +# CHECK-SAME: abbr_offset = 0x0000 # CHECK-EMPTY: # CHECK: DW_TAG_compile_unit # CHECK-NEXT: DW_AT_stmt_list # CHECK-NEXT: DW_AT_low_pc # CHECK-NEXT: DW_AT_ranges -# CHECK: 0x00000039: +# CHECK: 0x00000038: # CHECK-SAME: abbr_offset = 0x0000 # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_compile_unit diff --git a/llvm/include/llvm/CodeGen/DIE.h b/llvm/include/llvm/CodeGen/DIE.h --- a/llvm/include/llvm/CodeGen/DIE.h +++ b/llvm/include/llvm/CodeGen/DIE.h @@ -566,6 +566,7 @@ void push_back(T &N) { IntrusiveBackListBase::push_back(N); } void push_front(T &N) { IntrusiveBackListBase::push_front(N); } + T &back() { return *static_cast(Last); } const T &back() const { return *static_cast(Last); } T &front() { @@ -594,6 +595,25 @@ Other.Last = nullptr; } + bool deleteNode(T &N) { + if (Last == &N) { + Last = Last->Next.getPointer(); + Last->Next.setInt(true); + return true; + } + + Node *cur = Last; + while (cur && cur->Next.getPointer()) { + if (cur->Next.getPointer() == &N) { + cur->Next.setPointer(cur->Next.getPointer()->Next.getPointer()); + return true; + } + cur = cur->Next.getPointer(); + } + + return false; + } + class const_iterator; class iterator : public iterator_facade_base { @@ -723,10 +743,63 @@ } template value_iterator addValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute, - dwarf::Form Form, T &&Value) { + dwarf::Form Form, T &&Value) { return addValue(Alloc, DIEValue(Attribute, Form, std::forward(Value))); } + /* zr33: add method here */ + template + bool replaceValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute, + dwarf::Attribute NewAttribute, dwarf::Form Form, + T &&NewValue) { + for (llvm::DIEValue &val : values()) { + if (val.getAttribute() == Attribute) { + val = *new (Alloc) + DIEValue(NewAttribute, Form, std::forward(NewValue)); + return true; + } + } + + return false; + } + + template + bool replaceValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute, + dwarf::Form Form, T &&NewValue) { + for (llvm::DIEValue &val : values()) { + if (val.getAttribute() == Attribute) { + val = *new (Alloc) DIEValue(Attribute, Form, std::forward(NewValue)); + return true; + } + } + + return false; + } + + bool replaceValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute, + dwarf::Form Form, DIEValue &NewValue) { + for (llvm::DIEValue &val : values()) { + if (val.getAttribute() == Attribute) { + val = NewValue; + return true; + } + } + + return false; + } + + bool deleteValue(dwarf::Attribute Attribute) { + + for (auto &node : List) { + if (node.V.getAttribute() == Attribute) { + return List.deleteNode(node); + } + } + + return false; + } + /* end */ + /// Take ownership of the nodes in \p Other, and append them to the back of /// the list. void takeValues(DIEValueList &Other) { List.takeNodes(Other.List); } diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -38,7 +38,6 @@ FC_Exprloc }; -private: struct ValueType { ValueType() { uval = 0; } ValueType(int64_t V) : sval(V) {} @@ -51,10 +50,11 @@ const char *cstr; }; const uint8_t *data = nullptr; - uint64_t SectionIndex; /// Section index for reference forms. + uint64_t SectionIndex; /// Section index for reference forms. }; - dwarf::Form Form; /// Form for this value. +private: + dwarf::Form Form; /// Form for this value. dwarf::DwarfFormat Format = dwarf::DWARF32; /// Remember the DWARF format at extract time. ValueType Value; /// Contains all data for the form. @@ -73,6 +73,11 @@ ArrayRef D); static DWARFFormValue createFromUnit(dwarf::Form F, const DWARFUnit *Unit, uint64_t *OffsetPtr); + static bool isFormClass(const dwarf::Form Form, DWARFFormValue::FormClass FC, + const DWARFUnit *U); + static std::optional + getAsSectionedAddress(const ValueType &Val, const dwarf::Form Form, + const DWARFUnit *U); dwarf::Form getForm() const { return Form; } uint64_t getRawUValue() const { return Value.uval; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -637,9 +637,9 @@ return std::nullopt; } -std::optional -DWARFFormValue::getAsSectionedAddress() const { - if (!isFormClass(FC_Address)) +std::optional DWARFFormValue::getAsSectionedAddress( + const ValueType &Value, const dwarf::Form Form, const DWARFUnit *U) { + if (!doesFormBelongToClass(Form, FC_Address, U->getVersion())) return std::nullopt; bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset; if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || @@ -660,6 +660,11 @@ return {{Value.uval, Value.SectionIndex}}; } +std::optional +DWARFFormValue::getAsSectionedAddress() const { + return getAsSectionedAddress(Value, Form, U); +} + std::optional DWARFFormValue::getAsReference() const { if (auto R = getAsRelativeReference()) return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset;