12f09f445SMaksim Panchenko //===- bolt/Core/DebugData.cpp - Debugging information handling -----------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler // 92f09f445SMaksim Panchenko // This file implements functions and classes for handling debug info. 102f09f445SMaksim Panchenko // 11a34c753fSRafael Auler //===----------------------------------------------------------------------===// 12a34c753fSRafael Auler 13a34c753fSRafael Auler #include "bolt/Core/DebugData.h" 14f8c7fb49SAmir Ayupov #include "bolt/Core/BinaryContext.h" 15014cd37fSAlexander Yermolovich #include "bolt/Rewrite/RewriteInstance.h" 16a34c753fSRafael Auler #include "bolt/Utils/Utils.h" 17290e4823Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 18290e4823Sserge-sans-paille #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" 19014cd37fSAlexander Yermolovich #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" 2057f7c7d9Sserge-sans-paille #include "llvm/MC/MCAssembler.h" 21f8c7fb49SAmir Ayupov #include "llvm/MC/MCContext.h" 22a34c753fSRafael Auler #include "llvm/MC/MCObjectStreamer.h" 23a34c753fSRafael Auler #include "llvm/Support/CommandLine.h" 24a34c753fSRafael Auler #include "llvm/Support/EndianStream.h" 25a34c753fSRafael Auler #include "llvm/Support/LEB128.h" 269f3f9d19SAlexander Yermolovich #include "llvm/Support/SHA1.h" 27a34c753fSRafael Auler #include <algorithm> 28a34c753fSRafael Auler #include <cassert> 29a34c753fSRafael Auler #include <cstdint> 30*124ca880SAlexander Yermolovich #include <functional> 31a34c753fSRafael Auler #include <limits> 321c2f4bbeSAlexander Yermolovich #include <unordered_map> 33ba1ac98cSAlexander Yermolovich #include <vector> 34a34c753fSRafael Auler 35a34c753fSRafael Auler #define DEBUG_TYPE "bolt-debug-info" 36a34c753fSRafael Auler 37a34c753fSRafael Auler namespace opts { 38a34c753fSRafael Auler extern llvm::cl::opt<unsigned> Verbosity; 391c2f4bbeSAlexander Yermolovich } // namespace opts 40a34c753fSRafael Auler 41a34c753fSRafael Auler namespace llvm { 42f8c7fb49SAmir Ayupov class MCSymbol; 43f8c7fb49SAmir Ayupov 44a34c753fSRafael Auler namespace bolt { 45a34c753fSRafael Auler 46370e4761SAmir Ayupov std::optional<AttrInfo> 47bd1ebe9dSAlexander Yermolovich findAttributeInfo(const DWARFDie DIE, 48bd1ebe9dSAlexander Yermolovich const DWARFAbbreviationDeclaration *AbbrevDecl, 49bd1ebe9dSAlexander Yermolovich uint32_t Index) { 50bd1ebe9dSAlexander Yermolovich const DWARFUnit &U = *DIE.getDwarfUnit(); 51bd1ebe9dSAlexander Yermolovich uint64_t Offset = 52bd1ebe9dSAlexander Yermolovich AbbrevDecl->getAttributeOffsetFromIndex(Index, DIE.getOffset(), U); 5389fab98eSFangrui Song std::optional<DWARFFormValue> Value = 54bd1ebe9dSAlexander Yermolovich AbbrevDecl->getAttributeValueFromOffset(Index, Offset, U); 55bd1ebe9dSAlexander Yermolovich if (!Value) 56e324a80fSKazu Hirata return std::nullopt; 57bd1ebe9dSAlexander Yermolovich // AttributeSpec 58bd1ebe9dSAlexander Yermolovich const DWARFAbbreviationDeclaration::AttributeSpec *AttrVal = 59bd1ebe9dSAlexander Yermolovich AbbrevDecl->attributes().begin() + Index; 60bd1ebe9dSAlexander Yermolovich uint32_t ValSize = 0; 6189fab98eSFangrui Song std::optional<int64_t> ValSizeOpt = AttrVal->getByteSize(U); 62bd1ebe9dSAlexander Yermolovich if (ValSizeOpt) { 63bd1ebe9dSAlexander Yermolovich ValSize = static_cast<uint32_t>(*ValSizeOpt); 64bd1ebe9dSAlexander Yermolovich } else { 65bd1ebe9dSAlexander Yermolovich DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); 66bd1ebe9dSAlexander Yermolovich uint64_t NewOffset = Offset; 67bd1ebe9dSAlexander Yermolovich DWARFFormValue::skipValue(Value->getForm(), DebugInfoData, &NewOffset, 68bd1ebe9dSAlexander Yermolovich U.getFormParams()); 69bd1ebe9dSAlexander Yermolovich // This includes entire size of the entry, which might not be just the 70bd1ebe9dSAlexander Yermolovich // encoding part. For example for DW_AT_loc it will include expression 71bd1ebe9dSAlexander Yermolovich // location. 72bd1ebe9dSAlexander Yermolovich ValSize = NewOffset - Offset; 73bd1ebe9dSAlexander Yermolovich } 741c6dc43dSAlexander Yermolovich return AttrInfo{*Value, DIE.getAbbreviationDeclarationPtr(), Offset, ValSize}; 751c6dc43dSAlexander Yermolovich } 76bd1ebe9dSAlexander Yermolovich 77370e4761SAmir Ayupov std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE, 781c6dc43dSAlexander Yermolovich dwarf::Attribute Attr) { 791c6dc43dSAlexander Yermolovich if (!DIE.isValid()) 80e324a80fSKazu Hirata return std::nullopt; 811c6dc43dSAlexander Yermolovich const DWARFAbbreviationDeclaration *AbbrevDecl = 821c6dc43dSAlexander Yermolovich DIE.getAbbreviationDeclarationPtr(); 831c6dc43dSAlexander Yermolovich if (!AbbrevDecl) 84e324a80fSKazu Hirata return std::nullopt; 8589fab98eSFangrui Song std::optional<uint32_t> Index = AbbrevDecl->findAttributeIndex(Attr); 861c6dc43dSAlexander Yermolovich if (!Index) 87e324a80fSKazu Hirata return std::nullopt; 881c6dc43dSAlexander Yermolovich return findAttributeInfo(DIE, AbbrevDecl, *Index); 89bd1ebe9dSAlexander Yermolovich } 90bd1ebe9dSAlexander Yermolovich 91a34c753fSRafael Auler const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{0, 0}; 92a34c753fSRafael Auler 93a34c753fSRafael Auler namespace { 94a34c753fSRafael Auler 951c2f4bbeSAlexander Yermolovich LLVM_ATTRIBUTE_UNUSED 961c2f4bbeSAlexander Yermolovich static void printLE64(const std::string &S) { 971c2f4bbeSAlexander Yermolovich for (uint32_t I = 0, Size = S.size(); I < Size; ++I) { 981c2f4bbeSAlexander Yermolovich errs() << Twine::utohexstr(S[I]); 991c2f4bbeSAlexander Yermolovich errs() << Twine::utohexstr((int8_t)S[I]); 1001c2f4bbeSAlexander Yermolovich } 1011c2f4bbeSAlexander Yermolovich errs() << "\n"; 1021c2f4bbeSAlexander Yermolovich } 1031c2f4bbeSAlexander Yermolovich 104a34c753fSRafael Auler // Writes address ranges to Writer as pairs of 64-bit (address, size). 105a34c753fSRafael Auler // If RelativeRange is true, assumes the address range to be written must be of 106a34c753fSRafael Auler // the form (begin address, range size), otherwise (begin address, end address). 107a34c753fSRafael Auler // Terminates the list by writing a pair of two zeroes. 108a34c753fSRafael Auler // Returns the number of written bytes. 10940c2e0faSMaksim Panchenko uint64_t writeAddressRanges(raw_svector_ostream &Stream, 110a34c753fSRafael Auler const DebugAddressRangesVector &AddressRanges, 111a34c753fSRafael Auler const bool WriteRelativeRanges = false) { 112a34c753fSRafael Auler for (const DebugAddressRange &Range : AddressRanges) { 113a34c753fSRafael Auler support::endian::write(Stream, Range.LowPC, support::little); 114a34c753fSRafael Auler support::endian::write( 115a34c753fSRafael Auler Stream, WriteRelativeRanges ? Range.HighPC - Range.LowPC : Range.HighPC, 116a34c753fSRafael Auler support::little); 117a34c753fSRafael Auler } 118a34c753fSRafael Auler // Finish with 0 entries. 119a34c753fSRafael Auler support::endian::write(Stream, 0ULL, support::little); 120a34c753fSRafael Auler support::endian::write(Stream, 0ULL, support::little); 121a34c753fSRafael Auler return AddressRanges.size() * 16 + 16; 122a34c753fSRafael Auler } 123a34c753fSRafael Auler 124a34c753fSRafael Auler } // namespace 125a34c753fSRafael Auler 126a34c753fSRafael Auler DebugRangesSectionWriter::DebugRangesSectionWriter() { 127a34c753fSRafael Auler RangesBuffer = std::make_unique<DebugBufferVector>(); 128a34c753fSRafael Auler RangesStream = std::make_unique<raw_svector_ostream>(*RangesBuffer); 129a34c753fSRafael Auler 130a34c753fSRafael Auler // Add an empty range as the first entry; 131a34c753fSRafael Auler SectionOffset += 132a34c753fSRafael Auler writeAddressRanges(*RangesStream.get(), DebugAddressRangesVector{}); 133014cd37fSAlexander Yermolovich Kind = RangesWriterKind::DebugRangesWriter; 134a34c753fSRafael Auler } 135a34c753fSRafael Auler 136a34c753fSRafael Auler uint64_t DebugRangesSectionWriter::addRanges( 137a34c753fSRafael Auler DebugAddressRangesVector &&Ranges, 138a34c753fSRafael Auler std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) { 139a34c753fSRafael Auler if (Ranges.empty()) 140a34c753fSRafael Auler return getEmptyRangesOffset(); 141a34c753fSRafael Auler 142a34c753fSRafael Auler const auto RI = CachedRanges.find(Ranges); 143a34c753fSRafael Auler if (RI != CachedRanges.end()) 144a34c753fSRafael Auler return RI->second; 145a34c753fSRafael Auler 146a34c753fSRafael Auler const uint64_t EntryOffset = addRanges(Ranges); 147a34c753fSRafael Auler CachedRanges.emplace(std::move(Ranges), EntryOffset); 148a34c753fSRafael Auler 149a34c753fSRafael Auler return EntryOffset; 150a34c753fSRafael Auler } 151a34c753fSRafael Auler 152e22ff52cSAlexander Yermolovich uint64_t DebugRangesSectionWriter::addRanges(DebugAddressRangesVector &Ranges) { 153a34c753fSRafael Auler if (Ranges.empty()) 154a34c753fSRafael Auler return getEmptyRangesOffset(); 155a34c753fSRafael Auler 156a34c753fSRafael Auler // Reading the SectionOffset and updating it should be atomic to guarantee 157a34c753fSRafael Auler // unique and correct offsets in patches. 158a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(WriterMutex); 159a34c753fSRafael Auler const uint32_t EntryOffset = SectionOffset; 160a34c753fSRafael Auler SectionOffset += writeAddressRanges(*RangesStream.get(), Ranges); 161a34c753fSRafael Auler 162a34c753fSRafael Auler return EntryOffset; 163a34c753fSRafael Auler } 164a34c753fSRafael Auler 165a34c753fSRafael Auler uint64_t DebugRangesSectionWriter::getSectionOffset() { 166a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(WriterMutex); 167a34c753fSRafael Auler return SectionOffset; 168a34c753fSRafael Auler } 169a34c753fSRafael Auler 170014cd37fSAlexander Yermolovich DebugAddrWriter *DebugRangeListsSectionWriter::AddrWriter = nullptr; 171014cd37fSAlexander Yermolovich 172014cd37fSAlexander Yermolovich uint64_t DebugRangeListsSectionWriter::addRanges( 173014cd37fSAlexander Yermolovich DebugAddressRangesVector &&Ranges, 174014cd37fSAlexander Yermolovich std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) { 175014cd37fSAlexander Yermolovich return addRanges(Ranges); 176014cd37fSAlexander Yermolovich } 177014cd37fSAlexander Yermolovich 178014cd37fSAlexander Yermolovich struct LocListsRangelistsHeader { 179014cd37fSAlexander Yermolovich UnitLengthType UnitLength; // Size of loclist entris section, not including 180014cd37fSAlexander Yermolovich // size of header. 181014cd37fSAlexander Yermolovich VersionType Version; 182014cd37fSAlexander Yermolovich AddressSizeType AddressSize; 183014cd37fSAlexander Yermolovich SegmentSelectorType SegmentSelector; 184014cd37fSAlexander Yermolovich OffsetEntryCountType OffsetEntryCount; 185014cd37fSAlexander Yermolovich }; 186014cd37fSAlexander Yermolovich 187014cd37fSAlexander Yermolovich static std::unique_ptr<DebugBufferVector> 188014cd37fSAlexander Yermolovich getDWARF5Header(const LocListsRangelistsHeader &Header) { 189014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> HeaderBuffer = 190014cd37fSAlexander Yermolovich std::make_unique<DebugBufferVector>(); 191014cd37fSAlexander Yermolovich std::unique_ptr<raw_svector_ostream> HeaderStream = 192014cd37fSAlexander Yermolovich std::make_unique<raw_svector_ostream>(*HeaderBuffer); 193014cd37fSAlexander Yermolovich 194014cd37fSAlexander Yermolovich // 7.29 length of the set of entries for this compilation unit, not including 195014cd37fSAlexander Yermolovich // the length field itself 196014cd37fSAlexander Yermolovich const uint32_t HeaderSize = 197014cd37fSAlexander Yermolovich getDWARF5RngListLocListHeaderSize() - sizeof(UnitLengthType); 198014cd37fSAlexander Yermolovich 199014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.UnitLength + HeaderSize, 200014cd37fSAlexander Yermolovich support::little); 201014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.Version, support::little); 202014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.AddressSize, support::little); 203014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.SegmentSelector, 204014cd37fSAlexander Yermolovich support::little); 205014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.OffsetEntryCount, 206014cd37fSAlexander Yermolovich support::little); 207014cd37fSAlexander Yermolovich return HeaderBuffer; 208014cd37fSAlexander Yermolovich } 209014cd37fSAlexander Yermolovich 210*124ca880SAlexander Yermolovich struct OffsetEntry { 211*124ca880SAlexander Yermolovich uint32_t Index; 212*124ca880SAlexander Yermolovich uint32_t StartOffset; 213*124ca880SAlexander Yermolovich uint32_t EndOffset; 214*124ca880SAlexander Yermolovich }; 215*124ca880SAlexander Yermolovich template <typename DebugVector, typename ListEntry, typename DebugAddressEntry> 216*124ca880SAlexander Yermolovich static bool emitWithBase(raw_ostream &OS, const DebugVector &Entries, 217e22ff52cSAlexander Yermolovich DebugAddrWriter &AddrWriter, DWARFUnit &CU, 218*124ca880SAlexander Yermolovich uint32_t &Index, const ListEntry BaseAddressx, 219*124ca880SAlexander Yermolovich const ListEntry OffsetPair, const ListEntry EndOfList, 220*124ca880SAlexander Yermolovich const std::function<void(uint32_t)> &Func) { 221*124ca880SAlexander Yermolovich if (Entries.size() < 2) 222e22ff52cSAlexander Yermolovich return false; 223*124ca880SAlexander Yermolovich uint64_t Base = Entries[Index].LowPC; 224*124ca880SAlexander Yermolovich std::vector<OffsetEntry> Offsets; 225e22ff52cSAlexander Yermolovich uint8_t TempBuffer[64]; 226*124ca880SAlexander Yermolovich while (Index < Entries.size()) { 227*124ca880SAlexander Yermolovich const DebugAddressEntry &Entry = Entries[Index]; 228*124ca880SAlexander Yermolovich if (Entry.LowPC == 0) 229e22ff52cSAlexander Yermolovich break; 230*124ca880SAlexander Yermolovich assert(Base <= Entry.LowPC && "Entry base is higher than low PC"); 231*124ca880SAlexander Yermolovich uint32_t StartOffset = Entry.LowPC - Base; 232*124ca880SAlexander Yermolovich uint32_t EndOffset = Entry.HighPC - Base; 233e22ff52cSAlexander Yermolovich if (encodeULEB128(EndOffset, TempBuffer) > 2) 234e22ff52cSAlexander Yermolovich break; 235*124ca880SAlexander Yermolovich Offsets.push_back({Index, StartOffset, EndOffset}); 236e22ff52cSAlexander Yermolovich ++Index; 237e22ff52cSAlexander Yermolovich } 238e22ff52cSAlexander Yermolovich 239*124ca880SAlexander Yermolovich if (Offsets.size() < 2) { 240*124ca880SAlexander Yermolovich Index -= Offsets.size(); 241e22ff52cSAlexander Yermolovich return false; 242e22ff52cSAlexander Yermolovich } 243e22ff52cSAlexander Yermolovich 244*124ca880SAlexander Yermolovich support::endian::write(OS, static_cast<uint8_t>(BaseAddressx), 245e22ff52cSAlexander Yermolovich support::little); 246e22ff52cSAlexander Yermolovich uint32_t BaseIndex = AddrWriter.getIndexFromAddress(Base, CU); 247e22ff52cSAlexander Yermolovich encodeULEB128(BaseIndex, OS); 248*124ca880SAlexander Yermolovich for (auto &OffsetEntry : Offsets) { 249*124ca880SAlexander Yermolovich support::endian::write(OS, static_cast<uint8_t>(OffsetPair), 250e22ff52cSAlexander Yermolovich support::little); 251*124ca880SAlexander Yermolovich encodeULEB128(OffsetEntry.StartOffset, OS); 252*124ca880SAlexander Yermolovich encodeULEB128(OffsetEntry.EndOffset, OS); 253*124ca880SAlexander Yermolovich Func(OffsetEntry.Index); 254e22ff52cSAlexander Yermolovich } 255*124ca880SAlexander Yermolovich support::endian::write(OS, static_cast<uint8_t>(EndOfList), support::little); 256e22ff52cSAlexander Yermolovich return true; 257e22ff52cSAlexander Yermolovich } 258e22ff52cSAlexander Yermolovich 259e22ff52cSAlexander Yermolovich uint64_t 260e22ff52cSAlexander Yermolovich DebugRangeListsSectionWriter::addRanges(DebugAddressRangesVector &Ranges) { 261014cd37fSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 262014cd37fSAlexander Yermolovich 263014cd37fSAlexander Yermolovich RangeEntries.push_back(CurrentOffset); 264e22ff52cSAlexander Yermolovich bool WrittenStartxLength = false; 265e22ff52cSAlexander Yermolovich std::sort( 266e22ff52cSAlexander Yermolovich Ranges.begin(), Ranges.end(), 267e22ff52cSAlexander Yermolovich [](const DebugAddressRange &R1, const DebugAddressRange &R2) -> bool { 268e22ff52cSAlexander Yermolovich return R1.LowPC < R2.LowPC; 269e22ff52cSAlexander Yermolovich }); 270e22ff52cSAlexander Yermolovich for (unsigned I = 0; I < Ranges.size();) { 271e22ff52cSAlexander Yermolovich WrittenStartxLength = false; 272*124ca880SAlexander Yermolovich if (emitWithBase<DebugAddressRangesVector, dwarf::RnglistEntries, 273*124ca880SAlexander Yermolovich DebugAddressRange>( 274*124ca880SAlexander Yermolovich *CUBodyStream, Ranges, *AddrWriter, *CU, I, 275*124ca880SAlexander Yermolovich dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair, 276*124ca880SAlexander Yermolovich dwarf::DW_RLE_end_of_list, [](uint32_t Index) -> void {})) 277e22ff52cSAlexander Yermolovich continue; 278*124ca880SAlexander Yermolovich 279e22ff52cSAlexander Yermolovich const DebugAddressRange &Range = Ranges[I]; 280014cd37fSAlexander Yermolovich support::endian::write(*CUBodyStream, 281014cd37fSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_RLE_startx_length), 282014cd37fSAlexander Yermolovich support::little); 283ba1ac98cSAlexander Yermolovich uint32_t Index = AddrWriter->getIndexFromAddress(Range.LowPC, *CU); 284014cd37fSAlexander Yermolovich encodeULEB128(Index, *CUBodyStream); 285014cd37fSAlexander Yermolovich encodeULEB128(Range.HighPC - Range.LowPC, *CUBodyStream); 286e22ff52cSAlexander Yermolovich ++I; 287e22ff52cSAlexander Yermolovich WrittenStartxLength = true; 288014cd37fSAlexander Yermolovich } 289e22ff52cSAlexander Yermolovich if (WrittenStartxLength) 290014cd37fSAlexander Yermolovich support::endian::write(*CUBodyStream, 291014cd37fSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_RLE_end_of_list), 292014cd37fSAlexander Yermolovich support::little); 293014cd37fSAlexander Yermolovich CurrentOffset = CUBodyBuffer->size(); 294014cd37fSAlexander Yermolovich return RangeEntries.size() - 1; 295014cd37fSAlexander Yermolovich } 296014cd37fSAlexander Yermolovich 297014cd37fSAlexander Yermolovich void DebugRangeListsSectionWriter::finalizeSection() { 298014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> CUArrayBuffer = 299014cd37fSAlexander Yermolovich std::make_unique<DebugBufferVector>(); 300014cd37fSAlexander Yermolovich std::unique_ptr<raw_svector_ostream> CUArrayStream = 301014cd37fSAlexander Yermolovich std::make_unique<raw_svector_ostream>(*CUArrayBuffer); 302014cd37fSAlexander Yermolovich constexpr uint32_t SizeOfArrayEntry = 4; 303014cd37fSAlexander Yermolovich const uint32_t SizeOfArraySection = RangeEntries.size() * SizeOfArrayEntry; 304014cd37fSAlexander Yermolovich for (uint32_t Offset : RangeEntries) 305014cd37fSAlexander Yermolovich support::endian::write(*CUArrayStream, Offset + SizeOfArraySection, 306014cd37fSAlexander Yermolovich support::little); 307014cd37fSAlexander Yermolovich 308014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> Header = getDWARF5Header( 309014cd37fSAlexander Yermolovich {static_cast<uint32_t>(SizeOfArraySection + CUBodyBuffer.get()->size()), 310014cd37fSAlexander Yermolovich 5, 8, 0, static_cast<uint32_t>(RangeEntries.size())}); 311014cd37fSAlexander Yermolovich *RangesStream << *Header; 312014cd37fSAlexander Yermolovich *RangesStream << *CUArrayBuffer; 313014cd37fSAlexander Yermolovich *RangesStream << *CUBodyBuffer; 314014cd37fSAlexander Yermolovich SectionOffset = RangesBuffer->size(); 315014cd37fSAlexander Yermolovich } 316014cd37fSAlexander Yermolovich 317ba1ac98cSAlexander Yermolovich void DebugRangeListsSectionWriter::initSection(DWARFUnit &Unit) { 318014cd37fSAlexander Yermolovich CUBodyBuffer = std::make_unique<DebugBufferVector>(); 319014cd37fSAlexander Yermolovich CUBodyStream = std::make_unique<raw_svector_ostream>(*CUBodyBuffer); 320014cd37fSAlexander Yermolovich RangeEntries.clear(); 321014cd37fSAlexander Yermolovich CurrentOffset = 0; 322ba1ac98cSAlexander Yermolovich CU = &Unit; 323014cd37fSAlexander Yermolovich } 324014cd37fSAlexander Yermolovich 325a34c753fSRafael Auler void DebugARangesSectionWriter::addCURanges(uint64_t CUOffset, 326a34c753fSRafael Auler DebugAddressRangesVector &&Ranges) { 327a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(CUAddressRangesMutex); 328a34c753fSRafael Auler CUAddressRanges.emplace(CUOffset, std::move(Ranges)); 329a34c753fSRafael Auler } 330a34c753fSRafael Auler 331a34c753fSRafael Auler void DebugARangesSectionWriter::writeARangesSection( 332612f0f45SAlexander Yermolovich raw_svector_ostream &RangesStream, const CUOffsetMap &CUMap) const { 333a34c753fSRafael Auler // For reference on the format of the .debug_aranges section, see the DWARF4 334a34c753fSRafael Auler // specification, section 6.1.4 Lookup by Address 335a34c753fSRafael Auler // http://www.dwarfstd.org/doc/DWARF4.pdf 336a34c753fSRafael Auler for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) { 337a34c753fSRafael Auler const uint64_t Offset = CUOffsetAddressRangesPair.first; 338a34c753fSRafael Auler const DebugAddressRangesVector &AddressRanges = 339a34c753fSRafael Auler CUOffsetAddressRangesPair.second; 340a34c753fSRafael Auler 341a34c753fSRafael Auler // Emit header. 342a34c753fSRafael Auler 343a34c753fSRafael Auler // Size of this set: 8 (size of the header) + 4 (padding after header) 344a34c753fSRafael Auler // + 2*sizeof(uint64_t) bytes for each of the ranges, plus an extra 345a34c753fSRafael Auler // pair of uint64_t's for the terminating, zero-length range. 346a34c753fSRafael Auler // Does not include size field itself. 347a34c753fSRafael Auler uint32_t Size = 8 + 4 + 2 * sizeof(uint64_t) * (AddressRanges.size() + 1); 348a34c753fSRafael Auler 349a34c753fSRafael Auler // Header field #1: set size. 350a34c753fSRafael Auler support::endian::write(RangesStream, Size, support::little); 351a34c753fSRafael Auler 352a34c753fSRafael Auler // Header field #2: version number, 2 as per the specification. 353a34c753fSRafael Auler support::endian::write(RangesStream, static_cast<uint16_t>(2), 354a34c753fSRafael Auler support::little); 355a34c753fSRafael Auler 3561c2f4bbeSAlexander Yermolovich assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map"); 357a34c753fSRafael Auler // Header field #3: debug info offset of the correspondent compile unit. 358612f0f45SAlexander Yermolovich support::endian::write( 359612f0f45SAlexander Yermolovich RangesStream, static_cast<uint32_t>(CUMap.find(Offset)->second.Offset), 360a34c753fSRafael Auler support::little); 361a34c753fSRafael Auler 362a34c753fSRafael Auler // Header field #4: address size. 363a34c753fSRafael Auler // 8 since we only write ELF64 binaries for now. 364a34c753fSRafael Auler RangesStream << char(8); 365a34c753fSRafael Auler 366a34c753fSRafael Auler // Header field #5: segment size of target architecture. 367a34c753fSRafael Auler RangesStream << char(0); 368a34c753fSRafael Auler 369a34c753fSRafael Auler // Padding before address table - 4 bytes in the 64-bit-pointer case. 370a34c753fSRafael Auler support::endian::write(RangesStream, static_cast<uint32_t>(0), 371a34c753fSRafael Auler support::little); 372a34c753fSRafael Auler 373a34c753fSRafael Auler writeAddressRanges(RangesStream, AddressRanges, true); 374a34c753fSRafael Auler } 375a34c753fSRafael Auler } 376a34c753fSRafael Auler 377a34c753fSRafael Auler DebugAddrWriter::DebugAddrWriter(BinaryContext *Bc) { BC = Bc; } 378a34c753fSRafael Auler 379a34c753fSRafael Auler void DebugAddrWriter::AddressForDWOCU::dump() { 380a34c753fSRafael Auler std::vector<IndexAddressPair> SortedMap(indexToAddressBegin(), 381a34c753fSRafael Auler indexToAdddessEnd()); 382a34c753fSRafael Auler // Sorting address in increasing order of indices. 383c4302e4fSAmir Ayupov llvm::sort(SortedMap, llvm::less_first()); 384a34c753fSRafael Auler for (auto &Pair : SortedMap) 385a34c753fSRafael Auler dbgs() << Twine::utohexstr(Pair.second) << "\t" << Pair.first << "\n"; 386a34c753fSRafael Auler } 387ba1ac98cSAlexander Yermolovich uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, DWARFUnit &CU) { 388e579f5c6SAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 389ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(CU); 390014cd37fSAlexander Yermolovich if (!AddressMaps.count(CUID)) 391014cd37fSAlexander Yermolovich AddressMaps[CUID] = AddressForDWOCU(); 392a34c753fSRafael Auler 393014cd37fSAlexander Yermolovich AddressForDWOCU &Map = AddressMaps[CUID]; 394a34c753fSRafael Auler auto Entry = Map.find(Address); 395a34c753fSRafael Auler if (Entry == Map.end()) { 396a34c753fSRafael Auler auto Index = Map.getNextIndex(); 397a34c753fSRafael Auler Entry = Map.insert(Address, Index).first; 398a34c753fSRafael Auler } 399a34c753fSRafael Auler return Entry->second; 400a34c753fSRafael Auler } 401a34c753fSRafael Auler 402a34c753fSRafael Auler // Case1) Address is not in map insert in to AddresToIndex and IndexToAddres 403a34c753fSRafael Auler // Case2) Address is in the map but Index is higher or equal. Need to update 404a34c753fSRafael Auler // IndexToAddrss. Case3) Address is in the map but Index is lower. Need to 405a34c753fSRafael Auler // update AddressToIndex and IndexToAddress 406a34c753fSRafael Auler void DebugAddrWriter::addIndexAddress(uint64_t Address, uint32_t Index, 407ba1ac98cSAlexander Yermolovich DWARFUnit &CU) { 408e579f5c6SAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 409ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(CU); 410014cd37fSAlexander Yermolovich AddressForDWOCU &Map = AddressMaps[CUID]; 411a34c753fSRafael Auler auto Entry = Map.find(Address); 412a34c753fSRafael Auler if (Entry != Map.end()) { 413a34c753fSRafael Auler if (Entry->second > Index) 414a34c753fSRafael Auler Map.updateAddressToIndex(Address, Index); 415a34c753fSRafael Auler Map.updateIndexToAddrss(Address, Index); 4163652483cSRafael Auler } else { 417a34c753fSRafael Auler Map.insert(Address, Index); 418a34c753fSRafael Auler } 4193652483cSRafael Auler } 420a34c753fSRafael Auler 421a34c753fSRafael Auler AddressSectionBuffer DebugAddrWriter::finalize() { 422a34c753fSRafael Auler // Need to layout all sections within .debug_addr 423a34c753fSRafael Auler // Within each section sort Address by index. 424a34c753fSRafael Auler AddressSectionBuffer Buffer; 425a34c753fSRafael Auler raw_svector_ostream AddressStream(Buffer); 426a34c753fSRafael Auler for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) { 427a34c753fSRafael Auler // Handling the case wehre debug information is a mix of Debug fission and 428a34c753fSRafael Auler // monolitic. 429ba1ac98cSAlexander Yermolovich if (!CU->getDWOId()) 430a34c753fSRafael Auler continue; 431ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(*CU.get()); 432ba1ac98cSAlexander Yermolovich auto AM = AddressMaps.find(CUID); 433a34c753fSRafael Auler // Adding to map even if it did not contribute to .debug_addr. 4343abb68a6SAlexander Yermolovich // The Skeleton CU might still have DW_AT_GNU_addr_base. 435ba1ac98cSAlexander Yermolovich DWOIdToOffsetMap[CUID] = Buffer.size(); 436a34c753fSRafael Auler // If does not exist this CUs DWO section didn't contribute to .debug_addr. 437a34c753fSRafael Auler if (AM == AddressMaps.end()) 438a34c753fSRafael Auler continue; 439a34c753fSRafael Auler std::vector<IndexAddressPair> SortedMap(AM->second.indexToAddressBegin(), 440a34c753fSRafael Auler AM->second.indexToAdddessEnd()); 441a34c753fSRafael Auler // Sorting address in increasing order of indices. 442c4302e4fSAmir Ayupov llvm::sort(SortedMap, llvm::less_first()); 443a34c753fSRafael Auler 444a34c753fSRafael Auler uint8_t AddrSize = CU->getAddressByteSize(); 445a34c753fSRafael Auler uint32_t Counter = 0; 446a34c753fSRafael Auler auto WriteAddress = [&](uint64_t Address) -> void { 447a34c753fSRafael Auler ++Counter; 448a34c753fSRafael Auler switch (AddrSize) { 449a34c753fSRafael Auler default: 450a34c753fSRafael Auler assert(false && "Address Size is invalid."); 451a34c753fSRafael Auler break; 452a34c753fSRafael Auler case 4: 453a34c753fSRafael Auler support::endian::write(AddressStream, static_cast<uint32_t>(Address), 454a34c753fSRafael Auler support::little); 455a34c753fSRafael Auler break; 456a34c753fSRafael Auler case 8: 457a34c753fSRafael Auler support::endian::write(AddressStream, Address, support::little); 458a34c753fSRafael Auler break; 459a34c753fSRafael Auler } 460a34c753fSRafael Auler }; 461a34c753fSRafael Auler 462a34c753fSRafael Auler for (const IndexAddressPair &Val : SortedMap) { 463a34c753fSRafael Auler while (Val.first > Counter) 464a34c753fSRafael Auler WriteAddress(0); 465a34c753fSRafael Auler WriteAddress(Val.second); 466a34c753fSRafael Auler } 467a34c753fSRafael Auler } 468a34c753fSRafael Auler 469a34c753fSRafael Auler return Buffer; 470a34c753fSRafael Auler } 471014cd37fSAlexander Yermolovich AddressSectionBuffer DebugAddrWriterDwarf5::finalize() { 472014cd37fSAlexander Yermolovich // Need to layout all sections within .debug_addr 473014cd37fSAlexander Yermolovich // Within each section sort Address by index. 474014cd37fSAlexander Yermolovich AddressSectionBuffer Buffer; 475014cd37fSAlexander Yermolovich raw_svector_ostream AddressStream(Buffer); 476014cd37fSAlexander Yermolovich const endianness Endian = 477014cd37fSAlexander Yermolovich BC->DwCtx->isLittleEndian() ? support::little : support::big; 478014cd37fSAlexander Yermolovich const DWARFSection &AddrSec = BC->DwCtx->getDWARFObj().getAddrSection(); 479014cd37fSAlexander Yermolovich DWARFDataExtractor AddrData(BC->DwCtx->getDWARFObj(), AddrSec, Endian, 0); 480014cd37fSAlexander Yermolovich DWARFDebugAddrTable AddrTable; 481014cd37fSAlexander Yermolovich DIDumpOptions DumpOpts; 482014cd37fSAlexander Yermolovich constexpr uint32_t HeaderSize = 8; 483014cd37fSAlexander Yermolovich for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) { 484ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(*CU.get()); 485014cd37fSAlexander Yermolovich const uint8_t AddrSize = CU->getAddressByteSize(); 486ba1ac98cSAlexander Yermolovich auto AMIter = AddressMaps.find(CUID); 487014cd37fSAlexander Yermolovich // A case where CU has entry in .debug_addr, but we don't modify addresses 488014cd37fSAlexander Yermolovich // for it. 489ba1ac98cSAlexander Yermolovich if (AMIter == AddressMaps.end()) { 490ba1ac98cSAlexander Yermolovich AMIter = AddressMaps.insert({CUID, AddressForDWOCU()}).first; 49189fab98eSFangrui Song std::optional<uint64_t> BaseOffset = CU->getAddrOffsetSectionBase(); 492014cd37fSAlexander Yermolovich if (!BaseOffset) 493014cd37fSAlexander Yermolovich continue; 494014cd37fSAlexander Yermolovich // Address base offset is to the first entry. 495014cd37fSAlexander Yermolovich // The size of header is 8 bytes. 496014cd37fSAlexander Yermolovich uint64_t Offset = *BaseOffset - HeaderSize; 497014cd37fSAlexander Yermolovich if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddrSize, 498014cd37fSAlexander Yermolovich DumpOpts.WarningHandler)) { 499014cd37fSAlexander Yermolovich DumpOpts.RecoverableErrorHandler(std::move(Err)); 500014cd37fSAlexander Yermolovich continue; 501014cd37fSAlexander Yermolovich } 502014cd37fSAlexander Yermolovich uint32_t Index = 0; 503014cd37fSAlexander Yermolovich for (uint64_t Addr : AddrTable.getAddressEntries()) 504ba1ac98cSAlexander Yermolovich AMIter->second.insert(Addr, Index++); 505014cd37fSAlexander Yermolovich } 506a34c753fSRafael Auler 507014cd37fSAlexander Yermolovich DWOIdToOffsetMap[CUID] = Buffer.size() + HeaderSize; 508014cd37fSAlexander Yermolovich 509ba1ac98cSAlexander Yermolovich std::vector<IndexAddressPair> SortedMap( 510ba1ac98cSAlexander Yermolovich AMIter->second.indexToAddressBegin(), 511ba1ac98cSAlexander Yermolovich AMIter->second.indexToAdddessEnd()); 512014cd37fSAlexander Yermolovich // Sorting address in increasing order of indices. 513c4302e4fSAmir Ayupov llvm::sort(SortedMap, llvm::less_first()); 514014cd37fSAlexander Yermolovich // Writing out Header 515014cd37fSAlexander Yermolovich const uint32_t Length = SortedMap.size() * AddrSize + 4; 516014cd37fSAlexander Yermolovich support::endian::write(AddressStream, Length, Endian); 517014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint16_t>(5), Endian); 518014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint8_t>(AddrSize), 519014cd37fSAlexander Yermolovich Endian); 520014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint8_t>(0), Endian); 521014cd37fSAlexander Yermolovich 522014cd37fSAlexander Yermolovich uint32_t Counter = 0; 523014cd37fSAlexander Yermolovich auto writeAddress = [&](uint64_t Address) -> void { 524014cd37fSAlexander Yermolovich ++Counter; 525014cd37fSAlexander Yermolovich switch (AddrSize) { 526014cd37fSAlexander Yermolovich default: 527014cd37fSAlexander Yermolovich llvm_unreachable("Address Size is invalid."); 528014cd37fSAlexander Yermolovich break; 529014cd37fSAlexander Yermolovich case 4: 530014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint32_t>(Address), 531014cd37fSAlexander Yermolovich Endian); 532014cd37fSAlexander Yermolovich break; 533014cd37fSAlexander Yermolovich case 8: 534014cd37fSAlexander Yermolovich support::endian::write(AddressStream, Address, Endian); 535014cd37fSAlexander Yermolovich break; 536014cd37fSAlexander Yermolovich } 537014cd37fSAlexander Yermolovich }; 538014cd37fSAlexander Yermolovich 539014cd37fSAlexander Yermolovich for (const IndexAddressPair &Val : SortedMap) { 540014cd37fSAlexander Yermolovich while (Val.first > Counter) 541014cd37fSAlexander Yermolovich writeAddress(0); 542014cd37fSAlexander Yermolovich writeAddress(Val.second); 543014cd37fSAlexander Yermolovich } 544014cd37fSAlexander Yermolovich } 545014cd37fSAlexander Yermolovich 546014cd37fSAlexander Yermolovich return Buffer; 547014cd37fSAlexander Yermolovich } 548014cd37fSAlexander Yermolovich 549014cd37fSAlexander Yermolovich uint64_t DebugAddrWriter::getOffset(DWARFUnit &Unit) { 550ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(Unit); 551ba1ac98cSAlexander Yermolovich assert(CUID && "Can't get offset, not a skeleton CU."); 552ba1ac98cSAlexander Yermolovich auto Iter = DWOIdToOffsetMap.find(CUID); 553014cd37fSAlexander Yermolovich assert(Iter != DWOIdToOffsetMap.end() && 554014cd37fSAlexander Yermolovich "Offset in to.debug_addr was not found for DWO ID."); 555014cd37fSAlexander Yermolovich return Iter->second; 556014cd37fSAlexander Yermolovich } 557014cd37fSAlexander Yermolovich 558014cd37fSAlexander Yermolovich uint64_t DebugAddrWriterDwarf5::getOffset(DWARFUnit &Unit) { 559ba1ac98cSAlexander Yermolovich auto Iter = DWOIdToOffsetMap.find(getCUID(Unit)); 560a34c753fSRafael Auler assert(Iter != DWOIdToOffsetMap.end() && 5613abb68a6SAlexander Yermolovich "Offset in to.debug_addr was not found for CU ID."); 562a34c753fSRafael Auler return Iter->second; 563a34c753fSRafael Auler } 564a34c753fSRafael Auler 5651c6dc43dSAlexander Yermolovich void DebugLocWriter::init() { 566a34c753fSRafael Auler LocBuffer = std::make_unique<DebugBufferVector>(); 567a34c753fSRafael Auler LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer); 5681c6dc43dSAlexander Yermolovich // Writing out empty location list to which all references to empty location 5691c6dc43dSAlexander Yermolovich // lists will point. 5701c6dc43dSAlexander Yermolovich if (!LocSectionOffset && DwarfVersion < 5) { 5711c6dc43dSAlexander Yermolovich const char Zeroes[16] = {0}; 5721c6dc43dSAlexander Yermolovich *LocStream << StringRef(Zeroes, 16); 5731c6dc43dSAlexander Yermolovich LocSectionOffset += 16; 5741c6dc43dSAlexander Yermolovich } 575a34c753fSRafael Auler } 576a34c753fSRafael Auler 5771c6dc43dSAlexander Yermolovich uint32_t DebugLocWriter::LocSectionOffset = 0; 5781c6dc43dSAlexander Yermolovich void DebugLocWriter::addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, 5791c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, 5801c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) { 5811c6dc43dSAlexander Yermolovich const uint64_t AttrOffset = AttrVal.Offset; 582a34c753fSRafael Auler if (LocList.empty()) { 5831c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); 584a34c753fSRafael Auler return; 585a34c753fSRafael Auler } 586a34c753fSRafael Auler // Since there is a separate DebugLocWriter for each thread, 587a34c753fSRafael Auler // we don't need a lock to read the SectionOffset and update it. 5881c6dc43dSAlexander Yermolovich const uint32_t EntryOffset = LocSectionOffset; 589a34c753fSRafael Auler 590a34c753fSRafael Auler for (const DebugLocationEntry &Entry : LocList) { 591a34c753fSRafael Auler support::endian::write(*LocStream, static_cast<uint64_t>(Entry.LowPC), 592a34c753fSRafael Auler support::little); 593a34c753fSRafael Auler support::endian::write(*LocStream, static_cast<uint64_t>(Entry.HighPC), 594a34c753fSRafael Auler support::little); 595a34c753fSRafael Auler support::endian::write(*LocStream, static_cast<uint16_t>(Entry.Expr.size()), 596a34c753fSRafael Auler support::little); 597a34c753fSRafael Auler *LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()), 598a34c753fSRafael Auler Entry.Expr.size()); 5991c6dc43dSAlexander Yermolovich LocSectionOffset += 2 * 8 + 2 + Entry.Expr.size(); 600a34c753fSRafael Auler } 601a34c753fSRafael Auler LocStream->write_zeros(16); 6021c6dc43dSAlexander Yermolovich LocSectionOffset += 16; 603a34c753fSRafael Auler LocListDebugInfoPatches.push_back({AttrOffset, EntryOffset}); 6041c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); 605a34c753fSRafael Auler } 606a34c753fSRafael Auler 607a34c753fSRafael Auler std::unique_ptr<DebugBufferVector> DebugLocWriter::getBuffer() { 608a34c753fSRafael Auler return std::move(LocBuffer); 609a34c753fSRafael Auler } 610a34c753fSRafael Auler 611a34c753fSRafael Auler // DWARF 4: 2.6.2 6121c6dc43dSAlexander Yermolovich void DebugLocWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, 6131c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) {} 614a34c753fSRafael Auler 615014cd37fSAlexander Yermolovich static void writeEmptyListDwarf5(raw_svector_ostream &Stream) { 616014cd37fSAlexander Yermolovich support::endian::write(Stream, static_cast<uint32_t>(4), support::little); 617014cd37fSAlexander Yermolovich support::endian::write(Stream, static_cast<uint8_t>(dwarf::DW_LLE_start_end), 618014cd37fSAlexander Yermolovich support::little); 619014cd37fSAlexander Yermolovich 620014cd37fSAlexander Yermolovich const char Zeroes[16] = {0}; 621014cd37fSAlexander Yermolovich Stream << StringRef(Zeroes, 16); 622014cd37fSAlexander Yermolovich encodeULEB128(0, Stream); 623014cd37fSAlexander Yermolovich support::endian::write( 624014cd37fSAlexander Yermolovich Stream, static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), support::little); 625014cd37fSAlexander Yermolovich } 626014cd37fSAlexander Yermolovich 6271c6dc43dSAlexander Yermolovich static void writeLegacyLocList(AttrInfo &AttrVal, DebugLocationsVector &LocList, 6281c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, 6291c6dc43dSAlexander Yermolovich DebugAddrWriter &AddrWriter, 6301c6dc43dSAlexander Yermolovich DebugBufferVector &LocBuffer, DWARFUnit &CU, 6311c6dc43dSAlexander Yermolovich raw_svector_ostream &LocStream) { 6321c6dc43dSAlexander Yermolovich const uint64_t AttrOffset = AttrVal.Offset; 6331c6dc43dSAlexander Yermolovich if (LocList.empty()) { 6341c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); 6351c6dc43dSAlexander Yermolovich return; 6361c6dc43dSAlexander Yermolovich } 6371c6dc43dSAlexander Yermolovich 6381c6dc43dSAlexander Yermolovich const uint32_t EntryOffset = LocBuffer.size(); 6391c6dc43dSAlexander Yermolovich for (const DebugLocationEntry &Entry : LocList) { 6401c6dc43dSAlexander Yermolovich support::endian::write(LocStream, 6411c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_startx_length), 6421c6dc43dSAlexander Yermolovich support::little); 6431c6dc43dSAlexander Yermolovich const uint32_t Index = AddrWriter.getIndexFromAddress(Entry.LowPC, CU); 6441c6dc43dSAlexander Yermolovich encodeULEB128(Index, LocStream); 6451c6dc43dSAlexander Yermolovich 6461c6dc43dSAlexander Yermolovich support::endian::write(LocStream, 6471c6dc43dSAlexander Yermolovich static_cast<uint32_t>(Entry.HighPC - Entry.LowPC), 6481c6dc43dSAlexander Yermolovich support::little); 6491c6dc43dSAlexander Yermolovich support::endian::write(LocStream, static_cast<uint16_t>(Entry.Expr.size()), 6501c6dc43dSAlexander Yermolovich support::little); 6511c6dc43dSAlexander Yermolovich LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()), 6521c6dc43dSAlexander Yermolovich Entry.Expr.size()); 6531c6dc43dSAlexander Yermolovich } 6541c6dc43dSAlexander Yermolovich support::endian::write(LocStream, 6551c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), 6561c6dc43dSAlexander Yermolovich support::little); 6571c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); 6581c6dc43dSAlexander Yermolovich } 6591c6dc43dSAlexander Yermolovich 6601c6dc43dSAlexander Yermolovich static void writeDWARF5LocList( 6611c6dc43dSAlexander Yermolovich uint32_t &NumberOfEntries, AttrInfo &AttrVal, DebugLocationsVector &LocList, 6621c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter, 6631c6dc43dSAlexander Yermolovich DebugAddrWriter &AddrWriter, DebugBufferVector &LocBodyBuffer, 6641c6dc43dSAlexander Yermolovich std::vector<uint32_t> &RelativeLocListOffsets, DWARFUnit &CU, 6651c6dc43dSAlexander Yermolovich raw_svector_ostream &LocBodyStream) { 6661c6dc43dSAlexander Yermolovich if (AttrVal.V.getForm() != dwarf::DW_FORM_loclistx) { 6671c6dc43dSAlexander Yermolovich AbbrevWriter.addAttributePatch(CU, AttrVal.AbbrevDecl, 6681c6dc43dSAlexander Yermolovich dwarf::DW_AT_location, dwarf::DW_AT_location, 6691c6dc43dSAlexander Yermolovich dwarf::DW_FORM_loclistx); 6701c6dc43dSAlexander Yermolovich } 6711c6dc43dSAlexander Yermolovich DebugInfoPatcher.addUDataPatch(AttrVal.Offset, NumberOfEntries, AttrVal.Size); 6721c6dc43dSAlexander Yermolovich RelativeLocListOffsets.push_back(LocBodyBuffer.size()); 6731c6dc43dSAlexander Yermolovich ++NumberOfEntries; 6741c6dc43dSAlexander Yermolovich if (LocList.empty()) { 6751c6dc43dSAlexander Yermolovich writeEmptyListDwarf5(LocBodyStream); 6761c6dc43dSAlexander Yermolovich return; 6771c6dc43dSAlexander Yermolovich } 6781c6dc43dSAlexander Yermolovich 6791c6dc43dSAlexander Yermolovich std::vector<uint64_t> OffsetsArray; 680*124ca880SAlexander Yermolovich bool WrittenStartxLength = false; 681*124ca880SAlexander Yermolovich auto writeExpression = [&](uint32_t Index) -> void { 682*124ca880SAlexander Yermolovich const DebugLocationEntry &Entry = LocList[Index]; 683*124ca880SAlexander Yermolovich encodeULEB128(Entry.Expr.size(), LocBodyStream); 684*124ca880SAlexander Yermolovich LocBodyStream << StringRef( 685*124ca880SAlexander Yermolovich reinterpret_cast<const char *>(Entry.Expr.data()), Entry.Expr.size()); 686*124ca880SAlexander Yermolovich }; 687*124ca880SAlexander Yermolovich for (unsigned I = 0; I < LocList.size();) { 688*124ca880SAlexander Yermolovich WrittenStartxLength = false; 689*124ca880SAlexander Yermolovich if (emitWithBase<DebugLocationsVector, dwarf::LoclistEntries, 690*124ca880SAlexander Yermolovich DebugLocationEntry>( 691*124ca880SAlexander Yermolovich LocBodyStream, LocList, AddrWriter, CU, I, 692*124ca880SAlexander Yermolovich dwarf::DW_LLE_base_addressx, dwarf::DW_LLE_offset_pair, 693*124ca880SAlexander Yermolovich dwarf::DW_LLE_end_of_list, writeExpression)) 694*124ca880SAlexander Yermolovich continue; 695*124ca880SAlexander Yermolovich 696*124ca880SAlexander Yermolovich const DebugLocationEntry &Entry = LocList[I]; 6971c6dc43dSAlexander Yermolovich support::endian::write(LocBodyStream, 6981c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_startx_length), 6991c6dc43dSAlexander Yermolovich support::little); 7001c6dc43dSAlexander Yermolovich const uint32_t Index = AddrWriter.getIndexFromAddress(Entry.LowPC, CU); 7011c6dc43dSAlexander Yermolovich encodeULEB128(Index, LocBodyStream); 7021c6dc43dSAlexander Yermolovich encodeULEB128(Entry.HighPC - Entry.LowPC, LocBodyStream); 703*124ca880SAlexander Yermolovich writeExpression(I); 704*124ca880SAlexander Yermolovich ++I; 705*124ca880SAlexander Yermolovich WrittenStartxLength = true; 7061c6dc43dSAlexander Yermolovich } 707*124ca880SAlexander Yermolovich 708*124ca880SAlexander Yermolovich if (WrittenStartxLength) 7091c6dc43dSAlexander Yermolovich support::endian::write(LocBodyStream, 7101c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), 7111c6dc43dSAlexander Yermolovich support::little); 7121c6dc43dSAlexander Yermolovich } 7131c6dc43dSAlexander Yermolovich 7141c6dc43dSAlexander Yermolovich void DebugLoclistWriter::addList(AttrInfo &AttrVal, 7151c6dc43dSAlexander Yermolovich DebugLocationsVector &LocList, 7161c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, 7171c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) { 7181c6dc43dSAlexander Yermolovich if (DwarfVersion < 5) 7191c6dc43dSAlexander Yermolovich writeLegacyLocList(AttrVal, LocList, DebugInfoPatcher, *AddrWriter, 7201c6dc43dSAlexander Yermolovich *LocBuffer, CU, *LocStream); 7211c6dc43dSAlexander Yermolovich else 7221c6dc43dSAlexander Yermolovich writeDWARF5LocList(NumberOfEntries, AttrVal, LocList, DebugInfoPatcher, 7231c6dc43dSAlexander Yermolovich AbbrevWriter, *AddrWriter, *LocBodyBuffer, 7241c6dc43dSAlexander Yermolovich RelativeLocListOffsets, CU, *LocBodyStream); 7251c6dc43dSAlexander Yermolovich } 7261c6dc43dSAlexander Yermolovich 7271c6dc43dSAlexander Yermolovich uint32_t DebugLoclistWriter::LoclistBaseOffset = 0; 7281c6dc43dSAlexander Yermolovich void DebugLoclistWriter::finalizeDWARF5( 7291c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter) { 7301c6dc43dSAlexander Yermolovich if (LocBodyBuffer->empty()) 7311c6dc43dSAlexander Yermolovich return; 732014cd37fSAlexander Yermolovich 733014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> LocArrayBuffer = 734014cd37fSAlexander Yermolovich std::make_unique<DebugBufferVector>(); 735014cd37fSAlexander Yermolovich std::unique_ptr<raw_svector_ostream> LocArrayStream = 736014cd37fSAlexander Yermolovich std::make_unique<raw_svector_ostream>(*LocArrayBuffer); 737014cd37fSAlexander Yermolovich 7381c6dc43dSAlexander Yermolovich const uint32_t SizeOfArraySection = NumberOfEntries * sizeof(uint32_t); 739014cd37fSAlexander Yermolovich // Write out IndexArray 7401c6dc43dSAlexander Yermolovich for (uint32_t RelativeOffset : RelativeLocListOffsets) 741014cd37fSAlexander Yermolovich support::endian::write( 742014cd37fSAlexander Yermolovich *LocArrayStream, 7431c6dc43dSAlexander Yermolovich static_cast<uint32_t>(SizeOfArraySection + RelativeOffset), 744014cd37fSAlexander Yermolovich support::little); 7451c6dc43dSAlexander Yermolovich 7461c6dc43dSAlexander Yermolovich std::unique_ptr<DebugBufferVector> Header = getDWARF5Header( 7471c6dc43dSAlexander Yermolovich {static_cast<uint32_t>(SizeOfArraySection + LocBodyBuffer.get()->size()), 7481c6dc43dSAlexander Yermolovich 5, 8, 0, NumberOfEntries}); 749014cd37fSAlexander Yermolovich *LocStream << *Header; 750014cd37fSAlexander Yermolovich *LocStream << *LocArrayBuffer; 751014cd37fSAlexander Yermolovich *LocStream << *LocBodyBuffer; 7521c6dc43dSAlexander Yermolovich 7531c6dc43dSAlexander Yermolovich if (!isSplitDwarf()) { 754370e4761SAmir Ayupov if (std::optional<AttrInfo> AttrInfoVal = 7551c6dc43dSAlexander Yermolovich findAttributeInfo(CU.getUnitDIE(), dwarf::DW_AT_loclists_base)) 7561c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrInfoVal->Offset, 7571c6dc43dSAlexander Yermolovich LoclistBaseOffset + 7581c6dc43dSAlexander Yermolovich getDWARF5RngListLocListHeaderSize()); 7591c6dc43dSAlexander Yermolovich else { 7601c6dc43dSAlexander Yermolovich AbbrevWriter.addAttribute( 7611c6dc43dSAlexander Yermolovich CU, CU.getUnitDIE().getAbbreviationDeclarationPtr(), 7621c6dc43dSAlexander Yermolovich dwarf::DW_AT_loclists_base, dwarf::DW_FORM_sec_offset); 7631c6dc43dSAlexander Yermolovich DebugInfoPatcher.insertNewEntry(CU.getUnitDIE(), 7641c6dc43dSAlexander Yermolovich LoclistBaseOffset + Header->size()); 765014cd37fSAlexander Yermolovich } 7661c6dc43dSAlexander Yermolovich LoclistBaseOffset += LocBuffer->size(); 7671c6dc43dSAlexander Yermolovich } 7681c6dc43dSAlexander Yermolovich clearList(RelativeLocListOffsets); 7691c6dc43dSAlexander Yermolovich clearList(*LocArrayBuffer); 7701c6dc43dSAlexander Yermolovich clearList(*LocBodyBuffer); 771014cd37fSAlexander Yermolovich } 772014cd37fSAlexander Yermolovich 7731c6dc43dSAlexander Yermolovich void DebugLoclistWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, 7741c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) { 7751c6dc43dSAlexander Yermolovich if (DwarfVersion >= 5) 7761c6dc43dSAlexander Yermolovich finalizeDWARF5(DebugInfoPatcher, AbbrevWriter); 777014cd37fSAlexander Yermolovich } 778014cd37fSAlexander Yermolovich 779a34c753fSRafael Auler DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr; 780a34c753fSRafael Auler 7811c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addUnitBaseOffsetLabel(uint64_t Offset) { 7821c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 7831c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 784ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DWARFUnitOffsetBaseLabel(Offset)); 785a34c753fSRafael Auler } 786a34c753fSRafael Auler 7871c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addDestinationReferenceLabel(uint64_t Offset) { 7881c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 7891c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 7901c2f4bbeSAlexander Yermolovich auto RetVal = DestinationLabels.insert(Offset); 7911c2f4bbeSAlexander Yermolovich if (!RetVal.second) 7921c2f4bbeSAlexander Yermolovich return; 7931c2f4bbeSAlexander Yermolovich 794ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DestinationReferenceLabel(Offset)); 795a34c753fSRafael Auler } 796a34c753fSRafael Auler 797bd1ebe9dSAlexander Yermolovich static std::string encodeLE(size_t ByteSize, uint64_t NewValue) { 798bd1ebe9dSAlexander Yermolovich std::string LE64(ByteSize, 0); 799bd1ebe9dSAlexander Yermolovich for (size_t I = 0; I < ByteSize; ++I) { 800bd1ebe9dSAlexander Yermolovich LE64[I] = NewValue & 0xff; 801bd1ebe9dSAlexander Yermolovich NewValue >>= 8; 802bd1ebe9dSAlexander Yermolovich } 803bd1ebe9dSAlexander Yermolovich return LE64; 804bd1ebe9dSAlexander Yermolovich } 805bd1ebe9dSAlexander Yermolovich 806bd1ebe9dSAlexander Yermolovich void DebugInfoBinaryPatcher::insertNewEntry(const DWARFDie &DIE, 807bd1ebe9dSAlexander Yermolovich uint32_t Value) { 808bd1ebe9dSAlexander Yermolovich std::string StrValue = encodeLE(4, Value); 809bd1ebe9dSAlexander Yermolovich insertNewEntry(DIE, std::move(StrValue)); 810bd1ebe9dSAlexander Yermolovich } 811bd1ebe9dSAlexander Yermolovich 812bd1ebe9dSAlexander Yermolovich void DebugInfoBinaryPatcher::insertNewEntry(const DWARFDie &DIE, 813bd1ebe9dSAlexander Yermolovich std::string &&Value) { 814bd1ebe9dSAlexander Yermolovich const DWARFAbbreviationDeclaration *AbbrevDecl = 815bd1ebe9dSAlexander Yermolovich DIE.getAbbreviationDeclarationPtr(); 816bd1ebe9dSAlexander Yermolovich 817bd1ebe9dSAlexander Yermolovich // In case this DIE has no attributes. 818bd1ebe9dSAlexander Yermolovich uint32_t Offset = DIE.getOffset() + 1; 819bd1ebe9dSAlexander Yermolovich size_t NumOfAttributes = AbbrevDecl->getNumAttributes(); 820bd1ebe9dSAlexander Yermolovich if (NumOfAttributes) { 821370e4761SAmir Ayupov std::optional<AttrInfo> Val = 822bd1ebe9dSAlexander Yermolovich findAttributeInfo(DIE, AbbrevDecl, NumOfAttributes - 1); 823bd1ebe9dSAlexander Yermolovich assert(Val && "Invalid Value."); 824bd1ebe9dSAlexander Yermolovich 825bd1ebe9dSAlexander Yermolovich Offset = Val->Offset + Val->Size - DWPUnitOffset; 826bd1ebe9dSAlexander Yermolovich } 827bd1ebe9dSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 828bd1ebe9dSAlexander Yermolovich DebugPatches.emplace_back(new NewDebugEntry(Offset, std::move(Value))); 829bd1ebe9dSAlexander Yermolovich } 830bd1ebe9dSAlexander Yermolovich 8311c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addReferenceToPatch(uint64_t Offset, 8321c2f4bbeSAlexander Yermolovich uint32_t DestinationOffset, 8331c2f4bbeSAlexander Yermolovich uint32_t OldValueSize, 8341c2f4bbeSAlexander Yermolovich dwarf::Form Form) { 8351c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8361c2f4bbeSAlexander Yermolovich DestinationOffset -= DWPUnitOffset; 8371c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 838ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back( 839ea6c8b01SAlexander Yermolovich new DebugPatchReference(Offset, OldValueSize, DestinationOffset, Form)); 8401c2f4bbeSAlexander Yermolovich } 8411c2f4bbeSAlexander Yermolovich 8421c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t NewValue, 8431c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 8441c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8451c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 8461c2f4bbeSAlexander Yermolovich DebugPatches.emplace_back( 847ea6c8b01SAlexander Yermolovich new DebugPatchVariableSize(Offset, OldValueSize, NewValue)); 8481c2f4bbeSAlexander Yermolovich } 8491c2f4bbeSAlexander Yermolovich 8501c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) { 8511c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8521c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 853ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DebugPatch64(Offset, NewValue)); 8541c2f4bbeSAlexander Yermolovich } 8551c2f4bbeSAlexander Yermolovich 8561c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue, 8571c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 8581c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8591c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 8601c2f4bbeSAlexander Yermolovich if (OldValueSize == 4) 861ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DebugPatch32(Offset, NewValue)); 862a44fe319SAlexander Yermolovich else if (OldValueSize == 8) 863ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DebugPatch64to32(Offset, NewValue)); 864a44fe319SAlexander Yermolovich else 865a44fe319SAlexander Yermolovich DebugPatches.emplace_back( 866a44fe319SAlexander Yermolovich new DebugPatch32GenericSize(Offset, NewValue, OldValueSize)); 8671c2f4bbeSAlexander Yermolovich } 8681c2f4bbeSAlexander Yermolovich 8691c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addBinaryPatch(uint64_t Offset, 8701c2f4bbeSAlexander Yermolovich std::string &&NewValue, 8711c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 8721c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, std::move(NewValue)); 8731c2f4bbeSAlexander Yermolovich } 8741c2f4bbeSAlexander Yermolovich 8751c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addBytePatch(uint64_t Offset, uint8_t Value) { 8761c2f4bbeSAlexander Yermolovich auto Str = std::string(1, Value); 8771c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, std::move(Str)); 8781c2f4bbeSAlexander Yermolovich } 8791c2f4bbeSAlexander Yermolovich 8801c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addLEPatch(uint64_t Offset, uint64_t NewValue, 8811c2f4bbeSAlexander Yermolovich size_t ByteSize) { 8821c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, encodeLE(ByteSize, NewValue)); 8831c2f4bbeSAlexander Yermolovich } 8841c2f4bbeSAlexander Yermolovich 8851c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t Value, 8861c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 887a34c753fSRafael Auler std::string Buff; 888a34c753fSRafael Auler raw_string_ostream OS(Buff); 8891c2f4bbeSAlexander Yermolovich encodeULEB128(Value, OS, OldValueSize); 890a34c753fSRafael Auler 8911c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, std::move(Buff)); 892a34c753fSRafael Auler } 893a34c753fSRafael Auler 8941c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) { 895a34c753fSRafael Auler addLEPatch(Offset, NewValue, 8); 896a34c753fSRafael Auler } 897a34c753fSRafael Auler 8981c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue, 8991c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 900a34c753fSRafael Auler addLEPatch(Offset, NewValue, 4); 901a34c753fSRafael Auler } 902a34c753fSRafael Auler 9031c2f4bbeSAlexander Yermolovich std::string SimpleBinaryPatcher::patchBinary(StringRef BinaryContents) { 9041c2f4bbeSAlexander Yermolovich std::string BinaryContentsStr = std::string(BinaryContents); 905a34c753fSRafael Auler for (const auto &Patch : Patches) { 9061c2f4bbeSAlexander Yermolovich uint32_t Offset = Patch.first; 907a34c753fSRafael Auler const std::string &ByteSequence = Patch.second; 908a34c753fSRafael Auler assert(Offset + ByteSequence.size() <= BinaryContents.size() && 909a34c753fSRafael Auler "Applied patch runs over binary size."); 910a34c753fSRafael Auler for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I) { 9111c2f4bbeSAlexander Yermolovich BinaryContentsStr[Offset + I] = ByteSequence[I]; 912a34c753fSRafael Auler } 913a34c753fSRafael Auler } 9141c2f4bbeSAlexander Yermolovich return BinaryContentsStr; 9151c2f4bbeSAlexander Yermolovich } 9161c2f4bbeSAlexander Yermolovich 917612f0f45SAlexander Yermolovich CUOffsetMap DebugInfoBinaryPatcher::computeNewOffsets(DWARFContext &DWCtx, 918612f0f45SAlexander Yermolovich bool IsDWOContext) { 919612f0f45SAlexander Yermolovich CUOffsetMap CUMap; 920d2c87699SAmir Ayupov llvm::sort(DebugPatches, [](const UniquePatchPtrType &V1, 921d2c87699SAmir Ayupov const UniquePatchPtrType &V2) { 922bd1ebe9dSAlexander Yermolovich if (V1.get()->Offset == V2.get()->Offset) { 923bd1ebe9dSAlexander Yermolovich if (V1->Kind == DebugPatchKind::NewDebugEntry && 924bd1ebe9dSAlexander Yermolovich V2->Kind == DebugPatchKind::NewDebugEntry) 925d2c87699SAmir Ayupov return reinterpret_cast<const NewDebugEntry *>(V1.get())->CurrentOrder < 926d2c87699SAmir Ayupov reinterpret_cast<const NewDebugEntry *>(V2.get())->CurrentOrder; 927bd1ebe9dSAlexander Yermolovich 928bd1ebe9dSAlexander Yermolovich // This is a case where we are modifying first entry of next 929bd1ebe9dSAlexander Yermolovich // DIE, and adding a new one. 930bd1ebe9dSAlexander Yermolovich return V1->Kind == DebugPatchKind::NewDebugEntry; 931bd1ebe9dSAlexander Yermolovich } 9321c2f4bbeSAlexander Yermolovich return V1.get()->Offset < V2.get()->Offset; 9331c2f4bbeSAlexander Yermolovich }); 9341c2f4bbeSAlexander Yermolovich 935612f0f45SAlexander Yermolovich DWARFUnitVector::compile_unit_range CompileUnits = 936612f0f45SAlexander Yermolovich IsDWOContext ? DWCtx.dwo_compile_units() : DWCtx.compile_units(); 937612f0f45SAlexander Yermolovich 938612f0f45SAlexander Yermolovich for (const std::unique_ptr<DWARFUnit> &CU : CompileUnits) 939612f0f45SAlexander Yermolovich CUMap[CU->getOffset()] = {static_cast<uint32_t>(CU->getOffset()), 940612f0f45SAlexander Yermolovich static_cast<uint32_t>(CU->getLength())}; 941612f0f45SAlexander Yermolovich 9421c2f4bbeSAlexander Yermolovich // Calculating changes in .debug_info size from Patches to build a map of old 9431c2f4bbeSAlexander Yermolovich // to updated reference destination offsets. 944612f0f45SAlexander Yermolovich uint32_t PreviousOffset = 0; 945612f0f45SAlexander Yermolovich int32_t PreviousChangeInSize = 0; 946ea6c8b01SAlexander Yermolovich for (UniquePatchPtrType &PatchBase : DebugPatches) { 9471c2f4bbeSAlexander Yermolovich Patch *P = PatchBase.get(); 9481c2f4bbeSAlexander Yermolovich switch (P->Kind) { 9491c2f4bbeSAlexander Yermolovich default: 9501c2f4bbeSAlexander Yermolovich continue; 9511c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue64to32: { 952612f0f45SAlexander Yermolovich PreviousChangeInSize -= 4; 9531c2f4bbeSAlexander Yermolovich break; 9541c2f4bbeSAlexander Yermolovich } 955a44fe319SAlexander Yermolovich case DebugPatchKind::PatchValue32GenericSize: { 956a44fe319SAlexander Yermolovich DebugPatch32GenericSize *DPVS = 957a44fe319SAlexander Yermolovich reinterpret_cast<DebugPatch32GenericSize *>(P); 958a44fe319SAlexander Yermolovich PreviousChangeInSize += 4 - DPVS->OldValueSize; 959a44fe319SAlexander Yermolovich break; 960a44fe319SAlexander Yermolovich } 9611c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValueVariable: { 9621c2f4bbeSAlexander Yermolovich DebugPatchVariableSize *DPV = 9631c2f4bbeSAlexander Yermolovich reinterpret_cast<DebugPatchVariableSize *>(P); 9641c2f4bbeSAlexander Yermolovich std::string Temp; 9651c2f4bbeSAlexander Yermolovich raw_string_ostream OS(Temp); 9661c2f4bbeSAlexander Yermolovich encodeULEB128(DPV->Value, OS); 967612f0f45SAlexander Yermolovich PreviousChangeInSize += Temp.size() - DPV->OldValueSize; 9681c2f4bbeSAlexander Yermolovich break; 9691c2f4bbeSAlexander Yermolovich } 9701c2f4bbeSAlexander Yermolovich case DebugPatchKind::DestinationReferenceLabel: { 9711c2f4bbeSAlexander Yermolovich DestinationReferenceLabel *DRL = 9721c2f4bbeSAlexander Yermolovich reinterpret_cast<DestinationReferenceLabel *>(P); 973612f0f45SAlexander Yermolovich OldToNewOffset[DRL->Offset] = 974612f0f45SAlexander Yermolovich DRL->Offset + ChangeInSize + PreviousChangeInSize; 9751c2f4bbeSAlexander Yermolovich break; 9761c2f4bbeSAlexander Yermolovich } 9771c2f4bbeSAlexander Yermolovich case DebugPatchKind::ReferencePatchValue: { 9781c2f4bbeSAlexander Yermolovich // This doesn't look to be a common case, so will always encode as 4 bytes 9791c2f4bbeSAlexander Yermolovich // to reduce algorithmic complexity. 9801c2f4bbeSAlexander Yermolovich DebugPatchReference *RDP = reinterpret_cast<DebugPatchReference *>(P); 9811c2f4bbeSAlexander Yermolovich if (RDP->PatchInfo.IndirectRelative) { 982612f0f45SAlexander Yermolovich PreviousChangeInSize += 4 - RDP->PatchInfo.OldValueSize; 9831c2f4bbeSAlexander Yermolovich assert(RDP->PatchInfo.OldValueSize <= 4 && 9841c2f4bbeSAlexander Yermolovich "Variable encoding reference greater than 4 bytes."); 9851c2f4bbeSAlexander Yermolovich } 9861c2f4bbeSAlexander Yermolovich break; 9871c2f4bbeSAlexander Yermolovich } 9881c2f4bbeSAlexander Yermolovich case DebugPatchKind::DWARFUnitOffsetBaseLabel: { 9891c2f4bbeSAlexander Yermolovich DWARFUnitOffsetBaseLabel *BaseLabel = 9901c2f4bbeSAlexander Yermolovich reinterpret_cast<DWARFUnitOffsetBaseLabel *>(P); 9911c2f4bbeSAlexander Yermolovich uint32_t CUOffset = BaseLabel->Offset; 992612f0f45SAlexander Yermolovich ChangeInSize += PreviousChangeInSize; 9931c2f4bbeSAlexander Yermolovich uint32_t CUOffsetUpdate = CUOffset + ChangeInSize; 994612f0f45SAlexander Yermolovich CUMap[CUOffset].Offset = CUOffsetUpdate; 995612f0f45SAlexander Yermolovich CUMap[PreviousOffset].Length += PreviousChangeInSize; 996612f0f45SAlexander Yermolovich PreviousChangeInSize = 0; 997612f0f45SAlexander Yermolovich PreviousOffset = CUOffset; 998bd1ebe9dSAlexander Yermolovich break; 999bd1ebe9dSAlexander Yermolovich } 1000bd1ebe9dSAlexander Yermolovich case DebugPatchKind::NewDebugEntry: { 1001bd1ebe9dSAlexander Yermolovich NewDebugEntry *NDE = reinterpret_cast<NewDebugEntry *>(P); 1002bd1ebe9dSAlexander Yermolovich PreviousChangeInSize += NDE->Value.size(); 1003bd1ebe9dSAlexander Yermolovich break; 10041c2f4bbeSAlexander Yermolovich } 10051c2f4bbeSAlexander Yermolovich } 10061c2f4bbeSAlexander Yermolovich } 1007612f0f45SAlexander Yermolovich CUMap[PreviousOffset].Length += PreviousChangeInSize; 10081c2f4bbeSAlexander Yermolovich return CUMap; 10091c2f4bbeSAlexander Yermolovich } 1010bd1ebe9dSAlexander Yermolovich uint32_t DebugInfoBinaryPatcher::NewDebugEntry::OrderCounter = 0; 10111c2f4bbeSAlexander Yermolovich 10121c2f4bbeSAlexander Yermolovich std::string DebugInfoBinaryPatcher::patchBinary(StringRef BinaryContents) { 10131c2f4bbeSAlexander Yermolovich std::string NewBinaryContents; 10141c2f4bbeSAlexander Yermolovich NewBinaryContents.reserve(BinaryContents.size() + ChangeInSize); 10151c2f4bbeSAlexander Yermolovich uint32_t StartOffset = 0; 10161c2f4bbeSAlexander Yermolovich uint32_t DwarfUnitBaseOffset = 0; 10171c2f4bbeSAlexander Yermolovich uint32_t OldValueSize = 0; 10181c2f4bbeSAlexander Yermolovich uint32_t Offset = 0; 10191c2f4bbeSAlexander Yermolovich std::string ByteSequence; 10201c2f4bbeSAlexander Yermolovich std::vector<std::pair<uint32_t, uint32_t>> LengthPatches; 10211c2f4bbeSAlexander Yermolovich // Wasting one entry to avoid checks for first. 10221c2f4bbeSAlexander Yermolovich LengthPatches.push_back({0, 0}); 10231c2f4bbeSAlexander Yermolovich 10241c2f4bbeSAlexander Yermolovich // Applying all the patches replacing current entry. 10251c2f4bbeSAlexander Yermolovich // This might change the size of .debug_info section. 1026ea6c8b01SAlexander Yermolovich for (const UniquePatchPtrType &PatchBase : DebugPatches) { 10271c2f4bbeSAlexander Yermolovich Patch *P = PatchBase.get(); 10281c2f4bbeSAlexander Yermolovich switch (P->Kind) { 10291c2f4bbeSAlexander Yermolovich default: 10301c2f4bbeSAlexander Yermolovich continue; 10311c2f4bbeSAlexander Yermolovich case DebugPatchKind::ReferencePatchValue: { 10321c2f4bbeSAlexander Yermolovich DebugPatchReference *RDP = reinterpret_cast<DebugPatchReference *>(P); 10331c2f4bbeSAlexander Yermolovich uint32_t DestinationOffset = RDP->DestinationOffset; 10341c2f4bbeSAlexander Yermolovich assert(OldToNewOffset.count(DestinationOffset) && 10351c2f4bbeSAlexander Yermolovich "Destination Offset for reference not updated."); 10361c2f4bbeSAlexander Yermolovich uint32_t UpdatedOffset = OldToNewOffset[DestinationOffset]; 10371c2f4bbeSAlexander Yermolovich Offset = RDP->Offset; 10381c2f4bbeSAlexander Yermolovich OldValueSize = RDP->PatchInfo.OldValueSize; 10391c2f4bbeSAlexander Yermolovich if (RDP->PatchInfo.DirectRelative) { 10401c2f4bbeSAlexander Yermolovich UpdatedOffset -= DwarfUnitBaseOffset; 10411c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(OldValueSize, UpdatedOffset); 10421c2f4bbeSAlexander Yermolovich // In theory reference for DW_FORM_ref{1,2,4,8} can be right on the edge 10431c2f4bbeSAlexander Yermolovich // and overflow if later debug information grows. 10441c2f4bbeSAlexander Yermolovich if (ByteSequence.size() > OldValueSize) 10451c2f4bbeSAlexander Yermolovich errs() << "BOLT-ERROR: Relative reference of size " 10461c2f4bbeSAlexander Yermolovich << Twine::utohexstr(OldValueSize) 10471c2f4bbeSAlexander Yermolovich << " overflows with the new encoding.\n"; 10481c2f4bbeSAlexander Yermolovich } else if (RDP->PatchInfo.DirectAbsolute) { 10491c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(OldValueSize, UpdatedOffset); 10501c2f4bbeSAlexander Yermolovich } else if (RDP->PatchInfo.IndirectRelative) { 10511c2f4bbeSAlexander Yermolovich UpdatedOffset -= DwarfUnitBaseOffset; 10521c2f4bbeSAlexander Yermolovich ByteSequence.clear(); 10531c2f4bbeSAlexander Yermolovich raw_string_ostream OS(ByteSequence); 10541c2f4bbeSAlexander Yermolovich encodeULEB128(UpdatedOffset, OS, 4); 10551c2f4bbeSAlexander Yermolovich } else { 10561c2f4bbeSAlexander Yermolovich llvm_unreachable("Invalid Reference form."); 10571c2f4bbeSAlexander Yermolovich } 10581c2f4bbeSAlexander Yermolovich break; 10591c2f4bbeSAlexander Yermolovich } 10601c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue32: { 10611c2f4bbeSAlexander Yermolovich DebugPatch32 *P32 = reinterpret_cast<DebugPatch32 *>(P); 10621c2f4bbeSAlexander Yermolovich Offset = P32->Offset; 10631c2f4bbeSAlexander Yermolovich OldValueSize = 4; 10641c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(4, P32->Value); 10651c2f4bbeSAlexander Yermolovich break; 10661c2f4bbeSAlexander Yermolovich } 10671c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue64to32: { 10681c2f4bbeSAlexander Yermolovich DebugPatch64to32 *P64to32 = reinterpret_cast<DebugPatch64to32 *>(P); 10691c2f4bbeSAlexander Yermolovich Offset = P64to32->Offset; 10701c2f4bbeSAlexander Yermolovich OldValueSize = 8; 10711c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(4, P64to32->Value); 10721c2f4bbeSAlexander Yermolovich break; 10731c2f4bbeSAlexander Yermolovich } 1074a44fe319SAlexander Yermolovich case DebugPatchKind::PatchValue32GenericSize: { 1075a44fe319SAlexander Yermolovich DebugPatch32GenericSize *DPVS = 1076a44fe319SAlexander Yermolovich reinterpret_cast<DebugPatch32GenericSize *>(P); 1077a44fe319SAlexander Yermolovich Offset = DPVS->Offset; 1078a44fe319SAlexander Yermolovich OldValueSize = DPVS->OldValueSize; 1079a44fe319SAlexander Yermolovich ByteSequence = encodeLE(4, DPVS->Value); 1080a44fe319SAlexander Yermolovich break; 1081a44fe319SAlexander Yermolovich } 10821c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValueVariable: { 10831c2f4bbeSAlexander Yermolovich DebugPatchVariableSize *PV = 10841c2f4bbeSAlexander Yermolovich reinterpret_cast<DebugPatchVariableSize *>(P); 10851c2f4bbeSAlexander Yermolovich Offset = PV->Offset; 10861c2f4bbeSAlexander Yermolovich OldValueSize = PV->OldValueSize; 10871c2f4bbeSAlexander Yermolovich ByteSequence.clear(); 10881c2f4bbeSAlexander Yermolovich raw_string_ostream OS(ByteSequence); 10891c2f4bbeSAlexander Yermolovich encodeULEB128(PV->Value, OS); 10901c2f4bbeSAlexander Yermolovich break; 10911c2f4bbeSAlexander Yermolovich } 10921c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue64: { 10931c2f4bbeSAlexander Yermolovich DebugPatch64 *P64 = reinterpret_cast<DebugPatch64 *>(P); 10941c2f4bbeSAlexander Yermolovich Offset = P64->Offset; 10951c2f4bbeSAlexander Yermolovich OldValueSize = 8; 10961c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(8, P64->Value); 10971c2f4bbeSAlexander Yermolovich break; 10981c2f4bbeSAlexander Yermolovich } 10991c2f4bbeSAlexander Yermolovich case DebugPatchKind::DWARFUnitOffsetBaseLabel: { 11001c2f4bbeSAlexander Yermolovich DWARFUnitOffsetBaseLabel *BaseLabel = 11011c2f4bbeSAlexander Yermolovich reinterpret_cast<DWARFUnitOffsetBaseLabel *>(P); 11021c2f4bbeSAlexander Yermolovich Offset = BaseLabel->Offset; 11031c2f4bbeSAlexander Yermolovich OldValueSize = 0; 11041c2f4bbeSAlexander Yermolovich ByteSequence.clear(); 11051c2f4bbeSAlexander Yermolovich auto &Patch = LengthPatches.back(); 11061c2f4bbeSAlexander Yermolovich // Length to copy between last patch entry and next compile unit. 11071c2f4bbeSAlexander Yermolovich uint32_t RemainingLength = Offset - StartOffset; 11081c2f4bbeSAlexander Yermolovich uint32_t NewCUOffset = NewBinaryContents.size() + RemainingLength; 11091c2f4bbeSAlexander Yermolovich DwarfUnitBaseOffset = NewCUOffset; 11101c2f4bbeSAlexander Yermolovich // Length of previous CU = This CU Offset - sizeof(length) - last CU 11111c2f4bbeSAlexander Yermolovich // Offset. 11121c2f4bbeSAlexander Yermolovich Patch.second = NewCUOffset - 4 - Patch.first; 11131c2f4bbeSAlexander Yermolovich LengthPatches.push_back({NewCUOffset, 0}); 11141c2f4bbeSAlexander Yermolovich break; 11151c2f4bbeSAlexander Yermolovich } 1116bd1ebe9dSAlexander Yermolovich case DebugPatchKind::NewDebugEntry: { 1117bd1ebe9dSAlexander Yermolovich NewDebugEntry *NDE = reinterpret_cast<NewDebugEntry *>(P); 1118bd1ebe9dSAlexander Yermolovich Offset = NDE->Offset; 1119bd1ebe9dSAlexander Yermolovich OldValueSize = 0; 1120bd1ebe9dSAlexander Yermolovich ByteSequence = NDE->Value; 1121bd1ebe9dSAlexander Yermolovich break; 1122bd1ebe9dSAlexander Yermolovich } 11231c2f4bbeSAlexander Yermolovich } 11241c2f4bbeSAlexander Yermolovich 1125bd1ebe9dSAlexander Yermolovich assert((P->Kind == DebugPatchKind::NewDebugEntry || 1126bd1ebe9dSAlexander Yermolovich Offset + ByteSequence.size() <= BinaryContents.size()) && 11271c2f4bbeSAlexander Yermolovich "Applied patch runs over binary size."); 11281c2f4bbeSAlexander Yermolovich uint32_t Length = Offset - StartOffset; 11291c2f4bbeSAlexander Yermolovich NewBinaryContents.append(BinaryContents.substr(StartOffset, Length).data(), 11301c2f4bbeSAlexander Yermolovich Length); 11311c2f4bbeSAlexander Yermolovich NewBinaryContents.append(ByteSequence.data(), ByteSequence.size()); 11321c2f4bbeSAlexander Yermolovich StartOffset = Offset + OldValueSize; 11331c2f4bbeSAlexander Yermolovich } 11341c2f4bbeSAlexander Yermolovich uint32_t Length = BinaryContents.size() - StartOffset; 11351c2f4bbeSAlexander Yermolovich NewBinaryContents.append(BinaryContents.substr(StartOffset, Length).data(), 11361c2f4bbeSAlexander Yermolovich Length); 11371c2f4bbeSAlexander Yermolovich DebugPatches.clear(); 11381c2f4bbeSAlexander Yermolovich 11391c2f4bbeSAlexander Yermolovich // Patching lengths of CUs 11401c2f4bbeSAlexander Yermolovich auto &Patch = LengthPatches.back(); 11411c2f4bbeSAlexander Yermolovich Patch.second = NewBinaryContents.size() - 4 - Patch.first; 11421c2f4bbeSAlexander Yermolovich for (uint32_t J = 1, Size = LengthPatches.size(); J < Size; ++J) { 11431c2f4bbeSAlexander Yermolovich const auto &Patch = LengthPatches[J]; 11441c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(4, Patch.second); 11451c2f4bbeSAlexander Yermolovich Offset = Patch.first; 11461c2f4bbeSAlexander Yermolovich for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I) 11471c2f4bbeSAlexander Yermolovich NewBinaryContents[Offset + I] = ByteSequence[I]; 11481c2f4bbeSAlexander Yermolovich } 11491c2f4bbeSAlexander Yermolovich 11501c2f4bbeSAlexander Yermolovich return NewBinaryContents; 1151a34c753fSRafael Auler } 1152a34c753fSRafael Auler 1153ba1ac98cSAlexander Yermolovich void DebugStrOffsetsWriter::initialize( 1154ba1ac98cSAlexander Yermolovich const DWARFSection &StrOffsetsSection, 115589fab98eSFangrui Song const std::optional<StrOffsetsContributionDescriptor> Contr) { 1156ba1ac98cSAlexander Yermolovich if (!Contr) 1157ba1ac98cSAlexander Yermolovich return; 1158ba1ac98cSAlexander Yermolovich 1159ba1ac98cSAlexander Yermolovich const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize(); 1160ba1ac98cSAlexander Yermolovich assert(DwarfOffsetByteSize == 4 && 1161ba1ac98cSAlexander Yermolovich "Dwarf String Offsets Byte Size is not supported."); 1162ba1ac98cSAlexander Yermolovich uint32_t Index = 0; 1163ba1ac98cSAlexander Yermolovich for (uint64_t Offset = 0; Offset < Contr->Size; Offset += DwarfOffsetByteSize) 1164ba1ac98cSAlexander Yermolovich IndexToAddressMap[Index++] = *reinterpret_cast<const uint32_t *>( 1165ba1ac98cSAlexander Yermolovich StrOffsetsSection.Data.data() + Contr->Base + Offset); 1166ba1ac98cSAlexander Yermolovich } 1167ba1ac98cSAlexander Yermolovich 1168ba1ac98cSAlexander Yermolovich void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address) { 1169ba1ac98cSAlexander Yermolovich assert(IndexToAddressMap.count(Index) > 0 && "Index is not found."); 1170ba1ac98cSAlexander Yermolovich IndexToAddressMap[Index] = Address; 1171f7a21317SAlexander Yermolovich StrOffsetSectionWasModified = true; 1172ba1ac98cSAlexander Yermolovich } 1173ba1ac98cSAlexander Yermolovich 1174f7a21317SAlexander Yermolovich void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit) { 1175ba1ac98cSAlexander Yermolovich if (IndexToAddressMap.empty()) 1176ba1ac98cSAlexander Yermolovich return; 1177f7a21317SAlexander Yermolovich 1178f7a21317SAlexander Yermolovich std::optional<AttrInfo> AttrVal = 1179f7a21317SAlexander Yermolovich findAttributeInfo(Unit.getUnitDIE(), dwarf::DW_AT_str_offsets_base); 1180f7a21317SAlexander Yermolovich assert(AttrVal && "DW_AT_str_offsets_base not present."); 1181f7a21317SAlexander Yermolovich std::optional<uint64_t> Val = AttrVal->V.getAsSectionOffset(); 1182f7a21317SAlexander Yermolovich assert(Val && "DW_AT_str_offsets_base Value not present."); 1183f7a21317SAlexander Yermolovich auto RetVal = ProcessedBaseOffsets.insert(*Val); 1184f7a21317SAlexander Yermolovich if (RetVal.second) { 1185ba1ac98cSAlexander Yermolovich // Writing out the header for each section. 1186ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, CurrentSectionSize + 4, 1187ba1ac98cSAlexander Yermolovich support::little); 1188ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(5), 1189ba1ac98cSAlexander Yermolovich support::little); 1190ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(0), 1191ba1ac98cSAlexander Yermolovich support::little); 1192ba1ac98cSAlexander Yermolovich for (const auto &Entry : IndexToAddressMap) 1193ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, Entry.second, support::little); 1194f7a21317SAlexander Yermolovich } 1195f7a21317SAlexander Yermolovich // Will print error if we already processed this contribution, and now 1196f7a21317SAlexander Yermolovich // skipping it, but it was modified. 1197f7a21317SAlexander Yermolovich if (!RetVal.second && StrOffsetSectionWasModified) 1198f7a21317SAlexander Yermolovich errs() << "BOLT-WARNING: skipping string offsets section for CU at offset " 1199f7a21317SAlexander Yermolovich << Twine::utohexstr(Unit.getOffset()) << ", but it was modified\n"; 1200f7a21317SAlexander Yermolovich 1201f7a21317SAlexander Yermolovich StrOffsetSectionWasModified = false; 1202ba1ac98cSAlexander Yermolovich IndexToAddressMap.clear(); 1203ba1ac98cSAlexander Yermolovich } 1204ba1ac98cSAlexander Yermolovich 1205a34c753fSRafael Auler void DebugStrWriter::create() { 1206a34c753fSRafael Auler StrBuffer = std::make_unique<DebugStrBufferVector>(); 1207a34c753fSRafael Auler StrStream = std::make_unique<raw_svector_ostream>(*StrBuffer); 1208a34c753fSRafael Auler } 1209a34c753fSRafael Auler 1210a34c753fSRafael Auler void DebugStrWriter::initialize() { 1211ba1ac98cSAlexander Yermolovich auto StrSection = BC.DwCtx->getDWARFObj().getStrSection(); 1212a34c753fSRafael Auler (*StrStream) << StrSection; 1213a34c753fSRafael Auler } 1214a34c753fSRafael Auler 1215a34c753fSRafael Auler uint32_t DebugStrWriter::addString(StringRef Str) { 1216e579f5c6SAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 1217a34c753fSRafael Auler if (StrBuffer->empty()) 1218a34c753fSRafael Auler initialize(); 1219a34c753fSRafael Auler auto Offset = StrBuffer->size(); 1220a34c753fSRafael Auler (*StrStream) << Str; 1221a34c753fSRafael Auler StrStream->write_zeros(1); 1222a34c753fSRafael Auler return Offset; 1223a34c753fSRafael Auler } 1224a34c753fSRafael Auler 1225a34c753fSRafael Auler void DebugAbbrevWriter::addUnitAbbreviations(DWARFUnit &Unit) { 1226a34c753fSRafael Auler const DWARFAbbreviationDeclarationSet *Abbrevs = Unit.getAbbreviations(); 1227a34c753fSRafael Auler if (!Abbrevs) 1228a34c753fSRafael Auler return; 1229a34c753fSRafael Auler 123045f94abcSMaksim Panchenko const PatchesTy &UnitPatches = Patches[&Unit]; 1231bd1ebe9dSAlexander Yermolovich const AbbrevEntryTy &AbbrevEntries = NewAbbrevEntries[&Unit]; 1232a34c753fSRafael Auler 12339f3f9d19SAlexander Yermolovich // We are duplicating abbrev sections, to handle the case where for one CU we 12349f3f9d19SAlexander Yermolovich // modify it, but for another we don't. 12359f3f9d19SAlexander Yermolovich auto UnitDataPtr = std::make_unique<AbbrevData>(); 12369f3f9d19SAlexander Yermolovich AbbrevData &UnitData = *UnitDataPtr.get(); 12379f3f9d19SAlexander Yermolovich UnitData.Buffer = std::make_unique<DebugBufferVector>(); 12389f3f9d19SAlexander Yermolovich UnitData.Stream = std::make_unique<raw_svector_ostream>(*UnitData.Buffer); 1239bd1ebe9dSAlexander Yermolovich 1240a34c753fSRafael Auler raw_svector_ostream &OS = *UnitData.Stream.get(); 1241a34c753fSRafael Auler 12429f3f9d19SAlexander Yermolovich // Returns true if AbbrevData is re-used, false otherwise. 12439f3f9d19SAlexander Yermolovich auto hashAndAddAbbrev = [&](StringRef AbbrevData) -> bool { 12449f3f9d19SAlexander Yermolovich llvm::SHA1 Hasher; 12459f3f9d19SAlexander Yermolovich Hasher.update(AbbrevData); 1246330268baSArgyrios Kyrtzidis std::array<uint8_t, 20> Hash = Hasher.final(); 1247330268baSArgyrios Kyrtzidis StringRef Key((const char *)Hash.data(), Hash.size()); 12489f3f9d19SAlexander Yermolovich auto Iter = AbbrevDataCache.find(Key); 12499f3f9d19SAlexander Yermolovich if (Iter != AbbrevDataCache.end()) { 12509f3f9d19SAlexander Yermolovich UnitsAbbrevData[&Unit] = Iter->second.get(); 12519f3f9d19SAlexander Yermolovich return true; 12529f3f9d19SAlexander Yermolovich } 12539f3f9d19SAlexander Yermolovich AbbrevDataCache[Key] = std::move(UnitDataPtr); 12549f3f9d19SAlexander Yermolovich UnitsAbbrevData[&Unit] = &UnitData; 12559f3f9d19SAlexander Yermolovich return false; 12569f3f9d19SAlexander Yermolovich }; 1257a34c753fSRafael Auler // Take a fast path if there are no patches to apply. Simply copy the original 1258a34c753fSRafael Auler // contents. 1259bd1ebe9dSAlexander Yermolovich if (UnitPatches.empty() && AbbrevEntries.empty()) { 1260a34c753fSRafael Auler StringRef AbbrevSectionContents = 1261a34c753fSRafael Auler Unit.isDWOUnit() ? Unit.getContext().getDWARFObj().getAbbrevDWOSection() 1262a34c753fSRafael Auler : Unit.getContext().getDWARFObj().getAbbrevSection(); 1263a34c753fSRafael Auler StringRef AbbrevContents; 1264a34c753fSRafael Auler 1265a34c753fSRafael Auler const DWARFUnitIndex &CUIndex = Unit.getContext().getCUIndex(); 1266a34c753fSRafael Auler if (!CUIndex.getRows().empty()) { 1267a34c753fSRafael Auler // Handle DWP section contribution. 1268a34c753fSRafael Auler const DWARFUnitIndex::Entry *DWOEntry = 1269a34c753fSRafael Auler CUIndex.getFromHash(*Unit.getDWOId()); 1270a34c753fSRafael Auler if (!DWOEntry) 1271a34c753fSRafael Auler return; 1272a34c753fSRafael Auler 1273a34c753fSRafael Auler const DWARFUnitIndex::Entry::SectionContribution *DWOContrubution = 1274a34c753fSRafael Auler DWOEntry->getContribution(DWARFSectionKind::DW_SECT_ABBREV); 12757fc79340SAlexander Yermolovich AbbrevContents = AbbrevSectionContents.substr( 12767fc79340SAlexander Yermolovich DWOContrubution->getOffset(), DWOContrubution->getLength()); 127745f94abcSMaksim Panchenko } else if (!Unit.isDWOUnit()) { 1278a34c753fSRafael Auler const uint64_t StartOffset = Unit.getAbbreviationsOffset(); 127945f94abcSMaksim Panchenko 128045f94abcSMaksim Panchenko // We know where the unit's abbreviation set starts, but not where it ends 128145f94abcSMaksim Panchenko // as such data is not readily available. Hence, we have to build a sorted 128245f94abcSMaksim Panchenko // list of start addresses and find the next starting address to determine 128345f94abcSMaksim Panchenko // the set boundaries. 128445f94abcSMaksim Panchenko // 128545f94abcSMaksim Panchenko // FIXME: if we had a full access to DWARFDebugAbbrev::AbbrDeclSets 128645f94abcSMaksim Panchenko // we wouldn't have to build our own sorted list for the quick lookup. 128745f94abcSMaksim Panchenko if (AbbrevSetOffsets.empty()) { 1288a0c7ca8aSKazu Hirata for (const std::pair<const uint64_t, DWARFAbbreviationDeclarationSet> 1289a0c7ca8aSKazu Hirata &P : *Unit.getContext().getDebugAbbrev()) 129045f94abcSMaksim Panchenko AbbrevSetOffsets.push_back(P.first); 12911c2f4bbeSAlexander Yermolovich sort(AbbrevSetOffsets); 129245f94abcSMaksim Panchenko } 12931c2f4bbeSAlexander Yermolovich auto It = upper_bound(AbbrevSetOffsets, StartOffset); 129445f94abcSMaksim Panchenko const uint64_t EndOffset = 129545f94abcSMaksim Panchenko It == AbbrevSetOffsets.end() ? AbbrevSectionContents.size() : *It; 1296a34c753fSRafael Auler AbbrevContents = AbbrevSectionContents.slice(StartOffset, EndOffset); 129745f94abcSMaksim Panchenko } else { 129845f94abcSMaksim Panchenko // For DWO unit outside of DWP, we expect the entire section to hold 129945f94abcSMaksim Panchenko // abbreviations for this unit only. 130045f94abcSMaksim Panchenko AbbrevContents = AbbrevSectionContents; 1301a34c753fSRafael Auler } 1302a34c753fSRafael Auler 13039f3f9d19SAlexander Yermolovich if (!hashAndAddAbbrev(AbbrevContents)) { 1304a34c753fSRafael Auler OS.reserveExtraSpace(AbbrevContents.size()); 1305a34c753fSRafael Auler OS << AbbrevContents; 13069f3f9d19SAlexander Yermolovich } 1307a34c753fSRafael Auler return; 1308a34c753fSRafael Auler } 1309a34c753fSRafael Auler 1310a34c753fSRafael Auler for (auto I = Abbrevs->begin(), E = Abbrevs->end(); I != E; ++I) { 1311a34c753fSRafael Auler const DWARFAbbreviationDeclaration &Abbrev = *I; 1312a34c753fSRafael Auler auto Patch = UnitPatches.find(&Abbrev); 1313a34c753fSRafael Auler 1314a34c753fSRafael Auler encodeULEB128(Abbrev.getCode(), OS); 1315a34c753fSRafael Auler encodeULEB128(Abbrev.getTag(), OS); 1316a34c753fSRafael Auler encodeULEB128(Abbrev.hasChildren(), OS); 1317a34c753fSRafael Auler for (const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec : 1318a34c753fSRafael Auler Abbrev.attributes()) { 1319a34c753fSRafael Auler if (Patch != UnitPatches.end()) { 1320a34c753fSRafael Auler bool Patched = false; 1321a34c753fSRafael Auler // Patches added later take a precedence over earlier ones. 1322f40d25ddSAmir Ayupov for (const PatchInfo &PI : llvm::reverse(Patch->second)) { 1323f40d25ddSAmir Ayupov if (PI.OldAttr != AttrSpec.Attr) 1324a34c753fSRafael Auler continue; 1325a34c753fSRafael Auler 1326f40d25ddSAmir Ayupov encodeULEB128(PI.NewAttr, OS); 1327f40d25ddSAmir Ayupov encodeULEB128(PI.NewAttrForm, OS); 1328a34c753fSRafael Auler Patched = true; 1329a34c753fSRafael Auler break; 1330a34c753fSRafael Auler } 1331a34c753fSRafael Auler if (Patched) 1332a34c753fSRafael Auler continue; 1333a34c753fSRafael Auler } 1334a34c753fSRafael Auler 1335a34c753fSRafael Auler encodeULEB128(AttrSpec.Attr, OS); 1336a34c753fSRafael Auler encodeULEB128(AttrSpec.Form, OS); 1337a34c753fSRafael Auler if (AttrSpec.isImplicitConst()) 1338a34c753fSRafael Auler encodeSLEB128(AttrSpec.getImplicitConstValue(), OS); 1339a34c753fSRafael Auler } 1340bd1ebe9dSAlexander Yermolovich const auto Entries = AbbrevEntries.find(&Abbrev); 1341bd1ebe9dSAlexander Yermolovich // Adding new Abbrevs for inserted entries. 1342bd1ebe9dSAlexander Yermolovich if (Entries != AbbrevEntries.end()) { 1343bd1ebe9dSAlexander Yermolovich for (const AbbrevEntry &Entry : Entries->second) { 1344bd1ebe9dSAlexander Yermolovich encodeULEB128(Entry.Attr, OS); 1345bd1ebe9dSAlexander Yermolovich encodeULEB128(Entry.Form, OS); 1346bd1ebe9dSAlexander Yermolovich } 1347bd1ebe9dSAlexander Yermolovich } 1348a34c753fSRafael Auler encodeULEB128(0, OS); 1349a34c753fSRafael Auler encodeULEB128(0, OS); 1350a34c753fSRafael Auler } 1351a34c753fSRafael Auler encodeULEB128(0, OS); 13529f3f9d19SAlexander Yermolovich 13539f3f9d19SAlexander Yermolovich hashAndAddAbbrev(OS.str()); 1354a34c753fSRafael Auler } 1355a34c753fSRafael Auler 1356a34c753fSRafael Auler std::unique_ptr<DebugBufferVector> DebugAbbrevWriter::finalize() { 13579f3f9d19SAlexander Yermolovich // Used to create determinism for writing out abbrevs. 13589f3f9d19SAlexander Yermolovich std::vector<AbbrevData *> Abbrevs; 135945f94abcSMaksim Panchenko if (DWOId) { 136045f94abcSMaksim Panchenko // We expect abbrev_offset to always be zero for DWO units as there 136145f94abcSMaksim Panchenko // should be one CU per DWO, and TUs should share the same abbreviation 136245f94abcSMaksim Panchenko // set with the CU. 13631417f607SAlexander Yermolovich // For DWP AbbreviationsOffset is an Abbrev contribution in the DWP file, so 13641417f607SAlexander Yermolovich // can be none zero. Thus we are skipping the check for DWP. 136545f94abcSMaksim Panchenko bool IsDWP = !Context.getCUIndex().getRows().empty(); 13661417f607SAlexander Yermolovich if (!IsDWP) { 136745f94abcSMaksim Panchenko for (const std::unique_ptr<DWARFUnit> &Unit : Context.dwo_units()) { 136845f94abcSMaksim Panchenko if (Unit->getAbbreviationsOffset() != 0) { 136945f94abcSMaksim Panchenko errs() << "BOLT-ERROR: detected DWO unit with non-zero abbr_offset. " 137045f94abcSMaksim Panchenko "Unable to update debug info.\n"; 137145f94abcSMaksim Panchenko exit(1); 137245f94abcSMaksim Panchenko } 137345f94abcSMaksim Panchenko } 137445f94abcSMaksim Panchenko } 137545f94abcSMaksim Panchenko 13769f3f9d19SAlexander Yermolovich DWARFUnit *Unit = Context.getDWOCompileUnitForHash(*DWOId); 137745f94abcSMaksim Panchenko // Issue abbreviations for the DWO CU only. 137845f94abcSMaksim Panchenko addUnitAbbreviations(*Unit); 13799f3f9d19SAlexander Yermolovich AbbrevData *Abbrev = UnitsAbbrevData[Unit]; 13809f3f9d19SAlexander Yermolovich Abbrevs.push_back(Abbrev); 13819f3f9d19SAlexander Yermolovich } else { 13829f3f9d19SAlexander Yermolovich Abbrevs.reserve(Context.getNumCompileUnits() + Context.getNumTypeUnits()); 13839f3f9d19SAlexander Yermolovich std::unordered_set<AbbrevData *> ProcessedAbbrevs; 13849f3f9d19SAlexander Yermolovich // Add abbreviations from compile and type non-DWO units. 13859f3f9d19SAlexander Yermolovich for (const std::unique_ptr<DWARFUnit> &Unit : Context.normal_units()) { 13869f3f9d19SAlexander Yermolovich addUnitAbbreviations(*Unit); 13879f3f9d19SAlexander Yermolovich AbbrevData *Abbrev = UnitsAbbrevData[Unit.get()]; 13889f3f9d19SAlexander Yermolovich if (!ProcessedAbbrevs.insert(Abbrev).second) 13899f3f9d19SAlexander Yermolovich continue; 13909f3f9d19SAlexander Yermolovich Abbrevs.push_back(Abbrev); 13919f3f9d19SAlexander Yermolovich } 139245f94abcSMaksim Panchenko } 139345f94abcSMaksim Panchenko 1394a34c753fSRafael Auler DebugBufferVector ReturnBuffer; 1395a34c753fSRafael Auler // Pre-calculate the total size of abbrev section. 1396a34c753fSRafael Auler uint64_t Size = 0; 13979f3f9d19SAlexander Yermolovich for (const AbbrevData *UnitData : Abbrevs) 13989f3f9d19SAlexander Yermolovich Size += UnitData->Buffer->size(); 13999f3f9d19SAlexander Yermolovich 1400a34c753fSRafael Auler ReturnBuffer.reserve(Size); 1401a34c753fSRafael Auler 1402a34c753fSRafael Auler uint64_t Pos = 0; 14039f3f9d19SAlexander Yermolovich for (AbbrevData *UnitData : Abbrevs) { 14049f3f9d19SAlexander Yermolovich ReturnBuffer.append(*UnitData->Buffer); 14059f3f9d19SAlexander Yermolovich UnitData->Offset = Pos; 14069f3f9d19SAlexander Yermolovich Pos += UnitData->Buffer->size(); 1407a34c753fSRafael Auler 14089f3f9d19SAlexander Yermolovich UnitData->Buffer.reset(); 14099f3f9d19SAlexander Yermolovich UnitData->Stream.reset(); 1410a34c753fSRafael Auler } 1411a34c753fSRafael Auler 1412a34c753fSRafael Auler return std::make_unique<DebugBufferVector>(ReturnBuffer); 1413a34c753fSRafael Auler } 1414a34c753fSRafael Auler 1415a34c753fSRafael Auler static void emitDwarfSetLineAddrAbs(MCStreamer &OS, 1416a34c753fSRafael Auler MCDwarfLineTableParams Params, 1417a34c753fSRafael Auler int64_t LineDelta, uint64_t Address, 1418a34c753fSRafael Auler int PointerSize) { 1419a34c753fSRafael Auler // emit the sequence to set the address 1420a34c753fSRafael Auler OS.emitIntValue(dwarf::DW_LNS_extended_op, 1); 1421a34c753fSRafael Auler OS.emitULEB128IntValue(PointerSize + 1); 1422a34c753fSRafael Auler OS.emitIntValue(dwarf::DW_LNE_set_address, 1); 1423a34c753fSRafael Auler OS.emitIntValue(Address, PointerSize); 1424a34c753fSRafael Auler 1425a34c753fSRafael Auler // emit the sequence for the LineDelta (from 1) and a zero address delta. 1426a34c753fSRafael Auler MCDwarfLineAddr::Emit(&OS, Params, LineDelta, 0); 1427a34c753fSRafael Auler } 1428a34c753fSRafael Auler 1429a34c753fSRafael Auler static inline void emitBinaryDwarfLineTable( 1430a34c753fSRafael Auler MCStreamer *MCOS, MCDwarfLineTableParams Params, 1431a34c753fSRafael Auler const DWARFDebugLine::LineTable *Table, 1432a34c753fSRafael Auler const std::vector<DwarfLineTable::RowSequence> &InputSequences) { 1433a34c753fSRafael Auler if (InputSequences.empty()) 1434a34c753fSRafael Auler return; 1435a34c753fSRafael Auler 1436a34c753fSRafael Auler constexpr uint64_t InvalidAddress = UINT64_MAX; 1437a34c753fSRafael Auler unsigned FileNum = 1; 1438a34c753fSRafael Auler unsigned LastLine = 1; 1439a34c753fSRafael Auler unsigned Column = 0; 1440a34c753fSRafael Auler unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1441a34c753fSRafael Auler unsigned Isa = 0; 1442a34c753fSRafael Auler unsigned Discriminator = 0; 1443a34c753fSRafael Auler uint64_t LastAddress = InvalidAddress; 1444a34c753fSRafael Auler uint64_t PrevEndOfSequence = InvalidAddress; 1445a34c753fSRafael Auler const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo(); 1446a34c753fSRafael Auler 1447a34c753fSRafael Auler auto emitEndOfSequence = [&](uint64_t Address) { 1448a34c753fSRafael Auler MCDwarfLineAddr::Emit(MCOS, Params, INT64_MAX, Address - LastAddress); 1449a34c753fSRafael Auler FileNum = 1; 1450a34c753fSRafael Auler LastLine = 1; 1451a34c753fSRafael Auler Column = 0; 1452a34c753fSRafael Auler Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1453a34c753fSRafael Auler Isa = 0; 1454a34c753fSRafael Auler Discriminator = 0; 1455a34c753fSRafael Auler LastAddress = InvalidAddress; 1456a34c753fSRafael Auler }; 1457a34c753fSRafael Auler 1458a34c753fSRafael Auler for (const DwarfLineTable::RowSequence &Sequence : InputSequences) { 1459a34c753fSRafael Auler const uint64_t SequenceStart = 1460a34c753fSRafael Auler Table->Rows[Sequence.FirstIndex].Address.Address; 1461a34c753fSRafael Auler 1462a34c753fSRafael Auler // Check if we need to mark the end of the sequence. 1463a34c753fSRafael Auler if (PrevEndOfSequence != InvalidAddress && LastAddress != InvalidAddress && 1464a34c753fSRafael Auler PrevEndOfSequence != SequenceStart) { 1465a34c753fSRafael Auler emitEndOfSequence(PrevEndOfSequence); 1466a34c753fSRafael Auler } 1467a34c753fSRafael Auler 1468a34c753fSRafael Auler for (uint32_t RowIndex = Sequence.FirstIndex; 1469a34c753fSRafael Auler RowIndex <= Sequence.LastIndex; ++RowIndex) { 1470a34c753fSRafael Auler const DWARFDebugLine::Row &Row = Table->Rows[RowIndex]; 1471a34c753fSRafael Auler int64_t LineDelta = static_cast<int64_t>(Row.Line) - LastLine; 1472a34c753fSRafael Auler const uint64_t Address = Row.Address.Address; 1473a34c753fSRafael Auler 1474a34c753fSRafael Auler if (FileNum != Row.File) { 1475a34c753fSRafael Auler FileNum = Row.File; 1476a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_file); 1477a34c753fSRafael Auler MCOS->emitULEB128IntValue(FileNum); 1478a34c753fSRafael Auler } 1479a34c753fSRafael Auler if (Column != Row.Column) { 1480a34c753fSRafael Auler Column = Row.Column; 1481a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_column); 1482a34c753fSRafael Auler MCOS->emitULEB128IntValue(Column); 1483a34c753fSRafael Auler } 1484a34c753fSRafael Auler if (Discriminator != Row.Discriminator && 1485a34c753fSRafael Auler MCOS->getContext().getDwarfVersion() >= 4) { 1486a34c753fSRafael Auler Discriminator = Row.Discriminator; 1487a34c753fSRafael Auler unsigned Size = getULEB128Size(Discriminator); 1488a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_extended_op); 1489a34c753fSRafael Auler MCOS->emitULEB128IntValue(Size + 1); 1490a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNE_set_discriminator); 1491a34c753fSRafael Auler MCOS->emitULEB128IntValue(Discriminator); 1492a34c753fSRafael Auler } 1493a34c753fSRafael Auler if (Isa != Row.Isa) { 1494a34c753fSRafael Auler Isa = Row.Isa; 1495a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_isa); 1496a34c753fSRafael Auler MCOS->emitULEB128IntValue(Isa); 1497a34c753fSRafael Auler } 1498a34c753fSRafael Auler if (Row.IsStmt != Flags) { 1499a34c753fSRafael Auler Flags = Row.IsStmt; 1500a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_negate_stmt); 1501a34c753fSRafael Auler } 1502a34c753fSRafael Auler if (Row.BasicBlock) 1503a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_basic_block); 1504a34c753fSRafael Auler if (Row.PrologueEnd) 1505a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_prologue_end); 1506a34c753fSRafael Auler if (Row.EpilogueBegin) 1507a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin); 1508a34c753fSRafael Auler 1509a34c753fSRafael Auler // The end of the sequence is not normal in the middle of the input 1510a34c753fSRafael Auler // sequence, but could happen, e.g. for assembly code. 1511a34c753fSRafael Auler if (Row.EndSequence) { 1512a34c753fSRafael Auler emitEndOfSequence(Address); 1513a34c753fSRafael Auler } else { 1514a34c753fSRafael Auler if (LastAddress == InvalidAddress) 1515a34c753fSRafael Auler emitDwarfSetLineAddrAbs(*MCOS, Params, LineDelta, Address, 1516a34c753fSRafael Auler AsmInfo->getCodePointerSize()); 1517a34c753fSRafael Auler else 1518a34c753fSRafael Auler MCDwarfLineAddr::Emit(MCOS, Params, LineDelta, Address - LastAddress); 1519a34c753fSRafael Auler 1520a34c753fSRafael Auler LastAddress = Address; 1521a34c753fSRafael Auler LastLine = Row.Line; 1522a34c753fSRafael Auler } 1523a34c753fSRafael Auler 1524a34c753fSRafael Auler Discriminator = 0; 1525a34c753fSRafael Auler } 1526a34c753fSRafael Auler PrevEndOfSequence = Sequence.EndAddress; 1527a34c753fSRafael Auler } 1528a34c753fSRafael Auler 1529a34c753fSRafael Auler // Finish with the end of the sequence. 1530a34c753fSRafael Auler if (LastAddress != InvalidAddress) 1531a34c753fSRafael Auler emitEndOfSequence(PrevEndOfSequence); 1532a34c753fSRafael Auler } 1533a34c753fSRafael Auler 1534a34c753fSRafael Auler // This function is similar to the one from MCDwarfLineTable, except it handles 1535a34c753fSRafael Auler // end-of-sequence entries differently by utilizing line entries with 1536a34c753fSRafael Auler // DWARF2_FLAG_END_SEQUENCE flag. 1537a34c753fSRafael Auler static inline void emitDwarfLineTable( 1538a34c753fSRafael Auler MCStreamer *MCOS, MCSection *Section, 1539a34c753fSRafael Auler const MCLineSection::MCDwarfLineEntryCollection &LineEntries) { 1540a34c753fSRafael Auler unsigned FileNum = 1; 1541a34c753fSRafael Auler unsigned LastLine = 1; 1542a34c753fSRafael Auler unsigned Column = 0; 1543a34c753fSRafael Auler unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1544a34c753fSRafael Auler unsigned Isa = 0; 1545a34c753fSRafael Auler unsigned Discriminator = 0; 1546a34c753fSRafael Auler MCSymbol *LastLabel = nullptr; 1547a34c753fSRafael Auler const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo(); 1548a34c753fSRafael Auler 1549a34c753fSRafael Auler // Loop through each MCDwarfLineEntry and encode the dwarf line number table. 1550a34c753fSRafael Auler for (const MCDwarfLineEntry &LineEntry : LineEntries) { 1551a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_END_SEQUENCE) { 1552a34c753fSRafael Auler MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, LineEntry.getLabel(), 1553a34c753fSRafael Auler AsmInfo->getCodePointerSize()); 1554a34c753fSRafael Auler FileNum = 1; 1555a34c753fSRafael Auler LastLine = 1; 1556a34c753fSRafael Auler Column = 0; 1557a34c753fSRafael Auler Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1558a34c753fSRafael Auler Isa = 0; 1559a34c753fSRafael Auler Discriminator = 0; 1560a34c753fSRafael Auler LastLabel = nullptr; 1561a34c753fSRafael Auler continue; 1562a34c753fSRafael Auler } 1563a34c753fSRafael Auler 1564a34c753fSRafael Auler int64_t LineDelta = static_cast<int64_t>(LineEntry.getLine()) - LastLine; 1565a34c753fSRafael Auler 1566a34c753fSRafael Auler if (FileNum != LineEntry.getFileNum()) { 1567a34c753fSRafael Auler FileNum = LineEntry.getFileNum(); 1568a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_file); 1569a34c753fSRafael Auler MCOS->emitULEB128IntValue(FileNum); 1570a34c753fSRafael Auler } 1571a34c753fSRafael Auler if (Column != LineEntry.getColumn()) { 1572a34c753fSRafael Auler Column = LineEntry.getColumn(); 1573a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_column); 1574a34c753fSRafael Auler MCOS->emitULEB128IntValue(Column); 1575a34c753fSRafael Auler } 1576a34c753fSRafael Auler if (Discriminator != LineEntry.getDiscriminator() && 1577014cd37fSAlexander Yermolovich MCOS->getContext().getDwarfVersion() >= 2) { 1578a34c753fSRafael Auler Discriminator = LineEntry.getDiscriminator(); 1579a34c753fSRafael Auler unsigned Size = getULEB128Size(Discriminator); 1580a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_extended_op); 1581a34c753fSRafael Auler MCOS->emitULEB128IntValue(Size + 1); 1582a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNE_set_discriminator); 1583a34c753fSRafael Auler MCOS->emitULEB128IntValue(Discriminator); 1584a34c753fSRafael Auler } 1585a34c753fSRafael Auler if (Isa != LineEntry.getIsa()) { 1586a34c753fSRafael Auler Isa = LineEntry.getIsa(); 1587a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_isa); 1588a34c753fSRafael Auler MCOS->emitULEB128IntValue(Isa); 1589a34c753fSRafael Auler } 1590a34c753fSRafael Auler if ((LineEntry.getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { 1591a34c753fSRafael Auler Flags = LineEntry.getFlags(); 1592a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_negate_stmt); 1593a34c753fSRafael Auler } 1594a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_BASIC_BLOCK) 1595a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_basic_block); 1596a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_PROLOGUE_END) 1597a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_prologue_end); 1598a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) 1599a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin); 1600a34c753fSRafael Auler 1601a34c753fSRafael Auler MCSymbol *Label = LineEntry.getLabel(); 1602a34c753fSRafael Auler 1603a34c753fSRafael Auler // At this point we want to emit/create the sequence to encode the delta 1604a34c753fSRafael Auler // in line numbers and the increment of the address from the previous 1605a34c753fSRafael Auler // Label and the current Label. 1606a34c753fSRafael Auler MCOS->emitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label, 1607a34c753fSRafael Auler AsmInfo->getCodePointerSize()); 1608a34c753fSRafael Auler Discriminator = 0; 1609a34c753fSRafael Auler LastLine = LineEntry.getLine(); 1610a34c753fSRafael Auler LastLabel = Label; 1611a34c753fSRafael Auler } 1612a34c753fSRafael Auler 1613a34c753fSRafael Auler assert(LastLabel == nullptr && "end of sequence expected"); 1614a34c753fSRafael Auler } 1615a34c753fSRafael Auler 1616a34c753fSRafael Auler void DwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params, 1617f4c16c44SFangrui Song std::optional<MCDwarfLineStr> &LineStr, 1618b73c87bcSMaksim Panchenko BinaryContext &BC) const { 1619a34c753fSRafael Auler if (!RawData.empty()) { 1620a34c753fSRafael Auler assert(MCLineSections.getMCLineEntries().empty() && 1621a34c753fSRafael Auler InputSequences.empty() && 1622a34c753fSRafael Auler "cannot combine raw data with new line entries"); 1623a34c753fSRafael Auler MCOS->emitLabel(getLabel()); 1624a34c753fSRafael Auler MCOS->emitBytes(RawData); 1625a34c753fSRafael Auler 1626b73c87bcSMaksim Panchenko // Emit fake relocation for RuntimeDyld to always allocate the section. 1627b73c87bcSMaksim Panchenko // 1628b73c87bcSMaksim Panchenko // FIXME: remove this once RuntimeDyld stops skipping allocatable sections 1629b73c87bcSMaksim Panchenko // without relocations. 1630b73c87bcSMaksim Panchenko MCOS->emitRelocDirective( 1631b73c87bcSMaksim Panchenko *MCConstantExpr::create(0, *BC.Ctx), "BFD_RELOC_NONE", 1632b73c87bcSMaksim Panchenko MCSymbolRefExpr::create(getLabel(), *BC.Ctx), SMLoc(), *BC.STI); 1633b73c87bcSMaksim Panchenko 1634a34c753fSRafael Auler return; 1635a34c753fSRafael Auler } 1636a34c753fSRafael Auler 1637a34c753fSRafael Auler MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second; 1638a34c753fSRafael Auler 1639a34c753fSRafael Auler // Put out the line tables. 1640a34c753fSRafael Auler for (const auto &LineSec : MCLineSections.getMCLineEntries()) 1641a34c753fSRafael Auler emitDwarfLineTable(MCOS, LineSec.first, LineSec.second); 1642a34c753fSRafael Auler 1643a34c753fSRafael Auler // Emit line tables for the original code. 1644a34c753fSRafael Auler emitBinaryDwarfLineTable(MCOS, Params, InputTable, InputSequences); 1645a34c753fSRafael Auler 1646a34c753fSRafael Auler // This is the end of the section, so set the value of the symbol at the end 1647a34c753fSRafael Auler // of this section (that was used in a previous expression). 1648a34c753fSRafael Auler MCOS->emitLabel(LineEndSym); 1649a34c753fSRafael Auler } 1650a34c753fSRafael Auler 1651014cd37fSAlexander Yermolovich // Helper function to parse .debug_line_str, and populate one we are using. 1652014cd37fSAlexander Yermolovich // For functions that we do not modify we output them as raw data. 1653014cd37fSAlexander Yermolovich // Re-constructing .debug_line_str so that offsets are correct for those 1654014cd37fSAlexander Yermolovich // debut line tables. 1655014cd37fSAlexander Yermolovich // Bonus is that when we output a final binary we can re-use .debug_line_str 1656014cd37fSAlexander Yermolovich // section. So we don't have to do the SHF_ALLOC trick we did with 1657014cd37fSAlexander Yermolovich // .debug_line. 1658014cd37fSAlexander Yermolovich static void parseAndPopulateDebugLineStr(BinarySection &LineStrSection, 1659014cd37fSAlexander Yermolovich MCDwarfLineStr &LineStr, 1660014cd37fSAlexander Yermolovich BinaryContext &BC, 1661014cd37fSAlexander Yermolovich MCStreamer &Streamer) { 1662014cd37fSAlexander Yermolovich DataExtractor StrData(LineStrSection.getContents(), 1663014cd37fSAlexander Yermolovich BC.DwCtx->isLittleEndian(), 0); 1664014cd37fSAlexander Yermolovich uint64_t Offset = 0; 1665014cd37fSAlexander Yermolovich while (StrData.isValidOffset(Offset)) { 1666014cd37fSAlexander Yermolovich Error Err = Error::success(); 1667014cd37fSAlexander Yermolovich const char *CStr = StrData.getCStr(&Offset, &Err); 1668014cd37fSAlexander Yermolovich if (Err) { 1669014cd37fSAlexander Yermolovich errs() << "BOLT-ERROR: could not extract string from .debug_line_str"; 1670014cd37fSAlexander Yermolovich continue; 1671014cd37fSAlexander Yermolovich } 1672014cd37fSAlexander Yermolovich LineStr.emitRef(&Streamer, CStr); 1673014cd37fSAlexander Yermolovich } 1674014cd37fSAlexander Yermolovich } 1675014cd37fSAlexander Yermolovich 1676a34c753fSRafael Auler void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) { 1677a34c753fSRafael Auler MCAssembler &Assembler = 1678a34c753fSRafael Auler static_cast<MCObjectStreamer *>(&Streamer)->getAssembler(); 1679a34c753fSRafael Auler 1680a34c753fSRafael Auler MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams(); 1681a34c753fSRafael Auler 1682a34c753fSRafael Auler auto &LineTables = BC.getDwarfLineTables(); 1683a34c753fSRafael Auler 1684a34c753fSRafael Auler // Bail out early so we don't switch to the debug_line section needlessly and 1685a34c753fSRafael Auler // in doing so create an unnecessary (if empty) section. 1686a34c753fSRafael Auler if (LineTables.empty()) 1687a34c753fSRafael Auler return; 1688a34c753fSRafael Auler // In a v5 non-split line table, put the strings in a separate section. 1689f4c16c44SFangrui Song std::optional<MCDwarfLineStr> LineStr; 1690014cd37fSAlexander Yermolovich ErrorOr<BinarySection &> LineStrSection = 1691014cd37fSAlexander Yermolovich BC.getUniqueSectionByName(".debug_line_str"); 1692014cd37fSAlexander Yermolovich // Some versions of GCC output DWARF5 .debug_info, but DWARF4 or lower 1693014cd37fSAlexander Yermolovich // .debug_line 1694014cd37fSAlexander Yermolovich if (LineStrSection) { 169553113515SFangrui Song LineStr.emplace(*BC.Ctx); 1696014cd37fSAlexander Yermolovich parseAndPopulateDebugLineStr(*LineStrSection, *LineStr, BC, Streamer); 1697014cd37fSAlexander Yermolovich } 1698a34c753fSRafael Auler 1699a34c753fSRafael Auler // Switch to the section where the table will be emitted into. 1700adf4142fSFangrui Song Streamer.switchSection(BC.MOFI->getDwarfLineSection()); 1701a34c753fSRafael Auler 1702014cd37fSAlexander Yermolovich const uint16_t DwarfVersion = BC.Ctx->getDwarfVersion(); 1703a34c753fSRafael Auler // Handle the rest of the Compile Units. 1704a34c753fSRafael Auler for (auto &CUIDTablePair : LineTables) { 1705014cd37fSAlexander Yermolovich Streamer.getContext().setDwarfVersion( 1706014cd37fSAlexander Yermolovich CUIDTablePair.second.getDwarfVersion()); 1707b73c87bcSMaksim Panchenko CUIDTablePair.second.emitCU(&Streamer, Params, LineStr, BC); 1708a34c753fSRafael Auler } 1709014cd37fSAlexander Yermolovich 1710014cd37fSAlexander Yermolovich // Resetting DWARF version for rest of the flow. 1711014cd37fSAlexander Yermolovich BC.Ctx->setDwarfVersion(DwarfVersion); 1712014cd37fSAlexander Yermolovich 1713014cd37fSAlexander Yermolovich // Still need to write the section out for the ExecutionEngine, and temp in 1714014cd37fSAlexander Yermolovich // memory object we are constructing. 1715014cd37fSAlexander Yermolovich if (LineStr) { 1716014cd37fSAlexander Yermolovich LineStr->emitSection(&Streamer); 1717014cd37fSAlexander Yermolovich SmallString<0> Data = LineStr->getFinalizedData(); 1718014cd37fSAlexander Yermolovich BC.registerOrUpdateNoteSection(".debug_line_str", copyByteArray(Data.str()), 1719014cd37fSAlexander Yermolovich Data.size()); 1720014cd37fSAlexander Yermolovich } 1721a34c753fSRafael Auler } 1722a34c753fSRafael Auler 1723a34c753fSRafael Auler } // namespace bolt 1724a34c753fSRafael Auler } // namespace llvm 1725