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