xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h (revision 5956d97f4b3204318ceb6aa9c77bd0bc6ea87a41)
1 //===- DWARFAcceleratorTable.h ----------------------------------*- 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 #ifndef LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
10 #define LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
11 
12 #include "llvm/ADT/DenseSet.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/BinaryFormat/Dwarf.h"
15 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
16 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
17 #include <cstdint>
18 #include <utility>
19 
20 namespace llvm {
21 
22 class raw_ostream;
23 class ScopedPrinter;
24 
25 /// The accelerator tables are designed to allow efficient random access
26 /// (using a symbol name as a key) into debug info by providing an index of the
27 /// debug info DIEs. This class implements the common functionality of Apple and
28 /// DWARF 5 accelerator tables.
29 /// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it
30 /// to this class.
31 class DWARFAcceleratorTable {
32 protected:
33   DWARFDataExtractor AccelSection;
34   DataExtractor StringSection;
35 
36 public:
37   /// An abstract class representing a single entry in the accelerator tables.
38   class Entry {
39   protected:
40     SmallVector<DWARFFormValue, 3> Values;
41 
42     Entry() = default;
43 
44     // Make these protected so only (final) subclasses can be copied around.
45     Entry(const Entry &) = default;
46     Entry(Entry &&) = default;
47     Entry &operator=(const Entry &) = default;
48     Entry &operator=(Entry &&) = default;
49     ~Entry() = default;
50 
51 
52   public:
53     /// Returns the Offset of the Compilation Unit associated with this
54     /// Accelerator Entry or None if the Compilation Unit offset is not recorded
55     /// in this Accelerator Entry.
56     virtual Optional<uint64_t> getCUOffset() const = 0;
57 
58     /// Returns the Tag of the Debug Info Entry associated with this
59     /// Accelerator Entry or None if the Tag is not recorded in this
60     /// Accelerator Entry.
61     virtual Optional<dwarf::Tag> getTag() const = 0;
62 
63     /// Returns the raw values of fields in the Accelerator Entry. In general,
64     /// these can only be interpreted with the help of the metadata in the
65     /// owning Accelerator Table.
66     ArrayRef<DWARFFormValue> getValues() const { return Values; }
67   };
68 
69   DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
70                         DataExtractor StringSection)
71       : AccelSection(AccelSection), StringSection(StringSection) {}
72   virtual ~DWARFAcceleratorTable();
73 
74   virtual Error extract() = 0;
75   virtual void dump(raw_ostream &OS) const = 0;
76 
77   DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete;
78   void operator=(const DWARFAcceleratorTable &) = delete;
79 };
80 
81 /// This implements the Apple accelerator table format, a precursor of the
82 /// DWARF 5 accelerator table format.
83 class AppleAcceleratorTable : public DWARFAcceleratorTable {
84   struct Header {
85     uint32_t Magic;
86     uint16_t Version;
87     uint16_t HashFunction;
88     uint32_t BucketCount;
89     uint32_t HashCount;
90     uint32_t HeaderDataLength;
91 
92     void dump(ScopedPrinter &W) const;
93   };
94 
95   struct HeaderData {
96     using AtomType = uint16_t;
97     using Form = dwarf::Form;
98 
99     uint64_t DIEOffsetBase;
100     SmallVector<std::pair<AtomType, Form>, 3> Atoms;
101 
102     Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const;
103   };
104 
105   struct Header Hdr;
106   struct HeaderData HdrData;
107   bool IsValid = false;
108 
109   /// Returns true if we should continue scanning for entries or false if we've
110   /// reached the last (sentinel) entry of encountered a parsing error.
111   bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms,
112                 uint64_t *DataOffset) const;
113 
114 public:
115   /// Apple-specific implementation of an Accelerator Entry.
116   class Entry final : public DWARFAcceleratorTable::Entry {
117     const HeaderData *HdrData = nullptr;
118 
119     Entry(const HeaderData &Data);
120     Entry() = default;
121 
122     void extract(const AppleAcceleratorTable &AccelTable, uint64_t *Offset);
123 
124   public:
125     Optional<uint64_t> getCUOffset() const override;
126 
127     /// Returns the Section Offset of the Debug Info Entry associated with this
128     /// Accelerator Entry or None if the DIE offset is not recorded in this
129     /// Accelerator Entry. The returned offset is relative to the start of the
130     /// Section containing the DIE.
131     Optional<uint64_t> getDIESectionOffset() const;
132 
133     Optional<dwarf::Tag> getTag() const override;
134 
135     /// Returns the value of the Atom in this Accelerator Entry, if the Entry
136     /// contains such Atom.
137     Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
138 
139     friend class AppleAcceleratorTable;
140     friend class ValueIterator;
141   };
142 
143   class ValueIterator {
144     const AppleAcceleratorTable *AccelTable = nullptr;
145     Entry Current;           ///< The current entry.
146     uint64_t DataOffset = 0; ///< Offset into the section.
147     unsigned Data = 0; ///< Current data entry.
148     unsigned NumData = 0; ///< Number of data entries.
149 
150     /// Advance the iterator.
151     void Next();
152 
153   public:
154     using iterator_category = std::input_iterator_tag;
155     using value_type = Entry;
156     using difference_type = std::ptrdiff_t;
157     using pointer = value_type *;
158     using reference = value_type &;
159 
160     /// Construct a new iterator for the entries at \p DataOffset.
161     ValueIterator(const AppleAcceleratorTable &AccelTable, uint64_t DataOffset);
162     /// End marker.
163     ValueIterator() = default;
164 
165     const Entry &operator*() const { return Current; }
166     ValueIterator &operator++() { Next(); return *this; }
167     ValueIterator operator++(int) {
168       ValueIterator I = *this;
169       Next();
170       return I;
171     }
172     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
173       return A.NumData == B.NumData && A.DataOffset == B.DataOffset;
174     }
175     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
176       return !(A == B);
177     }
178   };
179 
180   AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
181                         DataExtractor StringSection)
182       : DWARFAcceleratorTable(AccelSection, StringSection) {}
183 
184   Error extract() override;
185   uint32_t getNumBuckets();
186   uint32_t getNumHashes();
187   uint32_t getSizeHdr();
188   uint32_t getHeaderDataLength();
189 
190   /// Return the Atom description, which can be used to interpret the raw values
191   /// of the Accelerator Entries in this table.
192   ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
193   bool validateForms();
194 
195   /// Return information related to the DWARF DIE we're looking for when
196   /// performing a lookup by name.
197   ///
198   /// \param HashDataOffset an offset into the hash data table
199   /// \returns <DieOffset, DieTag>
200   /// DieOffset is the offset into the .debug_info section for the DIE
201   /// related to the input hash data offset.
202   /// DieTag is the tag of the DIE
203   std::pair<uint64_t, dwarf::Tag> readAtoms(uint64_t *HashDataOffset);
204   void dump(raw_ostream &OS) const override;
205 
206   /// Look up all entries in the accelerator table matching \c Key.
207   iterator_range<ValueIterator> equal_range(StringRef Key) const;
208 };
209 
210 /// .debug_names section consists of one or more units. Each unit starts with a
211 /// header, which is followed by a list of compilation units, local and foreign
212 /// type units.
213 ///
214 /// These may be followed by an (optional) hash lookup table, which consists of
215 /// an array of buckets and hashes similar to the apple tables above. The only
216 /// difference is that the hashes array is 1-based, and consequently an empty
217 /// bucket is denoted by 0 and not UINT32_MAX.
218 ///
219 /// Next is the name table, which consists of an array of names and array of
220 /// entry offsets. This is different from the apple tables, which store names
221 /// next to the actual entries.
222 ///
223 /// The structure of the entries is described by an abbreviations table, which
224 /// comes after the name table. Unlike the apple tables, which have a uniform
225 /// entry structure described in the header, each .debug_names entry may have
226 /// different index attributes (DW_IDX_???) attached to it.
227 ///
228 /// The last segment consists of a list of entries, which is a 0-terminated list
229 /// referenced by the name table and interpreted with the help of the
230 /// abbreviation table.
231 class DWARFDebugNames : public DWARFAcceleratorTable {
232 public:
233   class NameIndex;
234   class NameIterator;
235   class ValueIterator;
236 
237   /// DWARF v5 Name Index header.
238   struct Header {
239     uint64_t UnitLength;
240     dwarf::DwarfFormat Format;
241     uint16_t Version;
242     uint32_t CompUnitCount;
243     uint32_t LocalTypeUnitCount;
244     uint32_t ForeignTypeUnitCount;
245     uint32_t BucketCount;
246     uint32_t NameCount;
247     uint32_t AbbrevTableSize;
248     uint32_t AugmentationStringSize;
249     SmallString<8> AugmentationString;
250 
251     Error extract(const DWARFDataExtractor &AS, uint64_t *Offset);
252     void dump(ScopedPrinter &W) const;
253   };
254 
255   /// Index attribute and its encoding.
256   struct AttributeEncoding {
257     dwarf::Index Index;
258     dwarf::Form Form;
259 
260     constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form)
261         : Index(Index), Form(Form) {}
262 
263     friend bool operator==(const AttributeEncoding &LHS,
264                            const AttributeEncoding &RHS) {
265       return LHS.Index == RHS.Index && LHS.Form == RHS.Form;
266     }
267   };
268 
269   /// Abbreviation describing the encoding of Name Index entries.
270   struct Abbrev {
271     uint32_t Code;  ///< Abbreviation code
272     dwarf::Tag Tag; ///< Dwarf Tag of the described entity.
273     std::vector<AttributeEncoding> Attributes; ///< List of index attributes.
274 
275     Abbrev(uint32_t Code, dwarf::Tag Tag,
276            std::vector<AttributeEncoding> Attributes)
277         : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {}
278 
279     void dump(ScopedPrinter &W) const;
280   };
281 
282   /// DWARF v5-specific implementation of an Accelerator Entry.
283   class Entry final : public DWARFAcceleratorTable::Entry {
284     const NameIndex *NameIdx;
285     const Abbrev *Abbr;
286 
287     Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
288 
289   public:
290     Optional<uint64_t> getCUOffset() const override;
291     Optional<dwarf::Tag> getTag() const override { return tag(); }
292 
293     /// Returns the Index into the Compilation Unit list of the owning Name
294     /// Index or None if this Accelerator Entry does not have an associated
295     /// Compilation Unit. It is up to the user to verify that the returned Index
296     /// is valid in the owning NameIndex (or use getCUOffset(), which will
297     /// handle that check itself). Note that entries in NameIndexes which index
298     /// just a single Compilation Unit are implicitly associated with that unit,
299     /// so this function will return 0 even without an explicit
300     /// DW_IDX_compile_unit attribute.
301     Optional<uint64_t> getCUIndex() const;
302 
303     /// .debug_names-specific getter, which always succeeds (DWARF v5 index
304     /// entries always have a tag).
305     dwarf::Tag tag() const { return Abbr->Tag; }
306 
307     /// Returns the Offset of the DIE within the containing CU or TU.
308     Optional<uint64_t> getDIEUnitOffset() const;
309 
310     /// Return the Abbreviation that can be used to interpret the raw values of
311     /// this Accelerator Entry.
312     const Abbrev &getAbbrev() const { return *Abbr; }
313 
314     /// Returns the value of the Index Attribute in this Accelerator Entry, if
315     /// the Entry contains such Attribute.
316     Optional<DWARFFormValue> lookup(dwarf::Index Index) const;
317 
318     void dump(ScopedPrinter &W) const;
319 
320     friend class NameIndex;
321     friend class ValueIterator;
322   };
323 
324   /// Error returned by NameIndex::getEntry to report it has reached the end of
325   /// the entry list.
326   class SentinelError : public ErrorInfo<SentinelError> {
327   public:
328     static char ID;
329 
330     void log(raw_ostream &OS) const override { OS << "Sentinel"; }
331     std::error_code convertToErrorCode() const override;
332   };
333 
334 private:
335   /// DenseMapInfo for struct Abbrev.
336   struct AbbrevMapInfo {
337     static Abbrev getEmptyKey();
338     static Abbrev getTombstoneKey();
339     static unsigned getHashValue(uint32_t Code) {
340       return DenseMapInfo<uint32_t>::getHashValue(Code);
341     }
342     static unsigned getHashValue(const Abbrev &Abbr) {
343       return getHashValue(Abbr.Code);
344     }
345     static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
346       return LHS == RHS.Code;
347     }
348     static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
349       return LHS.Code == RHS.Code;
350     }
351   };
352 
353 public:
354   /// A single entry in the Name Table (DWARF v5 sect. 6.1.1.4.6) of the Name
355   /// Index.
356   class NameTableEntry {
357     DataExtractor StrData;
358 
359     uint32_t Index;
360     uint64_t StringOffset;
361     uint64_t EntryOffset;
362 
363   public:
364     NameTableEntry(const DataExtractor &StrData, uint32_t Index,
365                    uint64_t StringOffset, uint64_t EntryOffset)
366         : StrData(StrData), Index(Index), StringOffset(StringOffset),
367           EntryOffset(EntryOffset) {}
368 
369     /// Return the index of this name in the parent Name Index.
370     uint32_t getIndex() const { return Index; }
371 
372     /// Returns the offset of the name of the described entities.
373     uint64_t getStringOffset() const { return StringOffset; }
374 
375     /// Return the string referenced by this name table entry or nullptr if the
376     /// string offset is not valid.
377     const char *getString() const {
378       uint64_t Off = StringOffset;
379       return StrData.getCStr(&Off);
380     }
381 
382     /// Returns the offset of the first Entry in the list.
383     uint64_t getEntryOffset() const { return EntryOffset; }
384   };
385 
386   /// Represents a single accelerator table within the DWARF v5 .debug_names
387   /// section.
388   class NameIndex {
389     DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
390     struct Header Hdr;
391     const DWARFDebugNames &Section;
392 
393     // Base of the whole unit and of various important tables, as offsets from
394     // the start of the section.
395     uint64_t Base;
396     uint64_t CUsBase;
397     uint64_t BucketsBase;
398     uint64_t HashesBase;
399     uint64_t StringOffsetsBase;
400     uint64_t EntryOffsetsBase;
401     uint64_t EntriesBase;
402 
403     void dumpCUs(ScopedPrinter &W) const;
404     void dumpLocalTUs(ScopedPrinter &W) const;
405     void dumpForeignTUs(ScopedPrinter &W) const;
406     void dumpAbbreviations(ScopedPrinter &W) const;
407     bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const;
408     void dumpName(ScopedPrinter &W, const NameTableEntry &NTE,
409                   Optional<uint32_t> Hash) const;
410     void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
411 
412     Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset);
413 
414     Expected<std::vector<AttributeEncoding>>
415     extractAttributeEncodings(uint64_t *Offset);
416 
417     Expected<Abbrev> extractAbbrev(uint64_t *Offset);
418 
419   public:
420     NameIndex(const DWARFDebugNames &Section, uint64_t Base)
421         : Section(Section), Base(Base) {}
422 
423     /// Reads offset of compilation unit CU. CU is 0-based.
424     uint64_t getCUOffset(uint32_t CU) const;
425     uint32_t getCUCount() const { return Hdr.CompUnitCount; }
426 
427     /// Reads offset of local type unit TU, TU is 0-based.
428     uint64_t getLocalTUOffset(uint32_t TU) const;
429     uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
430 
431     /// Reads signature of foreign type unit TU. TU is 0-based.
432     uint64_t getForeignTUSignature(uint32_t TU) const;
433     uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
434 
435     /// Reads an entry in the Bucket Array for the given Bucket. The returned
436     /// value is a (1-based) index into the Names, StringOffsets and
437     /// EntryOffsets arrays. The input Bucket index is 0-based.
438     uint32_t getBucketArrayEntry(uint32_t Bucket) const;
439     uint32_t getBucketCount() const { return Hdr.BucketCount; }
440 
441     /// Reads an entry in the Hash Array for the given Index. The input Index
442     /// is 1-based.
443     uint32_t getHashArrayEntry(uint32_t Index) const;
444 
445     /// Reads an entry in the Name Table for the given Index. The Name Table
446     /// consists of two arrays -- String Offsets and Entry Offsets. The returned
447     /// offsets are relative to the starts of respective sections. Input Index
448     /// is 1-based.
449     NameTableEntry getNameTableEntry(uint32_t Index) const;
450 
451     uint32_t getNameCount() const { return Hdr.NameCount; }
452 
453     const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
454       return Abbrevs;
455     }
456 
457     Expected<Entry> getEntry(uint64_t *Offset) const;
458 
459     /// Look up all entries in this Name Index matching \c Key.
460     iterator_range<ValueIterator> equal_range(StringRef Key) const;
461 
462     NameIterator begin() const { return NameIterator(this, 1); }
463     NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
464 
465     Error extract();
466     uint64_t getUnitOffset() const { return Base; }
467     uint64_t getNextUnitOffset() const {
468       return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) +
469              Hdr.UnitLength;
470     }
471     void dump(ScopedPrinter &W) const;
472 
473     friend class DWARFDebugNames;
474   };
475 
476   class ValueIterator {
477   public:
478     using iterator_category = std::input_iterator_tag;
479     using value_type = Entry;
480     using difference_type = std::ptrdiff_t;
481     using pointer = value_type *;
482     using reference = value_type &;
483 
484   private:
485     /// The Name Index we are currently iterating through. The implementation
486     /// relies on the fact that this can also be used as an iterator into the
487     /// "NameIndices" vector in the Accelerator section.
488     const NameIndex *CurrentIndex = nullptr;
489 
490     /// Whether this is a local iterator (searches in CurrentIndex only) or not
491     /// (searches all name indices).
492     bool IsLocal;
493 
494     Optional<Entry> CurrentEntry;
495     uint64_t DataOffset = 0; ///< Offset into the section.
496     std::string Key;         ///< The Key we are searching for.
497     Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
498 
499     bool getEntryAtCurrentOffset();
500     Optional<uint64_t> findEntryOffsetInCurrentIndex();
501     bool findInCurrentIndex();
502     void searchFromStartOfCurrentIndex();
503     void next();
504 
505     /// Set the iterator to the "end" state.
506     void setEnd() { *this = ValueIterator(); }
507 
508   public:
509     /// Create a "begin" iterator for looping over all entries in the
510     /// accelerator table matching Key. The iterator will run through all Name
511     /// Indexes in the section in sequence.
512     ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
513 
514     /// Create a "begin" iterator for looping over all entries in a specific
515     /// Name Index. Other indices in the section will not be visited.
516     ValueIterator(const NameIndex &NI, StringRef Key);
517 
518     /// End marker.
519     ValueIterator() = default;
520 
521     const Entry &operator*() const { return *CurrentEntry; }
522     ValueIterator &operator++() {
523       next();
524       return *this;
525     }
526     ValueIterator operator++(int) {
527       ValueIterator I = *this;
528       next();
529       return I;
530     }
531 
532     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
533       return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
534     }
535     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
536       return !(A == B);
537     }
538   };
539 
540   class NameIterator {
541 
542     /// The Name Index we are iterating through.
543     const NameIndex *CurrentIndex;
544 
545     /// The current name in the Name Index.
546     uint32_t CurrentName;
547 
548     void next() {
549       assert(CurrentName <= CurrentIndex->getNameCount());
550       ++CurrentName;
551     }
552 
553   public:
554     using iterator_category = std::input_iterator_tag;
555     using value_type = NameTableEntry;
556     using difference_type = uint32_t;
557     using pointer = NameTableEntry *;
558     using reference = NameTableEntry; // We return entries by value.
559 
560     /// Creates an iterator whose initial position is name CurrentName in
561     /// CurrentIndex.
562     NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
563         : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
564 
565     NameTableEntry operator*() const {
566       return CurrentIndex->getNameTableEntry(CurrentName);
567     }
568     NameIterator &operator++() {
569       next();
570       return *this;
571     }
572     NameIterator operator++(int) {
573       NameIterator I = *this;
574       next();
575       return I;
576     }
577 
578     friend bool operator==(const NameIterator &A, const NameIterator &B) {
579       return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
580     }
581     friend bool operator!=(const NameIterator &A, const NameIterator &B) {
582       return !(A == B);
583     }
584   };
585 
586 private:
587   SmallVector<NameIndex, 0> NameIndices;
588   DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
589 
590 public:
591   DWARFDebugNames(const DWARFDataExtractor &AccelSection,
592                   DataExtractor StringSection)
593       : DWARFAcceleratorTable(AccelSection, StringSection) {}
594 
595   Error extract() override;
596   void dump(raw_ostream &OS) const override;
597 
598   /// Look up all entries in the accelerator table matching \c Key.
599   iterator_range<ValueIterator> equal_range(StringRef Key) const;
600 
601   using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
602   const_iterator begin() const { return NameIndices.begin(); }
603   const_iterator end() const { return NameIndices.end(); }
604 
605   /// Return the Name Index covering the compile unit at CUOffset, or nullptr if
606   /// there is no Name Index covering that unit.
607   const NameIndex *getCUNameIndex(uint64_t CUOffset);
608 };
609 
610 } // end namespace llvm
611 
612 #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
613