1//===- bolt/Core/DebugData.cpp - Debugging information handling -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements functions and classes for handling debug info.
10//
11//===----------------------------------------------------------------------===//
12
13#include "bolt/Core/DebugData.h"
14#include "bolt/Core/BinaryContext.h"
15#include "bolt/Core/DIEBuilder.h"
16#include "bolt/Utils/Utils.h"
17#include "llvm/BinaryFormat/Dwarf.h"
18#include "llvm/CodeGen/DIE.h"
19#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
20#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
21#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
22#include "llvm/MC/MCAssembler.h"
23#include "llvm/MC/MCContext.h"
24#include "llvm/MC/MCObjectStreamer.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/EndianStream.h"
27#include "llvm/Support/LEB128.h"
28#include "llvm/Support/SHA1.h"
29#include <algorithm>
30#include <cassert>
31#include <cstdint>
32#include <functional>
33#include <memory>
34#include <unordered_map>
35#include <vector>
36
37#define DEBUG_TYPE "bolt-debug-info"
38
39namespace opts {
40extern llvm::cl::opt<unsigned> Verbosity;
41} // namespace opts
42
43namespace llvm {
44class MCSymbol;
45
46namespace bolt {
47
48static void replaceLocValbyForm(DIEBuilder &DIEBldr, DIE &Die, DIEValue DIEVal,
49 dwarf::Form Format, uint64_t NewVal) {
50 if (Format == dwarf::DW_FORM_loclistx)
51 DIEBldr.replaceValue(Die: &Die, Attribute: DIEVal.getAttribute(), Form: Format,
52 NewValue: DIELocList(NewVal));
53 else
54 DIEBldr.replaceValue(Die: &Die, Attribute: DIEVal.getAttribute(), Form: Format,
55 NewValue: DIEInteger(NewVal));
56}
57
58std::optional<AttrInfo>
59findAttributeInfo(const DWARFDie DIE,
60 const DWARFAbbreviationDeclaration *AbbrevDecl,
61 uint32_t Index) {
62 const DWARFUnit &U = *DIE.getDwarfUnit();
63 uint64_t Offset =
64 AbbrevDecl->getAttributeOffsetFromIndex(AttrIndex: Index, DIEOffset: DIE.getOffset(), U);
65 std::optional<DWARFFormValue> Value =
66 AbbrevDecl->getAttributeValueFromOffset(AttrIndex: Index, Offset, U);
67 if (!Value)
68 return std::nullopt;
69 // AttributeSpec
70 const DWARFAbbreviationDeclaration::AttributeSpec *AttrVal =
71 AbbrevDecl->attributes().begin() + Index;
72 uint32_t ValSize = 0;
73 std::optional<int64_t> ValSizeOpt = AttrVal->getByteSize(U);
74 if (ValSizeOpt) {
75 ValSize = static_cast<uint32_t>(*ValSizeOpt);
76 } else {
77 DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
78 uint64_t NewOffset = Offset;
79 DWARFFormValue::skipValue(Form: Value->getForm(), DebugInfoData, OffsetPtr: &NewOffset,
80 FormParams: U.getFormParams());
81 // This includes entire size of the entry, which might not be just the
82 // encoding part. For example for DW_AT_loc it will include expression
83 // location.
84 ValSize = NewOffset - Offset;
85 }
86 return AttrInfo{.V: *Value, .AbbrevDecl: DIE.getAbbreviationDeclarationPtr(), .Offset: Offset, .Size: ValSize};
87}
88
89std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
90 dwarf::Attribute Attr) {
91 if (!DIE.isValid())
92 return std::nullopt;
93 const DWARFAbbreviationDeclaration *AbbrevDecl =
94 DIE.getAbbreviationDeclarationPtr();
95 if (!AbbrevDecl)
96 return std::nullopt;
97 std::optional<uint32_t> Index = AbbrevDecl->findAttributeIndex(attr: Attr);
98 if (!Index)
99 return std::nullopt;
100 return findAttributeInfo(DIE, AbbrevDecl, Index: *Index);
101}
102
103const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{.DwCompileUnitIndex: 0, .RowIndex: 0};
104
105LLVM_ATTRIBUTE_UNUSED
106static void printLE64(const std::string &S) {
107 for (uint32_t I = 0, Size = S.size(); I < Size; ++I) {
108 errs() << Twine::utohexstr(Val: S[I]);
109 errs() << Twine::utohexstr(Val: (int8_t)S[I]);
110 }
111 errs() << "\n";
112}
113
114// Writes address ranges to Writer as pairs of 64-bit (address, size).
115// If RelativeRange is true, assumes the address range to be written must be of
116// the form (begin address, range size), otherwise (begin address, end address).
117// Terminates the list by writing a pair of two zeroes.
118// Returns the number of written bytes.
119static uint64_t
120writeAddressRanges(raw_svector_ostream &Stream,
121 const DebugAddressRangesVector &AddressRanges,
122 const bool WriteRelativeRanges = false) {
123 for (const DebugAddressRange &Range : AddressRanges) {
124 support::endian::write(os&: Stream, value: Range.LowPC, endian: llvm::endianness::little);
125 support::endian::write(
126 os&: Stream, value: WriteRelativeRanges ? Range.HighPC - Range.LowPC : Range.HighPC,
127 endian: llvm::endianness::little);
128 }
129 // Finish with 0 entries.
130 support::endian::write(os&: Stream, value: 0ULL, endian: llvm::endianness::little);
131 support::endian::write(os&: Stream, value: 0ULL, endian: llvm::endianness::little);
132 return AddressRanges.size() * 16 + 16;
133}
134
135DebugRangesSectionWriter::DebugRangesSectionWriter() {
136 RangesBuffer = std::make_unique<DebugBufferVector>();
137 RangesStream = std::make_unique<raw_svector_ostream>(args&: *RangesBuffer);
138
139 // Add an empty range as the first entry;
140 SectionOffset +=
141 writeAddressRanges(Stream&: *RangesStream.get(), AddressRanges: DebugAddressRangesVector{});
142 Kind = RangesWriterKind::DebugRangesWriter;
143}
144
145uint64_t DebugRangesSectionWriter::addRanges(
146 DebugAddressRangesVector &&Ranges,
147 std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) {
148 if (Ranges.empty())
149 return getEmptyRangesOffset();
150
151 const auto RI = CachedRanges.find(x: Ranges);
152 if (RI != CachedRanges.end())
153 return RI->second;
154
155 const uint64_t EntryOffset = addRanges(Ranges);
156 CachedRanges.emplace(args: std::move(Ranges), args: EntryOffset);
157
158 return EntryOffset;
159}
160
161uint64_t DebugRangesSectionWriter::addRanges(DebugAddressRangesVector &Ranges) {
162 if (Ranges.empty())
163 return getEmptyRangesOffset();
164
165 // Reading the SectionOffset and updating it should be atomic to guarantee
166 // unique and correct offsets in patches.
167 std::lock_guard<std::mutex> Lock(WriterMutex);
168 const uint32_t EntryOffset = SectionOffset;
169 SectionOffset += writeAddressRanges(Stream&: *RangesStream.get(), AddressRanges: Ranges);
170
171 return EntryOffset;
172}
173
174uint64_t DebugRangesSectionWriter::getSectionOffset() {
175 std::lock_guard<std::mutex> Lock(WriterMutex);
176 return SectionOffset;
177}
178
179DebugAddrWriter *DebugRangeListsSectionWriter::AddrWriter = nullptr;
180
181uint64_t DebugRangeListsSectionWriter::addRanges(
182 DebugAddressRangesVector &&Ranges,
183 std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) {
184 return addRanges(Ranges);
185}
186
187struct LocListsRangelistsHeader {
188 UnitLengthType UnitLength; // Size of loclist entries section, not including
189 // size of header.
190 VersionType Version;
191 AddressSizeType AddressSize;
192 SegmentSelectorType SegmentSelector;
193 OffsetEntryCountType OffsetEntryCount;
194};
195
196static std::unique_ptr<DebugBufferVector>
197getDWARF5Header(const LocListsRangelistsHeader &Header) {
198 std::unique_ptr<DebugBufferVector> HeaderBuffer =
199 std::make_unique<DebugBufferVector>();
200 std::unique_ptr<raw_svector_ostream> HeaderStream =
201 std::make_unique<raw_svector_ostream>(args&: *HeaderBuffer);
202
203 // 7.29 length of the set of entries for this compilation unit, not including
204 // the length field itself
205 const uint32_t HeaderSize =
206 getDWARF5RngListLocListHeaderSize() - sizeof(UnitLengthType);
207
208 support::endian::write(os&: *HeaderStream, value: Header.UnitLength + HeaderSize,
209 endian: llvm::endianness::little);
210 support::endian::write(os&: *HeaderStream, value: Header.Version,
211 endian: llvm::endianness::little);
212 support::endian::write(os&: *HeaderStream, value: Header.AddressSize,
213 endian: llvm::endianness::little);
214 support::endian::write(os&: *HeaderStream, value: Header.SegmentSelector,
215 endian: llvm::endianness::little);
216 support::endian::write(os&: *HeaderStream, value: Header.OffsetEntryCount,
217 endian: llvm::endianness::little);
218 return HeaderBuffer;
219}
220
221struct OffsetEntry {
222 uint32_t Index;
223 uint32_t StartOffset;
224 uint32_t EndOffset;
225};
226template <typename DebugVector, typename ListEntry, typename DebugAddressEntry>
227static bool emitWithBase(raw_ostream &OS, const DebugVector &Entries,
228 DebugAddrWriter &AddrWriter, DWARFUnit &CU,
229 uint32_t &Index, const ListEntry BaseAddressx,
230 const ListEntry OffsetPair,
231 const std::function<void(uint32_t)> &Func) {
232 if (Entries.size() < 2)
233 return false;
234 uint64_t Base = Entries[Index].LowPC;
235 std::vector<OffsetEntry> Offsets;
236 uint8_t TempBuffer[64];
237 while (Index < Entries.size()) {
238 const DebugAddressEntry &Entry = Entries[Index];
239 if (Entry.LowPC == 0)
240 break;
241 // In case rnglists or loclists are not sorted.
242 if (Base > Entry.LowPC)
243 break;
244 uint32_t StartOffset = Entry.LowPC - Base;
245 uint32_t EndOffset = Entry.HighPC - Base;
246 if (encodeULEB128(Value: EndOffset, p: TempBuffer) > 2)
247 break;
248 Offsets.push_back(x: {.Index: Index, .StartOffset: StartOffset, .EndOffset: EndOffset});
249 ++Index;
250 }
251
252 if (Offsets.size() < 2) {
253 Index -= Offsets.size();
254 return false;
255 }
256
257 support::endian::write(os&: OS, value: static_cast<uint8_t>(BaseAddressx),
258 endian: llvm::endianness::little);
259 uint32_t BaseIndex = AddrWriter.getIndexFromAddress(Address: Base, CU);
260 encodeULEB128(Value: BaseIndex, OS);
261 for (auto &OffsetEntry : Offsets) {
262 support::endian::write(os&: OS, value: static_cast<uint8_t>(OffsetPair),
263 endian: llvm::endianness::little);
264 encodeULEB128(Value: OffsetEntry.StartOffset, OS);
265 encodeULEB128(Value: OffsetEntry.EndOffset, OS);
266 Func(OffsetEntry.Index);
267 }
268 return true;
269}
270
271uint64_t
272DebugRangeListsSectionWriter::addRanges(DebugAddressRangesVector &Ranges) {
273 std::lock_guard<std::mutex> Lock(WriterMutex);
274
275 RangeEntries.push_back(Elt: CurrentOffset);
276 std::sort(
277 first: Ranges.begin(), last: Ranges.end(),
278 comp: [](const DebugAddressRange &R1, const DebugAddressRange &R2) -> bool {
279 return R1.LowPC < R2.LowPC;
280 });
281 for (unsigned I = 0; I < Ranges.size();) {
282 if (emitWithBase<DebugAddressRangesVector, dwarf::RnglistEntries,
283 DebugAddressRange>(OS&: *CUBodyStream, Entries: Ranges, AddrWriter&: *AddrWriter, CU&: *CU,
284 Index&: I, BaseAddressx: dwarf::DW_RLE_base_addressx,
285 OffsetPair: dwarf::DW_RLE_offset_pair,
286 Func: [](uint32_t Index) -> void {}))
287 continue;
288
289 const DebugAddressRange &Range = Ranges[I];
290 support::endian::write(os&: *CUBodyStream,
291 value: static_cast<uint8_t>(dwarf::DW_RLE_startx_length),
292 endian: llvm::endianness::little);
293 uint32_t Index = AddrWriter->getIndexFromAddress(Address: Range.LowPC, CU&: *CU);
294 encodeULEB128(Value: Index, OS&: *CUBodyStream);
295 encodeULEB128(Value: Range.HighPC - Range.LowPC, OS&: *CUBodyStream);
296 ++I;
297 }
298
299 support::endian::write(os&: *CUBodyStream,
300 value: static_cast<uint8_t>(dwarf::DW_RLE_end_of_list),
301 endian: llvm::endianness::little);
302 CurrentOffset = CUBodyBuffer->size();
303 return RangeEntries.size() - 1;
304}
305
306void DebugRangeListsSectionWriter::finalizeSection() {
307 std::unique_ptr<DebugBufferVector> CUArrayBuffer =
308 std::make_unique<DebugBufferVector>();
309 std::unique_ptr<raw_svector_ostream> CUArrayStream =
310 std::make_unique<raw_svector_ostream>(args&: *CUArrayBuffer);
311 constexpr uint32_t SizeOfArrayEntry = 4;
312 const uint32_t SizeOfArraySection = RangeEntries.size() * SizeOfArrayEntry;
313 for (uint32_t Offset : RangeEntries)
314 support::endian::write(os&: *CUArrayStream, value: Offset + SizeOfArraySection,
315 endian: llvm::endianness::little);
316
317 std::unique_ptr<DebugBufferVector> Header = getDWARF5Header(
318 Header: {.UnitLength: static_cast<uint32_t>(SizeOfArraySection + CUBodyBuffer.get()->size()),
319 .Version: 5, .AddressSize: 8, .SegmentSelector: 0, .OffsetEntryCount: static_cast<uint32_t>(RangeEntries.size())});
320 *RangesStream << *Header;
321 *RangesStream << *CUArrayBuffer;
322 *RangesStream << *CUBodyBuffer;
323 SectionOffset = RangesBuffer->size();
324}
325
326void DebugRangeListsSectionWriter::initSection(DWARFUnit &Unit) {
327 CUBodyBuffer = std::make_unique<DebugBufferVector>();
328 CUBodyStream = std::make_unique<raw_svector_ostream>(args&: *CUBodyBuffer);
329 RangeEntries.clear();
330 CurrentOffset = 0;
331 CU = &Unit;
332}
333
334void DebugARangesSectionWriter::addCURanges(uint64_t CUOffset,
335 DebugAddressRangesVector &&Ranges) {
336 std::lock_guard<std::mutex> Lock(CUAddressRangesMutex);
337 CUAddressRanges.emplace(args&: CUOffset, args: std::move(Ranges));
338}
339
340void DebugARangesSectionWriter::writeARangesSection(
341 raw_svector_ostream &RangesStream, const CUOffsetMap &CUMap) const {
342 // For reference on the format of the .debug_aranges section, see the DWARF4
343 // specification, section 6.1.4 Lookup by Address
344 // http://www.dwarfstd.org/doc/DWARF4.pdf
345 for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) {
346 const uint64_t Offset = CUOffsetAddressRangesPair.first;
347 const DebugAddressRangesVector &AddressRanges =
348 CUOffsetAddressRangesPair.second;
349
350 // Emit header.
351
352 // Size of this set: 8 (size of the header) + 4 (padding after header)
353 // + 2*sizeof(uint64_t) bytes for each of the ranges, plus an extra
354 // pair of uint64_t's for the terminating, zero-length range.
355 // Does not include size field itself.
356 uint32_t Size = 8 + 4 + 2 * sizeof(uint64_t) * (AddressRanges.size() + 1);
357
358 // Header field #1: set size.
359 support::endian::write(os&: RangesStream, value: Size, endian: llvm::endianness::little);
360
361 // Header field #2: version number, 2 as per the specification.
362 support::endian::write(os&: RangesStream, value: static_cast<uint16_t>(2),
363 endian: llvm::endianness::little);
364
365 assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map");
366 // Header field #3: debug info offset of the correspondent compile unit.
367 support::endian::write(
368 os&: RangesStream, value: static_cast<uint32_t>(CUMap.find(x: Offset)->second.Offset),
369 endian: llvm::endianness::little);
370
371 // Header field #4: address size.
372 // 8 since we only write ELF64 binaries for now.
373 RangesStream << char(8);
374
375 // Header field #5: segment size of target architecture.
376 RangesStream << char(0);
377
378 // Padding before address table - 4 bytes in the 64-bit-pointer case.
379 support::endian::write(os&: RangesStream, value: static_cast<uint32_t>(0),
380 endian: llvm::endianness::little);
381
382 writeAddressRanges(Stream&: RangesStream, AddressRanges, WriteRelativeRanges: true);
383 }
384}
385
386DebugAddrWriter::DebugAddrWriter(BinaryContext *BC) : BC(BC) {
387 Buffer = std::make_unique<AddressSectionBuffer>();
388 AddressStream = std::make_unique<raw_svector_ostream>(args&: *Buffer);
389}
390
391void DebugAddrWriter::AddressForDWOCU::dump() {
392 std::vector<IndexAddressPair> SortedMap(indexToAddressBegin(),
393 indexToAdddessEnd());
394 // Sorting address in increasing order of indices.
395 llvm::sort(C&: SortedMap, Comp: llvm::less_first());
396 for (auto &Pair : SortedMap)
397 dbgs() << Twine::utohexstr(Val: Pair.second) << "\t" << Pair.first << "\n";
398}
399uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, DWARFUnit &CU) {
400 std::lock_guard<std::mutex> Lock(WriterMutex);
401 const uint64_t CUID = getCUID(Unit&: CU);
402 if (!AddressMaps.count(x: CUID))
403 AddressMaps[CUID] = AddressForDWOCU();
404
405 AddressForDWOCU &Map = AddressMaps[CUID];
406 auto Entry = Map.find(Address);
407 if (Entry == Map.end()) {
408 auto Index = Map.getNextIndex();
409 Entry = Map.insert(Address, Index).first;
410 }
411 return Entry->second;
412}
413
414static void updateAddressBase(DIEBuilder &DIEBlder, DebugAddrWriter &AddrWriter,
415 DWARFUnit &CU, const uint64_t Offset) {
416 DIE *Die = DIEBlder.getUnitDIEbyUnit(DU: CU);
417 DIEValue GnuAddrBaseAttrInfo = Die->findAttribute(Attribute: dwarf::DW_AT_GNU_addr_base);
418 DIEValue AddrBaseAttrInfo = Die->findAttribute(Attribute: dwarf::DW_AT_addr_base);
419 dwarf::Form BaseAttrForm;
420 dwarf::Attribute BaseAttr;
421 // For cases where Skeleton CU does not have DW_AT_GNU_addr_base
422 if (!GnuAddrBaseAttrInfo && CU.getVersion() < 5)
423 return;
424
425 if (GnuAddrBaseAttrInfo) {
426 BaseAttrForm = GnuAddrBaseAttrInfo.getForm();
427 BaseAttr = GnuAddrBaseAttrInfo.getAttribute();
428 }
429
430 if (AddrBaseAttrInfo) {
431 BaseAttrForm = AddrBaseAttrInfo.getForm();
432 BaseAttr = AddrBaseAttrInfo.getAttribute();
433 }
434
435 if (GnuAddrBaseAttrInfo || AddrBaseAttrInfo) {
436 DIEBlder.replaceValue(Die, Attribute: BaseAttr, Form: BaseAttrForm, NewValue: DIEInteger(Offset));
437 } else if (CU.getVersion() >= 5) {
438 // A case where we were not using .debug_addr section, but after update
439 // now using it.
440 DIEBlder.addValue(Die, Attribute: dwarf::DW_AT_addr_base, Form: dwarf::DW_FORM_sec_offset,
441 Value: DIEInteger(Offset));
442 }
443}
444
445void DebugAddrWriter::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
446 // Handling the case where debug information is a mix of Debug fission and
447 // monolithic.
448 if (!CU.getDWOId())
449 return;
450 const uint64_t CUID = getCUID(Unit&: CU);
451 auto AM = AddressMaps.find(x: CUID);
452 // Adding to map even if it did not contribute to .debug_addr.
453 // The Skeleton CU might still have DW_AT_GNU_addr_base.
454 uint64_t Offset = Buffer->size();
455 // If does not exist this CUs DWO section didn't contribute to .debug_addr.
456 if (AM == AddressMaps.end())
457 return;
458 std::vector<IndexAddressPair> SortedMap(AM->second.indexToAddressBegin(),
459 AM->second.indexToAdddessEnd());
460 // Sorting address in increasing order of indices.
461 llvm::sort(C&: SortedMap, Comp: llvm::less_first());
462
463 uint8_t AddrSize = CU.getAddressByteSize();
464 uint32_t Counter = 0;
465 auto WriteAddress = [&](uint64_t Address) -> void {
466 ++Counter;
467 switch (AddrSize) {
468 default:
469 assert(false && "Address Size is invalid.");
470 break;
471 case 4:
472 support::endian::write(os&: *AddressStream, value: static_cast<uint32_t>(Address),
473 endian: llvm::endianness::little);
474 break;
475 case 8:
476 support::endian::write(os&: *AddressStream, value: Address, endian: llvm::endianness::little);
477 break;
478 }
479 };
480
481 for (const IndexAddressPair &Val : SortedMap) {
482 while (Val.first > Counter)
483 WriteAddress(0);
484 WriteAddress(Val.second);
485 }
486 updateAddressBase(DIEBlder, AddrWriter&: *this, CU, Offset);
487}
488
489void DebugAddrWriterDwarf5::update(DIEBuilder &DIEBlder, DWARFUnit &CU) {
490 // Need to layout all sections within .debug_addr
491 // Within each section sort Address by index.
492 const endianness Endian = BC->DwCtx->isLittleEndian()
493 ? llvm::endianness::little
494 : llvm::endianness::big;
495 const DWARFSection &AddrSec = BC->DwCtx->getDWARFObj().getAddrSection();
496 DWARFDataExtractor AddrData(BC->DwCtx->getDWARFObj(), AddrSec,
497 Endian == llvm::endianness::little, 0);
498 DWARFDebugAddrTable AddrTable;
499 DIDumpOptions DumpOpts;
500 constexpr uint32_t HeaderSize = 8;
501 const uint64_t CUID = getCUID(Unit&: CU);
502 const uint8_t AddrSize = CU.getAddressByteSize();
503 auto AMIter = AddressMaps.find(x: CUID);
504 // A case where CU has entry in .debug_addr, but we don't modify addresses
505 // for it.
506 if (AMIter == AddressMaps.end()) {
507 AMIter = AddressMaps.insert(x: {CUID, AddressForDWOCU()}).first;
508 std::optional<uint64_t> BaseOffset = CU.getAddrOffsetSectionBase();
509 if (!BaseOffset)
510 return;
511 // Address base offset is to the first entry.
512 // The size of header is 8 bytes.
513 uint64_t Offset = *BaseOffset - HeaderSize;
514 auto Iter = UnmodifiedAddressOffsets.find(Val: Offset);
515 if (Iter != UnmodifiedAddressOffsets.end()) {
516 updateAddressBase(DIEBlder, AddrWriter&: *this, CU, Offset: Iter->getSecond());
517 return;
518 }
519 UnmodifiedAddressOffsets[Offset] = Buffer->size() + HeaderSize;
520 if (Error Err = AddrTable.extract(Data: AddrData, OffsetPtr: &Offset, CUVersion: 5, CUAddrSize: AddrSize,
521 WarnCallback: DumpOpts.WarningHandler)) {
522 DumpOpts.RecoverableErrorHandler(std::move(Err));
523 return;
524 }
525
526 uint32_t Index = 0;
527 for (uint64_t Addr : AddrTable.getAddressEntries())
528 AMIter->second.insert(Address: Addr, Index: Index++);
529 }
530
531 updateAddressBase(DIEBlder, AddrWriter&: *this, CU, Offset: Buffer->size() + HeaderSize);
532
533 std::vector<IndexAddressPair> SortedMap(AMIter->second.indexToAddressBegin(),
534 AMIter->second.indexToAdddessEnd());
535 // Sorting address in increasing order of indices.
536 llvm::sort(C&: SortedMap, Comp: llvm::less_first());
537 // Writing out Header
538 const uint32_t Length = SortedMap.size() * AddrSize + 4;
539 support::endian::write(os&: *AddressStream, value: Length, endian: Endian);
540 support::endian::write(os&: *AddressStream, value: static_cast<uint16_t>(5), endian: Endian);
541 support::endian::write(os&: *AddressStream, value: static_cast<uint8_t>(AddrSize),
542 endian: Endian);
543 support::endian::write(os&: *AddressStream, value: static_cast<uint8_t>(0), endian: Endian);
544
545 uint32_t Counter = 0;
546 auto writeAddress = [&](uint64_t Address) -> void {
547 ++Counter;
548 switch (AddrSize) {
549 default:
550 llvm_unreachable("Address Size is invalid.");
551 break;
552 case 4:
553 support::endian::write(os&: *AddressStream, value: static_cast<uint32_t>(Address),
554 endian: Endian);
555 break;
556 case 8:
557 support::endian::write(os&: *AddressStream, value: Address, endian: Endian);
558 break;
559 }
560 };
561
562 for (const IndexAddressPair &Val : SortedMap) {
563 while (Val.first > Counter)
564 writeAddress(0);
565 writeAddress(Val.second);
566 }
567}
568
569void DebugLocWriter::init() {
570 LocBuffer = std::make_unique<DebugBufferVector>();
571 LocStream = std::make_unique<raw_svector_ostream>(args&: *LocBuffer);
572 // Writing out empty location list to which all references to empty location
573 // lists will point.
574 if (!LocSectionOffset && DwarfVersion < 5) {
575 const char Zeroes[16] = {0};
576 *LocStream << StringRef(Zeroes, 16);
577 LocSectionOffset += 16;
578 }
579}
580
581uint32_t DebugLocWriter::LocSectionOffset = 0;
582void DebugLocWriter::addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
583 DebugLocationsVector &LocList) {
584 if (LocList.empty()) {
585 replaceLocValbyForm(DIEBldr, Die, DIEVal: AttrInfo, Format: AttrInfo.getForm(),
586 NewVal: DebugLocWriter::EmptyListOffset);
587 return;
588 }
589 // Since there is a separate DebugLocWriter for each thread,
590 // we don't need a lock to read the SectionOffset and update it.
591 const uint32_t EntryOffset = LocSectionOffset;
592
593 for (const DebugLocationEntry &Entry : LocList) {
594 support::endian::write(os&: *LocStream, value: static_cast<uint64_t>(Entry.LowPC),
595 endian: llvm::endianness::little);
596 support::endian::write(os&: *LocStream, value: static_cast<uint64_t>(Entry.HighPC),
597 endian: llvm::endianness::little);
598 support::endian::write(os&: *LocStream, value: static_cast<uint16_t>(Entry.Expr.size()),
599 endian: llvm::endianness::little);
600 *LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()),
601 Entry.Expr.size());
602 LocSectionOffset += 2 * 8 + 2 + Entry.Expr.size();
603 }
604 LocStream->write_zeros(NumZeros: 16);
605 LocSectionOffset += 16;
606 LocListDebugInfoPatches.push_back(x: {.DebugInfoAttrOffset: 0xdeadbeee, .LocListOffset: EntryOffset}); // never seen
607 // use
608 replaceLocValbyForm(DIEBldr, Die, DIEVal: AttrInfo, Format: AttrInfo.getForm(), NewVal: EntryOffset);
609}
610
611std::unique_ptr<DebugBufferVector> DebugLocWriter::getBuffer() {
612 return std::move(LocBuffer);
613}
614
615// DWARF 4: 2.6.2
616void DebugLocWriter::finalize(DIEBuilder &DIEBldr, DIE &Die) {}
617
618static void writeEmptyListDwarf5(raw_svector_ostream &Stream) {
619 support::endian::write(os&: Stream, value: static_cast<uint32_t>(4),
620 endian: llvm::endianness::little);
621 support::endian::write(os&: Stream, value: static_cast<uint8_t>(dwarf::DW_LLE_start_end),
622 endian: llvm::endianness::little);
623
624 const char Zeroes[16] = {0};
625 Stream << StringRef(Zeroes, 16);
626 encodeULEB128(Value: 0, OS&: Stream);
627 support::endian::write(os&: Stream,
628 value: static_cast<uint8_t>(dwarf::DW_LLE_end_of_list),
629 endian: llvm::endianness::little);
630}
631
632static void writeLegacyLocList(DIEValue &AttrInfo,
633 DebugLocationsVector &LocList,
634 DIEBuilder &DIEBldr, DIE &Die,
635 DebugAddrWriter &AddrWriter,
636 DebugBufferVector &LocBuffer, DWARFUnit &CU,
637 raw_svector_ostream &LocStream) {
638 if (LocList.empty()) {
639 replaceLocValbyForm(DIEBldr, Die, DIEVal: AttrInfo, Format: AttrInfo.getForm(),
640 NewVal: DebugLocWriter::EmptyListOffset);
641 return;
642 }
643
644 const uint32_t EntryOffset = LocBuffer.size();
645 for (const DebugLocationEntry &Entry : LocList) {
646 support::endian::write(os&: LocStream,
647 value: static_cast<uint8_t>(dwarf::DW_LLE_startx_length),
648 endian: llvm::endianness::little);
649 const uint32_t Index = AddrWriter.getIndexFromAddress(Address: Entry.LowPC, CU);
650 encodeULEB128(Value: Index, OS&: LocStream);
651
652 support::endian::write(os&: LocStream,
653 value: static_cast<uint32_t>(Entry.HighPC - Entry.LowPC),
654 endian: llvm::endianness::little);
655 support::endian::write(os&: LocStream, value: static_cast<uint16_t>(Entry.Expr.size()),
656 endian: llvm::endianness::little);
657 LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()),
658 Entry.Expr.size());
659 }
660 support::endian::write(os&: LocStream,
661 value: static_cast<uint8_t>(dwarf::DW_LLE_end_of_list),
662 endian: llvm::endianness::little);
663 replaceLocValbyForm(DIEBldr, Die, DIEVal: AttrInfo, Format: AttrInfo.getForm(), NewVal: EntryOffset);
664}
665
666static void writeDWARF5LocList(uint32_t &NumberOfEntries, DIEValue &AttrInfo,
667 DebugLocationsVector &LocList, DIE &Die,
668 DIEBuilder &DIEBldr, DebugAddrWriter &AddrWriter,
669 DebugBufferVector &LocBodyBuffer,
670 std::vector<uint32_t> &RelativeLocListOffsets,
671 DWARFUnit &CU,
672 raw_svector_ostream &LocBodyStream) {
673
674 replaceLocValbyForm(DIEBldr, Die, DIEVal: AttrInfo, Format: dwarf::DW_FORM_loclistx,
675 NewVal: NumberOfEntries);
676
677 RelativeLocListOffsets.push_back(x: LocBodyBuffer.size());
678 ++NumberOfEntries;
679 if (LocList.empty()) {
680 writeEmptyListDwarf5(Stream&: LocBodyStream);
681 return;
682 }
683
684 std::vector<uint64_t> OffsetsArray;
685 auto writeExpression = [&](uint32_t Index) -> void {
686 const DebugLocationEntry &Entry = LocList[Index];
687 encodeULEB128(Value: Entry.Expr.size(), OS&: LocBodyStream);
688 LocBodyStream << StringRef(
689 reinterpret_cast<const char *>(Entry.Expr.data()), Entry.Expr.size());
690 };
691 for (unsigned I = 0; I < LocList.size();) {
692 if (emitWithBase<DebugLocationsVector, dwarf::LoclistEntries,
693 DebugLocationEntry>(OS&: LocBodyStream, Entries: LocList, AddrWriter, CU,
694 Index&: I, BaseAddressx: dwarf::DW_LLE_base_addressx,
695 OffsetPair: dwarf::DW_LLE_offset_pair,
696 Func: writeExpression))
697 continue;
698
699 const DebugLocationEntry &Entry = LocList[I];
700 support::endian::write(os&: LocBodyStream,
701 value: static_cast<uint8_t>(dwarf::DW_LLE_startx_length),
702 endian: llvm::endianness::little);
703 const uint32_t Index = AddrWriter.getIndexFromAddress(Address: Entry.LowPC, CU);
704 encodeULEB128(Value: Index, OS&: LocBodyStream);
705 encodeULEB128(Value: Entry.HighPC - Entry.LowPC, OS&: LocBodyStream);
706 writeExpression(I);
707 ++I;
708 }
709
710 support::endian::write(os&: LocBodyStream,
711 value: static_cast<uint8_t>(dwarf::DW_LLE_end_of_list),
712 endian: llvm::endianness::little);
713}
714
715void DebugLoclistWriter::addList(DIEBuilder &DIEBldr, DIE &Die,
716 DIEValue &AttrInfo,
717 DebugLocationsVector &LocList) {
718 if (DwarfVersion < 5)
719 writeLegacyLocList(AttrInfo, LocList, DIEBldr, Die, AddrWriter&: *AddrWriter, LocBuffer&: *LocBuffer,
720 CU, LocStream&: *LocStream);
721 else
722 writeDWARF5LocList(NumberOfEntries, AttrInfo, LocList, Die, DIEBldr,
723 AddrWriter&: *AddrWriter, LocBodyBuffer&: *LocBodyBuffer, RelativeLocListOffsets, CU,
724 LocBodyStream&: *LocBodyStream);
725}
726
727uint32_t DebugLoclistWriter::LoclistBaseOffset = 0;
728void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) {
729 if (LocBodyBuffer->empty()) {
730 DIEValue LocListBaseAttrInfo =
731 Die.findAttribute(Attribute: dwarf::DW_AT_loclists_base);
732 // Pointing to first one, because it doesn't matter. There are no uses of it
733 // in this CU.
734 if (!isSplitDwarf() && LocListBaseAttrInfo.getType())
735 DIEBldr.replaceValue(Die: &Die, Attribute: dwarf::DW_AT_loclists_base,
736 Form: LocListBaseAttrInfo.getForm(),
737 NewValue: DIEInteger(getDWARF5RngListLocListHeaderSize()));
738 return;
739 }
740
741 std::unique_ptr<DebugBufferVector> LocArrayBuffer =
742 std::make_unique<DebugBufferVector>();
743 std::unique_ptr<raw_svector_ostream> LocArrayStream =
744 std::make_unique<raw_svector_ostream>(args&: *LocArrayBuffer);
745
746 const uint32_t SizeOfArraySection = NumberOfEntries * sizeof(uint32_t);
747 // Write out IndexArray
748 for (uint32_t RelativeOffset : RelativeLocListOffsets)
749 support::endian::write(
750 os&: *LocArrayStream,
751 value: static_cast<uint32_t>(SizeOfArraySection + RelativeOffset),
752 endian: llvm::endianness::little);
753
754 std::unique_ptr<DebugBufferVector> Header = getDWARF5Header(
755 Header: {.UnitLength: static_cast<uint32_t>(SizeOfArraySection + LocBodyBuffer.get()->size()),
756 .Version: 5, .AddressSize: 8, .SegmentSelector: 0, .OffsetEntryCount: NumberOfEntries});
757 *LocStream << *Header;
758 *LocStream << *LocArrayBuffer;
759 *LocStream << *LocBodyBuffer;
760
761 if (!isSplitDwarf()) {
762 DIEValue LocListBaseAttrInfo =
763 Die.findAttribute(Attribute: dwarf::DW_AT_loclists_base);
764 if (LocListBaseAttrInfo.getType()) {
765 DIEBldr.replaceValue(
766 Die: &Die, Attribute: dwarf::DW_AT_loclists_base, Form: LocListBaseAttrInfo.getForm(),
767 NewValue: DIEInteger(LoclistBaseOffset + getDWARF5RngListLocListHeaderSize()));
768 } else {
769 DIEBldr.addValue(Die: &Die, Attribute: dwarf::DW_AT_loclists_base,
770 Form: dwarf::DW_FORM_sec_offset,
771 Value: DIEInteger(LoclistBaseOffset + Header->size()));
772 }
773 LoclistBaseOffset += LocBuffer->size();
774 }
775 clearList(List&: RelativeLocListOffsets);
776 clearList(List&: *LocArrayBuffer);
777 clearList(List&: *LocBodyBuffer);
778}
779
780void DebugLoclistWriter::finalize(DIEBuilder &DIEBldr, DIE &Die) {
781 if (DwarfVersion >= 5)
782 finalizeDWARF5(DIEBldr, Die);
783}
784
785DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr;
786
787static std::string encodeLE(size_t ByteSize, uint64_t NewValue) {
788 std::string LE64(ByteSize, 0);
789 for (size_t I = 0; I < ByteSize; ++I) {
790 LE64[I] = NewValue & 0xff;
791 NewValue >>= 8;
792 }
793 return LE64;
794}
795
796void SimpleBinaryPatcher::addBinaryPatch(uint64_t Offset,
797 std::string &&NewValue,
798 uint32_t OldValueSize) {
799 Patches.emplace_back(args&: Offset, args: std::move(NewValue));
800}
801
802void SimpleBinaryPatcher::addBytePatch(uint64_t Offset, uint8_t Value) {
803 auto Str = std::string(1, Value);
804 Patches.emplace_back(args&: Offset, args: std::move(Str));
805}
806
807void SimpleBinaryPatcher::addLEPatch(uint64_t Offset, uint64_t NewValue,
808 size_t ByteSize) {
809 Patches.emplace_back(args&: Offset, args: encodeLE(ByteSize, NewValue));
810}
811
812void SimpleBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t Value,
813 uint32_t OldValueSize) {
814 std::string Buff;
815 raw_string_ostream OS(Buff);
816 encodeULEB128(Value, OS, PadTo: OldValueSize);
817
818 Patches.emplace_back(args&: Offset, args: std::move(Buff));
819}
820
821void SimpleBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) {
822 addLEPatch(Offset, NewValue, ByteSize: 8);
823}
824
825void SimpleBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue,
826 uint32_t OldValueSize) {
827 addLEPatch(Offset, NewValue, ByteSize: 4);
828}
829
830std::string SimpleBinaryPatcher::patchBinary(StringRef BinaryContents) {
831 std::string BinaryContentsStr = std::string(BinaryContents);
832 for (const auto &Patch : Patches) {
833 uint32_t Offset = Patch.first;
834 const std::string &ByteSequence = Patch.second;
835 assert(Offset + ByteSequence.size() <= BinaryContents.size() &&
836 "Applied patch runs over binary size.");
837 for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I) {
838 BinaryContentsStr[Offset + I] = ByteSequence[I];
839 }
840 }
841 return BinaryContentsStr;
842}
843
844void DebugStrOffsetsWriter::initialize(DWARFUnit &Unit) {
845 if (Unit.getVersion() < 5)
846 return;
847 const DWARFSection &StrOffsetsSection = Unit.getStringOffsetSection();
848 const std::optional<StrOffsetsContributionDescriptor> &Contr =
849 Unit.getStringOffsetsTableContribution();
850 if (!Contr)
851 return;
852 const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize();
853 assert(DwarfOffsetByteSize == 4 &&
854 "Dwarf String Offsets Byte Size is not supported.");
855 StrOffsets.reserve(N: Contr->Size);
856 for (uint64_t Offset = 0; Offset < Contr->Size; Offset += DwarfOffsetByteSize)
857 StrOffsets.push_back(Elt: support::endian::read32le(
858 P: StrOffsetsSection.Data.data() + Contr->Base + Offset));
859}
860
861void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address) {
862 IndexToAddressMap[Index] = Address;
863 StrOffsetSectionWasModified = true;
864}
865
866void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit,
867 DIEBuilder &DIEBldr) {
868 std::optional<AttrInfo> AttrVal =
869 findAttributeInfo(DIE: Unit.getUnitDIE(), Attr: dwarf::DW_AT_str_offsets_base);
870 if (!AttrVal)
871 return;
872 std::optional<uint64_t> Val = AttrVal->V.getAsSectionOffset();
873 assert(Val && "DW_AT_str_offsets_base Value not present.");
874 DIE &Die = *DIEBldr.getUnitDIEbyUnit(DU: Unit);
875 DIEValue StrListBaseAttrInfo =
876 Die.findAttribute(Attribute: dwarf::DW_AT_str_offsets_base);
877 auto RetVal = ProcessedBaseOffsets.find(x: *Val);
878 // Handling re-use of str-offsets section.
879 if (RetVal == ProcessedBaseOffsets.end() || StrOffsetSectionWasModified) {
880 initialize(Unit);
881 // Update String Offsets that were modified.
882 for (const auto &Entry : IndexToAddressMap)
883 StrOffsets[Entry.first] = Entry.second;
884 // Writing out the header for each section.
885 support::endian::write(os&: *StrOffsetsStream,
886 value: static_cast<uint32_t>(StrOffsets.size() * 4 + 4),
887 endian: llvm::endianness::little);
888 support::endian::write(os&: *StrOffsetsStream, value: static_cast<uint16_t>(5),
889 endian: llvm::endianness::little);
890 support::endian::write(os&: *StrOffsetsStream, value: static_cast<uint16_t>(0),
891 endian: llvm::endianness::little);
892
893 uint64_t BaseOffset = StrOffsetsBuffer->size();
894 ProcessedBaseOffsets[*Val] = BaseOffset;
895 if (StrListBaseAttrInfo.getType())
896 DIEBldr.replaceValue(Die: &Die, Attribute: dwarf::DW_AT_str_offsets_base,
897 Form: StrListBaseAttrInfo.getForm(),
898 NewValue: DIEInteger(BaseOffset));
899 for (const uint32_t Offset : StrOffsets)
900 support::endian::write(os&: *StrOffsetsStream, value: Offset,
901 endian: llvm::endianness::little);
902 } else {
903 DIEBldr.replaceValue(Die: &Die, Attribute: dwarf::DW_AT_str_offsets_base,
904 Form: StrListBaseAttrInfo.getForm(),
905 NewValue: DIEInteger(RetVal->second));
906 }
907
908 StrOffsetSectionWasModified = false;
909 clear();
910}
911
912void DebugStrWriter::create() {
913 StrBuffer = std::make_unique<DebugStrBufferVector>();
914 StrStream = std::make_unique<raw_svector_ostream>(args&: *StrBuffer);
915}
916
917void DebugStrWriter::initialize() {
918 auto StrSection = BC.DwCtx->getDWARFObj().getStrSection();
919 (*StrStream) << StrSection;
920}
921
922uint32_t DebugStrWriter::addString(StringRef Str) {
923 std::lock_guard<std::mutex> Lock(WriterMutex);
924 if (StrBuffer->empty())
925 initialize();
926 auto Offset = StrBuffer->size();
927 (*StrStream) << Str;
928 StrStream->write_zeros(NumZeros: 1);
929 return Offset;
930}
931
932static void emitDwarfSetLineAddrAbs(MCStreamer &OS,
933 MCDwarfLineTableParams Params,
934 int64_t LineDelta, uint64_t Address,
935 int PointerSize) {
936 // emit the sequence to set the address
937 OS.emitIntValue(Value: dwarf::DW_LNS_extended_op, Size: 1);
938 OS.emitULEB128IntValue(Value: PointerSize + 1);
939 OS.emitIntValue(Value: dwarf::DW_LNE_set_address, Size: 1);
940 OS.emitIntValue(Value: Address, Size: PointerSize);
941
942 // emit the sequence for the LineDelta (from 1) and a zero address delta.
943 MCDwarfLineAddr::Emit(MCOS: &OS, Params, LineDelta, AddrDelta: 0);
944}
945
946static inline void emitBinaryDwarfLineTable(
947 MCStreamer *MCOS, MCDwarfLineTableParams Params,
948 const DWARFDebugLine::LineTable *Table,
949 const std::vector<DwarfLineTable::RowSequence> &InputSequences) {
950 if (InputSequences.empty())
951 return;
952
953 constexpr uint64_t InvalidAddress = UINT64_MAX;
954 unsigned FileNum = 1;
955 unsigned LastLine = 1;
956 unsigned Column = 0;
957 unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
958 unsigned Isa = 0;
959 unsigned Discriminator = 0;
960 uint64_t LastAddress = InvalidAddress;
961 uint64_t PrevEndOfSequence = InvalidAddress;
962 const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo();
963
964 auto emitEndOfSequence = [&](uint64_t Address) {
965 MCDwarfLineAddr::Emit(MCOS, Params, INT64_MAX, AddrDelta: Address - LastAddress);
966 FileNum = 1;
967 LastLine = 1;
968 Column = 0;
969 Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
970 Isa = 0;
971 Discriminator = 0;
972 LastAddress = InvalidAddress;
973 };
974
975 for (const DwarfLineTable::RowSequence &Sequence : InputSequences) {
976 const uint64_t SequenceStart =
977 Table->Rows[Sequence.FirstIndex].Address.Address;
978
979 // Check if we need to mark the end of the sequence.
980 if (PrevEndOfSequence != InvalidAddress && LastAddress != InvalidAddress &&
981 PrevEndOfSequence != SequenceStart) {
982 emitEndOfSequence(PrevEndOfSequence);
983 }
984
985 for (uint32_t RowIndex = Sequence.FirstIndex;
986 RowIndex <= Sequence.LastIndex; ++RowIndex) {
987 const DWARFDebugLine::Row &Row = Table->Rows[RowIndex];
988 int64_t LineDelta = static_cast<int64_t>(Row.Line) - LastLine;
989 const uint64_t Address = Row.Address.Address;
990
991 if (FileNum != Row.File) {
992 FileNum = Row.File;
993 MCOS->emitInt8(Value: dwarf::DW_LNS_set_file);
994 MCOS->emitULEB128IntValue(Value: FileNum);
995 }
996 if (Column != Row.Column) {
997 Column = Row.Column;
998 MCOS->emitInt8(Value: dwarf::DW_LNS_set_column);
999 MCOS->emitULEB128IntValue(Value: Column);
1000 }
1001 if (Discriminator != Row.Discriminator &&
1002 MCOS->getContext().getDwarfVersion() >= 4) {
1003 Discriminator = Row.Discriminator;
1004 unsigned Size = getULEB128Size(Value: Discriminator);
1005 MCOS->emitInt8(Value: dwarf::DW_LNS_extended_op);
1006 MCOS->emitULEB128IntValue(Value: Size + 1);
1007 MCOS->emitInt8(Value: dwarf::DW_LNE_set_discriminator);
1008 MCOS->emitULEB128IntValue(Value: Discriminator);
1009 }
1010 if (Isa != Row.Isa) {
1011 Isa = Row.Isa;
1012 MCOS->emitInt8(Value: dwarf::DW_LNS_set_isa);
1013 MCOS->emitULEB128IntValue(Value: Isa);
1014 }
1015 if (Row.IsStmt != Flags) {
1016 Flags = Row.IsStmt;
1017 MCOS->emitInt8(Value: dwarf::DW_LNS_negate_stmt);
1018 }
1019 if (Row.BasicBlock)
1020 MCOS->emitInt8(Value: dwarf::DW_LNS_set_basic_block);
1021 if (Row.PrologueEnd)
1022 MCOS->emitInt8(Value: dwarf::DW_LNS_set_prologue_end);
1023 if (Row.EpilogueBegin)
1024 MCOS->emitInt8(Value: dwarf::DW_LNS_set_epilogue_begin);
1025
1026 // The end of the sequence is not normal in the middle of the input
1027 // sequence, but could happen, e.g. for assembly code.
1028 if (Row.EndSequence) {
1029 emitEndOfSequence(Address);
1030 } else {
1031 if (LastAddress == InvalidAddress)
1032 emitDwarfSetLineAddrAbs(OS&: *MCOS, Params, LineDelta, Address,
1033 PointerSize: AsmInfo->getCodePointerSize());
1034 else
1035 MCDwarfLineAddr::Emit(MCOS, Params, LineDelta, AddrDelta: Address - LastAddress);
1036
1037 LastAddress = Address;
1038 LastLine = Row.Line;
1039 }
1040
1041 Discriminator = 0;
1042 }
1043 PrevEndOfSequence = Sequence.EndAddress;
1044 }
1045
1046 // Finish with the end of the sequence.
1047 if (LastAddress != InvalidAddress)
1048 emitEndOfSequence(PrevEndOfSequence);
1049}
1050
1051// This function is similar to the one from MCDwarfLineTable, except it handles
1052// end-of-sequence entries differently by utilizing line entries with
1053// DWARF2_FLAG_END_SEQUENCE flag.
1054static inline void emitDwarfLineTable(
1055 MCStreamer *MCOS, MCSection *Section,
1056 const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
1057 unsigned FileNum = 1;
1058 unsigned LastLine = 1;
1059 unsigned Column = 0;
1060 unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
1061 unsigned Isa = 0;
1062 unsigned Discriminator = 0;
1063 MCSymbol *LastLabel = nullptr;
1064 const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo();
1065
1066 // Loop through each MCDwarfLineEntry and encode the dwarf line number table.
1067 for (const MCDwarfLineEntry &LineEntry : LineEntries) {
1068 if (LineEntry.getFlags() & DWARF2_FLAG_END_SEQUENCE) {
1069 MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, Label: LineEntry.getLabel(),
1070 PointerSize: AsmInfo->getCodePointerSize());
1071 FileNum = 1;
1072 LastLine = 1;
1073 Column = 0;
1074 Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
1075 Isa = 0;
1076 Discriminator = 0;
1077 LastLabel = nullptr;
1078 continue;
1079 }
1080
1081 int64_t LineDelta = static_cast<int64_t>(LineEntry.getLine()) - LastLine;
1082
1083 if (FileNum != LineEntry.getFileNum()) {
1084 FileNum = LineEntry.getFileNum();
1085 MCOS->emitInt8(Value: dwarf::DW_LNS_set_file);
1086 MCOS->emitULEB128IntValue(Value: FileNum);
1087 }
1088 if (Column != LineEntry.getColumn()) {
1089 Column = LineEntry.getColumn();
1090 MCOS->emitInt8(Value: dwarf::DW_LNS_set_column);
1091 MCOS->emitULEB128IntValue(Value: Column);
1092 }
1093 if (Discriminator != LineEntry.getDiscriminator() &&
1094 MCOS->getContext().getDwarfVersion() >= 2) {
1095 Discriminator = LineEntry.getDiscriminator();
1096 unsigned Size = getULEB128Size(Value: Discriminator);
1097 MCOS->emitInt8(Value: dwarf::DW_LNS_extended_op);
1098 MCOS->emitULEB128IntValue(Value: Size + 1);
1099 MCOS->emitInt8(Value: dwarf::DW_LNE_set_discriminator);
1100 MCOS->emitULEB128IntValue(Value: Discriminator);
1101 }
1102 if (Isa != LineEntry.getIsa()) {
1103 Isa = LineEntry.getIsa();
1104 MCOS->emitInt8(Value: dwarf::DW_LNS_set_isa);
1105 MCOS->emitULEB128IntValue(Value: Isa);
1106 }
1107 if ((LineEntry.getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) {
1108 Flags = LineEntry.getFlags();
1109 MCOS->emitInt8(Value: dwarf::DW_LNS_negate_stmt);
1110 }
1111 if (LineEntry.getFlags() & DWARF2_FLAG_BASIC_BLOCK)
1112 MCOS->emitInt8(Value: dwarf::DW_LNS_set_basic_block);
1113 if (LineEntry.getFlags() & DWARF2_FLAG_PROLOGUE_END)
1114 MCOS->emitInt8(Value: dwarf::DW_LNS_set_prologue_end);
1115 if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN)
1116 MCOS->emitInt8(Value: dwarf::DW_LNS_set_epilogue_begin);
1117
1118 MCSymbol *Label = LineEntry.getLabel();
1119
1120 // At this point we want to emit/create the sequence to encode the delta
1121 // in line numbers and the increment of the address from the previous
1122 // Label and the current Label.
1123 MCOS->emitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label,
1124 PointerSize: AsmInfo->getCodePointerSize());
1125 Discriminator = 0;
1126 LastLine = LineEntry.getLine();
1127 LastLabel = Label;
1128 }
1129
1130 assert(LastLabel == nullptr && "end of sequence expected");
1131}
1132
1133void DwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
1134 std::optional<MCDwarfLineStr> &LineStr,
1135 BinaryContext &BC) const {
1136 if (!RawData.empty()) {
1137 assert(MCLineSections.getMCLineEntries().empty() &&
1138 InputSequences.empty() &&
1139 "cannot combine raw data with new line entries");
1140 MCOS->emitLabel(Symbol: getLabel());
1141 MCOS->emitBytes(Data: RawData);
1142 return;
1143 }
1144
1145 MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second;
1146
1147 // Put out the line tables.
1148 for (const auto &LineSec : MCLineSections.getMCLineEntries())
1149 emitDwarfLineTable(MCOS, Section: LineSec.first, LineEntries: LineSec.second);
1150
1151 // Emit line tables for the original code.
1152 emitBinaryDwarfLineTable(MCOS, Params, Table: InputTable, InputSequences);
1153
1154 // This is the end of the section, so set the value of the symbol at the end
1155 // of this section (that was used in a previous expression).
1156 MCOS->emitLabel(Symbol: LineEndSym);
1157}
1158
1159// Helper function to parse .debug_line_str, and populate one we are using.
1160// For functions that we do not modify we output them as raw data.
1161// Re-constructing .debug_line_str so that offsets are correct for those
1162// debug line tables.
1163// Bonus is that when we output a final binary we can re-use .debug_line_str
1164// section. So we don't have to do the SHF_ALLOC trick we did with
1165// .debug_line.
1166static void parseAndPopulateDebugLineStr(BinarySection &LineStrSection,
1167 MCDwarfLineStr &LineStr,
1168 BinaryContext &BC) {
1169 DataExtractor StrData(LineStrSection.getContents(),
1170 BC.DwCtx->isLittleEndian(), 0);
1171 uint64_t Offset = 0;
1172 while (StrData.isValidOffset(offset: Offset)) {
1173 const uint64_t StrOffset = Offset;
1174 Error Err = Error::success();
1175 const char *CStr = StrData.getCStr(OffsetPtr: &Offset, Err: &Err);
1176 if (Err) {
1177 BC.errs() << "BOLT-ERROR: could not extract string from .debug_line_str";
1178 continue;
1179 }
1180 const size_t NewOffset = LineStr.addString(Path: CStr);
1181 assert(StrOffset == NewOffset &&
1182 "New offset in .debug_line_str doesn't match original offset");
1183 (void)StrOffset;
1184 (void)NewOffset;
1185 }
1186}
1187
1188void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) {
1189 MCAssembler &Assembler =
1190 static_cast<MCObjectStreamer *>(&Streamer)->getAssembler();
1191
1192 MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams();
1193
1194 auto &LineTables = BC.getDwarfLineTables();
1195
1196 // Bail out early so we don't switch to the debug_line section needlessly and
1197 // in doing so create an unnecessary (if empty) section.
1198 if (LineTables.empty())
1199 return;
1200 // In a v5 non-split line table, put the strings in a separate section.
1201 std::optional<MCDwarfLineStr> LineStr;
1202 ErrorOr<BinarySection &> LineStrSection =
1203 BC.getUniqueSectionByName(SectionName: ".debug_line_str");
1204
1205 // Some versions of GCC output DWARF5 .debug_info, but DWARF4 or lower
1206 // .debug_line, so need to check if section exists.
1207 if (LineStrSection) {
1208 LineStr.emplace(args&: *BC.Ctx);
1209 parseAndPopulateDebugLineStr(LineStrSection&: *LineStrSection, LineStr&: *LineStr, BC);
1210 }
1211
1212 // Switch to the section where the table will be emitted into.
1213 Streamer.switchSection(Section: BC.MOFI->getDwarfLineSection());
1214
1215 const uint16_t DwarfVersion = BC.Ctx->getDwarfVersion();
1216 // Handle the rest of the Compile Units.
1217 for (auto &CUIDTablePair : LineTables) {
1218 Streamer.getContext().setDwarfVersion(
1219 CUIDTablePair.second.getDwarfVersion());
1220 CUIDTablePair.second.emitCU(MCOS: &Streamer, Params, LineStr, BC);
1221 }
1222
1223 // Resetting DWARF version for rest of the flow.
1224 BC.Ctx->setDwarfVersion(DwarfVersion);
1225
1226 // Still need to write the section out for the ExecutionEngine, and temp in
1227 // memory object we are constructing.
1228 if (LineStr)
1229 LineStr->emitSection(MCOS: &Streamer);
1230}
1231
1232} // namespace bolt
1233} // namespace llvm
1234

source code of bolt/lib/Core/DebugData.cpp