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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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