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