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 @@ -110,6 +110,13 @@ /// Common buffer vector used for debug info handling. using DebugBufferVector = SmallVector; +/// Map of old CU offset to new offset and length. +struct CUInfo { + uint32_t Offset; + uint32_t Length; +}; +using CUOffsetMap = std::map; + /// Serializes the .debug_ranges DWARF section. class DebugRangesSectionWriter { public: @@ -158,9 +165,8 @@ /// Writes .debug_aranges with the added ranges to the MCObjectWriter. /// Takes in \p RangesStream to write into, and \p CUMap which maps CU /// original offsets to new ones. - void - writeARangesSection(raw_svector_ostream &RangesStream, - const std::unordered_map CUMap) const; + void writeARangesSection(raw_svector_ostream &RangesStream, + const CUOffsetMap &CUMap) const; /// Resets the writer to a clear state. void reset() { CUAddressRanges.clear(); } @@ -650,8 +656,8 @@ void setDWPOffset(uint64_t DWPOffset) { DWPUnitOffset = DWPOffset; } /// When this function is invoked all of the DebugInfo Patches must be done. - /// Returns a map of old CU offsets to new ones. - std::unordered_map computeNewOffsets(); + /// Returns a map of old CU offsets to new offsets and new sizes. + CUOffsetMap computeNewOffsets(DWARFContext &DWCtx, bool IsDWOContext); private: struct PatchDeleter { 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 @@ -94,14 +94,14 @@ makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher); /// Finalize debug sections in the main binary. - void finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher); + CUOffsetMap finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher); /// Patches the binary for DWARF address ranges (e.g. in functions and lexical /// blocks) to be updated. void updateDebugAddressRanges(); /// Rewrite .gdb_index section if present. - void updateGdbIndexSection(); + void updateGdbIndexSection(CUOffsetMap &CUMap); /// Output .dwo files. void writeDWOFiles(std::unordered_map &DWOIdToName); 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 @@ -120,8 +120,7 @@ } void DebugARangesSectionWriter::writeARangesSection( - raw_svector_ostream &RangesStream, - const std::unordered_map CUMap) const { + raw_svector_ostream &RangesStream, const CUOffsetMap &CUMap) const { // For reference on the format of the .debug_aranges section, see the DWARF4 // specification, section 6.1.4 Lookup by Address // http://www.dwarfstd.org/doc/DWARF4.pdf @@ -147,9 +146,9 @@ assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map"); // Header field #3: debug info offset of the correspondent compile unit. - support::endian::write(RangesStream, - static_cast(CUMap.find(Offset)->second), - support::little); + support::endian::write( + RangesStream, static_cast(CUMap.find(Offset)->second.Offset), + support::little); // Header field #4: address size. // 8 since we only write ELF64 binaries for now. @@ -472,23 +471,32 @@ return BinaryContentsStr; } -std::unordered_map -DebugInfoBinaryPatcher::computeNewOffsets() { - std::unordered_map CUMap; +CUOffsetMap DebugInfoBinaryPatcher::computeNewOffsets(DWARFContext &DWCtx, + bool IsDWOContext) { + CUOffsetMap CUMap; std::sort(DebugPatches.begin(), DebugPatches.end(), [](const UniquePatchPtrType &V1, const UniquePatchPtrType &V2) { return V1.get()->Offset < V2.get()->Offset; }); + DWARFUnitVector::compile_unit_range CompileUnits = + IsDWOContext ? DWCtx.dwo_compile_units() : DWCtx.compile_units(); + + for (const std::unique_ptr &CU : CompileUnits) + CUMap[CU->getOffset()] = {static_cast(CU->getOffset()), + static_cast(CU->getLength())}; + // Calculating changes in .debug_info size from Patches to build a map of old // to updated reference destination offsets. + uint32_t PreviousOffset = 0; + uint32_t PreviousChangeInSize = 0; for (UniquePatchPtrType &PatchBase : DebugPatches) { Patch *P = PatchBase.get(); switch (P->Kind) { default: continue; case DebugPatchKind::PatchValue64to32: { - ChangeInSize -= 4; + PreviousChangeInSize -= 4; break; } case DebugPatchKind::PatchValueVariable: { @@ -497,13 +505,14 @@ std::string Temp; raw_string_ostream OS(Temp); encodeULEB128(DPV->Value, OS); - ChangeInSize += Temp.size() - DPV->OldValueSize; + PreviousChangeInSize += Temp.size() - DPV->OldValueSize; break; } case DebugPatchKind::DestinationReferenceLabel: { DestinationReferenceLabel *DRL = reinterpret_cast(P); - OldToNewOffset[DRL->Offset] = DRL->Offset + ChangeInSize; + OldToNewOffset[DRL->Offset] = + DRL->Offset + ChangeInSize + PreviousChangeInSize; break; } case DebugPatchKind::ReferencePatchValue: { @@ -511,7 +520,7 @@ // to reduce algorithmic complexity. DebugPatchReference *RDP = reinterpret_cast(P); if (RDP->PatchInfo.IndirectRelative) { - ChangeInSize += 4 - RDP->PatchInfo.OldValueSize; + PreviousChangeInSize += 4 - RDP->PatchInfo.OldValueSize; assert(RDP->PatchInfo.OldValueSize <= 4 && "Variable encoding reference greater than 4 bytes."); } @@ -521,11 +530,16 @@ DWARFUnitOffsetBaseLabel *BaseLabel = reinterpret_cast(P); uint32_t CUOffset = BaseLabel->Offset; + ChangeInSize += PreviousChangeInSize; uint32_t CUOffsetUpdate = CUOffset + ChangeInSize; - CUMap[CUOffset] = CUOffsetUpdate; + CUMap[CUOffset].Offset = CUOffsetUpdate; + CUMap[PreviousOffset].Length -= PreviousChangeInSize; + PreviousChangeInSize = 0; + PreviousOffset = CUOffset; } } } + CUMap[PreviousOffset].Length -= PreviousChangeInSize; return CUMap; } 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 @@ -325,14 +325,14 @@ DebugInfoPatcher->clearDestinationLabels(); flushPendingRanges(*DebugInfoPatcher); - finalizeDebugSections(*DebugInfoPatcher); + CUOffsetMap OffsetMap = finalizeDebugSections(*DebugInfoPatcher); if (opts::WriteDWP) writeDWP(DWOIdToName); else writeDWOFiles(DWOIdToName); - updateGdbIndexSection(); + updateGdbIndexSection(OffsetMap); } void DWARFRewriter::updateUnitDebugInfo( @@ -822,8 +822,8 @@ TypeInfoSection->setIsFinalized(); } -void DWARFRewriter::finalizeDebugSections( - DebugInfoBinaryPatcher &DebugInfoPatcher) { +CUOffsetMap +DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) { if (StrWriter->isInitialized()) { RewriteInstance::addToDebugSectionsToOverwrite(".debug_str"); std::unique_ptr DebugStrSectionContents = @@ -900,8 +900,8 @@ } // No more creating new DebugInfoPatches. - std::unordered_map CUMap = - DebugInfoPatcher.computeNewOffsets(); + CUOffsetMap CUMap = + DebugInfoPatcher.computeNewOffsets(*BC.DwCtx.get(), false); // Skip .debug_aranges if we are re-generating .gdb_index. if (opts::KeepARanges || !BC.getGdbIndexSection()) { @@ -918,6 +918,7 @@ copyByteArray(ARangesContents), ARangesContents.size()); } + return CUMap; } // Creates all the data structures necessary for creating MCStreamer. @@ -960,15 +961,14 @@ // Exctracts an appropriate slice if input is DWP. // Applies patches or overwrites the section. -Optional -updateDebugData(std::string &Storage, const SectionRef &Section, - const StringMap &KnownSections, - MCStreamer &Streamer, DWARFRewriter &Writer, - const DWARFUnitIndex::Entry *DWOEntry, uint64_t DWOId, - std::unique_ptr &OutputBuffer) { +Optional updateDebugData( + DWARFContext &DWCtx, std::string &Storage, const SectionRef &Section, + const StringMap &KnownSections, MCStreamer &Streamer, + DWARFRewriter &Writer, const DWARFUnitIndex::Entry *DWOEntry, + uint64_t DWOId, std::unique_ptr &OutputBuffer) { auto applyPatch = [&](DebugInfoBinaryPatcher *Patcher, StringRef Data) -> StringRef { - Patcher->computeNewOffsets(); + Patcher->computeNewOffsets(DWCtx, true); Storage = Patcher->patchBinary(Data); return StringRef(Storage.c_str(), Storage.size()); }; @@ -1129,9 +1129,9 @@ for (const SectionRef &Section : DWOFile->sections()) { std::string Storage = ""; std::unique_ptr OutputData; - Optional TOutData = - updateDebugData(Storage, Section, KnownSections, *Streamer, *this, - DWOEntry, *DWOId, OutputData); + Optional TOutData = updateDebugData( + (*DWOCU)->getContext(), Storage, Section, KnownSections, *Streamer, + *this, DWOEntry, *DWOId, OutputData); if (!TOutData) continue; @@ -1229,9 +1229,9 @@ for (const SectionRef &Section : File->sections()) { std::string Storage = ""; std::unique_ptr OutputData; - if (Optional OutData = - updateDebugData(Storage, Section, KnownSections, *Streamer, *this, - DWOEntry, *DWOId, OutputData)) + if (Optional OutData = updateDebugData( + (*DWOCU)->getContext(), Storage, Section, KnownSections, + *Streamer, *this, DWOEntry, *DWOId, OutputData)) Streamer->emitBytes(*OutData); } Streamer->Finish(); @@ -1239,7 +1239,7 @@ } } -void DWARFRewriter::updateGdbIndexSection() { +void DWARFRewriter::updateGdbIndexSection(CUOffsetMap &CUMap) { if (!BC.getGdbIndexSection()) return; @@ -1316,10 +1316,23 @@ write32le(Buffer + 20, ConstantPoolOffset + Delta); Buffer += 24; - // Copy over CU list and types CU list. - memcpy(Buffer, GdbIndexContents.data() + 24, - AddressTableOffset - CUListOffset); - Buffer += AddressTableOffset - CUListOffset; + // Writing out CU List + for (auto &CUInfo : CUMap) { + write64le(Buffer, CUInfo.second.Offset); + // Length encoded in CU doesn't contain first 4 bytes that encode length. + write64le(Buffer + 8, CUInfo.second.Length + 4); + Buffer += 16; + } + + // Copy over types CU list + // Spec says " triplet, the first value is the CU offset, the second value is + // the type offset in the CU, and the third value is the type signature" + // Looking at what is being generated by gdb-add-index. The first entry is TU + // offset, second entry is offset from it, and third entry is the type + // signature. + memcpy(Buffer, GdbIndexContents.data() + CUTypesOffset, + AddressTableOffset - CUTypesOffset); + Buffer += AddressTableOffset - CUTypesOffset; // Generate new address table. for (const std::pair &CURangesPair :