1//===- bolt/Core/DebugData.h - Debugging information handling ---*- C++ -*-===//
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 contains declaration of classes that represent and serialize
10// DWARF-related entities.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef BOLT_CORE_DEBUG_DATA_H
15#define BOLT_CORE_DEBUG_DATA_H
16
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/CodeGen/DIE.h"
19#include "llvm/DebugInfo/DWARF/DWARFContext.h"
20#include "llvm/MC/MCDwarf.h"
21#include "llvm/Support/FormatVariadic.h"
22#include "llvm/Support/SMLoc.h"
23#include "llvm/Support/raw_ostream.h"
24#include <cstdint>
25#include <map>
26#include <memory>
27#include <mutex>
28#include <string>
29#include <unordered_map>
30#include <utility>
31#include <vector>
32
33#define DWARF2_FLAG_END_SEQUENCE (1 << 4)
34
35namespace llvm {
36
37namespace bolt {
38
39class DIEBuilder;
40struct AttrInfo {
41 DWARFFormValue V;
42 const DWARFAbbreviationDeclaration *AbbrevDecl;
43 uint64_t Offset;
44 uint32_t Size; // Size of the attribute.
45};
46
47/// Finds attributes FormValue and Offset.
48///
49/// \param DIE die to look up in.
50/// \param AbbrevDecl abbrev declaration for the die.
51/// \param Index an index in Abbrev declaration entry.
52std::optional<AttrInfo>
53findAttributeInfo(const DWARFDie DIE,
54 const DWARFAbbreviationDeclaration *AbbrevDecl,
55 uint32_t Index);
56
57/// Finds attributes FormValue and Offset.
58///
59/// \param DIE die to look up in.
60/// \param Attr the attribute to extract.
61/// \return an optional AttrInfo with DWARFFormValue and Offset.
62std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
63 dwarf::Attribute Attr);
64
65// DWARF5 Header in order of encoding.
66// Types represent encoding sizes.
67using UnitLengthType = uint32_t;
68using VersionType = uint16_t;
69using AddressSizeType = uint8_t;
70using SegmentSelectorType = uint8_t;
71using OffsetEntryCountType = uint32_t;
72/// Get DWARF5 Header size.
73/// Rangelists and Loclists have the same header.
74constexpr uint32_t getDWARF5RngListLocListHeaderSize() {
75 return sizeof(UnitLengthType) + sizeof(VersionType) +
76 sizeof(AddressSizeType) + sizeof(SegmentSelectorType) +
77 sizeof(OffsetEntryCountType);
78}
79
80class BinaryContext;
81
82/// Address range representation. Takes less space than DWARFAddressRange.
83struct DebugAddressRange {
84 uint64_t LowPC{0};
85 uint64_t HighPC{0};
86
87 DebugAddressRange() = default;
88
89 DebugAddressRange(uint64_t LowPC, uint64_t HighPC)
90 : LowPC(LowPC), HighPC(HighPC) {}
91};
92
93static inline bool operator<(const DebugAddressRange &LHS,
94 const DebugAddressRange &RHS) {
95 return std::tie(args: LHS.LowPC, args: LHS.HighPC) < std::tie(args: RHS.LowPC, args: RHS.HighPC);
96}
97
98inline raw_ostream &operator<<(raw_ostream &OS,
99 const DebugAddressRange &Range) {
100 OS << formatv(Fmt: "[{0:x}, {1:x})", Vals: Range.LowPC, Vals: Range.HighPC);
101 return OS;
102}
103
104/// DebugAddressRangesVector - represents a set of absolute address ranges.
105using DebugAddressRangesVector = SmallVector<DebugAddressRange, 2>;
106
107/// Address range with location used by .debug_loc section.
108/// More compact than DWARFLocationEntry and uses absolute addresses.
109struct DebugLocationEntry {
110 uint64_t LowPC;
111 uint64_t HighPC;
112 SmallVector<uint8_t, 4> Expr;
113};
114
115inline raw_ostream &operator<<(raw_ostream &OS,
116 const DebugLocationEntry &Entry) {
117 OS << formatv(Fmt: "[{0:x}, {1:x}) : [", Vals: Entry.LowPC, Vals: Entry.HighPC);
118 const char *Sep = "";
119 for (unsigned Byte : Entry.Expr) {
120 OS << Sep << Byte;
121 Sep = ", ";
122 }
123 OS << "]";
124 return OS;
125}
126
127using DebugLocationsVector = SmallVector<DebugLocationEntry, 4>;
128
129/// References a row in a DWARFDebugLine::LineTable by the DWARF
130/// Context index of the DWARF Compile Unit that owns the Line Table and the row
131/// index. This is tied to our IR during disassembly so that we can later update
132/// .debug_line information. RowIndex has a base of 1, which means a RowIndex
133/// of 1 maps to the first row of the line table and a RowIndex of 0 is invalid.
134struct DebugLineTableRowRef {
135 uint32_t DwCompileUnitIndex;
136 uint32_t RowIndex;
137
138 const static DebugLineTableRowRef NULL_ROW;
139
140 bool operator==(const DebugLineTableRowRef &Rhs) const {
141 return DwCompileUnitIndex == Rhs.DwCompileUnitIndex &&
142 RowIndex == Rhs.RowIndex;
143 }
144
145 bool operator!=(const DebugLineTableRowRef &Rhs) const {
146 return !(*this == Rhs);
147 }
148
149 static DebugLineTableRowRef fromSMLoc(const SMLoc &Loc) {
150 union {
151 decltype(Loc.getPointer()) Ptr;
152 DebugLineTableRowRef Ref;
153 } U;
154 U.Ptr = Loc.getPointer();
155 return U.Ref;
156 }
157
158 SMLoc toSMLoc() const {
159 union {
160 decltype(SMLoc().getPointer()) Ptr;
161 DebugLineTableRowRef Ref;
162 } U;
163 U.Ref = *this;
164 return SMLoc::getFromPointer(Ptr: U.Ptr);
165 }
166};
167
168/// Common buffer vector used for debug info handling.
169using DebugBufferVector = SmallVector<char, 16>;
170
171/// Map of old CU offset to new offset and length.
172struct CUInfo {
173 uint32_t Offset;
174 uint32_t Length;
175};
176using CUOffsetMap = std::map<uint32_t, CUInfo>;
177
178enum class RangesWriterKind { DebugRangesWriter, DebugRangeListsWriter };
179/// Serializes the .debug_ranges DWARF section.
180class DebugRangesSectionWriter {
181public:
182 DebugRangesSectionWriter();
183
184 DebugRangesSectionWriter(RangesWriterKind K) : Kind(K){};
185
186 virtual ~DebugRangesSectionWriter(){};
187
188 /// Add ranges with caching.
189 virtual uint64_t
190 addRanges(DebugAddressRangesVector &&Ranges,
191 std::map<DebugAddressRangesVector, uint64_t> &CachedRanges);
192
193 /// Add ranges and return offset into section.
194 virtual uint64_t addRanges(DebugAddressRangesVector &Ranges);
195
196 /// Returns an offset of an empty address ranges list that is always written
197 /// to .debug_ranges
198 uint64_t getEmptyRangesOffset() const { return EmptyRangesOffset; }
199
200 /// Returns the SectionOffset.
201 uint64_t getSectionOffset();
202
203 /// Returns a buffer containing Ranges.
204 virtual std::unique_ptr<DebugBufferVector> releaseBuffer() {
205 return std::move(RangesBuffer);
206 }
207
208 RangesWriterKind getKind() const { return Kind; }
209
210 static bool classof(const DebugRangesSectionWriter *Writer) {
211 return Writer->getKind() == RangesWriterKind::DebugRangesWriter;
212 }
213
214 /// Writes out range lists for a current CU being processed.
215 void virtual finalizeSection(){};
216
217 /// Needs to be invoked before each \p CU is processed.
218 void virtual initSection(DWARFUnit &CU){};
219
220protected:
221 std::unique_ptr<DebugBufferVector> RangesBuffer;
222
223 std::unique_ptr<raw_svector_ostream> RangesStream;
224
225 std::mutex WriterMutex;
226
227 /// Current offset in the section (updated as new entries are written).
228 /// Starts with 16 since the first 16 bytes are reserved for an empty range.
229 uint32_t SectionOffset{0};
230
231 /// Offset of an empty address ranges list.
232 static constexpr uint64_t EmptyRangesOffset{0};
233
234private:
235 RangesWriterKind Kind;
236};
237
238class DebugAddrWriter;
239class DebugRangeListsSectionWriter : public DebugRangesSectionWriter {
240public:
241 DebugRangeListsSectionWriter()
242 : DebugRangesSectionWriter(RangesWriterKind::DebugRangeListsWriter) {
243 RangesBuffer = std::make_unique<DebugBufferVector>();
244 RangesStream = std::make_unique<raw_svector_ostream>(args&: *RangesBuffer);
245 };
246 virtual ~DebugRangeListsSectionWriter(){};
247
248 static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
249
250 /// Add ranges with caching.
251 uint64_t addRanges(
252 DebugAddressRangesVector &&Ranges,
253 std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) override;
254
255 /// Add ranges and return offset into section.
256 uint64_t addRanges(DebugAddressRangesVector &Ranges) override;
257
258 std::unique_ptr<DebugBufferVector> releaseBuffer() override {
259 return std::move(RangesBuffer);
260 }
261
262 /// Needs to be invoked before each \p CU is processed.
263 void initSection(DWARFUnit &CU) override;
264
265 /// Writes out range lists for a current CU being processed.
266 void finalizeSection() override;
267
268 // Returns true if section is empty.
269 bool empty() { return RangesBuffer->empty(); }
270
271 static bool classof(const DebugRangesSectionWriter *Writer) {
272 return Writer->getKind() == RangesWriterKind::DebugRangeListsWriter;
273 }
274
275private:
276 static DebugAddrWriter *AddrWriter;
277 /// Used to find unique CU ID.
278 DWARFUnit *CU;
279 /// Current relative offset of range list entry within this CUs rangelist
280 /// body.
281 uint32_t CurrentOffset{0};
282 /// Contains relative offset of each range list entry.
283 SmallVector<uint32_t, 1> RangeEntries;
284
285 std::unique_ptr<DebugBufferVector> CUBodyBuffer;
286 std::unique_ptr<raw_svector_ostream> CUBodyStream;
287};
288
289/// Serializes the .debug_aranges DWARF section.
290class DebugARangesSectionWriter {
291public:
292 /// Add ranges for CU matching \p CUOffset.
293 void addCURanges(uint64_t CUOffset, DebugAddressRangesVector &&Ranges);
294
295 /// Writes .debug_aranges with the added ranges to the MCObjectWriter.
296 /// Takes in \p RangesStream to write into, and \p CUMap which maps CU
297 /// original offsets to new ones.
298 void writeARangesSection(raw_svector_ostream &RangesStream,
299 const CUOffsetMap &CUMap) const;
300
301 /// Resets the writer to a clear state.
302 void reset() { CUAddressRanges.clear(); }
303
304 /// Map DWARFCompileUnit index to ranges.
305 using CUAddressRangesType = std::map<uint64_t, DebugAddressRangesVector>;
306
307 /// Return ranges for a given CU.
308 const CUAddressRangesType &getCUAddressRanges() const {
309 return CUAddressRanges;
310 }
311
312private:
313 /// Map from compile unit offset to the list of address intervals that belong
314 /// to that compile unit. Each interval is a pair
315 /// (first address, interval size).
316 CUAddressRangesType CUAddressRanges;
317
318 std::mutex CUAddressRangesMutex;
319};
320
321using IndexAddressPair = std::pair<uint32_t, uint64_t>;
322using AddressToIndexMap = std::unordered_map<uint64_t, uint32_t>;
323using IndexToAddressMap = std::unordered_map<uint32_t, uint64_t>;
324using AddressSectionBuffer = SmallVector<char, 4>;
325class DebugAddrWriter {
326public:
327 DebugAddrWriter() = delete;
328 DebugAddrWriter(BinaryContext *BC_);
329 virtual ~DebugAddrWriter(){};
330 /// Given an address returns an index in .debug_addr.
331 /// Adds Address to map.
332 uint32_t getIndexFromAddress(uint64_t Address, DWARFUnit &CU);
333
334 /// Write out entries in to .debug_addr section for CUs.
335 virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs);
336
337 /// Return buffer with all the entries in .debug_addr already writen out using
338 /// update(...).
339 virtual AddressSectionBuffer &finalize() { return *Buffer; }
340
341 /// Returns False if .debug_addr section was created..
342 bool isInitialized() const { return !AddressMaps.empty(); }
343
344protected:
345 class AddressForDWOCU {
346 public:
347 AddressToIndexMap::iterator find(uint64_t Address) {
348 return AddressToIndex.find(x: Address);
349 }
350 AddressToIndexMap::iterator end() { return AddressToIndex.end(); }
351 AddressToIndexMap::iterator begin() { return AddressToIndex.begin(); }
352
353 IndexToAddressMap::iterator indexToAdddessEnd() {
354 return IndexToAddress.end();
355 }
356 IndexToAddressMap::iterator indexToAddressBegin() {
357 return IndexToAddress.begin();
358 }
359 uint32_t getNextIndex() {
360 while (IndexToAddress.count(x: CurrentIndex))
361 ++CurrentIndex;
362 return CurrentIndex;
363 }
364
365 /// Inserts elements in to IndexToAddress and AddressToIndex.
366 /// Follows the same semantics as unordered_map insert.
367 std::pair<AddressToIndexMap::iterator, bool> insert(uint64_t Address,
368 uint32_t Index) {
369 IndexToAddress.insert(x: {Index, Address});
370 return AddressToIndex.insert(x: {Address, Index});
371 }
372
373 /// Updates AddressToIndex Map.
374 /// Follows the same semantics as unordered map [].
375 void updateAddressToIndex(uint64_t Address, uint32_t Index) {
376 AddressToIndex[Address] = Index;
377 }
378
379 /// Updates IndexToAddress Map.
380 /// Follows the same semantics as unordered map [].
381 void updateIndexToAddrss(uint64_t Address, uint32_t Index) {
382 IndexToAddress[Index] = Address;
383 }
384
385 void dump();
386
387 private:
388 AddressToIndexMap AddressToIndex;
389 IndexToAddressMap IndexToAddress;
390 uint32_t CurrentIndex{0};
391 };
392
393 virtual uint64_t getCUID(DWARFUnit &Unit) {
394 assert(Unit.getDWOId() && "Unit is not Skeleton CU.");
395 return *Unit.getDWOId();
396 }
397
398 BinaryContext *BC;
399 /// Maps DWOID to AddressForDWOCU.
400 std::unordered_map<uint64_t, AddressForDWOCU> AddressMaps;
401 /// Mutex used for parallel processing of debug info.
402 std::mutex WriterMutex;
403 std::unique_ptr<AddressSectionBuffer> Buffer;
404 std::unique_ptr<raw_svector_ostream> AddressStream;
405 /// Used to track sections that were not modified so that they can be re-used.
406 DenseMap<uint64_t, uint64_t> UnmodifiedAddressOffsets;
407};
408
409class DebugAddrWriterDwarf5 : public DebugAddrWriter {
410public:
411 DebugAddrWriterDwarf5() = delete;
412 DebugAddrWriterDwarf5(BinaryContext *BC) : DebugAddrWriter(BC) {}
413
414 /// Write out entries in to .debug_addr section for CUs.
415 virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs) override;
416
417protected:
418 /// Given DWARFUnit \p Unit returns either DWO ID or it's offset within
419 /// .debug_info.
420 uint64_t getCUID(DWARFUnit &Unit) override {
421 if (Unit.isDWOUnit()) {
422 DWARFUnit *SkeletonCU = Unit.getLinkedUnit();
423 return SkeletonCU->getOffset();
424 }
425 return Unit.getOffset();
426 }
427};
428
429/// This class is NOT thread safe.
430using DebugStrOffsetsBufferVector = SmallVector<char, 16>;
431class DebugStrOffsetsWriter {
432public:
433 DebugStrOffsetsWriter() {
434 StrOffsetsBuffer = std::make_unique<DebugStrOffsetsBufferVector>();
435 StrOffsetsStream = std::make_unique<raw_svector_ostream>(args&: *StrOffsetsBuffer);
436 }
437
438 /// Update Str offset in .debug_str in .debug_str_offsets.
439 void updateAddressMap(uint32_t Index, uint32_t Address);
440
441 /// Get offset for given index in original .debug_str_offsets section.
442 uint64_t getOffset(uint32_t Index) const { return StrOffsets[Index]; }
443 /// Writes out current sections entry into .debug_str_offsets.
444 void finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr);
445
446 /// Returns False if no strings were added to .debug_str.
447 bool isFinalized() const { return !StrOffsetsBuffer->empty(); }
448
449 /// Returns buffer containing .debug_str_offsets.
450 std::unique_ptr<DebugStrOffsetsBufferVector> releaseBuffer() {
451 return std::move(StrOffsetsBuffer);
452 }
453
454 /// Initializes Buffer and Stream.
455 void initialize(DWARFUnit &Unit);
456
457 /// Clear data.
458 void clear() {
459 IndexToAddressMap.clear();
460 StrOffsets.clear();
461 }
462
463private:
464 std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
465 std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
466 std::map<uint32_t, uint32_t> IndexToAddressMap;
467 SmallVector<uint32_t, 5> StrOffsets;
468 std::unordered_map<uint64_t, uint64_t> ProcessedBaseOffsets;
469 bool StrOffsetSectionWasModified = false;
470};
471
472using DebugStrBufferVector = SmallVector<char, 16>;
473class DebugStrWriter {
474public:
475 DebugStrWriter() = delete;
476 DebugStrWriter(BinaryContext &BC) : BC(BC) { create(); }
477 std::unique_ptr<DebugStrBufferVector> releaseBuffer() {
478 return std::move(StrBuffer);
479 }
480
481 /// Adds string to .debug_str.
482 /// On first invocation it initializes internal data structures.
483 uint32_t addString(StringRef Str);
484
485 /// Returns False if no strings were added to .debug_str.
486 bool isInitialized() const { return !StrBuffer->empty(); }
487
488 /// Initializes Buffer and Stream.
489 void initialize();
490
491private:
492 /// Mutex used for parallel processing of debug info.
493 std::mutex WriterMutex;
494 /// Creates internal data structures.
495 void create();
496 std::unique_ptr<DebugStrBufferVector> StrBuffer;
497 std::unique_ptr<raw_svector_ostream> StrStream;
498 BinaryContext &BC;
499};
500
501enum class LocWriterKind { DebugLocWriter, DebugLoclistWriter };
502
503/// Serializes part of a .debug_loc DWARF section with LocationLists.
504class SimpleBinaryPatcher;
505class DebugLocWriter {
506protected:
507 DebugLocWriter(uint8_t DwarfVersion, LocWriterKind Kind)
508 : DwarfVersion(DwarfVersion), Kind(Kind) {
509 init();
510 }
511
512public:
513 DebugLocWriter() { init(); };
514 virtual ~DebugLocWriter(){};
515
516 /// Writes out location lists and stores internal patches.
517 virtual void addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
518 DebugLocationsVector &LocList);
519
520 /// Writes out locations in to a local buffer, and adds Debug Info patches.
521 virtual void finalize(DIEBuilder &DIEBldr, DIE &Die);
522
523 /// Return internal buffer.
524 virtual std::unique_ptr<DebugBufferVector> getBuffer();
525
526 /// Returns DWARF version.
527 uint8_t getDwarfVersion() const { return DwarfVersion; }
528
529 /// Offset of an empty location list.
530 static constexpr uint32_t EmptyListOffset = 0;
531
532 LocWriterKind getKind() const { return Kind; }
533
534 static bool classof(const DebugLocWriter *Writer) {
535 return Writer->getKind() == LocWriterKind::DebugLocWriter;
536 }
537
538protected:
539 std::unique_ptr<DebugBufferVector> LocBuffer;
540 std::unique_ptr<raw_svector_ostream> LocStream;
541 /// Current offset in the section (updated as new entries are written).
542 /// Starts with 0 here since this only writes part of a full location lists
543 /// section. In the final section, for DWARF4, the first 16 bytes are reserved
544 /// for an empty list.
545 static uint32_t LocSectionOffset;
546 uint8_t DwarfVersion{4};
547 LocWriterKind Kind{LocWriterKind::DebugLocWriter};
548
549private:
550 /// Inits all the related data structures.
551 void init();
552 struct LocListDebugInfoPatchType {
553 uint64_t DebugInfoAttrOffset;
554 uint64_t LocListOffset;
555 };
556 using VectorLocListDebugInfoPatchType =
557 std::vector<LocListDebugInfoPatchType>;
558 /// The list of debug info patches to be made once individual
559 /// location list writers have been filled
560 VectorLocListDebugInfoPatchType LocListDebugInfoPatches;
561};
562
563class DebugLoclistWriter : public DebugLocWriter {
564public:
565 ~DebugLoclistWriter() {}
566 DebugLoclistWriter() = delete;
567 DebugLoclistWriter(DWARFUnit &Unit, uint8_t DV, bool SD)
568 : DebugLocWriter(DV, LocWriterKind::DebugLoclistWriter), CU(Unit),
569 IsSplitDwarf(SD) {
570 assert(DebugLoclistWriter::AddrWriter &&
571 "Please use SetAddressWriter to initialize "
572 "DebugAddrWriter before instantiation.");
573 if (DwarfVersion >= 5) {
574 LocBodyBuffer = std::make_unique<DebugBufferVector>();
575 LocBodyStream = std::make_unique<raw_svector_ostream>(args&: *LocBodyBuffer);
576 } else {
577 // Writing out empty location list to which all references to empty
578 // location lists will point.
579 const char Zeroes[16] = {0};
580 *LocStream << StringRef(Zeroes, 16);
581 }
582 }
583
584 static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
585
586 /// Stores location lists internally to be written out during finalize phase.
587 virtual void addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
588 DebugLocationsVector &LocList) override;
589
590 /// Writes out locations in to a local buffer and applies debug info patches.
591 void finalize(DIEBuilder &DIEBldr, DIE &Die) override;
592
593 /// Returns CU ID.
594 /// For Skeleton CU it is a CU Offset.
595 /// For DWO CU it is a DWO ID.
596 uint64_t getCUID() const {
597 return CU.isDWOUnit() ? *CU.getDWOId() : CU.getOffset();
598 }
599
600 LocWriterKind getKind() const { return DebugLocWriter::getKind(); }
601
602 static bool classof(const DebugLocWriter *Writer) {
603 return Writer->getKind() == LocWriterKind::DebugLoclistWriter;
604 }
605
606 bool isSplitDwarf() const { return IsSplitDwarf; }
607
608 constexpr static uint32_t InvalidIndex = UINT32_MAX;
609
610private:
611 /// Writes out locations in to a local buffer and applies debug info patches.
612 void finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die);
613
614 static DebugAddrWriter *AddrWriter;
615 DWARFUnit &CU;
616 bool IsSplitDwarf{false};
617 // Used for DWARF5 to store location lists before being finalized.
618 std::unique_ptr<DebugBufferVector> LocBodyBuffer;
619 std::unique_ptr<raw_svector_ostream> LocBodyStream;
620 std::vector<uint32_t> RelativeLocListOffsets;
621 uint32_t NumberOfEntries{0};
622 static uint32_t LoclistBaseOffset;
623};
624
625/// Abstract interface for classes that apply modifications to a binary string.
626class BinaryPatcher {
627public:
628 virtual ~BinaryPatcher() {}
629 /// Applies modifications to the copy of binary string \p BinaryContents .
630 /// Implementations do not need to guarantee that size of a new \p
631 /// BinaryContents remains unchanged.
632 virtual std::string patchBinary(StringRef BinaryContents) = 0;
633};
634
635/// Applies simple modifications to a binary string, such as directly replacing
636/// the contents of a certain portion with a string or an integer.
637class SimpleBinaryPatcher : public BinaryPatcher {
638private:
639 std::vector<std::pair<uint32_t, std::string>> Patches;
640
641 /// Adds a patch to replace the contents of \p ByteSize bytes with the integer
642 /// \p NewValue encoded in little-endian, with the least-significant byte
643 /// being written at the offset \p Offset.
644 void addLEPatch(uint64_t Offset, uint64_t NewValue, size_t ByteSize);
645
646 /// RangeBase for DWO DebugInfo Patcher.
647 uint64_t RangeBase{0};
648
649 /// Gets reset to false when setRangeBase is invoked.
650 /// Gets set to true when getRangeBase is called
651 uint64_t WasRangeBaseUsed{false};
652
653public:
654 virtual ~SimpleBinaryPatcher() {}
655
656 /// Adds a patch to replace the contents of the binary string starting at the
657 /// specified \p Offset with the string \p NewValue.
658 /// The \p OldValueSize is the size of the old value that will be replaced.
659 void addBinaryPatch(uint64_t Offset, std::string &&NewValue,
660 uint32_t OldValueSize);
661
662 /// Adds a patch to replace the contents of a single byte of the string, at
663 /// the offset \p Offset, with the value \Value.
664 void addBytePatch(uint64_t Offset, uint8_t Value);
665
666 /// Adds a patch to put the integer \p NewValue encoded as a 64-bit
667 /// little-endian value at offset \p Offset.
668 virtual void addLE64Patch(uint64_t Offset, uint64_t NewValue);
669
670 /// Adds a patch to put the integer \p NewValue encoded as a 32-bit
671 /// little-endian value at offset \p Offset.
672 /// The \p OldValueSize is the size of the old value that will be replaced.
673 virtual void addLE32Patch(uint64_t Offset, uint32_t NewValue,
674 uint32_t OldValueSize = 4);
675
676 /// Add a patch at \p Offset with \p Value using unsigned LEB128 encoding with
677 /// size \p OldValueSize.
678 /// The \p OldValueSize is the size of the old value that will be replaced.
679 virtual void addUDataPatch(uint64_t Offset, uint64_t Value,
680 uint32_t OldValueSize);
681
682 /// Setting DW_AT_GNU_ranges_base
683 void setRangeBase(uint64_t Rb) {
684 WasRangeBaseUsed = false;
685 RangeBase = Rb;
686 }
687
688 /// Gets DW_AT_GNU_ranges_base
689 uint64_t getRangeBase() {
690 WasRangeBaseUsed = true;
691 return RangeBase;
692 }
693
694 /// Proxy for if we broke up low_pc/high_pc to ranges.
695 bool getWasRangBasedUsed() const { return WasRangeBaseUsed; }
696
697 /// This function takes in \p BinaryContents, applies patches to it and
698 /// returns an updated string.
699 std::string patchBinary(StringRef BinaryContents) override;
700};
701
702/// Similar to MCDwarfLineEntry, but identifies the location by its address
703/// instead of MCLabel.
704class BinaryDwarfLineEntry : public MCDwarfLoc {
705 uint64_t Address;
706
707public:
708 // Constructor to create an BinaryDwarfLineEntry given a symbol and the dwarf
709 // loc.
710 BinaryDwarfLineEntry(uint64_t Address, const MCDwarfLoc loc)
711 : MCDwarfLoc(loc), Address(Address) {}
712
713 uint64_t getAddress() const { return Address; }
714};
715
716/// Line number information for the output binary. One instance per CU.
717///
718/// For any given CU, we may:
719/// 1. Generate new line table using:
720/// a) emitted code: getMCLineSections().addEntry()
721/// b) information from the input line table: addLineTableSequence()
722/// or
723/// 2. Copy line table from the input file: addRawContents().
724class DwarfLineTable {
725public:
726 /// Line number information on contiguous code region from the input binary.
727 /// It is represented by [FirstIndex, LastIndex] rows range in the input
728 /// line table, and the end address of the sequence used for issuing the end
729 /// of the sequence directive.
730 struct RowSequence {
731 uint32_t FirstIndex;
732 uint32_t LastIndex;
733 uint64_t EndAddress;
734 };
735
736private:
737 MCDwarfLineTableHeader Header;
738
739 /// MC line tables for the code generated via MC layer.
740 MCLineSection MCLineSections;
741
742 /// Line info for the original code. To be merged with tables for new code.
743 const DWARFDebugLine::LineTable *InputTable{nullptr};
744 std::vector<RowSequence> InputSequences;
745
746 /// Raw data representing complete debug line section for the unit.
747 StringRef RawData;
748
749 /// DWARF Version
750 uint16_t DwarfVersion;
751
752public:
753 /// Emit line info for all units in the binary context.
754 static void emit(BinaryContext &BC, MCStreamer &Streamer);
755
756 /// Emit the Dwarf file and the line tables for a given CU.
757 void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
758 std::optional<MCDwarfLineStr> &LineStr, BinaryContext &BC) const;
759
760 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
761 std::optional<MD5::MD5Result> Checksum,
762 std::optional<StringRef> Source,
763 uint16_t DwarfVersion,
764 unsigned FileNumber = 0) {
765 assert(RawData.empty() && "cannot use with raw data");
766 return Header.tryGetFile(Directory, FileName, Checksum, Source,
767 DwarfVersion, FileNumber);
768 }
769
770 /// Return label at the start of the emitted debug line for the unit.
771 MCSymbol *getLabel() const { return Header.Label; }
772
773 void setLabel(MCSymbol *Label) { Header.Label = Label; }
774
775 /// Sets the root file \p Directory, \p FileName, optional \p CheckSum, and
776 /// optional \p Source.
777 void setRootFile(StringRef Directory, StringRef FileName,
778 std::optional<MD5::MD5Result> Checksum,
779 std::optional<StringRef> Source) {
780 Header.setRootFile(Directory, FileName, Checksum, Source);
781 }
782
783 /// Access to MC line info.
784 MCLineSection &getMCLineSections() { return MCLineSections; }
785
786 /// Add line information using the sequence from the input line \p Table.
787 void addLineTableSequence(const DWARFDebugLine::LineTable *Table,
788 uint32_t FirstRow, uint32_t LastRow,
789 uint64_t EndOfSequenceAddress) {
790 assert((!InputTable || InputTable == Table) &&
791 "expected same table for CU");
792 InputTable = Table;
793 InputSequences.emplace_back(
794 args: RowSequence{.FirstIndex: FirstRow, .LastIndex: LastRow, .EndAddress: EndOfSequenceAddress});
795 }
796
797 /// Indicate that for the unit we should emit specified contents instead of
798 /// generating a new line info table.
799 void addRawContents(StringRef DebugLineContents) {
800 RawData = DebugLineContents;
801 }
802
803 /// Sets DWARF version for this line table.
804 void setDwarfVersion(uint16_t V) { DwarfVersion = V; }
805
806 // Returns DWARF Version for this line table.
807 uint16_t getDwarfVersion() const { return DwarfVersion; }
808};
809} // namespace bolt
810} // namespace llvm
811
812#endif
813

source code of bolt/include/bolt/Core/DebugData.h