xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/SmallString.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/BinaryFormat/Dwarf.h"
16 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
17 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
18 #include "llvm/Support/Compiler.h"
19 #include <cstdint>
20 #include <utility>
21 
22 namespace llvm {
23 
24 class raw_ostream;
25 class ScopedPrinter;
26 
27 /// The accelerator tables are designed to allow efficient random access
28 /// (using a symbol name as a key) into debug info by providing an index of the
29 /// debug info DIEs. This class implements the common functionality of Apple and
30 /// DWARF 5 accelerator tables.
31 /// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it
32 /// to this class.
33 class LLVM_ABI DWARFAcceleratorTable {
34 protected:
35   DWARFDataExtractor AccelSection;
36   DataExtractor StringSection;
37 
38 public:
39   /// An abstract class representing a single entry in the accelerator tables.
40   class Entry {
41   protected:
42     SmallVector<DWARFFormValue, 3> Values;
43 
44     Entry() = default;
45 
46     // Make these protected so only (final) subclasses can be copied around.
47     Entry(const Entry &) = default;
48     Entry(Entry &&) = default;
49     Entry &operator=(const Entry &) = default;
50     Entry &operator=(Entry &&) = default;
51     ~Entry() = default;
52 
53 
54   public:
55     /// Returns the Offset of the Compilation Unit associated with this
56     /// Accelerator Entry or std::nullopt if the Compilation Unit offset is not
57     /// recorded in this Accelerator Entry.
58     virtual std::optional<uint64_t> getCUOffset() const = 0;
59 
60     /// Returns the Offset of the Type Unit associated with this
61     /// Accelerator Entry or std::nullopt if the Type Unit offset is not
62     /// recorded in this Accelerator Entry.
getLocalTUOffset()63     virtual std::optional<uint64_t> getLocalTUOffset() const {
64       // Default return for accelerator tables that don't support type units.
65       return std::nullopt;
66     }
67 
68     /// Returns the type signature of the Type Unit associated with this
69     /// Accelerator Entry or std::nullopt if the Type Unit offset is not
70     /// recorded in this Accelerator Entry.
getForeignTUTypeSignature()71     virtual std::optional<uint64_t> getForeignTUTypeSignature() const {
72       // Default return for accelerator tables that don't support type units.
73       return std::nullopt;
74     }
75 
76     /// Returns the Tag of the Debug Info Entry associated with this
77     /// Accelerator Entry or std::nullopt if the Tag is not recorded in this
78     /// Accelerator Entry.
79     virtual std::optional<dwarf::Tag> getTag() const = 0;
80 
81     /// Returns the raw values of fields in the Accelerator Entry. In general,
82     /// these can only be interpreted with the help of the metadata in the
83     /// owning Accelerator Table.
getValues()84     ArrayRef<DWARFFormValue> getValues() const { return Values; }
85   };
86 
DWARFAcceleratorTable(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)87   DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
88                         DataExtractor StringSection)
89       : AccelSection(AccelSection), StringSection(StringSection) {}
90   virtual ~DWARFAcceleratorTable();
91 
92   virtual Error extract() = 0;
93   virtual void dump(raw_ostream &OS) const = 0;
94 
95   DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete;
96   void operator=(const DWARFAcceleratorTable &) = delete;
97 };
98 
99 /// This implements the Apple accelerator table format, a precursor of the
100 /// DWARF 5 accelerator table format.
101 class LLVM_ABI AppleAcceleratorTable : public DWARFAcceleratorTable {
102   struct Header {
103     uint32_t Magic;
104     uint16_t Version;
105     uint16_t HashFunction;
106     uint32_t BucketCount;
107     uint32_t HashCount;
108     uint32_t HeaderDataLength;
109 
110     LLVM_ABI void dump(ScopedPrinter &W) const;
111   };
112 
113   struct HeaderData {
114     using AtomType = uint16_t;
115     using Form = dwarf::Form;
116 
117     uint64_t DIEOffsetBase;
118     SmallVector<std::pair<AtomType, Form>, 3> Atoms;
119 
120     LLVM_ABI std::optional<uint64_t>
121     extractOffset(std::optional<DWARFFormValue> Value) const;
122   };
123 
124   Header Hdr;
125   HeaderData HdrData;
126   dwarf::FormParams FormParams;
127   uint32_t HashDataEntryLength;
128   bool IsValid = false;
129 
130   /// Returns true if we should continue scanning for entries or false if we've
131   /// reached the last (sentinel) entry of encountered a parsing error.
132   bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms,
133                 uint64_t *DataOffset) const;
134 
135   /// Reads an uint32_t from the accelerator table at Offset, which is
136   /// incremented by the number of bytes read.
137   std::optional<uint32_t> readU32FromAccel(uint64_t &Offset,
138                                            bool UseRelocation = false) const;
139 
140   /// Reads a StringRef from the string table at Offset.
141   std::optional<StringRef>
142   readStringFromStrSection(uint64_t StringSectionOffset) const;
143 
144   /// Return the offset into the section where the Buckets begin.
getBucketBase()145   uint64_t getBucketBase() const { return sizeof(Hdr) + Hdr.HeaderDataLength; }
146 
147   /// Return the offset into the section where the I-th bucket is.
getIthBucketBase(uint32_t I)148   uint64_t getIthBucketBase(uint32_t I) const {
149     return getBucketBase() + I * 4;
150   }
151 
152   /// Return the offset into the section where the hash list begins.
getHashBase()153   uint64_t getHashBase() const { return getBucketBase() + getNumBuckets() * 4; }
154 
155   /// Return the offset into the section where the I-th hash is.
getIthHashBase(uint32_t I)156   uint64_t getIthHashBase(uint32_t I) const { return getHashBase() + I * 4; }
157 
158   /// Return the offset into the section where the offset list begins.
getOffsetBase()159   uint64_t getOffsetBase() const { return getHashBase() + getNumHashes() * 4; }
160 
161   /// Return the offset into the section where the table entries begin.
getEntriesBase()162   uint64_t getEntriesBase() const {
163     return getOffsetBase() + getNumHashes() * 4;
164   }
165 
166   /// Return the offset into the section where the I-th offset is.
getIthOffsetBase(uint32_t I)167   uint64_t getIthOffsetBase(uint32_t I) const {
168     return getOffsetBase() + I * 4;
169   }
170 
171   /// Returns the index of the bucket where a hypothetical Hash would be.
hashToBucketIdx(uint32_t Hash)172   uint32_t hashToBucketIdx(uint32_t Hash) const {
173     return Hash % getNumBuckets();
174   }
175 
176   /// Returns true iff a hypothetical Hash would be assigned to the BucketIdx-th
177   /// bucket.
wouldHashBeInBucket(uint32_t Hash,uint32_t BucketIdx)178   bool wouldHashBeInBucket(uint32_t Hash, uint32_t BucketIdx) const {
179     return hashToBucketIdx(Hash) == BucketIdx;
180   }
181 
182   /// Reads the contents of the I-th bucket, that is, the index in the hash list
183   /// where the hashes corresponding to this bucket begin.
readIthBucket(uint32_t I)184   std::optional<uint32_t> readIthBucket(uint32_t I) const {
185     uint64_t Offset = getIthBucketBase(I);
186     return readU32FromAccel(Offset);
187   }
188 
189   /// Reads the I-th hash in the hash list.
readIthHash(uint32_t I)190   std::optional<uint32_t> readIthHash(uint32_t I) const {
191     uint64_t Offset = getIthHashBase(I);
192     return readU32FromAccel(Offset);
193   }
194 
195   /// Reads the I-th offset in the offset list.
readIthOffset(uint32_t I)196   std::optional<uint32_t> readIthOffset(uint32_t I) const {
197     uint64_t Offset = getIthOffsetBase(I);
198     return readU32FromAccel(Offset);
199   }
200 
201   /// Reads a string offset from the accelerator table at Offset, which is
202   /// incremented by the number of bytes read.
readStringOffsetAt(uint64_t & Offset)203   std::optional<uint32_t> readStringOffsetAt(uint64_t &Offset) const {
204     return readU32FromAccel(Offset, /*UseRelocation*/ true);
205   }
206 
207   /// Scans through all Hashes in the BucketIdx-th bucket, attempting to find
208   /// HashToFind. If it is found, its index in the list of hashes is returned.
209   std::optional<uint32_t> idxOfHashInBucket(uint32_t HashToFind,
210                                             uint32_t BucketIdx) const;
211 
212 public:
213   /// Apple-specific implementation of an Accelerator Entry.
214   class LLVM_ABI Entry final : public DWARFAcceleratorTable::Entry {
215     const AppleAcceleratorTable &Table;
216 
217     Entry(const AppleAcceleratorTable &Table);
218     void extract(uint64_t *Offset);
219 
220   public:
221     std::optional<uint64_t> getCUOffset() const override;
222 
223     /// Returns the Section Offset of the Debug Info Entry associated with this
224     /// Accelerator Entry or std::nullopt if the DIE offset is not recorded in
225     /// this Accelerator Entry. The returned offset is relative to the start of
226     /// the Section containing the DIE.
227     std::optional<uint64_t> getDIESectionOffset() const;
228 
229     std::optional<dwarf::Tag> getTag() const override;
230 
231     /// Returns the value of the Atom in this Accelerator Entry, if the Entry
232     /// contains such Atom.
233     std::optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
234 
235     friend class AppleAcceleratorTable;
236     friend class ValueIterator;
237   };
238 
239   /// An iterator for Entries all having the same string as key.
240   class SameNameIterator
241       : public iterator_facade_base<SameNameIterator, std::forward_iterator_tag,
242                                     Entry> {
243     Entry Current;
244     uint64_t Offset = 0;
245 
246   public:
247     /// Construct a new iterator for the entries at \p DataOffset.
248     LLVM_ABI SameNameIterator(const AppleAcceleratorTable &AccelTable,
249                               uint64_t DataOffset);
250 
251     const Entry &operator*() {
252       uint64_t OffsetCopy = Offset;
253       Current.extract(&OffsetCopy);
254       return Current;
255     }
256     SameNameIterator &operator++() {
257       Offset += Current.Table.getHashDataEntryLength();
258       return *this;
259     }
260     friend bool operator==(const SameNameIterator &A,
261                            const SameNameIterator &B) {
262       return A.Offset == B.Offset;
263     }
264   };
265 
266   struct EntryWithName {
EntryWithNameEntryWithName267     EntryWithName(const AppleAcceleratorTable &Table)
268         : BaseEntry(Table), StrOffset(0) {}
269 
readNameEntryWithName270     std::optional<StringRef> readName() const {
271       return BaseEntry.Table.readStringFromStrSection(StrOffset);
272     }
273 
274     Entry BaseEntry;
275     uint32_t StrOffset;
276   };
277 
278   /// An iterator for all entries in the table.
279   class Iterator
280       : public iterator_facade_base<Iterator, std::forward_iterator_tag,
281                                     EntryWithName> {
282     constexpr static auto EndMarker = std::numeric_limits<uint64_t>::max();
283 
284     EntryWithName Current;
285     uint64_t Offset = EndMarker;
286     uint32_t NumEntriesToCome = 0;
287 
setToEnd()288     void setToEnd() { Offset = EndMarker; }
isEnd()289     bool isEnd() const { return Offset == EndMarker; }
getTable()290     const AppleAcceleratorTable &getTable() const {
291       return Current.BaseEntry.Table;
292     }
293 
294     /// Reads the next Entry in the table, populating `Current`.
295     /// If not possible (e.g. end of the section), becomes the end iterator.
296     LLVM_ABI void prepareNextEntryOrEnd();
297 
298     /// Reads the next string pointer and the entry count for that string,
299     /// populating `NumEntriesToCome`.
300     /// If not possible (e.g. end of the section), becomes the end iterator.
301     /// Assumes `Offset` points to a string reference.
302     void prepareNextStringOrEnd();
303 
304   public:
305     LLVM_ABI Iterator(const AppleAcceleratorTable &Table, bool SetEnd = false);
306 
307     Iterator &operator++() {
308       prepareNextEntryOrEnd();
309       return *this;
310     }
311     bool operator==(const Iterator &It) const { return Offset == It.Offset; }
312     const EntryWithName &operator*() const {
313       assert(!isEnd() && "dereferencing end iterator");
314       return Current;
315     }
316   };
317 
AppleAcceleratorTable(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)318   AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
319                         DataExtractor StringSection)
320       : DWARFAcceleratorTable(AccelSection, StringSection) {}
321 
322   Error extract() override;
323   uint32_t getNumBuckets() const;
324   uint32_t getNumHashes() const;
325   uint32_t getSizeHdr() const;
326   uint32_t getHeaderDataLength() const;
327 
328   /// Returns the size of one HashData entry.
getHashDataEntryLength()329   uint32_t getHashDataEntryLength() const { return HashDataEntryLength; }
330 
331   /// Return the Atom description, which can be used to interpret the raw values
332   /// of the Accelerator Entries in this table.
333   ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
334 
335   /// Returns true iff `AtomTy` is one of the atoms available in Entries of this
336   /// table.
containsAtomType(HeaderData::AtomType AtomTy)337   bool containsAtomType(HeaderData::AtomType AtomTy) const {
338     return is_contained(make_first_range(HdrData.Atoms), AtomTy);
339   }
340 
341   bool validateForms();
342 
343   /// Return information related to the DWARF DIE we're looking for when
344   /// performing a lookup by name.
345   ///
346   /// \param HashDataOffset an offset into the hash data table
347   /// \returns <DieOffset, DieTag>
348   /// DieOffset is the offset into the .debug_info section for the DIE
349   /// related to the input hash data offset.
350   /// DieTag is the tag of the DIE
351   std::pair<uint64_t, dwarf::Tag> readAtoms(uint64_t *HashDataOffset);
352   void dump(raw_ostream &OS) const override;
353 
354   /// Look up all entries in the accelerator table matching \c Key.
355   iterator_range<SameNameIterator> equal_range(StringRef Key) const;
356 
357   /// Lookup all entries in the accelerator table.
entries()358   auto entries() const {
359     return make_range(Iterator(*this), Iterator(*this, /*SetEnd*/ true));
360   }
361 };
362 
363 /// .debug_names section consists of one or more units. Each unit starts with a
364 /// header, which is followed by a list of compilation units, local and foreign
365 /// type units.
366 ///
367 /// These may be followed by an (optional) hash lookup table, which consists of
368 /// an array of buckets and hashes similar to the apple tables above. The only
369 /// difference is that the hashes array is 1-based, and consequently an empty
370 /// bucket is denoted by 0 and not UINT32_MAX.
371 ///
372 /// Next is the name table, which consists of an array of names and array of
373 /// entry offsets. This is different from the apple tables, which store names
374 /// next to the actual entries.
375 ///
376 /// The structure of the entries is described by an abbreviations table, which
377 /// comes after the name table. Unlike the apple tables, which have a uniform
378 /// entry structure described in the header, each .debug_names entry may have
379 /// different index attributes (DW_IDX_???) attached to it.
380 ///
381 /// The last segment consists of a list of entries, which is a 0-terminated list
382 /// referenced by the name table and interpreted with the help of the
383 /// abbreviation table.
384 class LLVM_ABI DWARFDebugNames : public DWARFAcceleratorTable {
385 public:
386   class NameIndex;
387   class NameIterator;
388   class ValueIterator;
389 
390   /// DWARF v5 Name Index header.
391   struct Header {
392     uint64_t UnitLength;
393     dwarf::DwarfFormat Format;
394     uint16_t Version;
395     uint32_t CompUnitCount;
396     uint32_t LocalTypeUnitCount;
397     uint32_t ForeignTypeUnitCount;
398     uint32_t BucketCount;
399     uint32_t NameCount;
400     uint32_t AbbrevTableSize;
401     uint32_t AugmentationStringSize;
402     SmallString<8> AugmentationString;
403 
404     LLVM_ABI Error extract(const DWARFDataExtractor &AS, uint64_t *Offset);
405     LLVM_ABI void dump(ScopedPrinter &W) const;
406   };
407 
408   /// Index attribute and its encoding.
409   struct AttributeEncoding {
410     dwarf::Index Index;
411     dwarf::Form Form;
412 
AttributeEncodingAttributeEncoding413     constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form)
414         : Index(Index), Form(Form) {}
415 
416     friend bool operator==(const AttributeEncoding &LHS,
417                            const AttributeEncoding &RHS) {
418       return LHS.Index == RHS.Index && LHS.Form == RHS.Form;
419     }
420   };
421 
422   /// Abbreviation describing the encoding of Name Index entries.
423   struct Abbrev {
424     uint64_t AbbrevOffset; /// < Abbreviation offset in the .debug_names section
425     uint32_t Code;         ///< Abbreviation code
426     dwarf::Tag Tag; ///< Dwarf Tag of the described entity.
427     std::vector<AttributeEncoding> Attributes; ///< List of index attributes.
428 
AbbrevAbbrev429     Abbrev(uint32_t Code, dwarf::Tag Tag, uint64_t AbbrevOffset,
430            std::vector<AttributeEncoding> Attributes)
431         : AbbrevOffset(AbbrevOffset), Code(Code), Tag(Tag),
432           Attributes(std::move(Attributes)) {}
433 
434     LLVM_ABI void dump(ScopedPrinter &W) const;
435   };
436 
437   /// DWARF v5-specific implementation of an Accelerator Entry.
438   class LLVM_ABI Entry final : public DWARFAcceleratorTable::Entry {
439     const NameIndex *NameIdx;
440     const Abbrev *Abbr;
441 
442     Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
443 
444   public:
getNameIndex()445     const NameIndex *getNameIndex() const { return NameIdx; }
446     std::optional<uint64_t> getCUOffset() const override;
447     std::optional<uint64_t> getLocalTUOffset() const override;
448     std::optional<uint64_t> getForeignTUTypeSignature() const override;
getTag()449     std::optional<dwarf::Tag> getTag() const override { return tag(); }
450 
451     // Special function that will return the related CU offset needed type
452     // units. This gets used to find the .dwo file that originated the entries
453     // for a given type unit.
454     std::optional<uint64_t> getRelatedCUOffset() const;
455 
456     /// Returns the Index into the Compilation Unit list of the owning Name
457     /// Index or std::nullopt if this Accelerator Entry does not have an
458     /// associated Compilation Unit. It is up to the user to verify that the
459     /// returned Index is valid in the owning NameIndex (or use getCUOffset(),
460     /// which will handle that check itself). Note that entries in NameIndexes
461     /// which index just a single Compilation Unit are implicitly associated
462     /// with that unit, so this function will return 0 even without an explicit
463     /// DW_IDX_compile_unit attribute, unless there is a DW_IDX_type_unit
464     /// attribute.
465     std::optional<uint64_t> getCUIndex() const;
466 
467     /// Similar functionality to getCUIndex() but without the DW_IDX_type_unit
468     /// restriction. This allows us to get the associated a compilation unit
469     /// index for an entry that is a type unit.
470     std::optional<uint64_t> getRelatedCUIndex() const;
471 
472     /// Returns the index of the Type Unit of the owning
473     /// Name
474     /// Index or std::nullopt if this Accelerator Entry does not have an
475     /// associated Type Unit. It is up to the user to verify that the
476     /// returned Index is a valid index in the owning NameIndex (or use
477     /// getLocalTUOffset(), which will handle that check itself).
478     std::optional<uint64_t> getTUIndex() const;
479 
480     /// .debug_names-specific getter, which always succeeds (DWARF v5 index
481     /// entries always have a tag).
tag()482     dwarf::Tag tag() const { return Abbr->Tag; }
483 
484     /// Returns the Offset of the DIE within the containing CU or TU.
485     std::optional<uint64_t> getDIEUnitOffset() const;
486 
487     /// Returns true if this Entry has information about its parent DIE (i.e. if
488     /// it has an IDX_parent attribute)
489     bool hasParentInformation() const;
490 
491     /// Returns the Entry corresponding to the parent of the DIE represented by
492     /// `this` Entry. If the parent is not in the table, nullopt is returned.
493     /// Precondition: hasParentInformation() == true.
494     /// An error is returned for ill-formed tables.
495     Expected<std::optional<DWARFDebugNames::Entry>> getParentDIEEntry() const;
496 
497     /// Return the Abbreviation that can be used to interpret the raw values of
498     /// this Accelerator Entry.
getAbbrev()499     const Abbrev &getAbbrev() const { return *Abbr; }
500 
501     /// Returns the value of the Index Attribute in this Accelerator Entry, if
502     /// the Entry contains such Attribute.
503     std::optional<DWARFFormValue> lookup(dwarf::Index Index) const;
504 
505     void dump(ScopedPrinter &W) const;
506     void dumpParentIdx(ScopedPrinter &W, const DWARFFormValue &FormValue) const;
507 
508     friend class NameIndex;
509     friend class ValueIterator;
510   };
511 
512   /// Error returned by NameIndex::getEntry to report it has reached the end of
513   /// the entry list.
514   class LLVM_ABI SentinelError : public ErrorInfo<SentinelError> {
515   public:
516     static char ID;
517 
log(raw_ostream & OS)518     void log(raw_ostream &OS) const override { OS << "Sentinel"; }
519     std::error_code convertToErrorCode() const override;
520   };
521 
522 private:
523   /// DenseMapInfo for struct Abbrev.
524   struct AbbrevMapInfo {
525     LLVM_ABI static Abbrev getEmptyKey();
526     LLVM_ABI static Abbrev getTombstoneKey();
getHashValueAbbrevMapInfo527     static unsigned getHashValue(uint32_t Code) {
528       return DenseMapInfo<uint32_t>::getHashValue(Code);
529     }
getHashValueAbbrevMapInfo530     static unsigned getHashValue(const Abbrev &Abbr) {
531       return getHashValue(Abbr.Code);
532     }
isEqualAbbrevMapInfo533     static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
534       return LHS == RHS.Code;
535     }
isEqualAbbrevMapInfo536     static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
537       return LHS.Code == RHS.Code;
538     }
539   };
540 
541 public:
542   /// A single entry in the Name Table (DWARF v5 sect. 6.1.1.4.6) of the Name
543   /// Index.
544   class NameTableEntry {
545     DataExtractor StrData;
546 
547     uint32_t Index;
548     uint64_t StringOffset;
549     uint64_t EntryOffset;
550 
551   public:
NameTableEntry(const DataExtractor & StrData,uint32_t Index,uint64_t StringOffset,uint64_t EntryOffset)552     NameTableEntry(const DataExtractor &StrData, uint32_t Index,
553                    uint64_t StringOffset, uint64_t EntryOffset)
554         : StrData(StrData), Index(Index), StringOffset(StringOffset),
555           EntryOffset(EntryOffset) {}
556 
557     /// Return the index of this name in the parent Name Index.
getIndex()558     uint32_t getIndex() const { return Index; }
559 
560     /// Returns the offset of the name of the described entities.
getStringOffset()561     uint64_t getStringOffset() const { return StringOffset; }
562 
563     /// Return the string referenced by this name table entry or nullptr if the
564     /// string offset is not valid.
getString()565     const char *getString() const {
566       uint64_t Off = StringOffset;
567       return StrData.getCStr(&Off);
568     }
569 
570     /// Compares the name of this entry against Target, returning true if they
571     /// are equal. This is more efficient in hot code paths that do not need the
572     /// length of the name.
sameNameAs(StringRef Target)573     bool sameNameAs(StringRef Target) const {
574       // Note: this is not the name, but the rest of debug_str starting from
575       // name. This handles corrupt data (non-null terminated) without
576       // overrunning the buffer.
577       StringRef Data = StrData.getData().substr(StringOffset);
578       size_t TargetSize = Target.size();
579       return Data.size() > TargetSize && !Data[TargetSize] &&
580              strncmp(Data.data(), Target.data(), TargetSize) == 0;
581     }
582 
583     /// Returns the offset of the first Entry in the list.
getEntryOffset()584     uint64_t getEntryOffset() const { return EntryOffset; }
585   };
586 
587   /// Offsets for the start of various important tables from the start of the
588   /// section.
589   struct DWARFDebugNamesOffsets {
590     uint64_t CUsBase;
591     uint64_t BucketsBase;
592     uint64_t HashesBase;
593     uint64_t StringOffsetsBase;
594     uint64_t EntryOffsetsBase;
595     uint64_t EntriesBase;
596   };
597 
598   /// Represents a single accelerator table within the DWARF v5 .debug_names
599   /// section.
600   class NameIndex {
601     DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
602     struct Header Hdr;
603     const DWARFDebugNames &Section;
604 
605     // Base of the whole unit and of various important tables, as offsets from
606     // the start of the section.
607     uint64_t Base;
608     DWARFDebugNamesOffsets Offsets;
609 
610     void dumpCUs(ScopedPrinter &W) const;
611     void dumpLocalTUs(ScopedPrinter &W) const;
612     void dumpForeignTUs(ScopedPrinter &W) const;
613     void dumpAbbreviations(ScopedPrinter &W) const;
614     bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const;
615     void dumpName(ScopedPrinter &W, const NameTableEntry &NTE,
616                   std::optional<uint32_t> Hash) const;
617     void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
618 
619     Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset);
620 
621     Expected<std::vector<AttributeEncoding>>
622     extractAttributeEncodings(uint64_t *Offset);
623 
624     Expected<Abbrev> extractAbbrev(uint64_t *Offset);
625 
626   public:
NameIndex(const DWARFDebugNames & Section,uint64_t Base)627     NameIndex(const DWARFDebugNames &Section, uint64_t Base)
628         : Section(Section), Base(Base) {}
629 
630     /// Returns Hdr field
getHeader()631     Header getHeader() const { return Hdr; }
632 
633     /// Returns Offsets field
getOffsets()634     DWARFDebugNamesOffsets getOffsets() const { return Offsets; }
635 
636     /// Reads offset of compilation unit CU. CU is 0-based.
637     LLVM_ABI uint64_t getCUOffset(uint32_t CU) const;
getCUCount()638     uint32_t getCUCount() const { return Hdr.CompUnitCount; }
639 
640     /// Reads offset of local type unit TU, TU is 0-based.
641     LLVM_ABI uint64_t getLocalTUOffset(uint32_t TU) const;
getLocalTUCount()642     uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
643 
644     /// Reads signature of foreign type unit TU. TU is 0-based.
645     LLVM_ABI uint64_t getForeignTUSignature(uint32_t TU) const;
getForeignTUCount()646     uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
647 
648     /// Reads an entry in the Bucket Array for the given Bucket. The returned
649     /// value is a (1-based) index into the Names, StringOffsets and
650     /// EntryOffsets arrays. The input Bucket index is 0-based.
651     LLVM_ABI uint32_t getBucketArrayEntry(uint32_t Bucket) const;
getBucketCount()652     uint32_t getBucketCount() const { return Hdr.BucketCount; }
653 
654     /// Reads an entry in the Hash Array for the given Index. The input Index
655     /// is 1-based.
656     LLVM_ABI uint32_t getHashArrayEntry(uint32_t Index) const;
657 
658     /// Reads an entry in the Name Table for the given Index. The Name Table
659     /// consists of two arrays -- String Offsets and Entry Offsets. The returned
660     /// offsets are relative to the starts of respective sections. Input Index
661     /// is 1-based.
662     LLVM_ABI NameTableEntry getNameTableEntry(uint32_t Index) const;
663 
getNameCount()664     uint32_t getNameCount() const { return Hdr.NameCount; }
665 
getAbbrevs()666     const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
667       return Abbrevs;
668     }
669 
670     LLVM_ABI Expected<Entry> getEntry(uint64_t *Offset) const;
671 
672     /// Returns the Entry at the relative `Offset` from the start of the Entry
673     /// pool.
getEntryAtRelativeOffset(uint64_t Offset)674     Expected<Entry> getEntryAtRelativeOffset(uint64_t Offset) const {
675       auto OffsetFromSection = Offset + this->Offsets.EntriesBase;
676       return getEntry(&OffsetFromSection);
677     }
678 
679     /// Look up all entries in this Name Index matching \c Key.
680     LLVM_ABI iterator_range<ValueIterator> equal_range(StringRef Key) const;
681 
begin()682     NameIterator begin() const { return NameIterator(this, 1); }
end()683     NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
684 
685     LLVM_ABI Error extract();
getUnitOffset()686     uint64_t getUnitOffset() const { return Base; }
getNextUnitOffset()687     uint64_t getNextUnitOffset() const {
688       return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) +
689              Hdr.UnitLength;
690     }
691     LLVM_ABI void dump(ScopedPrinter &W) const;
692 
693     friend class DWARFDebugNames;
694   };
695 
696   class ValueIterator {
697   public:
698     using iterator_category = std::input_iterator_tag;
699     using value_type = Entry;
700     using difference_type = std::ptrdiff_t;
701     using pointer = value_type *;
702     using reference = value_type &;
703 
704   private:
705     /// The Name Index we are currently iterating through. The implementation
706     /// relies on the fact that this can also be used as an iterator into the
707     /// "NameIndices" vector in the Accelerator section.
708     const NameIndex *CurrentIndex = nullptr;
709 
710     /// Whether this is a local iterator (searches in CurrentIndex only) or not
711     /// (searches all name indices).
712     bool IsLocal;
713 
714     std::optional<Entry> CurrentEntry;
715     uint64_t DataOffset = 0; ///< Offset into the section.
716     std::string Key;         ///< The Key we are searching for.
717     std::optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
718 
719     bool getEntryAtCurrentOffset();
720     std::optional<uint64_t> findEntryOffsetInCurrentIndex();
721     bool findInCurrentIndex();
722     void searchFromStartOfCurrentIndex();
723     LLVM_ABI void next();
724 
725     /// Set the iterator to the "end" state.
setEnd()726     void setEnd() { *this = ValueIterator(); }
727 
728   public:
729     /// Create a "begin" iterator for looping over all entries in the
730     /// accelerator table matching Key. The iterator will run through all Name
731     /// Indexes in the section in sequence.
732     LLVM_ABI ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
733 
734     /// Create a "begin" iterator for looping over all entries in a specific
735     /// Name Index. Other indices in the section will not be visited.
736     LLVM_ABI ValueIterator(const NameIndex &NI, StringRef Key);
737 
738     /// End marker.
739     ValueIterator() = default;
740 
741     const Entry &operator*() const { return *CurrentEntry; }
742     ValueIterator &operator++() {
743       next();
744       return *this;
745     }
746     ValueIterator operator++(int) {
747       ValueIterator I = *this;
748       next();
749       return I;
750     }
751 
752     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
753       return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
754     }
755     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
756       return !(A == B);
757     }
758   };
759 
760   class NameIterator {
761 
762     /// The Name Index we are iterating through.
763     const NameIndex *CurrentIndex;
764 
765     /// The current name in the Name Index.
766     uint32_t CurrentName;
767 
next()768     void next() {
769       assert(CurrentName <= CurrentIndex->getNameCount());
770       ++CurrentName;
771     }
772 
773   public:
774     using size_type = size_t;
775     using iterator_category = std::input_iterator_tag;
776     using value_type = NameTableEntry;
777     using difference_type = uint32_t;
778     using pointer = NameTableEntry *;
779     using reference = NameTableEntry; // We return entries by value.
780 
781     /// Creates an iterator whose initial position is name CurrentName in
782     /// CurrentIndex.
NameIterator(const NameIndex * CurrentIndex,uint32_t CurrentName)783     NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
784         : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
785 
786     NameTableEntry operator*() const {
787       return CurrentIndex->getNameTableEntry(CurrentName);
788     }
789     NameIterator &operator++() {
790       next();
791       return *this;
792     }
793     NameIterator operator++(int) {
794       NameIterator I = *this;
795       next();
796       return I;
797     }
798     /// Accesses entry at specific index (1-based internally, 0-based
799     /// externally). For example how this is used in parallelForEach.
800     reference operator[](size_type idx) {
801       return CurrentIndex->getNameTableEntry(idx + 1);
802     }
803     /// Computes difference between iterators (used in parallelForEach).
804     difference_type operator-(const NameIterator &other) const {
805       assert(CurrentIndex == other.CurrentIndex);
806       return this->CurrentName - other.CurrentName;
807     }
808 
809     friend bool operator==(const NameIterator &A, const NameIterator &B) {
810       return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
811     }
812     friend bool operator!=(const NameIterator &A, const NameIterator &B) {
813       return !(A == B);
814     }
815   };
816 
817 private:
818   SmallVector<NameIndex, 0> NameIndices;
819   DenseMap<uint64_t, const NameIndex *> UnitOffsetToNameIndex;
820 
821 public:
DWARFDebugNames(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)822   DWARFDebugNames(const DWARFDataExtractor &AccelSection,
823                   DataExtractor StringSection)
824       : DWARFAcceleratorTable(AccelSection, StringSection) {}
825 
826   Error extract() override;
827   void dump(raw_ostream &OS) const override;
828 
829   /// Look up all entries in the accelerator table matching \c Key.
830   iterator_range<ValueIterator> equal_range(StringRef Key) const;
831 
832   using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
begin()833   const_iterator begin() const { return NameIndices.begin(); }
end()834   const_iterator end() const { return NameIndices.end(); }
835 
836   /// Return the Name Index covering the compile unit or local type unit at
837   /// UnitOffset, or nullptr if there is no Name Index covering that unit.
838   const NameIndex *getCUOrTUNameIndex(uint64_t UnitOffset);
839 };
840 
841 /// Calculates the starting offsets for various sections within the
842 /// .debug_names section.
843 namespace dwarf {
844 LLVM_ABI DWARFDebugNames::DWARFDebugNamesOffsets
845 findDebugNamesOffsets(uint64_t EndOfHeaderOffset,
846                       const DWARFDebugNames::Header &Hdr);
847 }
848 
849 /// If `Name` is the name of a templated function that includes template
850 /// parameters, returns a substring of `Name` containing no template
851 /// parameters.
852 /// E.g.: StripTemplateParameters("foo<int>") = "foo".
853 LLVM_ABI std::optional<StringRef> StripTemplateParameters(StringRef Name);
854 
855 struct ObjCSelectorNames {
856   /// For "-[A(Category) method:]", this would be "method:"
857   StringRef Selector;
858   /// For "-[A(Category) method:]", this would be "A(category)"
859   StringRef ClassName;
860   /// For "-[A(Category) method:]", this would be "A"
861   std::optional<StringRef> ClassNameNoCategory;
862   /// For "-[A(Category) method:]", this would be "A method:"
863   std::optional<std::string> MethodNameNoCategory;
864 };
865 
866 /// If `Name` is the AT_name of a DIE which refers to an Objective-C selector,
867 /// returns an instance of ObjCSelectorNames. The Selector and ClassName fields
868 /// are guaranteed to be non-empty in the result.
869 LLVM_ABI std::optional<ObjCSelectorNames>
870 getObjCNamesIfSelector(StringRef Name);
871 
872 } // end namespace llvm
873 
874 #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
875