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