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 @@ -34,6 +34,30 @@ namespace bolt { +struct AttrInfo { + DWARFFormValue V; + const DWARFAbbreviationDeclaration *AbbrevDecl; + uint64_t Offset; + uint32_t Size; // Size of the attribute. +}; + +/// Finds attributes FormValue and Offset. +/// +/// \param DIE die to look up in. +/// \param AbbrevDecl abbrev declaration for the die. +/// \param Index an index in Abbrev declaration entry. +Optional +findAttributeInfo(const DWARFDie DIE, + const DWARFAbbreviationDeclaration *AbbrevDecl, + uint32_t Index); + +/// Finds attributes FormValue and Offset. +/// +/// \param DIE die to look up in. +/// \param Attr the attribute to extract. +/// \return an optional AttrInfo with DWARFFormValue and Offset. +Optional findAttributeInfo(const DWARFDie DIE, dwarf::Attribute Attr); + // DWARF5 Header in order of encoding. // Types represent encodnig sizes. using UnitLengthType = uint32_t; @@ -447,23 +471,31 @@ BinaryContext &BC; }; +class DebugInfoBinaryPatcher; +class DebugAbbrevWriter; enum class LocWriterKind { DebugLocWriter, DebugLoclistWriter }; /// Serializes part of a .debug_loc DWARF section with LocationLists. class SimpleBinaryPatcher; class DebugLocWriter { +protected: + DebugLocWriter(uint8_t DwarfVersion, LocWriterKind Kind) + : DwarfVersion(DwarfVersion), Kind(Kind) { + init(); + } + public: - DebugLocWriter() = delete; - DebugLocWriter(BinaryContext *BC); + DebugLocWriter() { init(); }; virtual ~DebugLocWriter(){}; /// Writes out location lists and stores internal patches. - virtual void addList(uint64_t AttrOffset, uint32_t LocListIndex, - DebugLocationsVector &&LocList); + virtual void addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, + DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter); /// Writes out locations in to a local buffer, and adds Debug Info patches. - virtual void finalize(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher); + virtual void finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter); /// Return internal buffer. virtual std::unique_ptr getBuffer(); @@ -485,13 +517,15 @@ std::unique_ptr LocStream; /// Current offset in the section (updated as new entries are written). /// Starts with 0 here since this only writes part of a full location lists - /// section. In the final section, the first 16 bytes are reserved for an + /// section. In the final section, for DWARF4, the first 16 bytes are reserved for an /// empty list. - uint32_t SectionOffset{0}; + static uint32_t LocSectionOffset; uint8_t DwarfVersion{4}; LocWriterKind Kind{LocWriterKind::DebugLocWriter}; private: + /// Inits all the relative data structures. + void init(); struct LocListDebugInfoPatchType { uint64_t DebugInfoAttrOffset; uint64_t LocListOffset; @@ -501,36 +535,39 @@ /// The list of debug info patches to be made once individual /// location list writers have been filled VectorLocListDebugInfoPatchType LocListDebugInfoPatches; - - using VectorEmptyLocListAttributes = std::vector; - /// Contains all the attributes pointing to empty location list. - VectorEmptyLocListAttributes EmptyAttrLists; }; class DebugLoclistWriter : public DebugLocWriter { public: ~DebugLoclistWriter() {} DebugLoclistWriter() = delete; - DebugLoclistWriter(BinaryContext *BC, DWARFUnit &Unit, - uint32_t LocListsBaseAttrOffset, uint8_t DV, bool SD) - : DebugLocWriter(BC), CU(Unit), - LocListsBaseAttrOffset(LocListsBaseAttrOffset), IsSplitDwarf(SD) { - Kind = LocWriterKind::DebugLoclistWriter; - DwarfVersion = DV; + DebugLoclistWriter(DWARFUnit &Unit, uint8_t DV, bool SD) + : DebugLocWriter(DV, LocWriterKind::DebugLoclistWriter), CU(Unit), + IsSplitDwarf(SD) { assert(DebugLoclistWriter::AddrWriter && "Please use SetAddressWriter to initialize " "DebugAddrWriter before instantiation."); + if (DwarfVersion >= 5) { + LocBodyBuffer = std::make_unique(); + LocBodyStream = std::make_unique(*LocBodyBuffer); + } else { + // Writing out empty location list to which all references to empty + // location lists will point. + const char Zeroes[16] = {0}; + *LocStream << StringRef(Zeroes, 16); + } } static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; } /// Stores location lists internally to be written out during finalize phase. - virtual void addList(uint64_t AttrOffset, uint32_t LocListIndex, - DebugLocationsVector &&LocList) override; + virtual void addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, + DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter) override; /// Writes out locations in to a local buffer and applies debug info patches. - void finalize(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher) override; + void finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter) override; /// Returns CU ID. /// For Skelton CU it is a CU Offset. @@ -548,36 +585,21 @@ bool isSplitDwarf() const { return IsSplitDwarf; } constexpr static uint32_t InvalidIndex = UINT32_MAX; - constexpr static uint32_t InvalidLocListsBaseAttrOffset = UINT32_MAX; private: /// Writes out locations in to a local buffer and applies debug info patches. - void finalizeDWARFLegacy(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher); - - /// Writes out locations in to a local buffer and applies debug info patches. - void finalizeDWARF5(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher); - - struct LocPatch { - uint64_t AttrOffset{0}; - uint32_t Index; - DebugLocationsVector LocList; - }; - using LocPatchVec = SmallVector; - LocPatchVec Patches; + void finalizeDWARF5(DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter); - class Patch { - public: - Patch() = delete; - Patch(uint64_t O, uint64_t A) : Offset(O), Address(A) {} - uint64_t Offset{0}; - uint64_t Address{0}; - }; static DebugAddrWriter *AddrWriter; DWARFUnit &CU; - uint32_t LocListsBaseAttrOffset{InvalidLocListsBaseAttrOffset}; bool IsSplitDwarf{false}; + // Used for DWARF5 to store location lists before being finalized. + std::unique_ptr LocBodyBuffer; + std::unique_ptr LocBodyStream; + std::vector RelativeLocListOffsets; + uint32_t NumberOfentries{0}; + static uint32_t LoclistBaseOffset; }; enum class PatcherKind { SimpleBinaryPatcher, DebugInfoBinaryPatcher }; @@ -1156,18 +1178,6 @@ // Returns DWARF Version for this line table. uint16_t getDwarfVersion() const { return DwarfVersion; } }; - -struct AttrInfo { - DWARFFormValue V; - uint64_t Offset; - uint32_t Size; // Size of the attribute. -}; - -Optional -findAttributeInfo(const DWARFDie DIE, - const DWARFAbbreviationDeclaration *AbbrevDecl, - uint32_t Index); - } // namespace bolt } // namespace llvm 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 @@ -104,7 +104,7 @@ Optional RangesBase = None); std::unique_ptr - makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher, + makeFinalLocListsSection(DebugInfoBinaryPatcher &DebugInfoPatcher, DWARFVersion Version); /// Finalize debug sections in the main binary. 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 @@ -75,8 +75,26 @@ // location. ValSize = NewOffset - Offset; } + return AttrInfo{*Value, DIE.getAbbreviationDeclarationPtr(), Offset, ValSize}; +} - return AttrInfo{*Value, Offset, ValSize}; +/// Finds attributes FormValue and Offset. +/// +/// \param DIE die to look up in. +/// \param Attr the attribute to extract. +/// \return an optional AttrInfo with DWARFFormValue and Offset. +Optional findAttributeInfo(const DWARFDie DIE, + dwarf::Attribute Attr) { + if (!DIE.isValid()) + return None; + const DWARFAbbreviationDeclaration *AbbrevDecl = + DIE.getAbbreviationDeclarationPtr(); + if (!AbbrevDecl) + return None; + Optional Index = AbbrevDecl->findAttributeIndex(Attr); + if (!Index) + return None; + return findAttributeInfo(DIE, AbbrevDecl, *Index); } const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{0, 0}; @@ -496,20 +514,30 @@ return Iter->second; } -DebugLocWriter::DebugLocWriter(BinaryContext *BC) { +void DebugLocWriter::init() { LocBuffer = std::make_unique(); LocStream = std::make_unique(*LocBuffer); + // Writing out empty location list to which all references to empty location + // lists will point. + if (!LocSectionOffset && DwarfVersion < 5) { + const char Zeroes[16] = {0}; + *LocStream << StringRef(Zeroes, 16); + LocSectionOffset += 16; + } } -void DebugLocWriter::addList(uint64_t AttrOffset, uint32_t LocListIndex, - DebugLocationsVector &&LocList) { +uint32_t DebugLocWriter::LocSectionOffset = 0; +void DebugLocWriter::addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, + DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter) { + const uint64_t AttrOffset = AttrVal.Offset; if (LocList.empty()) { - EmptyAttrLists.push_back(AttrOffset); + DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); return; } // Since there is a separate DebugLocWriter for each thread, // we don't need a lock to read the SectionOffset and update it. - const uint32_t EntryOffset = SectionOffset; + const uint32_t EntryOffset = LocSectionOffset; for (const DebugLocationEntry &Entry : LocList) { support::endian::write(*LocStream, static_cast(Entry.LowPC), @@ -520,16 +548,12 @@ support::little); *LocStream << StringRef(reinterpret_cast(Entry.Expr.data()), Entry.Expr.size()); - SectionOffset += 2 * 8 + 2 + Entry.Expr.size(); + LocSectionOffset += 2 * 8 + 2 + Entry.Expr.size(); } LocStream->write_zeros(16); - SectionOffset += 16; + LocSectionOffset += 16; LocListDebugInfoPatches.push_back({AttrOffset, EntryOffset}); -} - -void DebugLoclistWriter::addList(uint64_t AttrOffset, uint32_t LocListIndex, - DebugLocationsVector &&LocList) { - Patches.push_back({AttrOffset, LocListIndex, std::move(LocList)}); + DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); } std::unique_ptr DebugLocWriter::getBuffer() { @@ -537,18 +561,8 @@ } // DWARF 4: 2.6.2 -void DebugLocWriter::finalize(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher) { - for (const auto LocListDebugInfoPatchType : LocListDebugInfoPatches) { - uint64_t Offset = SectionOffset + LocListDebugInfoPatchType.LocListOffset; - DebugInfoPatcher.addLE32Patch(LocListDebugInfoPatchType.DebugInfoAttrOffset, - Offset); - } - - for (uint64_t DebugInfoAttrOffset : EmptyAttrLists) - DebugInfoPatcher.addLE32Patch(DebugInfoAttrOffset, - DebugLocWriter::EmptyListOffset); -} +void DebugLocWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter) {} static void writeEmptyListDwarf5(raw_svector_ostream &Stream) { support::endian::write(Stream, static_cast(4), support::little); @@ -562,123 +576,138 @@ Stream, static_cast(dwarf::DW_LLE_end_of_list), support::little); } -void DebugLoclistWriter::finalizeDWARF5(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher) { +static void writeLegacyLocList(AttrInfo &AttrVal, DebugLocationsVector &LocList, + DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAddrWriter &AddrWriter, + DebugBufferVector &LocBuffer, DWARFUnit &CU, + raw_svector_ostream &LocStream) { + const uint64_t AttrOffset = AttrVal.Offset; + if (LocList.empty()) { + DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); + return; + } - std::unique_ptr LocArrayBuffer = - std::make_unique(); - std::unique_ptr LocArrayStream = - std::make_unique(*LocArrayBuffer); - std::unique_ptr LocBodyBuffer = - std::make_unique(); - std::unique_ptr LocBodyStream = - std::make_unique(*LocBodyBuffer); + const uint32_t EntryOffset = LocBuffer.size(); + for (const DebugLocationEntry &Entry : LocList) { + support::endian::write(LocStream, + static_cast(dwarf::DW_LLE_startx_length), + support::little); + const uint32_t Index = AddrWriter.getIndexFromAddress(Entry.LowPC, CU); + encodeULEB128(Index, LocStream); - const uint32_t SizeOfArraySection = Patches.size() * sizeof(uint32_t); - std::sort(Patches.begin(), Patches.end(), - [](const LocPatch &P1, const LocPatch &P2) -> bool { - return P1.Index < P2.Index; - }); + support::endian::write(LocStream, + static_cast(Entry.HighPC - Entry.LowPC), + support::little); + support::endian::write(LocStream, static_cast(Entry.Expr.size()), + support::little); + LocStream << StringRef(reinterpret_cast(Entry.Expr.data()), + Entry.Expr.size()); + } + support::endian::write(LocStream, + static_cast(dwarf::DW_LLE_end_of_list), + support::little); + DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); +} - if (LocListsBaseAttrOffset != InvalidLocListsBaseAttrOffset) - DebugInfoPatcher.addLE32Patch(LocListsBaseAttrOffset, - SectionOffset + - getDWARF5RngListLocListHeaderSize()); +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); + RelativeLocListOffsets.push_back(LocBodyBuffer.size()); + ++NumberOfentries; + if (LocList.empty()) { + writeEmptyListDwarf5(LocBodyStream); + return; + } - uint32_t Index{0}; - for (LocPatch &Patch : Patches) { - const uint32_t EntryOffset = LocBodyBuffer->size(); - if (Patch.LocList.empty()) { - if (Patch.Index == DebugLoclistWriter::InvalidIndex) - DebugInfoPatcher.addLE32Patch(Patch.AttrOffset, EntryOffset); + std::vector OffsetsArray; + for (const DebugLocationEntry &Entry : LocList) { + support::endian::write(LocBodyStream, + static_cast(dwarf::DW_LLE_startx_length), + support::little); + const uint32_t Index = AddrWriter.getIndexFromAddress(Entry.LowPC, CU); + encodeULEB128(Index, LocBodyStream); + encodeULEB128(Entry.HighPC - Entry.LowPC, LocBodyStream); + encodeULEB128(Entry.Expr.size(), LocBodyStream); + LocBodyStream << StringRef( + reinterpret_cast(Entry.Expr.data()), Entry.Expr.size()); + } + support::endian::write(LocBodyStream, + static_cast(dwarf::DW_LLE_end_of_list), + support::little); +} - writeEmptyListDwarf5(*LocBodyStream); - continue; - } +void DebugLoclistWriter::addList(AttrInfo &AttrVal, + DebugLocationsVector &LocList, + DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter) { + if (DwarfVersion < 5) + writeLegacyLocList(AttrVal, LocList, DebugInfoPatcher, *AddrWriter, + *LocBuffer, CU, *LocStream); + else + writeDWARF5LocList(NumberOfentries, AttrVal, LocList, DebugInfoPatcher, + AbbrevWriter, *AddrWriter, *LocBodyBuffer, + RelativeLocListOffsets, CU, *LocBodyStream); +} - assert(Patch.Index == DebugLoclistWriter::InvalidIndex || - Patch.Index == Index++ && "Gap in LocList Index Array."); - (void)Index; - - std::vector OffsetsArray; - for (const DebugLocationEntry &Entry : Patch.LocList) { - support::endian::write(*LocBodyStream, - static_cast(dwarf::DW_LLE_startx_length), - support::little); - const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CU); - encodeULEB128(Index, *LocBodyStream); - encodeULEB128(Entry.HighPC - Entry.LowPC, *LocBodyStream); - encodeULEB128(Entry.Expr.size(), *LocBodyStream); - *LocBodyStream << StringRef( - reinterpret_cast(Entry.Expr.data()), Entry.Expr.size()); - } - support::endian::write(*LocBodyStream, - static_cast(dwarf::DW_LLE_end_of_list), - support::little); +uint32_t DebugLoclistWriter::LoclistBaseOffset = 0; +void DebugLoclistWriter::finalizeDWARF5( + DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter) { + if (LocBodyBuffer->empty()) + return; + + std::unique_ptr LocArrayBuffer = + std::make_unique(); + std::unique_ptr LocArrayStream = + std::make_unique(*LocArrayBuffer); - // Write out IndexArray + const uint32_t SizeOfArraySection = NumberOfentries * sizeof(uint32_t); + // Write out IndexArray + for (uint32_t RelativeOffset : RelativeLocListOffsets) support::endian::write( *LocArrayStream, - static_cast(SizeOfArraySection + EntryOffset), + static_cast(SizeOfArraySection + RelativeOffset), support::little); - // Don't need to patch Index since we are re-using them. - if (Patch.Index == DebugLoclistWriter::InvalidIndex) - DebugInfoPatcher.addLE32Patch(Patch.AttrOffset, EntryOffset); - clearList(Patch.LocList); - } - if (!Patches.empty()) { - std::unique_ptr Header = - getDWARF5Header({static_cast(SizeOfArraySection + - LocBodyBuffer.get()->size()), - 5, 8, 0, static_cast(Patches.size())}); - *LocStream << *Header; - *LocStream << *LocArrayBuffer; - *LocStream << *LocBodyBuffer; - } - clearList(Patches); -} -void DebugLoclistWriter::finalizeDWARFLegacy( - uint64_t SectionOffset, SimpleBinaryPatcher &DebugInfoPatcher) { - for (LocPatch &Patch : Patches) { - if (Patch.LocList.empty()) { - DebugInfoPatcher.addLE32Patch(Patch.AttrOffset, - DebugLocWriter::EmptyListOffset); - continue; - } - const uint32_t EntryOffset = LocBuffer->size(); - for (const DebugLocationEntry &Entry : Patch.LocList) { - support::endian::write(*LocStream, - static_cast(dwarf::DW_LLE_startx_length), - support::little); - const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CU); - encodeULEB128(Index, *LocStream); - - // TODO: Support DWARF5 - support::endian::write(*LocStream, - static_cast(Entry.HighPC - Entry.LowPC), - support::little); - support::endian::write(*LocStream, - static_cast(Entry.Expr.size()), - support::little); - *LocStream << StringRef(reinterpret_cast(Entry.Expr.data()), - Entry.Expr.size()); + std::unique_ptr Header = getDWARF5Header( + {static_cast(SizeOfArraySection + LocBodyBuffer.get()->size()), + 5, 8, 0, NumberOfentries}); + *LocStream << *Header; + *LocStream << *LocArrayBuffer; + *LocStream << *LocBodyBuffer; + + if (!isSplitDwarf()) { + if (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()); } - support::endian::write(*LocStream, - static_cast(dwarf::DW_LLE_end_of_list), - support::little); - DebugInfoPatcher.addLE32Patch(Patch.AttrOffset, EntryOffset); - clearList(Patch.LocList); + LoclistBaseOffset += LocBuffer->size(); } - clearList(Patches); + clearList(RelativeLocListOffsets); + clearList(*LocArrayBuffer); + clearList(*LocBodyBuffer); } -void DebugLoclistWriter::finalize(uint64_t SectionOffset, - SimpleBinaryPatcher &DebugInfoPatcher) { - if (DwarfVersion < 5) - finalizeDWARFLegacy(SectionOffset, DebugInfoPatcher); - else - finalizeDWARF5(SectionOffset, DebugInfoPatcher); +void DebugLoclistWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, + DebugAbbrevWriter &AbbrevWriter) { + if (DwarfVersion >= 5) + finalizeDWARF5(DebugInfoPatcher, AbbrevWriter); } DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr; 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 @@ -55,25 +55,6 @@ namespace llvm { namespace bolt { -/// Finds attributes FormValue and Offset. -/// -/// \param DIE die to look up in. -/// \param Attr the attribute to extract. -/// \return an optional AttrInfo with DWARFFormValue and Offset. -static Optional findAttributeInfo(const DWARFDie DIE, - dwarf::Attribute Attr) { - if (!DIE.isValid()) - return None; - const DWARFAbbreviationDeclaration *AbbrevDecl = - DIE.getAbbreviationDeclarationPtr(); - if (!AbbrevDecl) - return None; - Optional Index = AbbrevDecl->findAttributeIndex(Attr); - if (!Index) - return None; - return findAttributeInfo(DIE, AbbrevDecl, *Index); -} - /// Finds attributes FormValue and Offset. /// /// \param DIE die to look up in. @@ -191,10 +172,13 @@ AbbrevWriter = std::make_unique(*BC.DwCtx); - if (BC.isDWARF5Used()) { - // Disabling none deterministic mode for dwarf5, to keep implementation - // simpler. + if (!opts::DeterministicDebugInfo) { opts::DeterministicDebugInfo = true; + llvm::errs() + << "BOLT-WARNING: --deterministic-debuginfo is being deprecated.\n"; + } + + if (BC.isDWARF5Used()) { AddrWriter = std::make_unique(&BC); RangesSectionWriter = std::make_unique(); DebugRangeListsSectionWriter::setAddressWriter(AddrWriter.get()); @@ -209,14 +193,9 @@ for (std::unique_ptr &CU : BC.DwCtx->compile_units()) { const uint16_t DwarfVersion = CU->getVersion(); if (DwarfVersion >= 5) { - uint32_t AttrInfoOffset = - DebugLoclistWriter::InvalidLocListsBaseAttrOffset; - if (Optional AttrInfoVal = - findAttributeInfo(CU->getUnitDIE(), dwarf::DW_AT_loclists_base)) { - AttrInfoOffset = AttrInfoVal->Offset; - LocListWritersByCU[CUIndex] = std::make_unique( - &BC, *CU.get(), AttrInfoOffset, DwarfVersion, false); - } + LocListWritersByCU[CUIndex] = + std::make_unique(*CU.get(), DwarfVersion, false); + if (Optional DWOId = CU->getDWOId()) { assert(LocListWritersByCU.count(*DWOId) == 0 && "RangeLists writer for DWO unit already exists."); @@ -227,7 +206,7 @@ } } else { - LocListWritersByCU[CUIndex] = std::make_unique(&BC); + LocListWritersByCU[CUIndex] = std::make_unique(); } if (Optional DWOId = CU->getDWOId()) { @@ -235,10 +214,8 @@ "LocList writer for DWO unit already exists."); // Work around some bug in llvm-15. If I pass in directly lld reports // undefined symbol. - auto constexpr WorkAround = - DebugLoclistWriter::InvalidLocListsBaseAttrOffset; - LocListWritersByCU[*DWOId] = std::make_unique( - &BC, *CU.get(), WorkAround, DwarfVersion, true); + LocListWritersByCU[*DWOId] = + std::make_unique(*CU.get(), DwarfVersion, true); } ++CUIndex; } @@ -318,6 +295,7 @@ createBinaryDWOAbbrevWriter((*SplitCU)->getContext(), *DWOId); updateUnitDebugInfo(*(*SplitCU), *DwoDebugInfoPatcher, *DWOAbbrevWriter, *DebugLocWriter, *TempRangesSectionWriter); + DebugLocWriter->finalize(*DwoDebugInfoPatcher, *DWOAbbrevWriter); DwoDebugInfoPatcher->clearDestinationLabels(); if (!DwoDebugInfoPatcher->getWasRangBasedUsed()) RangesBase = None; @@ -341,6 +319,7 @@ DebugInfoPatcher->addUnitBaseOffsetLabel(Unit->getOffset()); updateUnitDebugInfo(*Unit, *DebugInfoPatcher, *AbbrevWriter, *DebugLocWriter, *RangesSectionWriter, RangesBase); + DebugLocWriter->finalize(*DebugInfoPatcher, *AbbrevWriter); if (Unit->getVersion() >= 5) RangesSectionWriter.get()->finalizeSection(); }; @@ -517,7 +496,8 @@ if (SectionAddress) BaseAddress = SectionAddress->Address; - if (Unit.getVersion() >= 5) { + if (Unit.getVersion() >= 5 && + AttrVal->V.getForm() == dwarf::DW_FORM_loclistx) { Optional LocOffset = Unit.getLoclistOffset(Offset); assert(LocOffset && "Location Offset is invalid."); Offset = *LocOffset; @@ -545,7 +525,7 @@ BaseAddress + Entry.Value0, BaseAddress + Entry.Value1, Entry.Loc}); break; - case dwarf::DW_RLE_start_length: + case dwarf::DW_LLE_start_length: InputLL.emplace_back(DebugLocationEntry{ Entry.Value0, Entry.Value0 + Entry.Value1, Entry.Loc}); break; @@ -604,24 +584,8 @@ // information. OutputLL = InputLL; } - uint32_t LocListIndex = 0; - dwarf::Form Form = Value.getForm(); - if (Form == dwarf::DW_FORM_sec_offset || - Form == dwarf::DW_FORM_data4) { - // For DWARF5 we can access location list entry either using - // index, or offset. If it's offset, then it's from begnning of - // the file. This implementation was before we could add entries - // to the DIE. For DWARF4 this is no-op. - // TODO: For DWARF5 convert all the offset based entries to index - // based, and insert loclist_base if necessary. - LocListIndex = DebugLoclistWriter::InvalidIndex; - } else if (Form == dwarf::DW_FORM_loclistx) { - LocListIndex = Value.getRawUValue(); - } else { - llvm_unreachable("Unsupported LocList access Form."); - } - DebugLocWriter.addList(AttrOffset, LocListIndex, - std::move(OutputLL)); + DebugLocWriter.addList(*AttrVal, OutputLL, DebugInfoPatcher, + AbbrevWriter); } } else { assert((Value.isFormClass(DWARFFormValue::FC_Exprloc) || @@ -971,17 +935,19 @@ if (BC.isDWARF5Used()) { std::unique_ptr LocationListSectionContents = makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARF5); - BC.registerOrUpdateNoteSection(".debug_loclists", - copyByteArray(*LocationListSectionContents), - LocationListSectionContents->size()); + if (!LocationListSectionContents->empty()) + BC.registerOrUpdateNoteSection( + ".debug_loclists", copyByteArray(*LocationListSectionContents), + LocationListSectionContents->size()); } if (BC.isDWARFLegacyUsed()) { std::unique_ptr LocationListSectionContents = makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARFLegacy); - BC.registerOrUpdateNoteSection(".debug_loc", - copyByteArray(*LocationListSectionContents), - LocationListSectionContents->size()); + if (!LocationListSectionContents->empty()) + BC.registerOrUpdateNoteSection( + ".debug_loc", copyByteArray(*LocationListSectionContents), + LocationListSectionContents->size()); } // AddrWriter should be finalized after debug_loc since more addresses can be @@ -1584,49 +1550,37 @@ NewGdbIndexSize); } -std::unique_ptr -DWARFRewriter::makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher, - DWARFVersion Version) { +std::unique_ptr DWARFRewriter::makeFinalLocListsSection( + DebugInfoBinaryPatcher &DebugInfoPatcher, DWARFVersion Version) { auto LocBuffer = std::make_unique(); auto LocStream = std::make_unique(*LocBuffer); auto Writer = std::unique_ptr(BC.createObjectWriter(*LocStream)); - uint64_t SectionOffset = 0; - // Add an empty list as the first entry; - if (LocListWritersByCU.empty() || - LocListWritersByCU.begin()->second.get()->getDwarfVersion() < 5) { - // Should be fine for both DWARF4 and DWARF5? - const char Zeroes[16] = {0}; - *LocStream << StringRef(Zeroes, 16); - SectionOffset += 2 * 8; - } - for (std::pair> &Loc : LocListWritersByCU) { DebugLocWriter *LocWriter = Loc.second.get(); auto *LocListWriter = llvm::dyn_cast(LocWriter); + // Filter out DWARF4, writing out DWARF5 if (Version == DWARFVersion::DWARF5 && (!LocListWriter || LocListWriter->getDwarfVersion() <= 4)) continue; + // Filter out DWARF5, writing out DWARF4 if (Version == DWARFVersion::DWARFLegacy && (LocListWriter && LocListWriter->getDwarfVersion() >= 5)) continue; + + // Skipping DWARF4/5 split dwarf. if (LocListWriter && (LocListWriter->getDwarfVersion() <= 4 || (LocListWriter->getDwarfVersion() >= 5 && LocListWriter->isSplitDwarf()))) { - SimpleBinaryPatcher *Patcher = - getBinaryDWODebugInfoPatcher(LocListWriter->getCUID()); - LocListWriter->finalize(0, *Patcher); continue; } - LocWriter->finalize(SectionOffset, DebugInfoPatcher); std::unique_ptr CurrCULocationLists = LocWriter->getBuffer(); *LocStream << *CurrCULocationLists; - SectionOffset += CurrCULocationLists->size(); } return LocBuffer; diff --git a/bolt/test/Inputs/dwarf5-loclist-offset-form-helper.s b/bolt/test/Inputs/dwarf5-loclist-offset-form-helper.s new file mode 100644 --- /dev/null +++ b/bolt/test/Inputs/dwarf5-loclist-offset-form-helper.s @@ -0,0 +1,420 @@ +# int fooVar = 0; +# void useFoo(int * x) { +# *x += 4; +# } +# int foo(int argc) { +# int x = argc; +# useFoo(&x); +# return x; +# } + + .text + .file "helper.cpp" + .file 0 "." "helper.cpp" md5 0xf1508be63cfcbaf913e2dfef3cd5bccc + .globl _Z6useFooPi # -- Begin function _Z6useFooPi + .p2align 4, 0x90 + .type _Z6useFooPi,@function +_Z6useFooPi: # @_Z6useFooPi +.Lfunc_begin0: + .loc 0 2 0 # helper.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + #DEBUG_VALUE: useFoo:x <- $rdi + .loc 0 3 5 prologue_end # helper.cpp:3:5 + addl $4, (%rdi) + .loc 0 4 2 # helper.cpp:4:2 + retq +.Ltmp0: +.Lfunc_end0: + .size _Z6useFooPi, .Lfunc_end0-_Z6useFooPi + .cfi_endproc + # -- End function + .globl _Z3fooi # -- Begin function _Z3fooi + .p2align 4, 0x90 + .type _Z3fooi,@function +_Z3fooi: # @_Z3fooi +.Lfunc_begin1: + .loc 0 6 0 # helper.cpp:6:0 + .cfi_startproc +# %bb.0: # %entry + #DEBUG_VALUE: foo:argc <- $edi + #DEBUG_VALUE: foo:x <- $edi + # kill: def $edi killed $edi def $rdi + #DEBUG_VALUE: useFoo:x <- undef + .loc 0 3 5 prologue_end # helper.cpp:3:5 + leal 4(%rdi), %eax +.Ltmp1: + #DEBUG_VALUE: foo:x <- $eax + .loc 0 9 5 # helper.cpp:9:5 + retq +.Ltmp2: +.Lfunc_end1: + .size _Z3fooi, .Lfunc_end1-_Z3fooi + .cfi_endproc + # -- End function + .type fooVar,@object # @fooVar + .bss + .globl fooVar + .p2align 2 +fooVar: + .long 0 # 0x0 + .size fooVar, 4 + + .section .debug_loclists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.Lloclists_table_base0: + .long .Ldebug_loc0-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 4 # DW_LLE_offset_pair + .uleb128 .Lfunc_begin1-.Lfunc_begin0 # starting offset + .uleb128 .Ltmp1-.Lfunc_begin0 # ending offset + .byte 1 # Loc expr size + .byte 85 # super-register DW_OP_reg5 + .byte 4 # DW_LLE_offset_pair + .uleb128 .Ltmp1-.Lfunc_begin0 # starting offset + .uleb128 .Lfunc_end1-.Lfunc_begin0 # ending offset + .byte 1 # Loc expr size + .byte 80 # super-register DW_OP_reg0 + .byte 0 # DW_LLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 122 # DW_AT_call_all_calls + .byte 25 # DW_FORM_flag_present + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 33 # DW_FORM_implicit_const + .byte 1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 122 # DW_AT_call_all_calls + .byte 25 # DW_FORM_flag_present + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 0 # DW_CHILDREN_no + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x83 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 2 # Abbrev [2] 0x27:0xb DW_TAG_variable + .byte 3 # DW_AT_name + .long 50 # DW_AT_type + # DW_AT_external + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .byte 2 # DW_AT_location + .byte 161 + .byte 0 + .byte 3 # Abbrev [3] 0x32:0x4 DW_TAG_base_type + .byte 4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 4 # Abbrev [4] 0x36:0x14 DW_TAG_subprogram + .byte 1 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + # DW_AT_call_all_calls + .long 74 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0x42:0x7 DW_TAG_formal_parameter + .byte 1 # DW_AT_location + .byte 85 + .long 79 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x4a:0xe DW_TAG_subprogram + .byte 5 # DW_AT_linkage_name + .byte 6 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + # DW_AT_external + # DW_AT_inline + .byte 7 # Abbrev [7] 0x4f:0x8 DW_TAG_formal_parameter + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 88 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x58:0x5 DW_TAG_pointer_type + .long 50 # DW_AT_type + .byte 9 # Abbrev [9] 0x5d:0x31 DW_TAG_subprogram + .byte 2 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + # DW_AT_call_all_calls + .byte 8 # DW_AT_linkage_name + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + .long 50 # DW_AT_type + # DW_AT_external + .byte 10 # Abbrev [10] 0x6d:0xa DW_TAG_formal_parameter + .byte 1 # DW_AT_location + .byte 85 + .byte 10 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + .long 50 # DW_AT_type + .byte 11 # Abbrev [11] 0x77:0x9 DW_TAG_variable + .long .Ldebug_loc0 # DW_AT_location + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 50 # DW_AT_type + .byte 12 # Abbrev [12] 0x80:0xd DW_TAG_inlined_subroutine + .long 74 # DW_AT_abstract_origin + .byte 2 # DW_AT_low_pc + .long .Ltmp1-.Lfunc_begin1 # DW_AT_high_pc + .byte 0 # DW_AT_call_file + .byte 8 # DW_AT_call_line + .byte 5 # DW_AT_call_column + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_str_offsets,"",@progbits + .long 48 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 15.0.0" # string offset=0 +.Linfo_string1: + .asciz "helper.cpp" # string offset=134 +.Linfo_string2: + .asciz "." # string offset=145 +.Linfo_string3: + .asciz "fooVar" # string offset=183 +.Linfo_string4: + .asciz "int" # string offset=190 +.Linfo_string5: + .asciz "_Z6useFooPi" # string offset=194 +.Linfo_string6: + .asciz "useFoo" # string offset=206 +.Linfo_string7: + .asciz "x" # string offset=213 +.Linfo_string8: + .asciz "_Z3fooi" # string offset=215 +.Linfo_string9: + .asciz "foo" # string offset=223 +.Linfo_string10: + .asciz "argc" # string offset=227 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad fooVar + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .ident "clang version 15.0.0" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/Inputs/dwarf5-loclist-offset-form-main.s b/bolt/test/Inputs/dwarf5-loclist-offset-form-main.s new file mode 100644 --- /dev/null +++ b/bolt/test/Inputs/dwarf5-loclist-offset-form-main.s @@ -0,0 +1,390 @@ +# void use(int * x, int * y) { +# *x += 4; +# *y -= 2; +# } +# +# extern int fooVar; +# int main(int argc, char *argv[]) { +# int x = argc; +# int y = fooVar + 3; +# use(&x, &y); +# return x + y; +# } + + .text + .file "main.cpp" + .globl _Z3usePiS_ # -- Begin function _Z3usePiS_ + .p2align 4, 0x90 + .type _Z3usePiS_,@function +_Z3usePiS_: # @_Z3usePiS_ +.Lfunc_begin0: + .file 0 "." "main.cpp" md5 0x0df8b93231613cae17dbf82c0897c3b3 + .loc 0 1 0 # main.cpp:1:0 + .cfi_startproc +# %bb.0: # %entry + #DEBUG_VALUE: use:x <- $rdi + #DEBUG_VALUE: use:y <- $rsi + .loc 0 2 6 prologue_end # main.cpp:2:6 + addl $4, (%rdi) + .loc 0 3 6 # main.cpp:3:6 + addl $-2, (%rsi) + .loc 0 4 1 # main.cpp:4:1 + retq +.Ltmp0: +.Lfunc_end0: + .size _Z3usePiS_, .Lfunc_end0-_Z3usePiS_ + .cfi_endproc + # -- End function + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin1: + .loc 0 7 0 # main.cpp:7:0 + .cfi_startproc +# %bb.0: # %entry + #DEBUG_VALUE: main:argc <- $edi + #DEBUG_VALUE: main:argv <- $rsi + #DEBUG_VALUE: main:x <- $edi + # kill: def $edi killed $edi def $rdi + .loc 0 9 13 prologue_end # main.cpp:9:13 + movq fooVar@GOTPCREL(%rip), %rax + movl (%rax), %eax +.Ltmp1: + #DEBUG_VALUE: main:y <- [DW_OP_plus_uconst 3, DW_OP_stack_value] $eax + #DEBUG_VALUE: main:y <- [DW_OP_plus_uconst 1, DW_OP_stack_value] $eax + #DEBUG_VALUE: main:x <- [DW_OP_plus_uconst 4, DW_OP_stack_value] $edi + .loc 0 11 14 # main.cpp:11:14 + addl %edi, %eax +.Ltmp2: + addl $5, %eax + .loc 0 11 5 is_stmt 0 # main.cpp:11:5 + retq +.Ltmp3: +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + # -- End function + .section .debug_loclists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 2 # Offset entry count +.Lloclists_table_base0: + .long .Ldebug_loc0-.Lloclists_table_base0 + .long .Ldebug_loc1-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 4 # DW_LLE_offset_pair + .uleb128 .Lfunc_begin1-.Lfunc_begin0 # starting offset + .uleb128 .Ltmp1-.Lfunc_begin0 # ending offset + .byte 1 # Loc expr size + .byte 85 # super-register DW_OP_reg5 + .byte 4 # DW_LLE_offset_pair + .uleb128 .Ltmp1-.Lfunc_begin0 # starting offset + .uleb128 .Lfunc_end1-.Lfunc_begin0 # ending offset + .byte 10 # Loc expr size + .byte 117 # DW_OP_breg5 + .byte 4 # 4 + .byte 16 # DW_OP_constu + .byte 255 # 4294967295 + .byte 255 # + .byte 255 # + .byte 255 # + .byte 15 # + .byte 26 # DW_OP_and + .byte 159 # DW_OP_stack_value + .byte 0 # DW_LLE_end_of_list +.Ldebug_loc1: + .byte 4 # DW_LLE_offset_pair + .uleb128 .Ltmp1-.Lfunc_begin0 # starting offset + .uleb128 .Ltmp2-.Lfunc_begin0 # ending offset + .byte 10 # Loc expr size + .byte 112 # DW_OP_breg0 + .byte 1 # 1 + .byte 16 # DW_OP_constu + .byte 255 # 4294967295 + .byte 255 # + .byte 255 # + .byte 255 # + .byte 15 # + .byte 26 # DW_OP_and + .byte 159 # DW_OP_stack_value + .byte 0 # DW_LLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 122 # DW_AT_call_all_calls + .byte 25 # DW_FORM_flag_present + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 122 # DW_AT_call_all_calls + .byte 25 # DW_FORM_flag_present + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x8a DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 0 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 2 # Abbrev [2] 0x27:0x21 DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + # DW_AT_call_all_calls + .byte 3 # DW_AT_linkage_name + .byte 4 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + # DW_AT_external + .byte 3 # Abbrev [3] 0x33:0xa DW_TAG_formal_parameter + .byte 1 # DW_AT_location + .byte 85 + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 130 # DW_AT_type + .byte 3 # Abbrev [3] 0x3d:0xa DW_TAG_formal_parameter + .byte 1 # DW_AT_location + .byte 84 + .byte 8 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 130 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x48:0x36 DW_TAG_subprogram + .byte 1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + # DW_AT_call_all_calls + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 126 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x57:0xa DW_TAG_formal_parameter + .byte 1 # DW_AT_location + .byte 85 + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 126 # DW_AT_type + .byte 3 # Abbrev [3] 0x61:0xa DW_TAG_formal_parameter + .byte 1 # DW_AT_location + .byte 84 + .byte 10 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 135 # DW_AT_type + .byte 5 # Abbrev [5] 0x6b:0x9 DW_TAG_variable + .long .Ldebug_loc0 # DW_AT_location + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 126 # DW_AT_type + .byte 5 # Abbrev [5] 0x74:0x9 DW_TAG_variable + .long .Ldebug_loc1 # DW_AT_location + .byte 8 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 126 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x7e:0x4 DW_TAG_base_type + .byte 6 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 7 # Abbrev [7] 0x82:0x5 DW_TAG_pointer_type + .long 126 # DW_AT_type + .byte 7 # Abbrev [7] 0x87:0x5 DW_TAG_pointer_type + .long 140 # DW_AT_type + .byte 7 # Abbrev [7] 0x8c:0x5 DW_TAG_pointer_type + .long 145 # DW_AT_type + .byte 6 # Abbrev [6] 0x91:0x4 DW_TAG_base_type + .byte 11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_str_offsets,"",@progbits + .long 52 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 15.0.0" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=134 +.Linfo_string2: + .asciz "." # string offset=143 +.Linfo_string3: + .asciz "_Z3usePiS_" # string offset=181 +.Linfo_string4: + .asciz "use" # string offset=192 +.Linfo_string5: + .asciz "main" # string offset=196 +.Linfo_string6: + .asciz "int" # string offset=201 +.Linfo_string7: + .asciz "x" # string offset=205 +.Linfo_string8: + .asciz "y" # string offset=207 +.Linfo_string9: + .asciz "argc" # string offset=209 +.Linfo_string10: + .asciz "argv" # string offset=214 +.Linfo_string11: + .asciz "char" # string offset=219 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .long .Linfo_string11 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .ident "clang version 15.0.0" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf4-df-dualcu-loclist.test b/bolt/test/X86/dwarf4-df-dualcu-loclist.test --- a/bolt/test/X86/dwarf4-df-dualcu-loclist.test +++ b/bolt/test/X86/dwarf4-df-dualcu-loclist.test @@ -26,13 +26,13 @@ ; BOLT-DWO-MAIN: version = 0x0004 ; BOLT-DWO-MAIN: DW_TAG_formal_parameter [10] -; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000: +; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000010: ; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length (0x0000000000000002, 0x0000000000000014) ; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length (0x0000000000000003, 0x0000000000000005) ; BOLT-DWO-MAIN: DW_TAG_formal_parameter [10] -; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000016: +; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000026: ; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length (0x0000000000000002, 0x000000000000000c) -; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length (0x0000000000000005, 0x000000000000000d) +; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length (0x0000000000000004, 0x000000000000000d) ; PRE-BOLT-DWO-HELPER: version = 0x0004 @@ -43,6 +43,6 @@ ; BOLT-DWO-HELPER: version = 0x0004 ; BOLT-DWO-HELPER: DW_TAG_formal_parameter [5] -; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000: +; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000010: ; BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length (0x0000000000000002, 0x0000000000000008): DW_OP_reg5 RDI ; BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length (0x0000000000000003, 0x0000000000000016) diff --git a/bolt/test/dwarf5-loclist-offset-form.test b/bolt/test/dwarf5-loclist-offset-form.test new file mode 100644 --- /dev/null +++ b/bolt/test/dwarf5-loclist-offset-form.test @@ -0,0 +1,56 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-loclist-offset-form-main.s -o %tmain.o +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-loclist-offset-form-helper.s -o %thelper.o +# RUN: %clang %cflags -dwarf-5 %tmain.o %thelper.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s +# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt +# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s + +# Checks we can handle DWARF5 CU with DWARF4 DW_AT_location access pattern. + +# PRECHECK: DW_TAG_compile_unit +# PRECHECK: DW_TAG_variable [5] +# PRECHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] +# PRECHECK: DW_TAG_variable [5] +# PRECHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] +# PRECHECK: DW_TAG_compile_unit +# PRECHECK: DW_TAG_variable [11] +# PRECHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] + +# POSTCHECK: Addrs: [ +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR1:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR2:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR3:]] +# For second CU. +# POSTCHECK: Addrs: [ +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR4:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR5:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR6:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR7:]] +# POSTCHECK-NEXT: 0x[[#%.16x,ADDR8:]] + +# POSTCHECK: DW_TAG_compile_unit +# POSTCHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c) +# POSTCHECK: DW_TAG_variable [5] +# POSTCHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) +# POSTCHECK-NEXT: [0x[[#ADDR1]] +# POSTCHECK-SAME: 0x[[#ADDR1 + 9]] +# POSTCHECK-NEXT: [0x[[#ADDR3]] +# POSTCHECK-SAME: 0x[[#ADDR3 + 6]] +# POSTCHECK: DW_TAG_variable [5] +# POSTCHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x1) +# POSTCHECK-NEXT: [0x[[#ADDR3]] +# POSTCHECK-SAME: 0x[[#ADDR3 + 2]] + +# POSTCHECK: DW_TAG_compile_unit +# POSTCHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x00000043) +# POSTCHECK: DW_TAG_variable [11] +# POSTCHECK-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) +# POSTCHECK-NEXT: [0x[[#ADDR5]] +# POSTCHECK-SAME: 0x[[#ADDR5 + 3]] +# POSTCHECK-NEXT: [0x[[#ADDR8]] +# POSTCHECK-SAME: 0x[[#ADDR8 + 1]]