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> 30a34c753fSRafael Auler #include <limits> 311c2f4bbeSAlexander Yermolovich #include <unordered_map> 32ba1ac98cSAlexander Yermolovich #include <vector> 33a34c753fSRafael Auler 34a34c753fSRafael Auler #define DEBUG_TYPE "bolt-debug-info" 35a34c753fSRafael Auler 36a34c753fSRafael Auler namespace opts { 37a34c753fSRafael Auler extern llvm::cl::opt<unsigned> Verbosity; 381c2f4bbeSAlexander Yermolovich } // namespace opts 39a34c753fSRafael Auler 40a34c753fSRafael Auler namespace llvm { 41f8c7fb49SAmir Ayupov class MCSymbol; 42f8c7fb49SAmir Ayupov 43a34c753fSRafael Auler namespace bolt { 44a34c753fSRafael Auler 45370e4761SAmir Ayupov std::optional<AttrInfo> 46bd1ebe9dSAlexander Yermolovich findAttributeInfo(const DWARFDie DIE, 47bd1ebe9dSAlexander Yermolovich const DWARFAbbreviationDeclaration *AbbrevDecl, 48bd1ebe9dSAlexander Yermolovich uint32_t Index) { 49bd1ebe9dSAlexander Yermolovich const DWARFUnit &U = *DIE.getDwarfUnit(); 50bd1ebe9dSAlexander Yermolovich uint64_t Offset = 51bd1ebe9dSAlexander Yermolovich AbbrevDecl->getAttributeOffsetFromIndex(Index, DIE.getOffset(), U); 5289fab98eSFangrui Song std::optional<DWARFFormValue> Value = 53bd1ebe9dSAlexander Yermolovich AbbrevDecl->getAttributeValueFromOffset(Index, Offset, U); 54bd1ebe9dSAlexander Yermolovich if (!Value) 55e324a80fSKazu Hirata return std::nullopt; 56bd1ebe9dSAlexander Yermolovich // AttributeSpec 57bd1ebe9dSAlexander Yermolovich const DWARFAbbreviationDeclaration::AttributeSpec *AttrVal = 58bd1ebe9dSAlexander Yermolovich AbbrevDecl->attributes().begin() + Index; 59bd1ebe9dSAlexander Yermolovich uint32_t ValSize = 0; 6089fab98eSFangrui Song std::optional<int64_t> ValSizeOpt = AttrVal->getByteSize(U); 61bd1ebe9dSAlexander Yermolovich if (ValSizeOpt) { 62bd1ebe9dSAlexander Yermolovich ValSize = static_cast<uint32_t>(*ValSizeOpt); 63bd1ebe9dSAlexander Yermolovich } else { 64bd1ebe9dSAlexander Yermolovich DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); 65bd1ebe9dSAlexander Yermolovich uint64_t NewOffset = Offset; 66bd1ebe9dSAlexander Yermolovich DWARFFormValue::skipValue(Value->getForm(), DebugInfoData, &NewOffset, 67bd1ebe9dSAlexander Yermolovich U.getFormParams()); 68bd1ebe9dSAlexander Yermolovich // This includes entire size of the entry, which might not be just the 69bd1ebe9dSAlexander Yermolovich // encoding part. For example for DW_AT_loc it will include expression 70bd1ebe9dSAlexander Yermolovich // location. 71bd1ebe9dSAlexander Yermolovich ValSize = NewOffset - Offset; 72bd1ebe9dSAlexander Yermolovich } 731c6dc43dSAlexander Yermolovich return AttrInfo{*Value, DIE.getAbbreviationDeclarationPtr(), Offset, ValSize}; 741c6dc43dSAlexander Yermolovich } 75bd1ebe9dSAlexander Yermolovich 76370e4761SAmir Ayupov std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE, 771c6dc43dSAlexander Yermolovich dwarf::Attribute Attr) { 781c6dc43dSAlexander Yermolovich if (!DIE.isValid()) 79e324a80fSKazu Hirata return std::nullopt; 801c6dc43dSAlexander Yermolovich const DWARFAbbreviationDeclaration *AbbrevDecl = 811c6dc43dSAlexander Yermolovich DIE.getAbbreviationDeclarationPtr(); 821c6dc43dSAlexander Yermolovich if (!AbbrevDecl) 83e324a80fSKazu Hirata return std::nullopt; 8489fab98eSFangrui Song std::optional<uint32_t> Index = AbbrevDecl->findAttributeIndex(Attr); 851c6dc43dSAlexander Yermolovich if (!Index) 86e324a80fSKazu Hirata return std::nullopt; 871c6dc43dSAlexander Yermolovich return findAttributeInfo(DIE, AbbrevDecl, *Index); 88bd1ebe9dSAlexander Yermolovich } 89bd1ebe9dSAlexander Yermolovich 90a34c753fSRafael Auler const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{0, 0}; 91a34c753fSRafael Auler 92a34c753fSRafael Auler namespace { 93a34c753fSRafael Auler 941c2f4bbeSAlexander Yermolovich LLVM_ATTRIBUTE_UNUSED 951c2f4bbeSAlexander Yermolovich static void printLE64(const std::string &S) { 961c2f4bbeSAlexander Yermolovich for (uint32_t I = 0, Size = S.size(); I < Size; ++I) { 971c2f4bbeSAlexander Yermolovich errs() << Twine::utohexstr(S[I]); 981c2f4bbeSAlexander Yermolovich errs() << Twine::utohexstr((int8_t)S[I]); 991c2f4bbeSAlexander Yermolovich } 1001c2f4bbeSAlexander Yermolovich errs() << "\n"; 1011c2f4bbeSAlexander Yermolovich } 1021c2f4bbeSAlexander Yermolovich 103a34c753fSRafael Auler // Writes address ranges to Writer as pairs of 64-bit (address, size). 104a34c753fSRafael Auler // If RelativeRange is true, assumes the address range to be written must be of 105a34c753fSRafael Auler // the form (begin address, range size), otherwise (begin address, end address). 106a34c753fSRafael Auler // Terminates the list by writing a pair of two zeroes. 107a34c753fSRafael Auler // Returns the number of written bytes. 10840c2e0faSMaksim Panchenko uint64_t writeAddressRanges(raw_svector_ostream &Stream, 109a34c753fSRafael Auler const DebugAddressRangesVector &AddressRanges, 110a34c753fSRafael Auler const bool WriteRelativeRanges = false) { 111a34c753fSRafael Auler for (const DebugAddressRange &Range : AddressRanges) { 112a34c753fSRafael Auler support::endian::write(Stream, Range.LowPC, support::little); 113a34c753fSRafael Auler support::endian::write( 114a34c753fSRafael Auler Stream, WriteRelativeRanges ? Range.HighPC - Range.LowPC : Range.HighPC, 115a34c753fSRafael Auler support::little); 116a34c753fSRafael Auler } 117a34c753fSRafael Auler // Finish with 0 entries. 118a34c753fSRafael Auler support::endian::write(Stream, 0ULL, support::little); 119a34c753fSRafael Auler support::endian::write(Stream, 0ULL, support::little); 120a34c753fSRafael Auler return AddressRanges.size() * 16 + 16; 121a34c753fSRafael Auler } 122a34c753fSRafael Auler 123a34c753fSRafael Auler } // namespace 124a34c753fSRafael Auler 125a34c753fSRafael Auler DebugRangesSectionWriter::DebugRangesSectionWriter() { 126a34c753fSRafael Auler RangesBuffer = std::make_unique<DebugBufferVector>(); 127a34c753fSRafael Auler RangesStream = std::make_unique<raw_svector_ostream>(*RangesBuffer); 128a34c753fSRafael Auler 129a34c753fSRafael Auler // Add an empty range as the first entry; 130a34c753fSRafael Auler SectionOffset += 131a34c753fSRafael Auler writeAddressRanges(*RangesStream.get(), DebugAddressRangesVector{}); 132014cd37fSAlexander Yermolovich Kind = RangesWriterKind::DebugRangesWriter; 133a34c753fSRafael Auler } 134a34c753fSRafael Auler 135a34c753fSRafael Auler uint64_t DebugRangesSectionWriter::addRanges( 136a34c753fSRafael Auler DebugAddressRangesVector &&Ranges, 137a34c753fSRafael Auler std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) { 138a34c753fSRafael Auler if (Ranges.empty()) 139a34c753fSRafael Auler return getEmptyRangesOffset(); 140a34c753fSRafael Auler 141a34c753fSRafael Auler const auto RI = CachedRanges.find(Ranges); 142a34c753fSRafael Auler if (RI != CachedRanges.end()) 143a34c753fSRafael Auler return RI->second; 144a34c753fSRafael Auler 145a34c753fSRafael Auler const uint64_t EntryOffset = addRanges(Ranges); 146a34c753fSRafael Auler CachedRanges.emplace(std::move(Ranges), EntryOffset); 147a34c753fSRafael Auler 148a34c753fSRafael Auler return EntryOffset; 149a34c753fSRafael Auler } 150a34c753fSRafael Auler 151e22ff52cSAlexander Yermolovich uint64_t DebugRangesSectionWriter::addRanges(DebugAddressRangesVector &Ranges) { 152a34c753fSRafael Auler if (Ranges.empty()) 153a34c753fSRafael Auler return getEmptyRangesOffset(); 154a34c753fSRafael Auler 155a34c753fSRafael Auler // Reading the SectionOffset and updating it should be atomic to guarantee 156a34c753fSRafael Auler // unique and correct offsets in patches. 157a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(WriterMutex); 158a34c753fSRafael Auler const uint32_t EntryOffset = SectionOffset; 159a34c753fSRafael Auler SectionOffset += writeAddressRanges(*RangesStream.get(), Ranges); 160a34c753fSRafael Auler 161a34c753fSRafael Auler return EntryOffset; 162a34c753fSRafael Auler } 163a34c753fSRafael Auler 164a34c753fSRafael Auler uint64_t DebugRangesSectionWriter::getSectionOffset() { 165a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(WriterMutex); 166a34c753fSRafael Auler return SectionOffset; 167a34c753fSRafael Auler } 168a34c753fSRafael Auler 169014cd37fSAlexander Yermolovich DebugAddrWriter *DebugRangeListsSectionWriter::AddrWriter = nullptr; 170014cd37fSAlexander Yermolovich 171014cd37fSAlexander Yermolovich uint64_t DebugRangeListsSectionWriter::addRanges( 172014cd37fSAlexander Yermolovich DebugAddressRangesVector &&Ranges, 173014cd37fSAlexander Yermolovich std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) { 174014cd37fSAlexander Yermolovich return addRanges(Ranges); 175014cd37fSAlexander Yermolovich } 176014cd37fSAlexander Yermolovich 177014cd37fSAlexander Yermolovich struct LocListsRangelistsHeader { 178014cd37fSAlexander Yermolovich UnitLengthType UnitLength; // Size of loclist entris section, not including 179014cd37fSAlexander Yermolovich // size of header. 180014cd37fSAlexander Yermolovich VersionType Version; 181014cd37fSAlexander Yermolovich AddressSizeType AddressSize; 182014cd37fSAlexander Yermolovich SegmentSelectorType SegmentSelector; 183014cd37fSAlexander Yermolovich OffsetEntryCountType OffsetEntryCount; 184014cd37fSAlexander Yermolovich }; 185014cd37fSAlexander Yermolovich 186014cd37fSAlexander Yermolovich static std::unique_ptr<DebugBufferVector> 187014cd37fSAlexander Yermolovich getDWARF5Header(const LocListsRangelistsHeader &Header) { 188014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> HeaderBuffer = 189014cd37fSAlexander Yermolovich std::make_unique<DebugBufferVector>(); 190014cd37fSAlexander Yermolovich std::unique_ptr<raw_svector_ostream> HeaderStream = 191014cd37fSAlexander Yermolovich std::make_unique<raw_svector_ostream>(*HeaderBuffer); 192014cd37fSAlexander Yermolovich 193014cd37fSAlexander Yermolovich // 7.29 length of the set of entries for this compilation unit, not including 194014cd37fSAlexander Yermolovich // the length field itself 195014cd37fSAlexander Yermolovich const uint32_t HeaderSize = 196014cd37fSAlexander Yermolovich getDWARF5RngListLocListHeaderSize() - sizeof(UnitLengthType); 197014cd37fSAlexander Yermolovich 198014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.UnitLength + HeaderSize, 199014cd37fSAlexander Yermolovich support::little); 200014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.Version, support::little); 201014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.AddressSize, support::little); 202014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.SegmentSelector, 203014cd37fSAlexander Yermolovich support::little); 204014cd37fSAlexander Yermolovich support::endian::write(*HeaderStream, Header.OffsetEntryCount, 205014cd37fSAlexander Yermolovich support::little); 206014cd37fSAlexander Yermolovich return HeaderBuffer; 207014cd37fSAlexander Yermolovich } 208014cd37fSAlexander Yermolovich 209e22ff52cSAlexander Yermolovich static bool emitWithBase(raw_ostream &OS, 210e22ff52cSAlexander Yermolovich const DebugAddressRangesVector &Ranges, 211e22ff52cSAlexander Yermolovich DebugAddrWriter &AddrWriter, DWARFUnit &CU, 212e22ff52cSAlexander Yermolovich uint32_t &Index) { 213e22ff52cSAlexander Yermolovich if (Ranges.size() < 2) 214e22ff52cSAlexander Yermolovich return false; 215e22ff52cSAlexander Yermolovich uint64_t Base = Ranges[Index].LowPC; 216e22ff52cSAlexander Yermolovich std::vector<std::pair<uint16_t, uint16_t>> RangeOffsets; 217e22ff52cSAlexander Yermolovich uint8_t TempBuffer[64]; 218e22ff52cSAlexander Yermolovich while (Index < Ranges.size()) { 219e22ff52cSAlexander Yermolovich const DebugAddressRange &Range = Ranges[Index]; 220e22ff52cSAlexander Yermolovich if (Range.LowPC == 0) 221e22ff52cSAlexander Yermolovich break; 222e22ff52cSAlexander Yermolovich assert(Base <= Range.LowPC && "Range base is higher than low PC"); 223e22ff52cSAlexander Yermolovich uint32_t StartOffset = Range.LowPC - Base; 224e22ff52cSAlexander Yermolovich uint32_t EndOffset = Range.HighPC - Base; 225e22ff52cSAlexander Yermolovich if (encodeULEB128(EndOffset, TempBuffer) > 2) 226e22ff52cSAlexander Yermolovich break; 227e22ff52cSAlexander Yermolovich RangeOffsets.emplace_back(StartOffset, EndOffset); 228e22ff52cSAlexander Yermolovich ++Index; 229e22ff52cSAlexander Yermolovich } 230e22ff52cSAlexander Yermolovich 231e22ff52cSAlexander Yermolovich if (RangeOffsets.size() < 2) { 232e22ff52cSAlexander Yermolovich Index -= RangeOffsets.size(); 233e22ff52cSAlexander Yermolovich return false; 234e22ff52cSAlexander Yermolovich } 235e22ff52cSAlexander Yermolovich 236e22ff52cSAlexander Yermolovich support::endian::write(OS, static_cast<uint8_t>(dwarf::DW_RLE_base_addressx), 237e22ff52cSAlexander Yermolovich support::little); 238e22ff52cSAlexander Yermolovich uint32_t BaseIndex = AddrWriter.getIndexFromAddress(Base, CU); 239e22ff52cSAlexander Yermolovich encodeULEB128(BaseIndex, OS); 240e22ff52cSAlexander Yermolovich for (auto &Offset : RangeOffsets) { 241e22ff52cSAlexander Yermolovich support::endian::write(OS, static_cast<uint8_t>(dwarf::DW_RLE_offset_pair), 242e22ff52cSAlexander Yermolovich support::little); 243e22ff52cSAlexander Yermolovich encodeULEB128(Offset.first, OS); 244e22ff52cSAlexander Yermolovich encodeULEB128(Offset.second, OS); 245e22ff52cSAlexander Yermolovich } 246e22ff52cSAlexander Yermolovich support::endian::write(OS, static_cast<uint8_t>(dwarf::DW_RLE_end_of_list), 247e22ff52cSAlexander Yermolovich support::little); 248e22ff52cSAlexander Yermolovich return true; 249e22ff52cSAlexander Yermolovich } 250e22ff52cSAlexander Yermolovich 251e22ff52cSAlexander Yermolovich uint64_t 252e22ff52cSAlexander Yermolovich DebugRangeListsSectionWriter::addRanges(DebugAddressRangesVector &Ranges) { 253014cd37fSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 254014cd37fSAlexander Yermolovich 255014cd37fSAlexander Yermolovich RangeEntries.push_back(CurrentOffset); 256e22ff52cSAlexander Yermolovich bool WrittenStartxLength = false; 257e22ff52cSAlexander Yermolovich std::sort( 258e22ff52cSAlexander Yermolovich Ranges.begin(), Ranges.end(), 259e22ff52cSAlexander Yermolovich [](const DebugAddressRange &R1, const DebugAddressRange &R2) -> bool { 260e22ff52cSAlexander Yermolovich return R1.LowPC < R2.LowPC; 261e22ff52cSAlexander Yermolovich }); 262e22ff52cSAlexander Yermolovich for (unsigned I = 0; I < Ranges.size();) { 263e22ff52cSAlexander Yermolovich WrittenStartxLength = false; 264e22ff52cSAlexander Yermolovich if (emitWithBase(*CUBodyStream, Ranges, *AddrWriter, *CU, I)) 265e22ff52cSAlexander Yermolovich continue; 266e22ff52cSAlexander Yermolovich const DebugAddressRange &Range = Ranges[I]; 267014cd37fSAlexander Yermolovich support::endian::write(*CUBodyStream, 268014cd37fSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_RLE_startx_length), 269014cd37fSAlexander Yermolovich support::little); 270ba1ac98cSAlexander Yermolovich uint32_t Index = AddrWriter->getIndexFromAddress(Range.LowPC, *CU); 271014cd37fSAlexander Yermolovich encodeULEB128(Index, *CUBodyStream); 272014cd37fSAlexander Yermolovich encodeULEB128(Range.HighPC - Range.LowPC, *CUBodyStream); 273e22ff52cSAlexander Yermolovich ++I; 274e22ff52cSAlexander Yermolovich WrittenStartxLength = true; 275014cd37fSAlexander Yermolovich } 276e22ff52cSAlexander Yermolovich if (WrittenStartxLength) 277014cd37fSAlexander Yermolovich support::endian::write(*CUBodyStream, 278014cd37fSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_RLE_end_of_list), 279014cd37fSAlexander Yermolovich support::little); 280014cd37fSAlexander Yermolovich CurrentOffset = CUBodyBuffer->size(); 281014cd37fSAlexander Yermolovich return RangeEntries.size() - 1; 282014cd37fSAlexander Yermolovich } 283014cd37fSAlexander Yermolovich 284014cd37fSAlexander Yermolovich void DebugRangeListsSectionWriter::finalizeSection() { 285014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> CUArrayBuffer = 286014cd37fSAlexander Yermolovich std::make_unique<DebugBufferVector>(); 287014cd37fSAlexander Yermolovich std::unique_ptr<raw_svector_ostream> CUArrayStream = 288014cd37fSAlexander Yermolovich std::make_unique<raw_svector_ostream>(*CUArrayBuffer); 289014cd37fSAlexander Yermolovich constexpr uint32_t SizeOfArrayEntry = 4; 290014cd37fSAlexander Yermolovich const uint32_t SizeOfArraySection = RangeEntries.size() * SizeOfArrayEntry; 291014cd37fSAlexander Yermolovich for (uint32_t Offset : RangeEntries) 292014cd37fSAlexander Yermolovich support::endian::write(*CUArrayStream, Offset + SizeOfArraySection, 293014cd37fSAlexander Yermolovich support::little); 294014cd37fSAlexander Yermolovich 295014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> Header = getDWARF5Header( 296014cd37fSAlexander Yermolovich {static_cast<uint32_t>(SizeOfArraySection + CUBodyBuffer.get()->size()), 297014cd37fSAlexander Yermolovich 5, 8, 0, static_cast<uint32_t>(RangeEntries.size())}); 298014cd37fSAlexander Yermolovich *RangesStream << *Header; 299014cd37fSAlexander Yermolovich *RangesStream << *CUArrayBuffer; 300014cd37fSAlexander Yermolovich *RangesStream << *CUBodyBuffer; 301014cd37fSAlexander Yermolovich SectionOffset = RangesBuffer->size(); 302014cd37fSAlexander Yermolovich } 303014cd37fSAlexander Yermolovich 304ba1ac98cSAlexander Yermolovich void DebugRangeListsSectionWriter::initSection(DWARFUnit &Unit) { 305014cd37fSAlexander Yermolovich CUBodyBuffer = std::make_unique<DebugBufferVector>(); 306014cd37fSAlexander Yermolovich CUBodyStream = std::make_unique<raw_svector_ostream>(*CUBodyBuffer); 307014cd37fSAlexander Yermolovich RangeEntries.clear(); 308014cd37fSAlexander Yermolovich CurrentOffset = 0; 309ba1ac98cSAlexander Yermolovich CU = &Unit; 310014cd37fSAlexander Yermolovich } 311014cd37fSAlexander Yermolovich 312a34c753fSRafael Auler void DebugARangesSectionWriter::addCURanges(uint64_t CUOffset, 313a34c753fSRafael Auler DebugAddressRangesVector &&Ranges) { 314a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(CUAddressRangesMutex); 315a34c753fSRafael Auler CUAddressRanges.emplace(CUOffset, std::move(Ranges)); 316a34c753fSRafael Auler } 317a34c753fSRafael Auler 318a34c753fSRafael Auler void DebugARangesSectionWriter::writeARangesSection( 319612f0f45SAlexander Yermolovich raw_svector_ostream &RangesStream, const CUOffsetMap &CUMap) const { 320a34c753fSRafael Auler // For reference on the format of the .debug_aranges section, see the DWARF4 321a34c753fSRafael Auler // specification, section 6.1.4 Lookup by Address 322a34c753fSRafael Auler // http://www.dwarfstd.org/doc/DWARF4.pdf 323a34c753fSRafael Auler for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) { 324a34c753fSRafael Auler const uint64_t Offset = CUOffsetAddressRangesPair.first; 325a34c753fSRafael Auler const DebugAddressRangesVector &AddressRanges = 326a34c753fSRafael Auler CUOffsetAddressRangesPair.second; 327a34c753fSRafael Auler 328a34c753fSRafael Auler // Emit header. 329a34c753fSRafael Auler 330a34c753fSRafael Auler // Size of this set: 8 (size of the header) + 4 (padding after header) 331a34c753fSRafael Auler // + 2*sizeof(uint64_t) bytes for each of the ranges, plus an extra 332a34c753fSRafael Auler // pair of uint64_t's for the terminating, zero-length range. 333a34c753fSRafael Auler // Does not include size field itself. 334a34c753fSRafael Auler uint32_t Size = 8 + 4 + 2 * sizeof(uint64_t) * (AddressRanges.size() + 1); 335a34c753fSRafael Auler 336a34c753fSRafael Auler // Header field #1: set size. 337a34c753fSRafael Auler support::endian::write(RangesStream, Size, support::little); 338a34c753fSRafael Auler 339a34c753fSRafael Auler // Header field #2: version number, 2 as per the specification. 340a34c753fSRafael Auler support::endian::write(RangesStream, static_cast<uint16_t>(2), 341a34c753fSRafael Auler support::little); 342a34c753fSRafael Auler 3431c2f4bbeSAlexander Yermolovich assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map"); 344a34c753fSRafael Auler // Header field #3: debug info offset of the correspondent compile unit. 345612f0f45SAlexander Yermolovich support::endian::write( 346612f0f45SAlexander Yermolovich RangesStream, static_cast<uint32_t>(CUMap.find(Offset)->second.Offset), 347a34c753fSRafael Auler support::little); 348a34c753fSRafael Auler 349a34c753fSRafael Auler // Header field #4: address size. 350a34c753fSRafael Auler // 8 since we only write ELF64 binaries for now. 351a34c753fSRafael Auler RangesStream << char(8); 352a34c753fSRafael Auler 353a34c753fSRafael Auler // Header field #5: segment size of target architecture. 354a34c753fSRafael Auler RangesStream << char(0); 355a34c753fSRafael Auler 356a34c753fSRafael Auler // Padding before address table - 4 bytes in the 64-bit-pointer case. 357a34c753fSRafael Auler support::endian::write(RangesStream, static_cast<uint32_t>(0), 358a34c753fSRafael Auler support::little); 359a34c753fSRafael Auler 360a34c753fSRafael Auler writeAddressRanges(RangesStream, AddressRanges, true); 361a34c753fSRafael Auler } 362a34c753fSRafael Auler } 363a34c753fSRafael Auler 364a34c753fSRafael Auler DebugAddrWriter::DebugAddrWriter(BinaryContext *Bc) { BC = Bc; } 365a34c753fSRafael Auler 366a34c753fSRafael Auler void DebugAddrWriter::AddressForDWOCU::dump() { 367a34c753fSRafael Auler std::vector<IndexAddressPair> SortedMap(indexToAddressBegin(), 368a34c753fSRafael Auler indexToAdddessEnd()); 369a34c753fSRafael Auler // Sorting address in increasing order of indices. 370c4302e4fSAmir Ayupov llvm::sort(SortedMap, llvm::less_first()); 371a34c753fSRafael Auler for (auto &Pair : SortedMap) 372a34c753fSRafael Auler dbgs() << Twine::utohexstr(Pair.second) << "\t" << Pair.first << "\n"; 373a34c753fSRafael Auler } 374ba1ac98cSAlexander Yermolovich uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, DWARFUnit &CU) { 375e579f5c6SAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 376ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(CU); 377014cd37fSAlexander Yermolovich if (!AddressMaps.count(CUID)) 378014cd37fSAlexander Yermolovich AddressMaps[CUID] = AddressForDWOCU(); 379a34c753fSRafael Auler 380014cd37fSAlexander Yermolovich AddressForDWOCU &Map = AddressMaps[CUID]; 381a34c753fSRafael Auler auto Entry = Map.find(Address); 382a34c753fSRafael Auler if (Entry == Map.end()) { 383a34c753fSRafael Auler auto Index = Map.getNextIndex(); 384a34c753fSRafael Auler Entry = Map.insert(Address, Index).first; 385a34c753fSRafael Auler } 386a34c753fSRafael Auler return Entry->second; 387a34c753fSRafael Auler } 388a34c753fSRafael Auler 389a34c753fSRafael Auler // Case1) Address is not in map insert in to AddresToIndex and IndexToAddres 390a34c753fSRafael Auler // Case2) Address is in the map but Index is higher or equal. Need to update 391a34c753fSRafael Auler // IndexToAddrss. Case3) Address is in the map but Index is lower. Need to 392a34c753fSRafael Auler // update AddressToIndex and IndexToAddress 393a34c753fSRafael Auler void DebugAddrWriter::addIndexAddress(uint64_t Address, uint32_t Index, 394ba1ac98cSAlexander Yermolovich DWARFUnit &CU) { 395e579f5c6SAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 396ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(CU); 397014cd37fSAlexander Yermolovich AddressForDWOCU &Map = AddressMaps[CUID]; 398a34c753fSRafael Auler auto Entry = Map.find(Address); 399a34c753fSRafael Auler if (Entry != Map.end()) { 400a34c753fSRafael Auler if (Entry->second > Index) 401a34c753fSRafael Auler Map.updateAddressToIndex(Address, Index); 402a34c753fSRafael Auler Map.updateIndexToAddrss(Address, Index); 4033652483cSRafael Auler } else { 404a34c753fSRafael Auler Map.insert(Address, Index); 405a34c753fSRafael Auler } 4063652483cSRafael Auler } 407a34c753fSRafael Auler 408a34c753fSRafael Auler AddressSectionBuffer DebugAddrWriter::finalize() { 409a34c753fSRafael Auler // Need to layout all sections within .debug_addr 410a34c753fSRafael Auler // Within each section sort Address by index. 411a34c753fSRafael Auler AddressSectionBuffer Buffer; 412a34c753fSRafael Auler raw_svector_ostream AddressStream(Buffer); 413a34c753fSRafael Auler for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) { 414a34c753fSRafael Auler // Handling the case wehre debug information is a mix of Debug fission and 415a34c753fSRafael Auler // monolitic. 416ba1ac98cSAlexander Yermolovich if (!CU->getDWOId()) 417a34c753fSRafael Auler continue; 418ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(*CU.get()); 419ba1ac98cSAlexander Yermolovich auto AM = AddressMaps.find(CUID); 420a34c753fSRafael Auler // Adding to map even if it did not contribute to .debug_addr. 4213abb68a6SAlexander Yermolovich // The Skeleton CU might still have DW_AT_GNU_addr_base. 422ba1ac98cSAlexander Yermolovich DWOIdToOffsetMap[CUID] = Buffer.size(); 423a34c753fSRafael Auler // If does not exist this CUs DWO section didn't contribute to .debug_addr. 424a34c753fSRafael Auler if (AM == AddressMaps.end()) 425a34c753fSRafael Auler continue; 426a34c753fSRafael Auler std::vector<IndexAddressPair> SortedMap(AM->second.indexToAddressBegin(), 427a34c753fSRafael Auler AM->second.indexToAdddessEnd()); 428a34c753fSRafael Auler // Sorting address in increasing order of indices. 429c4302e4fSAmir Ayupov llvm::sort(SortedMap, llvm::less_first()); 430a34c753fSRafael Auler 431a34c753fSRafael Auler uint8_t AddrSize = CU->getAddressByteSize(); 432a34c753fSRafael Auler uint32_t Counter = 0; 433a34c753fSRafael Auler auto WriteAddress = [&](uint64_t Address) -> void { 434a34c753fSRafael Auler ++Counter; 435a34c753fSRafael Auler switch (AddrSize) { 436a34c753fSRafael Auler default: 437a34c753fSRafael Auler assert(false && "Address Size is invalid."); 438a34c753fSRafael Auler break; 439a34c753fSRafael Auler case 4: 440a34c753fSRafael Auler support::endian::write(AddressStream, static_cast<uint32_t>(Address), 441a34c753fSRafael Auler support::little); 442a34c753fSRafael Auler break; 443a34c753fSRafael Auler case 8: 444a34c753fSRafael Auler support::endian::write(AddressStream, Address, support::little); 445a34c753fSRafael Auler break; 446a34c753fSRafael Auler } 447a34c753fSRafael Auler }; 448a34c753fSRafael Auler 449a34c753fSRafael Auler for (const IndexAddressPair &Val : SortedMap) { 450a34c753fSRafael Auler while (Val.first > Counter) 451a34c753fSRafael Auler WriteAddress(0); 452a34c753fSRafael Auler WriteAddress(Val.second); 453a34c753fSRafael Auler } 454a34c753fSRafael Auler } 455a34c753fSRafael Auler 456a34c753fSRafael Auler return Buffer; 457a34c753fSRafael Auler } 458014cd37fSAlexander Yermolovich AddressSectionBuffer DebugAddrWriterDwarf5::finalize() { 459014cd37fSAlexander Yermolovich // Need to layout all sections within .debug_addr 460014cd37fSAlexander Yermolovich // Within each section sort Address by index. 461014cd37fSAlexander Yermolovich AddressSectionBuffer Buffer; 462014cd37fSAlexander Yermolovich raw_svector_ostream AddressStream(Buffer); 463014cd37fSAlexander Yermolovich const endianness Endian = 464014cd37fSAlexander Yermolovich BC->DwCtx->isLittleEndian() ? support::little : support::big; 465014cd37fSAlexander Yermolovich const DWARFSection &AddrSec = BC->DwCtx->getDWARFObj().getAddrSection(); 466014cd37fSAlexander Yermolovich DWARFDataExtractor AddrData(BC->DwCtx->getDWARFObj(), AddrSec, Endian, 0); 467014cd37fSAlexander Yermolovich DWARFDebugAddrTable AddrTable; 468014cd37fSAlexander Yermolovich DIDumpOptions DumpOpts; 469014cd37fSAlexander Yermolovich constexpr uint32_t HeaderSize = 8; 470014cd37fSAlexander Yermolovich for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) { 471ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(*CU.get()); 472014cd37fSAlexander Yermolovich const uint8_t AddrSize = CU->getAddressByteSize(); 473ba1ac98cSAlexander Yermolovich auto AMIter = AddressMaps.find(CUID); 474014cd37fSAlexander Yermolovich // A case where CU has entry in .debug_addr, but we don't modify addresses 475014cd37fSAlexander Yermolovich // for it. 476ba1ac98cSAlexander Yermolovich if (AMIter == AddressMaps.end()) { 477ba1ac98cSAlexander Yermolovich AMIter = AddressMaps.insert({CUID, AddressForDWOCU()}).first; 47889fab98eSFangrui Song std::optional<uint64_t> BaseOffset = CU->getAddrOffsetSectionBase(); 479014cd37fSAlexander Yermolovich if (!BaseOffset) 480014cd37fSAlexander Yermolovich continue; 481014cd37fSAlexander Yermolovich // Address base offset is to the first entry. 482014cd37fSAlexander Yermolovich // The size of header is 8 bytes. 483014cd37fSAlexander Yermolovich uint64_t Offset = *BaseOffset - HeaderSize; 484014cd37fSAlexander Yermolovich if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddrSize, 485014cd37fSAlexander Yermolovich DumpOpts.WarningHandler)) { 486014cd37fSAlexander Yermolovich DumpOpts.RecoverableErrorHandler(std::move(Err)); 487014cd37fSAlexander Yermolovich continue; 488014cd37fSAlexander Yermolovich } 489014cd37fSAlexander Yermolovich uint32_t Index = 0; 490014cd37fSAlexander Yermolovich for (uint64_t Addr : AddrTable.getAddressEntries()) 491ba1ac98cSAlexander Yermolovich AMIter->second.insert(Addr, Index++); 492014cd37fSAlexander Yermolovich } 493a34c753fSRafael Auler 494014cd37fSAlexander Yermolovich DWOIdToOffsetMap[CUID] = Buffer.size() + HeaderSize; 495014cd37fSAlexander Yermolovich 496ba1ac98cSAlexander Yermolovich std::vector<IndexAddressPair> SortedMap( 497ba1ac98cSAlexander Yermolovich AMIter->second.indexToAddressBegin(), 498ba1ac98cSAlexander Yermolovich AMIter->second.indexToAdddessEnd()); 499014cd37fSAlexander Yermolovich // Sorting address in increasing order of indices. 500c4302e4fSAmir Ayupov llvm::sort(SortedMap, llvm::less_first()); 501014cd37fSAlexander Yermolovich // Writing out Header 502014cd37fSAlexander Yermolovich const uint32_t Length = SortedMap.size() * AddrSize + 4; 503014cd37fSAlexander Yermolovich support::endian::write(AddressStream, Length, Endian); 504014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint16_t>(5), Endian); 505014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint8_t>(AddrSize), 506014cd37fSAlexander Yermolovich Endian); 507014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint8_t>(0), Endian); 508014cd37fSAlexander Yermolovich 509014cd37fSAlexander Yermolovich uint32_t Counter = 0; 510014cd37fSAlexander Yermolovich auto writeAddress = [&](uint64_t Address) -> void { 511014cd37fSAlexander Yermolovich ++Counter; 512014cd37fSAlexander Yermolovich switch (AddrSize) { 513014cd37fSAlexander Yermolovich default: 514014cd37fSAlexander Yermolovich llvm_unreachable("Address Size is invalid."); 515014cd37fSAlexander Yermolovich break; 516014cd37fSAlexander Yermolovich case 4: 517014cd37fSAlexander Yermolovich support::endian::write(AddressStream, static_cast<uint32_t>(Address), 518014cd37fSAlexander Yermolovich Endian); 519014cd37fSAlexander Yermolovich break; 520014cd37fSAlexander Yermolovich case 8: 521014cd37fSAlexander Yermolovich support::endian::write(AddressStream, Address, Endian); 522014cd37fSAlexander Yermolovich break; 523014cd37fSAlexander Yermolovich } 524014cd37fSAlexander Yermolovich }; 525014cd37fSAlexander Yermolovich 526014cd37fSAlexander Yermolovich for (const IndexAddressPair &Val : SortedMap) { 527014cd37fSAlexander Yermolovich while (Val.first > Counter) 528014cd37fSAlexander Yermolovich writeAddress(0); 529014cd37fSAlexander Yermolovich writeAddress(Val.second); 530014cd37fSAlexander Yermolovich } 531014cd37fSAlexander Yermolovich } 532014cd37fSAlexander Yermolovich 533014cd37fSAlexander Yermolovich return Buffer; 534014cd37fSAlexander Yermolovich } 535014cd37fSAlexander Yermolovich 536014cd37fSAlexander Yermolovich uint64_t DebugAddrWriter::getOffset(DWARFUnit &Unit) { 537ba1ac98cSAlexander Yermolovich const uint64_t CUID = getCUID(Unit); 538ba1ac98cSAlexander Yermolovich assert(CUID && "Can't get offset, not a skeleton CU."); 539ba1ac98cSAlexander Yermolovich auto Iter = DWOIdToOffsetMap.find(CUID); 540014cd37fSAlexander Yermolovich assert(Iter != DWOIdToOffsetMap.end() && 541014cd37fSAlexander Yermolovich "Offset in to.debug_addr was not found for DWO ID."); 542014cd37fSAlexander Yermolovich return Iter->second; 543014cd37fSAlexander Yermolovich } 544014cd37fSAlexander Yermolovich 545014cd37fSAlexander Yermolovich uint64_t DebugAddrWriterDwarf5::getOffset(DWARFUnit &Unit) { 546ba1ac98cSAlexander Yermolovich auto Iter = DWOIdToOffsetMap.find(getCUID(Unit)); 547a34c753fSRafael Auler assert(Iter != DWOIdToOffsetMap.end() && 5483abb68a6SAlexander Yermolovich "Offset in to.debug_addr was not found for CU ID."); 549a34c753fSRafael Auler return Iter->second; 550a34c753fSRafael Auler } 551a34c753fSRafael Auler 5521c6dc43dSAlexander Yermolovich void DebugLocWriter::init() { 553a34c753fSRafael Auler LocBuffer = std::make_unique<DebugBufferVector>(); 554a34c753fSRafael Auler LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer); 5551c6dc43dSAlexander Yermolovich // Writing out empty location list to which all references to empty location 5561c6dc43dSAlexander Yermolovich // lists will point. 5571c6dc43dSAlexander Yermolovich if (!LocSectionOffset && DwarfVersion < 5) { 5581c6dc43dSAlexander Yermolovich const char Zeroes[16] = {0}; 5591c6dc43dSAlexander Yermolovich *LocStream << StringRef(Zeroes, 16); 5601c6dc43dSAlexander Yermolovich LocSectionOffset += 16; 5611c6dc43dSAlexander Yermolovich } 562a34c753fSRafael Auler } 563a34c753fSRafael Auler 5641c6dc43dSAlexander Yermolovich uint32_t DebugLocWriter::LocSectionOffset = 0; 5651c6dc43dSAlexander Yermolovich void DebugLocWriter::addList(AttrInfo &AttrVal, DebugLocationsVector &LocList, 5661c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, 5671c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) { 5681c6dc43dSAlexander Yermolovich const uint64_t AttrOffset = AttrVal.Offset; 569a34c753fSRafael Auler if (LocList.empty()) { 5701c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); 571a34c753fSRafael Auler return; 572a34c753fSRafael Auler } 573a34c753fSRafael Auler // Since there is a separate DebugLocWriter for each thread, 574a34c753fSRafael Auler // we don't need a lock to read the SectionOffset and update it. 5751c6dc43dSAlexander Yermolovich const uint32_t EntryOffset = LocSectionOffset; 576a34c753fSRafael Auler 577a34c753fSRafael Auler for (const DebugLocationEntry &Entry : LocList) { 578a34c753fSRafael Auler support::endian::write(*LocStream, static_cast<uint64_t>(Entry.LowPC), 579a34c753fSRafael Auler support::little); 580a34c753fSRafael Auler support::endian::write(*LocStream, static_cast<uint64_t>(Entry.HighPC), 581a34c753fSRafael Auler support::little); 582a34c753fSRafael Auler support::endian::write(*LocStream, static_cast<uint16_t>(Entry.Expr.size()), 583a34c753fSRafael Auler support::little); 584a34c753fSRafael Auler *LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()), 585a34c753fSRafael Auler Entry.Expr.size()); 5861c6dc43dSAlexander Yermolovich LocSectionOffset += 2 * 8 + 2 + Entry.Expr.size(); 587a34c753fSRafael Auler } 588a34c753fSRafael Auler LocStream->write_zeros(16); 5891c6dc43dSAlexander Yermolovich LocSectionOffset += 16; 590a34c753fSRafael Auler LocListDebugInfoPatches.push_back({AttrOffset, EntryOffset}); 5911c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); 592a34c753fSRafael Auler } 593a34c753fSRafael Auler 594a34c753fSRafael Auler std::unique_ptr<DebugBufferVector> DebugLocWriter::getBuffer() { 595a34c753fSRafael Auler return std::move(LocBuffer); 596a34c753fSRafael Auler } 597a34c753fSRafael Auler 598a34c753fSRafael Auler // DWARF 4: 2.6.2 5991c6dc43dSAlexander Yermolovich void DebugLocWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, 6001c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) {} 601a34c753fSRafael Auler 602014cd37fSAlexander Yermolovich static void writeEmptyListDwarf5(raw_svector_ostream &Stream) { 603014cd37fSAlexander Yermolovich support::endian::write(Stream, static_cast<uint32_t>(4), support::little); 604014cd37fSAlexander Yermolovich support::endian::write(Stream, static_cast<uint8_t>(dwarf::DW_LLE_start_end), 605014cd37fSAlexander Yermolovich support::little); 606014cd37fSAlexander Yermolovich 607014cd37fSAlexander Yermolovich const char Zeroes[16] = {0}; 608014cd37fSAlexander Yermolovich Stream << StringRef(Zeroes, 16); 609014cd37fSAlexander Yermolovich encodeULEB128(0, Stream); 610014cd37fSAlexander Yermolovich support::endian::write( 611014cd37fSAlexander Yermolovich Stream, static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), support::little); 612014cd37fSAlexander Yermolovich } 613014cd37fSAlexander Yermolovich 6141c6dc43dSAlexander Yermolovich static void writeLegacyLocList(AttrInfo &AttrVal, DebugLocationsVector &LocList, 6151c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, 6161c6dc43dSAlexander Yermolovich DebugAddrWriter &AddrWriter, 6171c6dc43dSAlexander Yermolovich DebugBufferVector &LocBuffer, DWARFUnit &CU, 6181c6dc43dSAlexander Yermolovich raw_svector_ostream &LocStream) { 6191c6dc43dSAlexander Yermolovich const uint64_t AttrOffset = AttrVal.Offset; 6201c6dc43dSAlexander Yermolovich if (LocList.empty()) { 6211c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, DebugLocWriter::EmptyListOffset); 6221c6dc43dSAlexander Yermolovich return; 6231c6dc43dSAlexander Yermolovich } 6241c6dc43dSAlexander Yermolovich 6251c6dc43dSAlexander Yermolovich const uint32_t EntryOffset = LocBuffer.size(); 6261c6dc43dSAlexander Yermolovich for (const DebugLocationEntry &Entry : LocList) { 6271c6dc43dSAlexander Yermolovich support::endian::write(LocStream, 6281c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_startx_length), 6291c6dc43dSAlexander Yermolovich support::little); 6301c6dc43dSAlexander Yermolovich const uint32_t Index = AddrWriter.getIndexFromAddress(Entry.LowPC, CU); 6311c6dc43dSAlexander Yermolovich encodeULEB128(Index, LocStream); 6321c6dc43dSAlexander Yermolovich 6331c6dc43dSAlexander Yermolovich support::endian::write(LocStream, 6341c6dc43dSAlexander Yermolovich static_cast<uint32_t>(Entry.HighPC - Entry.LowPC), 6351c6dc43dSAlexander Yermolovich support::little); 6361c6dc43dSAlexander Yermolovich support::endian::write(LocStream, static_cast<uint16_t>(Entry.Expr.size()), 6371c6dc43dSAlexander Yermolovich support::little); 6381c6dc43dSAlexander Yermolovich LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()), 6391c6dc43dSAlexander Yermolovich Entry.Expr.size()); 6401c6dc43dSAlexander Yermolovich } 6411c6dc43dSAlexander Yermolovich support::endian::write(LocStream, 6421c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), 6431c6dc43dSAlexander Yermolovich support::little); 6441c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrOffset, EntryOffset); 6451c6dc43dSAlexander Yermolovich } 6461c6dc43dSAlexander Yermolovich 6471c6dc43dSAlexander Yermolovich static void writeDWARF5LocList( 6481c6dc43dSAlexander Yermolovich uint32_t &NumberOfEntries, AttrInfo &AttrVal, DebugLocationsVector &LocList, 6491c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter, 6501c6dc43dSAlexander Yermolovich DebugAddrWriter &AddrWriter, DebugBufferVector &LocBodyBuffer, 6511c6dc43dSAlexander Yermolovich std::vector<uint32_t> &RelativeLocListOffsets, DWARFUnit &CU, 6521c6dc43dSAlexander Yermolovich raw_svector_ostream &LocBodyStream) { 6531c6dc43dSAlexander Yermolovich if (AttrVal.V.getForm() != dwarf::DW_FORM_loclistx) { 6541c6dc43dSAlexander Yermolovich AbbrevWriter.addAttributePatch(CU, AttrVal.AbbrevDecl, 6551c6dc43dSAlexander Yermolovich dwarf::DW_AT_location, dwarf::DW_AT_location, 6561c6dc43dSAlexander Yermolovich dwarf::DW_FORM_loclistx); 6571c6dc43dSAlexander Yermolovich } 6581c6dc43dSAlexander Yermolovich DebugInfoPatcher.addUDataPatch(AttrVal.Offset, NumberOfEntries, AttrVal.Size); 6591c6dc43dSAlexander Yermolovich RelativeLocListOffsets.push_back(LocBodyBuffer.size()); 6601c6dc43dSAlexander Yermolovich ++NumberOfEntries; 6611c6dc43dSAlexander Yermolovich if (LocList.empty()) { 6621c6dc43dSAlexander Yermolovich writeEmptyListDwarf5(LocBodyStream); 6631c6dc43dSAlexander Yermolovich return; 6641c6dc43dSAlexander Yermolovich } 6651c6dc43dSAlexander Yermolovich 6661c6dc43dSAlexander Yermolovich std::vector<uint64_t> OffsetsArray; 6671c6dc43dSAlexander Yermolovich for (const DebugLocationEntry &Entry : LocList) { 6681c6dc43dSAlexander Yermolovich support::endian::write(LocBodyStream, 6691c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_startx_length), 6701c6dc43dSAlexander Yermolovich support::little); 6711c6dc43dSAlexander Yermolovich const uint32_t Index = AddrWriter.getIndexFromAddress(Entry.LowPC, CU); 6721c6dc43dSAlexander Yermolovich encodeULEB128(Index, LocBodyStream); 6731c6dc43dSAlexander Yermolovich encodeULEB128(Entry.HighPC - Entry.LowPC, LocBodyStream); 6741c6dc43dSAlexander Yermolovich encodeULEB128(Entry.Expr.size(), LocBodyStream); 6751c6dc43dSAlexander Yermolovich LocBodyStream << StringRef( 6761c6dc43dSAlexander Yermolovich reinterpret_cast<const char *>(Entry.Expr.data()), Entry.Expr.size()); 6771c6dc43dSAlexander Yermolovich } 6781c6dc43dSAlexander Yermolovich support::endian::write(LocBodyStream, 6791c6dc43dSAlexander Yermolovich static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), 6801c6dc43dSAlexander Yermolovich support::little); 6811c6dc43dSAlexander Yermolovich } 6821c6dc43dSAlexander Yermolovich 6831c6dc43dSAlexander Yermolovich void DebugLoclistWriter::addList(AttrInfo &AttrVal, 6841c6dc43dSAlexander Yermolovich DebugLocationsVector &LocList, 6851c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, 6861c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) { 6871c6dc43dSAlexander Yermolovich if (DwarfVersion < 5) 6881c6dc43dSAlexander Yermolovich writeLegacyLocList(AttrVal, LocList, DebugInfoPatcher, *AddrWriter, 6891c6dc43dSAlexander Yermolovich *LocBuffer, CU, *LocStream); 6901c6dc43dSAlexander Yermolovich else 6911c6dc43dSAlexander Yermolovich writeDWARF5LocList(NumberOfEntries, AttrVal, LocList, DebugInfoPatcher, 6921c6dc43dSAlexander Yermolovich AbbrevWriter, *AddrWriter, *LocBodyBuffer, 6931c6dc43dSAlexander Yermolovich RelativeLocListOffsets, CU, *LocBodyStream); 6941c6dc43dSAlexander Yermolovich } 6951c6dc43dSAlexander Yermolovich 6961c6dc43dSAlexander Yermolovich uint32_t DebugLoclistWriter::LoclistBaseOffset = 0; 6971c6dc43dSAlexander Yermolovich void DebugLoclistWriter::finalizeDWARF5( 6981c6dc43dSAlexander Yermolovich DebugInfoBinaryPatcher &DebugInfoPatcher, DebugAbbrevWriter &AbbrevWriter) { 6991c6dc43dSAlexander Yermolovich if (LocBodyBuffer->empty()) 7001c6dc43dSAlexander Yermolovich return; 701014cd37fSAlexander Yermolovich 702014cd37fSAlexander Yermolovich std::unique_ptr<DebugBufferVector> LocArrayBuffer = 703014cd37fSAlexander Yermolovich std::make_unique<DebugBufferVector>(); 704014cd37fSAlexander Yermolovich std::unique_ptr<raw_svector_ostream> LocArrayStream = 705014cd37fSAlexander Yermolovich std::make_unique<raw_svector_ostream>(*LocArrayBuffer); 706014cd37fSAlexander Yermolovich 7071c6dc43dSAlexander Yermolovich const uint32_t SizeOfArraySection = NumberOfEntries * sizeof(uint32_t); 708014cd37fSAlexander Yermolovich // Write out IndexArray 7091c6dc43dSAlexander Yermolovich for (uint32_t RelativeOffset : RelativeLocListOffsets) 710014cd37fSAlexander Yermolovich support::endian::write( 711014cd37fSAlexander Yermolovich *LocArrayStream, 7121c6dc43dSAlexander Yermolovich static_cast<uint32_t>(SizeOfArraySection + RelativeOffset), 713014cd37fSAlexander Yermolovich support::little); 7141c6dc43dSAlexander Yermolovich 7151c6dc43dSAlexander Yermolovich std::unique_ptr<DebugBufferVector> Header = getDWARF5Header( 7161c6dc43dSAlexander Yermolovich {static_cast<uint32_t>(SizeOfArraySection + LocBodyBuffer.get()->size()), 7171c6dc43dSAlexander Yermolovich 5, 8, 0, NumberOfEntries}); 718014cd37fSAlexander Yermolovich *LocStream << *Header; 719014cd37fSAlexander Yermolovich *LocStream << *LocArrayBuffer; 720014cd37fSAlexander Yermolovich *LocStream << *LocBodyBuffer; 7211c6dc43dSAlexander Yermolovich 7221c6dc43dSAlexander Yermolovich if (!isSplitDwarf()) { 723370e4761SAmir Ayupov if (std::optional<AttrInfo> AttrInfoVal = 7241c6dc43dSAlexander Yermolovich findAttributeInfo(CU.getUnitDIE(), dwarf::DW_AT_loclists_base)) 7251c6dc43dSAlexander Yermolovich DebugInfoPatcher.addLE32Patch(AttrInfoVal->Offset, 7261c6dc43dSAlexander Yermolovich LoclistBaseOffset + 7271c6dc43dSAlexander Yermolovich getDWARF5RngListLocListHeaderSize()); 7281c6dc43dSAlexander Yermolovich else { 7291c6dc43dSAlexander Yermolovich AbbrevWriter.addAttribute( 7301c6dc43dSAlexander Yermolovich CU, CU.getUnitDIE().getAbbreviationDeclarationPtr(), 7311c6dc43dSAlexander Yermolovich dwarf::DW_AT_loclists_base, dwarf::DW_FORM_sec_offset); 7321c6dc43dSAlexander Yermolovich DebugInfoPatcher.insertNewEntry(CU.getUnitDIE(), 7331c6dc43dSAlexander Yermolovich LoclistBaseOffset + Header->size()); 734014cd37fSAlexander Yermolovich } 7351c6dc43dSAlexander Yermolovich LoclistBaseOffset += LocBuffer->size(); 7361c6dc43dSAlexander Yermolovich } 7371c6dc43dSAlexander Yermolovich clearList(RelativeLocListOffsets); 7381c6dc43dSAlexander Yermolovich clearList(*LocArrayBuffer); 7391c6dc43dSAlexander Yermolovich clearList(*LocBodyBuffer); 740014cd37fSAlexander Yermolovich } 741014cd37fSAlexander Yermolovich 7421c6dc43dSAlexander Yermolovich void DebugLoclistWriter::finalize(DebugInfoBinaryPatcher &DebugInfoPatcher, 7431c6dc43dSAlexander Yermolovich DebugAbbrevWriter &AbbrevWriter) { 7441c6dc43dSAlexander Yermolovich if (DwarfVersion >= 5) 7451c6dc43dSAlexander Yermolovich finalizeDWARF5(DebugInfoPatcher, AbbrevWriter); 746014cd37fSAlexander Yermolovich } 747014cd37fSAlexander Yermolovich 748a34c753fSRafael Auler DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr; 749a34c753fSRafael Auler 7501c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addUnitBaseOffsetLabel(uint64_t Offset) { 7511c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 7521c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 753ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DWARFUnitOffsetBaseLabel(Offset)); 754a34c753fSRafael Auler } 755a34c753fSRafael Auler 7561c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addDestinationReferenceLabel(uint64_t Offset) { 7571c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 7581c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 7591c2f4bbeSAlexander Yermolovich auto RetVal = DestinationLabels.insert(Offset); 7601c2f4bbeSAlexander Yermolovich if (!RetVal.second) 7611c2f4bbeSAlexander Yermolovich return; 7621c2f4bbeSAlexander Yermolovich 763ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DestinationReferenceLabel(Offset)); 764a34c753fSRafael Auler } 765a34c753fSRafael Auler 766bd1ebe9dSAlexander Yermolovich static std::string encodeLE(size_t ByteSize, uint64_t NewValue) { 767bd1ebe9dSAlexander Yermolovich std::string LE64(ByteSize, 0); 768bd1ebe9dSAlexander Yermolovich for (size_t I = 0; I < ByteSize; ++I) { 769bd1ebe9dSAlexander Yermolovich LE64[I] = NewValue & 0xff; 770bd1ebe9dSAlexander Yermolovich NewValue >>= 8; 771bd1ebe9dSAlexander Yermolovich } 772bd1ebe9dSAlexander Yermolovich return LE64; 773bd1ebe9dSAlexander Yermolovich } 774bd1ebe9dSAlexander Yermolovich 775bd1ebe9dSAlexander Yermolovich void DebugInfoBinaryPatcher::insertNewEntry(const DWARFDie &DIE, 776bd1ebe9dSAlexander Yermolovich uint32_t Value) { 777bd1ebe9dSAlexander Yermolovich std::string StrValue = encodeLE(4, Value); 778bd1ebe9dSAlexander Yermolovich insertNewEntry(DIE, std::move(StrValue)); 779bd1ebe9dSAlexander Yermolovich } 780bd1ebe9dSAlexander Yermolovich 781bd1ebe9dSAlexander Yermolovich void DebugInfoBinaryPatcher::insertNewEntry(const DWARFDie &DIE, 782bd1ebe9dSAlexander Yermolovich std::string &&Value) { 783bd1ebe9dSAlexander Yermolovich const DWARFAbbreviationDeclaration *AbbrevDecl = 784bd1ebe9dSAlexander Yermolovich DIE.getAbbreviationDeclarationPtr(); 785bd1ebe9dSAlexander Yermolovich 786bd1ebe9dSAlexander Yermolovich // In case this DIE has no attributes. 787bd1ebe9dSAlexander Yermolovich uint32_t Offset = DIE.getOffset() + 1; 788bd1ebe9dSAlexander Yermolovich size_t NumOfAttributes = AbbrevDecl->getNumAttributes(); 789bd1ebe9dSAlexander Yermolovich if (NumOfAttributes) { 790370e4761SAmir Ayupov std::optional<AttrInfo> Val = 791bd1ebe9dSAlexander Yermolovich findAttributeInfo(DIE, AbbrevDecl, NumOfAttributes - 1); 792bd1ebe9dSAlexander Yermolovich assert(Val && "Invalid Value."); 793bd1ebe9dSAlexander Yermolovich 794bd1ebe9dSAlexander Yermolovich Offset = Val->Offset + Val->Size - DWPUnitOffset; 795bd1ebe9dSAlexander Yermolovich } 796bd1ebe9dSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 797bd1ebe9dSAlexander Yermolovich DebugPatches.emplace_back(new NewDebugEntry(Offset, std::move(Value))); 798bd1ebe9dSAlexander Yermolovich } 799bd1ebe9dSAlexander Yermolovich 8001c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addReferenceToPatch(uint64_t Offset, 8011c2f4bbeSAlexander Yermolovich uint32_t DestinationOffset, 8021c2f4bbeSAlexander Yermolovich uint32_t OldValueSize, 8031c2f4bbeSAlexander Yermolovich dwarf::Form Form) { 8041c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8051c2f4bbeSAlexander Yermolovich DestinationOffset -= DWPUnitOffset; 8061c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 807ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back( 808ea6c8b01SAlexander Yermolovich new DebugPatchReference(Offset, OldValueSize, DestinationOffset, Form)); 8091c2f4bbeSAlexander Yermolovich } 8101c2f4bbeSAlexander Yermolovich 8111c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t NewValue, 8121c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 8131c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8141c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 8151c2f4bbeSAlexander Yermolovich DebugPatches.emplace_back( 816ea6c8b01SAlexander Yermolovich new DebugPatchVariableSize(Offset, OldValueSize, NewValue)); 8171c2f4bbeSAlexander Yermolovich } 8181c2f4bbeSAlexander Yermolovich 8191c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) { 8201c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8211c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 822ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DebugPatch64(Offset, NewValue)); 8231c2f4bbeSAlexander Yermolovich } 8241c2f4bbeSAlexander Yermolovich 8251c2f4bbeSAlexander Yermolovich void DebugInfoBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue, 8261c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 8271c2f4bbeSAlexander Yermolovich Offset -= DWPUnitOffset; 8281c2f4bbeSAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 8291c2f4bbeSAlexander Yermolovich if (OldValueSize == 4) 830ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DebugPatch32(Offset, NewValue)); 831a44fe319SAlexander Yermolovich else if (OldValueSize == 8) 832ea6c8b01SAlexander Yermolovich DebugPatches.emplace_back(new DebugPatch64to32(Offset, NewValue)); 833a44fe319SAlexander Yermolovich else 834a44fe319SAlexander Yermolovich DebugPatches.emplace_back( 835a44fe319SAlexander Yermolovich new DebugPatch32GenericSize(Offset, NewValue, OldValueSize)); 8361c2f4bbeSAlexander Yermolovich } 8371c2f4bbeSAlexander Yermolovich 8381c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addBinaryPatch(uint64_t Offset, 8391c2f4bbeSAlexander Yermolovich std::string &&NewValue, 8401c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 8411c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, std::move(NewValue)); 8421c2f4bbeSAlexander Yermolovich } 8431c2f4bbeSAlexander Yermolovich 8441c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addBytePatch(uint64_t Offset, uint8_t Value) { 8451c2f4bbeSAlexander Yermolovich auto Str = std::string(1, Value); 8461c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, std::move(Str)); 8471c2f4bbeSAlexander Yermolovich } 8481c2f4bbeSAlexander Yermolovich 8491c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addLEPatch(uint64_t Offset, uint64_t NewValue, 8501c2f4bbeSAlexander Yermolovich size_t ByteSize) { 8511c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, encodeLE(ByteSize, NewValue)); 8521c2f4bbeSAlexander Yermolovich } 8531c2f4bbeSAlexander Yermolovich 8541c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t Value, 8551c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 856a34c753fSRafael Auler std::string Buff; 857a34c753fSRafael Auler raw_string_ostream OS(Buff); 8581c2f4bbeSAlexander Yermolovich encodeULEB128(Value, OS, OldValueSize); 859a34c753fSRafael Auler 8601c2f4bbeSAlexander Yermolovich Patches.emplace_back(Offset, std::move(Buff)); 861a34c753fSRafael Auler } 862a34c753fSRafael Auler 8631c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) { 864a34c753fSRafael Auler addLEPatch(Offset, NewValue, 8); 865a34c753fSRafael Auler } 866a34c753fSRafael Auler 8671c2f4bbeSAlexander Yermolovich void SimpleBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue, 8681c2f4bbeSAlexander Yermolovich uint32_t OldValueSize) { 869a34c753fSRafael Auler addLEPatch(Offset, NewValue, 4); 870a34c753fSRafael Auler } 871a34c753fSRafael Auler 8721c2f4bbeSAlexander Yermolovich std::string SimpleBinaryPatcher::patchBinary(StringRef BinaryContents) { 8731c2f4bbeSAlexander Yermolovich std::string BinaryContentsStr = std::string(BinaryContents); 874a34c753fSRafael Auler for (const auto &Patch : Patches) { 8751c2f4bbeSAlexander Yermolovich uint32_t Offset = Patch.first; 876a34c753fSRafael Auler const std::string &ByteSequence = Patch.second; 877a34c753fSRafael Auler assert(Offset + ByteSequence.size() <= BinaryContents.size() && 878a34c753fSRafael Auler "Applied patch runs over binary size."); 879a34c753fSRafael Auler for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I) { 8801c2f4bbeSAlexander Yermolovich BinaryContentsStr[Offset + I] = ByteSequence[I]; 881a34c753fSRafael Auler } 882a34c753fSRafael Auler } 8831c2f4bbeSAlexander Yermolovich return BinaryContentsStr; 8841c2f4bbeSAlexander Yermolovich } 8851c2f4bbeSAlexander Yermolovich 886612f0f45SAlexander Yermolovich CUOffsetMap DebugInfoBinaryPatcher::computeNewOffsets(DWARFContext &DWCtx, 887612f0f45SAlexander Yermolovich bool IsDWOContext) { 888612f0f45SAlexander Yermolovich CUOffsetMap CUMap; 889d2c87699SAmir Ayupov llvm::sort(DebugPatches, [](const UniquePatchPtrType &V1, 890d2c87699SAmir Ayupov const UniquePatchPtrType &V2) { 891bd1ebe9dSAlexander Yermolovich if (V1.get()->Offset == V2.get()->Offset) { 892bd1ebe9dSAlexander Yermolovich if (V1->Kind == DebugPatchKind::NewDebugEntry && 893bd1ebe9dSAlexander Yermolovich V2->Kind == DebugPatchKind::NewDebugEntry) 894d2c87699SAmir Ayupov return reinterpret_cast<const NewDebugEntry *>(V1.get())->CurrentOrder < 895d2c87699SAmir Ayupov reinterpret_cast<const NewDebugEntry *>(V2.get())->CurrentOrder; 896bd1ebe9dSAlexander Yermolovich 897bd1ebe9dSAlexander Yermolovich // This is a case where we are modifying first entry of next 898bd1ebe9dSAlexander Yermolovich // DIE, and adding a new one. 899bd1ebe9dSAlexander Yermolovich return V1->Kind == DebugPatchKind::NewDebugEntry; 900bd1ebe9dSAlexander Yermolovich } 9011c2f4bbeSAlexander Yermolovich return V1.get()->Offset < V2.get()->Offset; 9021c2f4bbeSAlexander Yermolovich }); 9031c2f4bbeSAlexander Yermolovich 904612f0f45SAlexander Yermolovich DWARFUnitVector::compile_unit_range CompileUnits = 905612f0f45SAlexander Yermolovich IsDWOContext ? DWCtx.dwo_compile_units() : DWCtx.compile_units(); 906612f0f45SAlexander Yermolovich 907612f0f45SAlexander Yermolovich for (const std::unique_ptr<DWARFUnit> &CU : CompileUnits) 908612f0f45SAlexander Yermolovich CUMap[CU->getOffset()] = {static_cast<uint32_t>(CU->getOffset()), 909612f0f45SAlexander Yermolovich static_cast<uint32_t>(CU->getLength())}; 910612f0f45SAlexander Yermolovich 9111c2f4bbeSAlexander Yermolovich // Calculating changes in .debug_info size from Patches to build a map of old 9121c2f4bbeSAlexander Yermolovich // to updated reference destination offsets. 913612f0f45SAlexander Yermolovich uint32_t PreviousOffset = 0; 914612f0f45SAlexander Yermolovich int32_t PreviousChangeInSize = 0; 915ea6c8b01SAlexander Yermolovich for (UniquePatchPtrType &PatchBase : DebugPatches) { 9161c2f4bbeSAlexander Yermolovich Patch *P = PatchBase.get(); 9171c2f4bbeSAlexander Yermolovich switch (P->Kind) { 9181c2f4bbeSAlexander Yermolovich default: 9191c2f4bbeSAlexander Yermolovich continue; 9201c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue64to32: { 921612f0f45SAlexander Yermolovich PreviousChangeInSize -= 4; 9221c2f4bbeSAlexander Yermolovich break; 9231c2f4bbeSAlexander Yermolovich } 924a44fe319SAlexander Yermolovich case DebugPatchKind::PatchValue32GenericSize: { 925a44fe319SAlexander Yermolovich DebugPatch32GenericSize *DPVS = 926a44fe319SAlexander Yermolovich reinterpret_cast<DebugPatch32GenericSize *>(P); 927a44fe319SAlexander Yermolovich PreviousChangeInSize += 4 - DPVS->OldValueSize; 928a44fe319SAlexander Yermolovich break; 929a44fe319SAlexander Yermolovich } 9301c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValueVariable: { 9311c2f4bbeSAlexander Yermolovich DebugPatchVariableSize *DPV = 9321c2f4bbeSAlexander Yermolovich reinterpret_cast<DebugPatchVariableSize *>(P); 9331c2f4bbeSAlexander Yermolovich std::string Temp; 9341c2f4bbeSAlexander Yermolovich raw_string_ostream OS(Temp); 9351c2f4bbeSAlexander Yermolovich encodeULEB128(DPV->Value, OS); 936612f0f45SAlexander Yermolovich PreviousChangeInSize += Temp.size() - DPV->OldValueSize; 9371c2f4bbeSAlexander Yermolovich break; 9381c2f4bbeSAlexander Yermolovich } 9391c2f4bbeSAlexander Yermolovich case DebugPatchKind::DestinationReferenceLabel: { 9401c2f4bbeSAlexander Yermolovich DestinationReferenceLabel *DRL = 9411c2f4bbeSAlexander Yermolovich reinterpret_cast<DestinationReferenceLabel *>(P); 942612f0f45SAlexander Yermolovich OldToNewOffset[DRL->Offset] = 943612f0f45SAlexander Yermolovich DRL->Offset + ChangeInSize + PreviousChangeInSize; 9441c2f4bbeSAlexander Yermolovich break; 9451c2f4bbeSAlexander Yermolovich } 9461c2f4bbeSAlexander Yermolovich case DebugPatchKind::ReferencePatchValue: { 9471c2f4bbeSAlexander Yermolovich // This doesn't look to be a common case, so will always encode as 4 bytes 9481c2f4bbeSAlexander Yermolovich // to reduce algorithmic complexity. 9491c2f4bbeSAlexander Yermolovich DebugPatchReference *RDP = reinterpret_cast<DebugPatchReference *>(P); 9501c2f4bbeSAlexander Yermolovich if (RDP->PatchInfo.IndirectRelative) { 951612f0f45SAlexander Yermolovich PreviousChangeInSize += 4 - RDP->PatchInfo.OldValueSize; 9521c2f4bbeSAlexander Yermolovich assert(RDP->PatchInfo.OldValueSize <= 4 && 9531c2f4bbeSAlexander Yermolovich "Variable encoding reference greater than 4 bytes."); 9541c2f4bbeSAlexander Yermolovich } 9551c2f4bbeSAlexander Yermolovich break; 9561c2f4bbeSAlexander Yermolovich } 9571c2f4bbeSAlexander Yermolovich case DebugPatchKind::DWARFUnitOffsetBaseLabel: { 9581c2f4bbeSAlexander Yermolovich DWARFUnitOffsetBaseLabel *BaseLabel = 9591c2f4bbeSAlexander Yermolovich reinterpret_cast<DWARFUnitOffsetBaseLabel *>(P); 9601c2f4bbeSAlexander Yermolovich uint32_t CUOffset = BaseLabel->Offset; 961612f0f45SAlexander Yermolovich ChangeInSize += PreviousChangeInSize; 9621c2f4bbeSAlexander Yermolovich uint32_t CUOffsetUpdate = CUOffset + ChangeInSize; 963612f0f45SAlexander Yermolovich CUMap[CUOffset].Offset = CUOffsetUpdate; 964612f0f45SAlexander Yermolovich CUMap[PreviousOffset].Length += PreviousChangeInSize; 965612f0f45SAlexander Yermolovich PreviousChangeInSize = 0; 966612f0f45SAlexander Yermolovich PreviousOffset = CUOffset; 967bd1ebe9dSAlexander Yermolovich break; 968bd1ebe9dSAlexander Yermolovich } 969bd1ebe9dSAlexander Yermolovich case DebugPatchKind::NewDebugEntry: { 970bd1ebe9dSAlexander Yermolovich NewDebugEntry *NDE = reinterpret_cast<NewDebugEntry *>(P); 971bd1ebe9dSAlexander Yermolovich PreviousChangeInSize += NDE->Value.size(); 972bd1ebe9dSAlexander Yermolovich break; 9731c2f4bbeSAlexander Yermolovich } 9741c2f4bbeSAlexander Yermolovich } 9751c2f4bbeSAlexander Yermolovich } 976612f0f45SAlexander Yermolovich CUMap[PreviousOffset].Length += PreviousChangeInSize; 9771c2f4bbeSAlexander Yermolovich return CUMap; 9781c2f4bbeSAlexander Yermolovich } 979bd1ebe9dSAlexander Yermolovich uint32_t DebugInfoBinaryPatcher::NewDebugEntry::OrderCounter = 0; 9801c2f4bbeSAlexander Yermolovich 9811c2f4bbeSAlexander Yermolovich std::string DebugInfoBinaryPatcher::patchBinary(StringRef BinaryContents) { 9821c2f4bbeSAlexander Yermolovich std::string NewBinaryContents; 9831c2f4bbeSAlexander Yermolovich NewBinaryContents.reserve(BinaryContents.size() + ChangeInSize); 9841c2f4bbeSAlexander Yermolovich uint32_t StartOffset = 0; 9851c2f4bbeSAlexander Yermolovich uint32_t DwarfUnitBaseOffset = 0; 9861c2f4bbeSAlexander Yermolovich uint32_t OldValueSize = 0; 9871c2f4bbeSAlexander Yermolovich uint32_t Offset = 0; 9881c2f4bbeSAlexander Yermolovich std::string ByteSequence; 9891c2f4bbeSAlexander Yermolovich std::vector<std::pair<uint32_t, uint32_t>> LengthPatches; 9901c2f4bbeSAlexander Yermolovich // Wasting one entry to avoid checks for first. 9911c2f4bbeSAlexander Yermolovich LengthPatches.push_back({0, 0}); 9921c2f4bbeSAlexander Yermolovich 9931c2f4bbeSAlexander Yermolovich // Applying all the patches replacing current entry. 9941c2f4bbeSAlexander Yermolovich // This might change the size of .debug_info section. 995ea6c8b01SAlexander Yermolovich for (const UniquePatchPtrType &PatchBase : DebugPatches) { 9961c2f4bbeSAlexander Yermolovich Patch *P = PatchBase.get(); 9971c2f4bbeSAlexander Yermolovich switch (P->Kind) { 9981c2f4bbeSAlexander Yermolovich default: 9991c2f4bbeSAlexander Yermolovich continue; 10001c2f4bbeSAlexander Yermolovich case DebugPatchKind::ReferencePatchValue: { 10011c2f4bbeSAlexander Yermolovich DebugPatchReference *RDP = reinterpret_cast<DebugPatchReference *>(P); 10021c2f4bbeSAlexander Yermolovich uint32_t DestinationOffset = RDP->DestinationOffset; 10031c2f4bbeSAlexander Yermolovich assert(OldToNewOffset.count(DestinationOffset) && 10041c2f4bbeSAlexander Yermolovich "Destination Offset for reference not updated."); 10051c2f4bbeSAlexander Yermolovich uint32_t UpdatedOffset = OldToNewOffset[DestinationOffset]; 10061c2f4bbeSAlexander Yermolovich Offset = RDP->Offset; 10071c2f4bbeSAlexander Yermolovich OldValueSize = RDP->PatchInfo.OldValueSize; 10081c2f4bbeSAlexander Yermolovich if (RDP->PatchInfo.DirectRelative) { 10091c2f4bbeSAlexander Yermolovich UpdatedOffset -= DwarfUnitBaseOffset; 10101c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(OldValueSize, UpdatedOffset); 10111c2f4bbeSAlexander Yermolovich // In theory reference for DW_FORM_ref{1,2,4,8} can be right on the edge 10121c2f4bbeSAlexander Yermolovich // and overflow if later debug information grows. 10131c2f4bbeSAlexander Yermolovich if (ByteSequence.size() > OldValueSize) 10141c2f4bbeSAlexander Yermolovich errs() << "BOLT-ERROR: Relative reference of size " 10151c2f4bbeSAlexander Yermolovich << Twine::utohexstr(OldValueSize) 10161c2f4bbeSAlexander Yermolovich << " overflows with the new encoding.\n"; 10171c2f4bbeSAlexander Yermolovich } else if (RDP->PatchInfo.DirectAbsolute) { 10181c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(OldValueSize, UpdatedOffset); 10191c2f4bbeSAlexander Yermolovich } else if (RDP->PatchInfo.IndirectRelative) { 10201c2f4bbeSAlexander Yermolovich UpdatedOffset -= DwarfUnitBaseOffset; 10211c2f4bbeSAlexander Yermolovich ByteSequence.clear(); 10221c2f4bbeSAlexander Yermolovich raw_string_ostream OS(ByteSequence); 10231c2f4bbeSAlexander Yermolovich encodeULEB128(UpdatedOffset, OS, 4); 10241c2f4bbeSAlexander Yermolovich } else { 10251c2f4bbeSAlexander Yermolovich llvm_unreachable("Invalid Reference form."); 10261c2f4bbeSAlexander Yermolovich } 10271c2f4bbeSAlexander Yermolovich break; 10281c2f4bbeSAlexander Yermolovich } 10291c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue32: { 10301c2f4bbeSAlexander Yermolovich DebugPatch32 *P32 = reinterpret_cast<DebugPatch32 *>(P); 10311c2f4bbeSAlexander Yermolovich Offset = P32->Offset; 10321c2f4bbeSAlexander Yermolovich OldValueSize = 4; 10331c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(4, P32->Value); 10341c2f4bbeSAlexander Yermolovich break; 10351c2f4bbeSAlexander Yermolovich } 10361c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue64to32: { 10371c2f4bbeSAlexander Yermolovich DebugPatch64to32 *P64to32 = reinterpret_cast<DebugPatch64to32 *>(P); 10381c2f4bbeSAlexander Yermolovich Offset = P64to32->Offset; 10391c2f4bbeSAlexander Yermolovich OldValueSize = 8; 10401c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(4, P64to32->Value); 10411c2f4bbeSAlexander Yermolovich break; 10421c2f4bbeSAlexander Yermolovich } 1043a44fe319SAlexander Yermolovich case DebugPatchKind::PatchValue32GenericSize: { 1044a44fe319SAlexander Yermolovich DebugPatch32GenericSize *DPVS = 1045a44fe319SAlexander Yermolovich reinterpret_cast<DebugPatch32GenericSize *>(P); 1046a44fe319SAlexander Yermolovich Offset = DPVS->Offset; 1047a44fe319SAlexander Yermolovich OldValueSize = DPVS->OldValueSize; 1048a44fe319SAlexander Yermolovich ByteSequence = encodeLE(4, DPVS->Value); 1049a44fe319SAlexander Yermolovich break; 1050a44fe319SAlexander Yermolovich } 10511c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValueVariable: { 10521c2f4bbeSAlexander Yermolovich DebugPatchVariableSize *PV = 10531c2f4bbeSAlexander Yermolovich reinterpret_cast<DebugPatchVariableSize *>(P); 10541c2f4bbeSAlexander Yermolovich Offset = PV->Offset; 10551c2f4bbeSAlexander Yermolovich OldValueSize = PV->OldValueSize; 10561c2f4bbeSAlexander Yermolovich ByteSequence.clear(); 10571c2f4bbeSAlexander Yermolovich raw_string_ostream OS(ByteSequence); 10581c2f4bbeSAlexander Yermolovich encodeULEB128(PV->Value, OS); 10591c2f4bbeSAlexander Yermolovich break; 10601c2f4bbeSAlexander Yermolovich } 10611c2f4bbeSAlexander Yermolovich case DebugPatchKind::PatchValue64: { 10621c2f4bbeSAlexander Yermolovich DebugPatch64 *P64 = reinterpret_cast<DebugPatch64 *>(P); 10631c2f4bbeSAlexander Yermolovich Offset = P64->Offset; 10641c2f4bbeSAlexander Yermolovich OldValueSize = 8; 10651c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(8, P64->Value); 10661c2f4bbeSAlexander Yermolovich break; 10671c2f4bbeSAlexander Yermolovich } 10681c2f4bbeSAlexander Yermolovich case DebugPatchKind::DWARFUnitOffsetBaseLabel: { 10691c2f4bbeSAlexander Yermolovich DWARFUnitOffsetBaseLabel *BaseLabel = 10701c2f4bbeSAlexander Yermolovich reinterpret_cast<DWARFUnitOffsetBaseLabel *>(P); 10711c2f4bbeSAlexander Yermolovich Offset = BaseLabel->Offset; 10721c2f4bbeSAlexander Yermolovich OldValueSize = 0; 10731c2f4bbeSAlexander Yermolovich ByteSequence.clear(); 10741c2f4bbeSAlexander Yermolovich auto &Patch = LengthPatches.back(); 10751c2f4bbeSAlexander Yermolovich // Length to copy between last patch entry and next compile unit. 10761c2f4bbeSAlexander Yermolovich uint32_t RemainingLength = Offset - StartOffset; 10771c2f4bbeSAlexander Yermolovich uint32_t NewCUOffset = NewBinaryContents.size() + RemainingLength; 10781c2f4bbeSAlexander Yermolovich DwarfUnitBaseOffset = NewCUOffset; 10791c2f4bbeSAlexander Yermolovich // Length of previous CU = This CU Offset - sizeof(length) - last CU 10801c2f4bbeSAlexander Yermolovich // Offset. 10811c2f4bbeSAlexander Yermolovich Patch.second = NewCUOffset - 4 - Patch.first; 10821c2f4bbeSAlexander Yermolovich LengthPatches.push_back({NewCUOffset, 0}); 10831c2f4bbeSAlexander Yermolovich break; 10841c2f4bbeSAlexander Yermolovich } 1085bd1ebe9dSAlexander Yermolovich case DebugPatchKind::NewDebugEntry: { 1086bd1ebe9dSAlexander Yermolovich NewDebugEntry *NDE = reinterpret_cast<NewDebugEntry *>(P); 1087bd1ebe9dSAlexander Yermolovich Offset = NDE->Offset; 1088bd1ebe9dSAlexander Yermolovich OldValueSize = 0; 1089bd1ebe9dSAlexander Yermolovich ByteSequence = NDE->Value; 1090bd1ebe9dSAlexander Yermolovich break; 1091bd1ebe9dSAlexander Yermolovich } 10921c2f4bbeSAlexander Yermolovich } 10931c2f4bbeSAlexander Yermolovich 1094bd1ebe9dSAlexander Yermolovich assert((P->Kind == DebugPatchKind::NewDebugEntry || 1095bd1ebe9dSAlexander Yermolovich Offset + ByteSequence.size() <= BinaryContents.size()) && 10961c2f4bbeSAlexander Yermolovich "Applied patch runs over binary size."); 10971c2f4bbeSAlexander Yermolovich uint32_t Length = Offset - StartOffset; 10981c2f4bbeSAlexander Yermolovich NewBinaryContents.append(BinaryContents.substr(StartOffset, Length).data(), 10991c2f4bbeSAlexander Yermolovich Length); 11001c2f4bbeSAlexander Yermolovich NewBinaryContents.append(ByteSequence.data(), ByteSequence.size()); 11011c2f4bbeSAlexander Yermolovich StartOffset = Offset + OldValueSize; 11021c2f4bbeSAlexander Yermolovich } 11031c2f4bbeSAlexander Yermolovich uint32_t Length = BinaryContents.size() - StartOffset; 11041c2f4bbeSAlexander Yermolovich NewBinaryContents.append(BinaryContents.substr(StartOffset, Length).data(), 11051c2f4bbeSAlexander Yermolovich Length); 11061c2f4bbeSAlexander Yermolovich DebugPatches.clear(); 11071c2f4bbeSAlexander Yermolovich 11081c2f4bbeSAlexander Yermolovich // Patching lengths of CUs 11091c2f4bbeSAlexander Yermolovich auto &Patch = LengthPatches.back(); 11101c2f4bbeSAlexander Yermolovich Patch.second = NewBinaryContents.size() - 4 - Patch.first; 11111c2f4bbeSAlexander Yermolovich for (uint32_t J = 1, Size = LengthPatches.size(); J < Size; ++J) { 11121c2f4bbeSAlexander Yermolovich const auto &Patch = LengthPatches[J]; 11131c2f4bbeSAlexander Yermolovich ByteSequence = encodeLE(4, Patch.second); 11141c2f4bbeSAlexander Yermolovich Offset = Patch.first; 11151c2f4bbeSAlexander Yermolovich for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I) 11161c2f4bbeSAlexander Yermolovich NewBinaryContents[Offset + I] = ByteSequence[I]; 11171c2f4bbeSAlexander Yermolovich } 11181c2f4bbeSAlexander Yermolovich 11191c2f4bbeSAlexander Yermolovich return NewBinaryContents; 1120a34c753fSRafael Auler } 1121a34c753fSRafael Auler 1122ba1ac98cSAlexander Yermolovich void DebugStrOffsetsWriter::initialize( 1123ba1ac98cSAlexander Yermolovich const DWARFSection &StrOffsetsSection, 112489fab98eSFangrui Song const std::optional<StrOffsetsContributionDescriptor> Contr) { 1125ba1ac98cSAlexander Yermolovich if (!Contr) 1126ba1ac98cSAlexander Yermolovich return; 1127ba1ac98cSAlexander Yermolovich 1128ba1ac98cSAlexander Yermolovich const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize(); 1129ba1ac98cSAlexander Yermolovich assert(DwarfOffsetByteSize == 4 && 1130ba1ac98cSAlexander Yermolovich "Dwarf String Offsets Byte Size is not supported."); 1131ba1ac98cSAlexander Yermolovich uint32_t Index = 0; 1132ba1ac98cSAlexander Yermolovich for (uint64_t Offset = 0; Offset < Contr->Size; Offset += DwarfOffsetByteSize) 1133ba1ac98cSAlexander Yermolovich IndexToAddressMap[Index++] = *reinterpret_cast<const uint32_t *>( 1134ba1ac98cSAlexander Yermolovich StrOffsetsSection.Data.data() + Contr->Base + Offset); 1135ba1ac98cSAlexander Yermolovich } 1136ba1ac98cSAlexander Yermolovich 1137ba1ac98cSAlexander Yermolovich void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address) { 1138ba1ac98cSAlexander Yermolovich assert(IndexToAddressMap.count(Index) > 0 && "Index is not found."); 1139ba1ac98cSAlexander Yermolovich IndexToAddressMap[Index] = Address; 1140f7a21317SAlexander Yermolovich StrOffsetSectionWasModified = true; 1141ba1ac98cSAlexander Yermolovich } 1142ba1ac98cSAlexander Yermolovich 1143f7a21317SAlexander Yermolovich void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit) { 1144ba1ac98cSAlexander Yermolovich if (IndexToAddressMap.empty()) 1145ba1ac98cSAlexander Yermolovich return; 1146f7a21317SAlexander Yermolovich 1147f7a21317SAlexander Yermolovich std::optional<AttrInfo> AttrVal = 1148f7a21317SAlexander Yermolovich findAttributeInfo(Unit.getUnitDIE(), dwarf::DW_AT_str_offsets_base); 1149f7a21317SAlexander Yermolovich assert(AttrVal && "DW_AT_str_offsets_base not present."); 1150f7a21317SAlexander Yermolovich std::optional<uint64_t> Val = AttrVal->V.getAsSectionOffset(); 1151f7a21317SAlexander Yermolovich assert(Val && "DW_AT_str_offsets_base Value not present."); 1152f7a21317SAlexander Yermolovich auto RetVal = ProcessedBaseOffsets.insert(*Val); 1153f7a21317SAlexander Yermolovich if (RetVal.second) { 1154ba1ac98cSAlexander Yermolovich // Writing out the header for each section. 1155ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, CurrentSectionSize + 4, 1156ba1ac98cSAlexander Yermolovich support::little); 1157ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(5), 1158ba1ac98cSAlexander Yermolovich support::little); 1159ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(0), 1160ba1ac98cSAlexander Yermolovich support::little); 1161ba1ac98cSAlexander Yermolovich for (const auto &Entry : IndexToAddressMap) 1162ba1ac98cSAlexander Yermolovich support::endian::write(*StrOffsetsStream, Entry.second, support::little); 1163f7a21317SAlexander Yermolovich } 1164f7a21317SAlexander Yermolovich // Will print error if we already processed this contribution, and now 1165f7a21317SAlexander Yermolovich // skipping it, but it was modified. 1166f7a21317SAlexander Yermolovich if (!RetVal.second && StrOffsetSectionWasModified) 1167f7a21317SAlexander Yermolovich errs() << "BOLT-WARNING: skipping string offsets section for CU at offset " 1168f7a21317SAlexander Yermolovich << Twine::utohexstr(Unit.getOffset()) << ", but it was modified\n"; 1169f7a21317SAlexander Yermolovich 1170f7a21317SAlexander Yermolovich StrOffsetSectionWasModified = false; 1171ba1ac98cSAlexander Yermolovich IndexToAddressMap.clear(); 1172ba1ac98cSAlexander Yermolovich } 1173ba1ac98cSAlexander Yermolovich 1174a34c753fSRafael Auler void DebugStrWriter::create() { 1175a34c753fSRafael Auler StrBuffer = std::make_unique<DebugStrBufferVector>(); 1176a34c753fSRafael Auler StrStream = std::make_unique<raw_svector_ostream>(*StrBuffer); 1177a34c753fSRafael Auler } 1178a34c753fSRafael Auler 1179a34c753fSRafael Auler void DebugStrWriter::initialize() { 1180ba1ac98cSAlexander Yermolovich auto StrSection = BC.DwCtx->getDWARFObj().getStrSection(); 1181a34c753fSRafael Auler (*StrStream) << StrSection; 1182a34c753fSRafael Auler } 1183a34c753fSRafael Auler 1184a34c753fSRafael Auler uint32_t DebugStrWriter::addString(StringRef Str) { 1185e579f5c6SAlexander Yermolovich std::lock_guard<std::mutex> Lock(WriterMutex); 1186a34c753fSRafael Auler if (StrBuffer->empty()) 1187a34c753fSRafael Auler initialize(); 1188a34c753fSRafael Auler auto Offset = StrBuffer->size(); 1189a34c753fSRafael Auler (*StrStream) << Str; 1190a34c753fSRafael Auler StrStream->write_zeros(1); 1191a34c753fSRafael Auler return Offset; 1192a34c753fSRafael Auler } 1193a34c753fSRafael Auler 1194a34c753fSRafael Auler void DebugAbbrevWriter::addUnitAbbreviations(DWARFUnit &Unit) { 1195a34c753fSRafael Auler const DWARFAbbreviationDeclarationSet *Abbrevs = Unit.getAbbreviations(); 1196a34c753fSRafael Auler if (!Abbrevs) 1197a34c753fSRafael Auler return; 1198a34c753fSRafael Auler 119945f94abcSMaksim Panchenko const PatchesTy &UnitPatches = Patches[&Unit]; 1200bd1ebe9dSAlexander Yermolovich const AbbrevEntryTy &AbbrevEntries = NewAbbrevEntries[&Unit]; 1201a34c753fSRafael Auler 12029f3f9d19SAlexander Yermolovich // We are duplicating abbrev sections, to handle the case where for one CU we 12039f3f9d19SAlexander Yermolovich // modify it, but for another we don't. 12049f3f9d19SAlexander Yermolovich auto UnitDataPtr = std::make_unique<AbbrevData>(); 12059f3f9d19SAlexander Yermolovich AbbrevData &UnitData = *UnitDataPtr.get(); 12069f3f9d19SAlexander Yermolovich UnitData.Buffer = std::make_unique<DebugBufferVector>(); 12079f3f9d19SAlexander Yermolovich UnitData.Stream = std::make_unique<raw_svector_ostream>(*UnitData.Buffer); 1208bd1ebe9dSAlexander Yermolovich 1209a34c753fSRafael Auler raw_svector_ostream &OS = *UnitData.Stream.get(); 1210a34c753fSRafael Auler 12119f3f9d19SAlexander Yermolovich // Returns true if AbbrevData is re-used, false otherwise. 12129f3f9d19SAlexander Yermolovich auto hashAndAddAbbrev = [&](StringRef AbbrevData) -> bool { 12139f3f9d19SAlexander Yermolovich llvm::SHA1 Hasher; 12149f3f9d19SAlexander Yermolovich Hasher.update(AbbrevData); 1215330268baSArgyrios Kyrtzidis std::array<uint8_t, 20> Hash = Hasher.final(); 1216330268baSArgyrios Kyrtzidis StringRef Key((const char *)Hash.data(), Hash.size()); 12179f3f9d19SAlexander Yermolovich auto Iter = AbbrevDataCache.find(Key); 12189f3f9d19SAlexander Yermolovich if (Iter != AbbrevDataCache.end()) { 12199f3f9d19SAlexander Yermolovich UnitsAbbrevData[&Unit] = Iter->second.get(); 12209f3f9d19SAlexander Yermolovich return true; 12219f3f9d19SAlexander Yermolovich } 12229f3f9d19SAlexander Yermolovich AbbrevDataCache[Key] = std::move(UnitDataPtr); 12239f3f9d19SAlexander Yermolovich UnitsAbbrevData[&Unit] = &UnitData; 12249f3f9d19SAlexander Yermolovich return false; 12259f3f9d19SAlexander Yermolovich }; 1226a34c753fSRafael Auler // Take a fast path if there are no patches to apply. Simply copy the original 1227a34c753fSRafael Auler // contents. 1228bd1ebe9dSAlexander Yermolovich if (UnitPatches.empty() && AbbrevEntries.empty()) { 1229a34c753fSRafael Auler StringRef AbbrevSectionContents = 1230a34c753fSRafael Auler Unit.isDWOUnit() ? Unit.getContext().getDWARFObj().getAbbrevDWOSection() 1231a34c753fSRafael Auler : Unit.getContext().getDWARFObj().getAbbrevSection(); 1232a34c753fSRafael Auler StringRef AbbrevContents; 1233a34c753fSRafael Auler 1234a34c753fSRafael Auler const DWARFUnitIndex &CUIndex = Unit.getContext().getCUIndex(); 1235a34c753fSRafael Auler if (!CUIndex.getRows().empty()) { 1236a34c753fSRafael Auler // Handle DWP section contribution. 1237a34c753fSRafael Auler const DWARFUnitIndex::Entry *DWOEntry = 1238a34c753fSRafael Auler CUIndex.getFromHash(*Unit.getDWOId()); 1239a34c753fSRafael Auler if (!DWOEntry) 1240a34c753fSRafael Auler return; 1241a34c753fSRafael Auler 1242a34c753fSRafael Auler const DWARFUnitIndex::Entry::SectionContribution *DWOContrubution = 1243a34c753fSRafael Auler DWOEntry->getContribution(DWARFSectionKind::DW_SECT_ABBREV); 1244*7fc79340SAlexander Yermolovich AbbrevContents = AbbrevSectionContents.substr( 1245*7fc79340SAlexander Yermolovich DWOContrubution->getOffset(), DWOContrubution->getLength()); 124645f94abcSMaksim Panchenko } else if (!Unit.isDWOUnit()) { 1247a34c753fSRafael Auler const uint64_t StartOffset = Unit.getAbbreviationsOffset(); 124845f94abcSMaksim Panchenko 124945f94abcSMaksim Panchenko // We know where the unit's abbreviation set starts, but not where it ends 125045f94abcSMaksim Panchenko // as such data is not readily available. Hence, we have to build a sorted 125145f94abcSMaksim Panchenko // list of start addresses and find the next starting address to determine 125245f94abcSMaksim Panchenko // the set boundaries. 125345f94abcSMaksim Panchenko // 125445f94abcSMaksim Panchenko // FIXME: if we had a full access to DWARFDebugAbbrev::AbbrDeclSets 125545f94abcSMaksim Panchenko // we wouldn't have to build our own sorted list for the quick lookup. 125645f94abcSMaksim Panchenko if (AbbrevSetOffsets.empty()) { 1257a0c7ca8aSKazu Hirata for (const std::pair<const uint64_t, DWARFAbbreviationDeclarationSet> 1258a0c7ca8aSKazu Hirata &P : *Unit.getContext().getDebugAbbrev()) 125945f94abcSMaksim Panchenko AbbrevSetOffsets.push_back(P.first); 12601c2f4bbeSAlexander Yermolovich sort(AbbrevSetOffsets); 126145f94abcSMaksim Panchenko } 12621c2f4bbeSAlexander Yermolovich auto It = upper_bound(AbbrevSetOffsets, StartOffset); 126345f94abcSMaksim Panchenko const uint64_t EndOffset = 126445f94abcSMaksim Panchenko It == AbbrevSetOffsets.end() ? AbbrevSectionContents.size() : *It; 1265a34c753fSRafael Auler AbbrevContents = AbbrevSectionContents.slice(StartOffset, EndOffset); 126645f94abcSMaksim Panchenko } else { 126745f94abcSMaksim Panchenko // For DWO unit outside of DWP, we expect the entire section to hold 126845f94abcSMaksim Panchenko // abbreviations for this unit only. 126945f94abcSMaksim Panchenko AbbrevContents = AbbrevSectionContents; 1270a34c753fSRafael Auler } 1271a34c753fSRafael Auler 12729f3f9d19SAlexander Yermolovich if (!hashAndAddAbbrev(AbbrevContents)) { 1273a34c753fSRafael Auler OS.reserveExtraSpace(AbbrevContents.size()); 1274a34c753fSRafael Auler OS << AbbrevContents; 12759f3f9d19SAlexander Yermolovich } 1276a34c753fSRafael Auler return; 1277a34c753fSRafael Auler } 1278a34c753fSRafael Auler 1279a34c753fSRafael Auler for (auto I = Abbrevs->begin(), E = Abbrevs->end(); I != E; ++I) { 1280a34c753fSRafael Auler const DWARFAbbreviationDeclaration &Abbrev = *I; 1281a34c753fSRafael Auler auto Patch = UnitPatches.find(&Abbrev); 1282a34c753fSRafael Auler 1283a34c753fSRafael Auler encodeULEB128(Abbrev.getCode(), OS); 1284a34c753fSRafael Auler encodeULEB128(Abbrev.getTag(), OS); 1285a34c753fSRafael Auler encodeULEB128(Abbrev.hasChildren(), OS); 1286a34c753fSRafael Auler for (const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec : 1287a34c753fSRafael Auler Abbrev.attributes()) { 1288a34c753fSRafael Auler if (Patch != UnitPatches.end()) { 1289a34c753fSRafael Auler bool Patched = false; 1290a34c753fSRafael Auler // Patches added later take a precedence over earlier ones. 1291f40d25ddSAmir Ayupov for (const PatchInfo &PI : llvm::reverse(Patch->second)) { 1292f40d25ddSAmir Ayupov if (PI.OldAttr != AttrSpec.Attr) 1293a34c753fSRafael Auler continue; 1294a34c753fSRafael Auler 1295f40d25ddSAmir Ayupov encodeULEB128(PI.NewAttr, OS); 1296f40d25ddSAmir Ayupov encodeULEB128(PI.NewAttrForm, OS); 1297a34c753fSRafael Auler Patched = true; 1298a34c753fSRafael Auler break; 1299a34c753fSRafael Auler } 1300a34c753fSRafael Auler if (Patched) 1301a34c753fSRafael Auler continue; 1302a34c753fSRafael Auler } 1303a34c753fSRafael Auler 1304a34c753fSRafael Auler encodeULEB128(AttrSpec.Attr, OS); 1305a34c753fSRafael Auler encodeULEB128(AttrSpec.Form, OS); 1306a34c753fSRafael Auler if (AttrSpec.isImplicitConst()) 1307a34c753fSRafael Auler encodeSLEB128(AttrSpec.getImplicitConstValue(), OS); 1308a34c753fSRafael Auler } 1309bd1ebe9dSAlexander Yermolovich const auto Entries = AbbrevEntries.find(&Abbrev); 1310bd1ebe9dSAlexander Yermolovich // Adding new Abbrevs for inserted entries. 1311bd1ebe9dSAlexander Yermolovich if (Entries != AbbrevEntries.end()) { 1312bd1ebe9dSAlexander Yermolovich for (const AbbrevEntry &Entry : Entries->second) { 1313bd1ebe9dSAlexander Yermolovich encodeULEB128(Entry.Attr, OS); 1314bd1ebe9dSAlexander Yermolovich encodeULEB128(Entry.Form, OS); 1315bd1ebe9dSAlexander Yermolovich } 1316bd1ebe9dSAlexander Yermolovich } 1317a34c753fSRafael Auler encodeULEB128(0, OS); 1318a34c753fSRafael Auler encodeULEB128(0, OS); 1319a34c753fSRafael Auler } 1320a34c753fSRafael Auler encodeULEB128(0, OS); 13219f3f9d19SAlexander Yermolovich 13229f3f9d19SAlexander Yermolovich hashAndAddAbbrev(OS.str()); 1323a34c753fSRafael Auler } 1324a34c753fSRafael Auler 1325a34c753fSRafael Auler std::unique_ptr<DebugBufferVector> DebugAbbrevWriter::finalize() { 13269f3f9d19SAlexander Yermolovich // Used to create determinism for writing out abbrevs. 13279f3f9d19SAlexander Yermolovich std::vector<AbbrevData *> Abbrevs; 132845f94abcSMaksim Panchenko if (DWOId) { 132945f94abcSMaksim Panchenko // We expect abbrev_offset to always be zero for DWO units as there 133045f94abcSMaksim Panchenko // should be one CU per DWO, and TUs should share the same abbreviation 133145f94abcSMaksim Panchenko // set with the CU. 13321417f607SAlexander Yermolovich // For DWP AbbreviationsOffset is an Abbrev contribution in the DWP file, so 13331417f607SAlexander Yermolovich // can be none zero. Thus we are skipping the check for DWP. 133445f94abcSMaksim Panchenko bool IsDWP = !Context.getCUIndex().getRows().empty(); 13351417f607SAlexander Yermolovich if (!IsDWP) { 133645f94abcSMaksim Panchenko for (const std::unique_ptr<DWARFUnit> &Unit : Context.dwo_units()) { 133745f94abcSMaksim Panchenko if (Unit->getAbbreviationsOffset() != 0) { 133845f94abcSMaksim Panchenko errs() << "BOLT-ERROR: detected DWO unit with non-zero abbr_offset. " 133945f94abcSMaksim Panchenko "Unable to update debug info.\n"; 134045f94abcSMaksim Panchenko exit(1); 134145f94abcSMaksim Panchenko } 134245f94abcSMaksim Panchenko } 134345f94abcSMaksim Panchenko } 134445f94abcSMaksim Panchenko 13459f3f9d19SAlexander Yermolovich DWARFUnit *Unit = Context.getDWOCompileUnitForHash(*DWOId); 134645f94abcSMaksim Panchenko // Issue abbreviations for the DWO CU only. 134745f94abcSMaksim Panchenko addUnitAbbreviations(*Unit); 13489f3f9d19SAlexander Yermolovich AbbrevData *Abbrev = UnitsAbbrevData[Unit]; 13499f3f9d19SAlexander Yermolovich Abbrevs.push_back(Abbrev); 13509f3f9d19SAlexander Yermolovich } else { 13519f3f9d19SAlexander Yermolovich Abbrevs.reserve(Context.getNumCompileUnits() + Context.getNumTypeUnits()); 13529f3f9d19SAlexander Yermolovich std::unordered_set<AbbrevData *> ProcessedAbbrevs; 13539f3f9d19SAlexander Yermolovich // Add abbreviations from compile and type non-DWO units. 13549f3f9d19SAlexander Yermolovich for (const std::unique_ptr<DWARFUnit> &Unit : Context.normal_units()) { 13559f3f9d19SAlexander Yermolovich addUnitAbbreviations(*Unit); 13569f3f9d19SAlexander Yermolovich AbbrevData *Abbrev = UnitsAbbrevData[Unit.get()]; 13579f3f9d19SAlexander Yermolovich if (!ProcessedAbbrevs.insert(Abbrev).second) 13589f3f9d19SAlexander Yermolovich continue; 13599f3f9d19SAlexander Yermolovich Abbrevs.push_back(Abbrev); 13609f3f9d19SAlexander Yermolovich } 136145f94abcSMaksim Panchenko } 136245f94abcSMaksim Panchenko 1363a34c753fSRafael Auler DebugBufferVector ReturnBuffer; 1364a34c753fSRafael Auler // Pre-calculate the total size of abbrev section. 1365a34c753fSRafael Auler uint64_t Size = 0; 13669f3f9d19SAlexander Yermolovich for (const AbbrevData *UnitData : Abbrevs) 13679f3f9d19SAlexander Yermolovich Size += UnitData->Buffer->size(); 13689f3f9d19SAlexander Yermolovich 1369a34c753fSRafael Auler ReturnBuffer.reserve(Size); 1370a34c753fSRafael Auler 1371a34c753fSRafael Auler uint64_t Pos = 0; 13729f3f9d19SAlexander Yermolovich for (AbbrevData *UnitData : Abbrevs) { 13739f3f9d19SAlexander Yermolovich ReturnBuffer.append(*UnitData->Buffer); 13749f3f9d19SAlexander Yermolovich UnitData->Offset = Pos; 13759f3f9d19SAlexander Yermolovich Pos += UnitData->Buffer->size(); 1376a34c753fSRafael Auler 13779f3f9d19SAlexander Yermolovich UnitData->Buffer.reset(); 13789f3f9d19SAlexander Yermolovich UnitData->Stream.reset(); 1379a34c753fSRafael Auler } 1380a34c753fSRafael Auler 1381a34c753fSRafael Auler return std::make_unique<DebugBufferVector>(ReturnBuffer); 1382a34c753fSRafael Auler } 1383a34c753fSRafael Auler 1384a34c753fSRafael Auler static void emitDwarfSetLineAddrAbs(MCStreamer &OS, 1385a34c753fSRafael Auler MCDwarfLineTableParams Params, 1386a34c753fSRafael Auler int64_t LineDelta, uint64_t Address, 1387a34c753fSRafael Auler int PointerSize) { 1388a34c753fSRafael Auler // emit the sequence to set the address 1389a34c753fSRafael Auler OS.emitIntValue(dwarf::DW_LNS_extended_op, 1); 1390a34c753fSRafael Auler OS.emitULEB128IntValue(PointerSize + 1); 1391a34c753fSRafael Auler OS.emitIntValue(dwarf::DW_LNE_set_address, 1); 1392a34c753fSRafael Auler OS.emitIntValue(Address, PointerSize); 1393a34c753fSRafael Auler 1394a34c753fSRafael Auler // emit the sequence for the LineDelta (from 1) and a zero address delta. 1395a34c753fSRafael Auler MCDwarfLineAddr::Emit(&OS, Params, LineDelta, 0); 1396a34c753fSRafael Auler } 1397a34c753fSRafael Auler 1398a34c753fSRafael Auler static inline void emitBinaryDwarfLineTable( 1399a34c753fSRafael Auler MCStreamer *MCOS, MCDwarfLineTableParams Params, 1400a34c753fSRafael Auler const DWARFDebugLine::LineTable *Table, 1401a34c753fSRafael Auler const std::vector<DwarfLineTable::RowSequence> &InputSequences) { 1402a34c753fSRafael Auler if (InputSequences.empty()) 1403a34c753fSRafael Auler return; 1404a34c753fSRafael Auler 1405a34c753fSRafael Auler constexpr uint64_t InvalidAddress = UINT64_MAX; 1406a34c753fSRafael Auler unsigned FileNum = 1; 1407a34c753fSRafael Auler unsigned LastLine = 1; 1408a34c753fSRafael Auler unsigned Column = 0; 1409a34c753fSRafael Auler unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1410a34c753fSRafael Auler unsigned Isa = 0; 1411a34c753fSRafael Auler unsigned Discriminator = 0; 1412a34c753fSRafael Auler uint64_t LastAddress = InvalidAddress; 1413a34c753fSRafael Auler uint64_t PrevEndOfSequence = InvalidAddress; 1414a34c753fSRafael Auler const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo(); 1415a34c753fSRafael Auler 1416a34c753fSRafael Auler auto emitEndOfSequence = [&](uint64_t Address) { 1417a34c753fSRafael Auler MCDwarfLineAddr::Emit(MCOS, Params, INT64_MAX, Address - LastAddress); 1418a34c753fSRafael Auler FileNum = 1; 1419a34c753fSRafael Auler LastLine = 1; 1420a34c753fSRafael Auler Column = 0; 1421a34c753fSRafael Auler Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1422a34c753fSRafael Auler Isa = 0; 1423a34c753fSRafael Auler Discriminator = 0; 1424a34c753fSRafael Auler LastAddress = InvalidAddress; 1425a34c753fSRafael Auler }; 1426a34c753fSRafael Auler 1427a34c753fSRafael Auler for (const DwarfLineTable::RowSequence &Sequence : InputSequences) { 1428a34c753fSRafael Auler const uint64_t SequenceStart = 1429a34c753fSRafael Auler Table->Rows[Sequence.FirstIndex].Address.Address; 1430a34c753fSRafael Auler 1431a34c753fSRafael Auler // Check if we need to mark the end of the sequence. 1432a34c753fSRafael Auler if (PrevEndOfSequence != InvalidAddress && LastAddress != InvalidAddress && 1433a34c753fSRafael Auler PrevEndOfSequence != SequenceStart) { 1434a34c753fSRafael Auler emitEndOfSequence(PrevEndOfSequence); 1435a34c753fSRafael Auler } 1436a34c753fSRafael Auler 1437a34c753fSRafael Auler for (uint32_t RowIndex = Sequence.FirstIndex; 1438a34c753fSRafael Auler RowIndex <= Sequence.LastIndex; ++RowIndex) { 1439a34c753fSRafael Auler const DWARFDebugLine::Row &Row = Table->Rows[RowIndex]; 1440a34c753fSRafael Auler int64_t LineDelta = static_cast<int64_t>(Row.Line) - LastLine; 1441a34c753fSRafael Auler const uint64_t Address = Row.Address.Address; 1442a34c753fSRafael Auler 1443a34c753fSRafael Auler if (FileNum != Row.File) { 1444a34c753fSRafael Auler FileNum = Row.File; 1445a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_file); 1446a34c753fSRafael Auler MCOS->emitULEB128IntValue(FileNum); 1447a34c753fSRafael Auler } 1448a34c753fSRafael Auler if (Column != Row.Column) { 1449a34c753fSRafael Auler Column = Row.Column; 1450a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_column); 1451a34c753fSRafael Auler MCOS->emitULEB128IntValue(Column); 1452a34c753fSRafael Auler } 1453a34c753fSRafael Auler if (Discriminator != Row.Discriminator && 1454a34c753fSRafael Auler MCOS->getContext().getDwarfVersion() >= 4) { 1455a34c753fSRafael Auler Discriminator = Row.Discriminator; 1456a34c753fSRafael Auler unsigned Size = getULEB128Size(Discriminator); 1457a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_extended_op); 1458a34c753fSRafael Auler MCOS->emitULEB128IntValue(Size + 1); 1459a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNE_set_discriminator); 1460a34c753fSRafael Auler MCOS->emitULEB128IntValue(Discriminator); 1461a34c753fSRafael Auler } 1462a34c753fSRafael Auler if (Isa != Row.Isa) { 1463a34c753fSRafael Auler Isa = Row.Isa; 1464a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_isa); 1465a34c753fSRafael Auler MCOS->emitULEB128IntValue(Isa); 1466a34c753fSRafael Auler } 1467a34c753fSRafael Auler if (Row.IsStmt != Flags) { 1468a34c753fSRafael Auler Flags = Row.IsStmt; 1469a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_negate_stmt); 1470a34c753fSRafael Auler } 1471a34c753fSRafael Auler if (Row.BasicBlock) 1472a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_basic_block); 1473a34c753fSRafael Auler if (Row.PrologueEnd) 1474a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_prologue_end); 1475a34c753fSRafael Auler if (Row.EpilogueBegin) 1476a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin); 1477a34c753fSRafael Auler 1478a34c753fSRafael Auler // The end of the sequence is not normal in the middle of the input 1479a34c753fSRafael Auler // sequence, but could happen, e.g. for assembly code. 1480a34c753fSRafael Auler if (Row.EndSequence) { 1481a34c753fSRafael Auler emitEndOfSequence(Address); 1482a34c753fSRafael Auler } else { 1483a34c753fSRafael Auler if (LastAddress == InvalidAddress) 1484a34c753fSRafael Auler emitDwarfSetLineAddrAbs(*MCOS, Params, LineDelta, Address, 1485a34c753fSRafael Auler AsmInfo->getCodePointerSize()); 1486a34c753fSRafael Auler else 1487a34c753fSRafael Auler MCDwarfLineAddr::Emit(MCOS, Params, LineDelta, Address - LastAddress); 1488a34c753fSRafael Auler 1489a34c753fSRafael Auler LastAddress = Address; 1490a34c753fSRafael Auler LastLine = Row.Line; 1491a34c753fSRafael Auler } 1492a34c753fSRafael Auler 1493a34c753fSRafael Auler Discriminator = 0; 1494a34c753fSRafael Auler } 1495a34c753fSRafael Auler PrevEndOfSequence = Sequence.EndAddress; 1496a34c753fSRafael Auler } 1497a34c753fSRafael Auler 1498a34c753fSRafael Auler // Finish with the end of the sequence. 1499a34c753fSRafael Auler if (LastAddress != InvalidAddress) 1500a34c753fSRafael Auler emitEndOfSequence(PrevEndOfSequence); 1501a34c753fSRafael Auler } 1502a34c753fSRafael Auler 1503a34c753fSRafael Auler // This function is similar to the one from MCDwarfLineTable, except it handles 1504a34c753fSRafael Auler // end-of-sequence entries differently by utilizing line entries with 1505a34c753fSRafael Auler // DWARF2_FLAG_END_SEQUENCE flag. 1506a34c753fSRafael Auler static inline void emitDwarfLineTable( 1507a34c753fSRafael Auler MCStreamer *MCOS, MCSection *Section, 1508a34c753fSRafael Auler const MCLineSection::MCDwarfLineEntryCollection &LineEntries) { 1509a34c753fSRafael Auler unsigned FileNum = 1; 1510a34c753fSRafael Auler unsigned LastLine = 1; 1511a34c753fSRafael Auler unsigned Column = 0; 1512a34c753fSRafael Auler unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1513a34c753fSRafael Auler unsigned Isa = 0; 1514a34c753fSRafael Auler unsigned Discriminator = 0; 1515a34c753fSRafael Auler MCSymbol *LastLabel = nullptr; 1516a34c753fSRafael Auler const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo(); 1517a34c753fSRafael Auler 1518a34c753fSRafael Auler // Loop through each MCDwarfLineEntry and encode the dwarf line number table. 1519a34c753fSRafael Auler for (const MCDwarfLineEntry &LineEntry : LineEntries) { 1520a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_END_SEQUENCE) { 1521a34c753fSRafael Auler MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, LineEntry.getLabel(), 1522a34c753fSRafael Auler AsmInfo->getCodePointerSize()); 1523a34c753fSRafael Auler FileNum = 1; 1524a34c753fSRafael Auler LastLine = 1; 1525a34c753fSRafael Auler Column = 0; 1526a34c753fSRafael Auler Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; 1527a34c753fSRafael Auler Isa = 0; 1528a34c753fSRafael Auler Discriminator = 0; 1529a34c753fSRafael Auler LastLabel = nullptr; 1530a34c753fSRafael Auler continue; 1531a34c753fSRafael Auler } 1532a34c753fSRafael Auler 1533a34c753fSRafael Auler int64_t LineDelta = static_cast<int64_t>(LineEntry.getLine()) - LastLine; 1534a34c753fSRafael Auler 1535a34c753fSRafael Auler if (FileNum != LineEntry.getFileNum()) { 1536a34c753fSRafael Auler FileNum = LineEntry.getFileNum(); 1537a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_file); 1538a34c753fSRafael Auler MCOS->emitULEB128IntValue(FileNum); 1539a34c753fSRafael Auler } 1540a34c753fSRafael Auler if (Column != LineEntry.getColumn()) { 1541a34c753fSRafael Auler Column = LineEntry.getColumn(); 1542a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_column); 1543a34c753fSRafael Auler MCOS->emitULEB128IntValue(Column); 1544a34c753fSRafael Auler } 1545a34c753fSRafael Auler if (Discriminator != LineEntry.getDiscriminator() && 1546014cd37fSAlexander Yermolovich MCOS->getContext().getDwarfVersion() >= 2) { 1547a34c753fSRafael Auler Discriminator = LineEntry.getDiscriminator(); 1548a34c753fSRafael Auler unsigned Size = getULEB128Size(Discriminator); 1549a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_extended_op); 1550a34c753fSRafael Auler MCOS->emitULEB128IntValue(Size + 1); 1551a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNE_set_discriminator); 1552a34c753fSRafael Auler MCOS->emitULEB128IntValue(Discriminator); 1553a34c753fSRafael Auler } 1554a34c753fSRafael Auler if (Isa != LineEntry.getIsa()) { 1555a34c753fSRafael Auler Isa = LineEntry.getIsa(); 1556a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_isa); 1557a34c753fSRafael Auler MCOS->emitULEB128IntValue(Isa); 1558a34c753fSRafael Auler } 1559a34c753fSRafael Auler if ((LineEntry.getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { 1560a34c753fSRafael Auler Flags = LineEntry.getFlags(); 1561a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_negate_stmt); 1562a34c753fSRafael Auler } 1563a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_BASIC_BLOCK) 1564a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_basic_block); 1565a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_PROLOGUE_END) 1566a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_prologue_end); 1567a34c753fSRafael Auler if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) 1568a34c753fSRafael Auler MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin); 1569a34c753fSRafael Auler 1570a34c753fSRafael Auler MCSymbol *Label = LineEntry.getLabel(); 1571a34c753fSRafael Auler 1572a34c753fSRafael Auler // At this point we want to emit/create the sequence to encode the delta 1573a34c753fSRafael Auler // in line numbers and the increment of the address from the previous 1574a34c753fSRafael Auler // Label and the current Label. 1575a34c753fSRafael Auler MCOS->emitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label, 1576a34c753fSRafael Auler AsmInfo->getCodePointerSize()); 1577a34c753fSRafael Auler Discriminator = 0; 1578a34c753fSRafael Auler LastLine = LineEntry.getLine(); 1579a34c753fSRafael Auler LastLabel = Label; 1580a34c753fSRafael Auler } 1581a34c753fSRafael Auler 1582a34c753fSRafael Auler assert(LastLabel == nullptr && "end of sequence expected"); 1583a34c753fSRafael Auler } 1584a34c753fSRafael Auler 1585a34c753fSRafael Auler void DwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params, 1586f4c16c44SFangrui Song std::optional<MCDwarfLineStr> &LineStr, 1587b73c87bcSMaksim Panchenko BinaryContext &BC) const { 1588a34c753fSRafael Auler if (!RawData.empty()) { 1589a34c753fSRafael Auler assert(MCLineSections.getMCLineEntries().empty() && 1590a34c753fSRafael Auler InputSequences.empty() && 1591a34c753fSRafael Auler "cannot combine raw data with new line entries"); 1592a34c753fSRafael Auler MCOS->emitLabel(getLabel()); 1593a34c753fSRafael Auler MCOS->emitBytes(RawData); 1594a34c753fSRafael Auler 1595b73c87bcSMaksim Panchenko // Emit fake relocation for RuntimeDyld to always allocate the section. 1596b73c87bcSMaksim Panchenko // 1597b73c87bcSMaksim Panchenko // FIXME: remove this once RuntimeDyld stops skipping allocatable sections 1598b73c87bcSMaksim Panchenko // without relocations. 1599b73c87bcSMaksim Panchenko MCOS->emitRelocDirective( 1600b73c87bcSMaksim Panchenko *MCConstantExpr::create(0, *BC.Ctx), "BFD_RELOC_NONE", 1601b73c87bcSMaksim Panchenko MCSymbolRefExpr::create(getLabel(), *BC.Ctx), SMLoc(), *BC.STI); 1602b73c87bcSMaksim Panchenko 1603a34c753fSRafael Auler return; 1604a34c753fSRafael Auler } 1605a34c753fSRafael Auler 1606a34c753fSRafael Auler MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second; 1607a34c753fSRafael Auler 1608a34c753fSRafael Auler // Put out the line tables. 1609a34c753fSRafael Auler for (const auto &LineSec : MCLineSections.getMCLineEntries()) 1610a34c753fSRafael Auler emitDwarfLineTable(MCOS, LineSec.first, LineSec.second); 1611a34c753fSRafael Auler 1612a34c753fSRafael Auler // Emit line tables for the original code. 1613a34c753fSRafael Auler emitBinaryDwarfLineTable(MCOS, Params, InputTable, InputSequences); 1614a34c753fSRafael Auler 1615a34c753fSRafael Auler // This is the end of the section, so set the value of the symbol at the end 1616a34c753fSRafael Auler // of this section (that was used in a previous expression). 1617a34c753fSRafael Auler MCOS->emitLabel(LineEndSym); 1618a34c753fSRafael Auler } 1619a34c753fSRafael Auler 1620014cd37fSAlexander Yermolovich // Helper function to parse .debug_line_str, and populate one we are using. 1621014cd37fSAlexander Yermolovich // For functions that we do not modify we output them as raw data. 1622014cd37fSAlexander Yermolovich // Re-constructing .debug_line_str so that offsets are correct for those 1623014cd37fSAlexander Yermolovich // debut line tables. 1624014cd37fSAlexander Yermolovich // Bonus is that when we output a final binary we can re-use .debug_line_str 1625014cd37fSAlexander Yermolovich // section. So we don't have to do the SHF_ALLOC trick we did with 1626014cd37fSAlexander Yermolovich // .debug_line. 1627014cd37fSAlexander Yermolovich static void parseAndPopulateDebugLineStr(BinarySection &LineStrSection, 1628014cd37fSAlexander Yermolovich MCDwarfLineStr &LineStr, 1629014cd37fSAlexander Yermolovich BinaryContext &BC, 1630014cd37fSAlexander Yermolovich MCStreamer &Streamer) { 1631014cd37fSAlexander Yermolovich DataExtractor StrData(LineStrSection.getContents(), 1632014cd37fSAlexander Yermolovich BC.DwCtx->isLittleEndian(), 0); 1633014cd37fSAlexander Yermolovich uint64_t Offset = 0; 1634014cd37fSAlexander Yermolovich while (StrData.isValidOffset(Offset)) { 1635014cd37fSAlexander Yermolovich Error Err = Error::success(); 1636014cd37fSAlexander Yermolovich const char *CStr = StrData.getCStr(&Offset, &Err); 1637014cd37fSAlexander Yermolovich if (Err) { 1638014cd37fSAlexander Yermolovich errs() << "BOLT-ERROR: could not extract string from .debug_line_str"; 1639014cd37fSAlexander Yermolovich continue; 1640014cd37fSAlexander Yermolovich } 1641014cd37fSAlexander Yermolovich LineStr.emitRef(&Streamer, CStr); 1642014cd37fSAlexander Yermolovich } 1643014cd37fSAlexander Yermolovich } 1644014cd37fSAlexander Yermolovich 1645a34c753fSRafael Auler void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) { 1646a34c753fSRafael Auler MCAssembler &Assembler = 1647a34c753fSRafael Auler static_cast<MCObjectStreamer *>(&Streamer)->getAssembler(); 1648a34c753fSRafael Auler 1649a34c753fSRafael Auler MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams(); 1650a34c753fSRafael Auler 1651a34c753fSRafael Auler auto &LineTables = BC.getDwarfLineTables(); 1652a34c753fSRafael Auler 1653a34c753fSRafael Auler // Bail out early so we don't switch to the debug_line section needlessly and 1654a34c753fSRafael Auler // in doing so create an unnecessary (if empty) section. 1655a34c753fSRafael Auler if (LineTables.empty()) 1656a34c753fSRafael Auler return; 1657a34c753fSRafael Auler // In a v5 non-split line table, put the strings in a separate section. 1658f4c16c44SFangrui Song std::optional<MCDwarfLineStr> LineStr; 1659014cd37fSAlexander Yermolovich ErrorOr<BinarySection &> LineStrSection = 1660014cd37fSAlexander Yermolovich BC.getUniqueSectionByName(".debug_line_str"); 1661014cd37fSAlexander Yermolovich // Some versions of GCC output DWARF5 .debug_info, but DWARF4 or lower 1662014cd37fSAlexander Yermolovich // .debug_line 1663014cd37fSAlexander Yermolovich if (LineStrSection) { 166453113515SFangrui Song LineStr.emplace(*BC.Ctx); 1665014cd37fSAlexander Yermolovich parseAndPopulateDebugLineStr(*LineStrSection, *LineStr, BC, Streamer); 1666014cd37fSAlexander Yermolovich } 1667a34c753fSRafael Auler 1668a34c753fSRafael Auler // Switch to the section where the table will be emitted into. 1669adf4142fSFangrui Song Streamer.switchSection(BC.MOFI->getDwarfLineSection()); 1670a34c753fSRafael Auler 1671014cd37fSAlexander Yermolovich const uint16_t DwarfVersion = BC.Ctx->getDwarfVersion(); 1672a34c753fSRafael Auler // Handle the rest of the Compile Units. 1673a34c753fSRafael Auler for (auto &CUIDTablePair : LineTables) { 1674014cd37fSAlexander Yermolovich Streamer.getContext().setDwarfVersion( 1675014cd37fSAlexander Yermolovich CUIDTablePair.second.getDwarfVersion()); 1676b73c87bcSMaksim Panchenko CUIDTablePair.second.emitCU(&Streamer, Params, LineStr, BC); 1677a34c753fSRafael Auler } 1678014cd37fSAlexander Yermolovich 1679014cd37fSAlexander Yermolovich // Resetting DWARF version for rest of the flow. 1680014cd37fSAlexander Yermolovich BC.Ctx->setDwarfVersion(DwarfVersion); 1681014cd37fSAlexander Yermolovich 1682014cd37fSAlexander Yermolovich // Still need to write the section out for the ExecutionEngine, and temp in 1683014cd37fSAlexander Yermolovich // memory object we are constructing. 1684014cd37fSAlexander Yermolovich if (LineStr) { 1685014cd37fSAlexander Yermolovich LineStr->emitSection(&Streamer); 1686014cd37fSAlexander Yermolovich SmallString<0> Data = LineStr->getFinalizedData(); 1687014cd37fSAlexander Yermolovich BC.registerOrUpdateNoteSection(".debug_line_str", copyByteArray(Data.str()), 1688014cd37fSAlexander Yermolovich Data.size()); 1689014cd37fSAlexander Yermolovich } 1690a34c753fSRafael Auler } 1691a34c753fSRafael Auler 1692a34c753fSRafael Auler } // namespace bolt 1693a34c753fSRafael Auler } // namespace llvm 1694