• 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     /// Reads offset of compilation unit CU. CU is 0-based.
609     uint64_t getCUOffset(uint32_t CU) const;
getCUCount()610     uint32_t getCUCount() const { return Hdr.CompUnitCount; }
611 
612     /// Reads offset of local type unit TU, TU is 0-based.
613     uint64_t getLocalTUOffset(uint32_t TU) const;
getLocalTUCount()614     uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
615 
616     /// Reads signature of foreign type unit TU. TU is 0-based.
617     uint64_t getForeignTUSignature(uint32_t TU) const;
getForeignTUCount()618     uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
619 
620     /// Reads an entry in the Bucket Array for the given Bucket. The returned
621     /// value is a (1-based) index into the Names, StringOffsets and
622     /// EntryOffsets arrays. The input Bucket index is 0-based.
623     uint32_t getBucketArrayEntry(uint32_t Bucket) const;
getBucketCount()624     uint32_t getBucketCount() const { return Hdr.BucketCount; }
625 
626     /// Reads an entry in the Hash Array for the given Index. The input Index
627     /// is 1-based.
628     uint32_t getHashArrayEntry(uint32_t Index) const;
629 
630     /// Reads an entry in the Name Table for the given Index. The Name Table
631     /// consists of two arrays -- String Offsets and Entry Offsets. The returned
632     /// offsets are relative to the starts of respective sections. Input Index
633     /// is 1-based.
634     NameTableEntry getNameTableEntry(uint32_t Index) const;
635 
getNameCount()636     uint32_t getNameCount() const { return Hdr.NameCount; }
637 
getAbbrevs()638     const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
639       return Abbrevs;
640     }
641 
642     Expected<Entry> getEntry(uint64_t *Offset) const;
643 
644     /// Returns the Entry at the relative `Offset` from the start of the Entry
645     /// pool.
getEntryAtRelativeOffset(uint64_t Offset)646     Expected<Entry> getEntryAtRelativeOffset(uint64_t Offset) const {
647       auto OffsetFromSection = Offset + this->Offsets.EntriesBase;
648       return getEntry(&OffsetFromSection);
649     }
650 
651     /// Look up all entries in this Name Index matching \c Key.
652     iterator_range<ValueIterator> equal_range(StringRef Key) const;
653 
begin()654     NameIterator begin() const { return NameIterator(this, 1); }
end()655     NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
656 
657     Error extract();
getUnitOffset()658     uint64_t getUnitOffset() const { return Base; }
getNextUnitOffset()659     uint64_t getNextUnitOffset() const {
660       return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) +
661              Hdr.UnitLength;
662     }
663     void dump(ScopedPrinter &W) const;
664 
665     friend class DWARFDebugNames;
666   };
667 
668   class ValueIterator {
669   public:
670     using iterator_category = std::input_iterator_tag;
671     using value_type = Entry;
672     using difference_type = std::ptrdiff_t;
673     using pointer = value_type *;
674     using reference = value_type &;
675 
676   private:
677     /// The Name Index we are currently iterating through. The implementation
678     /// relies on the fact that this can also be used as an iterator into the
679     /// "NameIndices" vector in the Accelerator section.
680     const NameIndex *CurrentIndex = nullptr;
681 
682     /// Whether this is a local iterator (searches in CurrentIndex only) or not
683     /// (searches all name indices).
684     bool IsLocal;
685 
686     std::optional<Entry> CurrentEntry;
687     uint64_t DataOffset = 0; ///< Offset into the section.
688     std::string Key;         ///< The Key we are searching for.
689     std::optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
690 
691     bool getEntryAtCurrentOffset();
692     std::optional<uint64_t> findEntryOffsetInCurrentIndex();
693     bool findInCurrentIndex();
694     void searchFromStartOfCurrentIndex();
695     void next();
696 
697     /// Set the iterator to the "end" state.
setEnd()698     void setEnd() { *this = ValueIterator(); }
699 
700   public:
701     /// Create a "begin" iterator for looping over all entries in the
702     /// accelerator table matching Key. The iterator will run through all Name
703     /// Indexes in the section in sequence.
704     ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
705 
706     /// Create a "begin" iterator for looping over all entries in a specific
707     /// Name Index. Other indices in the section will not be visited.
708     ValueIterator(const NameIndex &NI, StringRef Key);
709 
710     /// End marker.
711     ValueIterator() = default;
712 
713     const Entry &operator*() const { return *CurrentEntry; }
714     ValueIterator &operator++() {
715       next();
716       return *this;
717     }
718     ValueIterator operator++(int) {
719       ValueIterator I = *this;
720       next();
721       return I;
722     }
723 
724     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
725       return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
726     }
727     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
728       return !(A == B);
729     }
730   };
731 
732   class NameIterator {
733 
734     /// The Name Index we are iterating through.
735     const NameIndex *CurrentIndex;
736 
737     /// The current name in the Name Index.
738     uint32_t CurrentName;
739 
next()740     void next() {
741       assert(CurrentName <= CurrentIndex->getNameCount());
742       ++CurrentName;
743     }
744 
745   public:
746     using iterator_category = std::input_iterator_tag;
747     using value_type = NameTableEntry;
748     using difference_type = uint32_t;
749     using pointer = NameTableEntry *;
750     using reference = NameTableEntry; // We return entries by value.
751 
752     /// Creates an iterator whose initial position is name CurrentName in
753     /// CurrentIndex.
NameIterator(const NameIndex * CurrentIndex,uint32_t CurrentName)754     NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
755         : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
756 
757     NameTableEntry operator*() const {
758       return CurrentIndex->getNameTableEntry(CurrentName);
759     }
760     NameIterator &operator++() {
761       next();
762       return *this;
763     }
764     NameIterator operator++(int) {
765       NameIterator I = *this;
766       next();
767       return I;
768     }
769 
770     friend bool operator==(const NameIterator &A, const NameIterator &B) {
771       return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
772     }
773     friend bool operator!=(const NameIterator &A, const NameIterator &B) {
774       return !(A == B);
775     }
776   };
777 
778 private:
779   SmallVector<NameIndex, 0> NameIndices;
780   DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
781 
782 public:
DWARFDebugNames(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)783   DWARFDebugNames(const DWARFDataExtractor &AccelSection,
784                   DataExtractor StringSection)
785       : DWARFAcceleratorTable(AccelSection, StringSection) {}
786 
787   Error extract() override;
788   void dump(raw_ostream &OS) const override;
789 
790   /// Look up all entries in the accelerator table matching \c Key.
791   iterator_range<ValueIterator> equal_range(StringRef Key) const;
792 
793   using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
begin()794   const_iterator begin() const { return NameIndices.begin(); }
end()795   const_iterator end() const { return NameIndices.end(); }
796 
797   /// Return the Name Index covering the compile unit at CUOffset, or nullptr if
798   /// there is no Name Index covering that unit.
799   const NameIndex *getCUNameIndex(uint64_t CUOffset);
800 };
801 
802 /// Calculates the starting offsets for various sections within the
803 /// .debug_names section.
804 void findDebugNamesOffsets(DWARFDebugNames::DWARFDebugNamesOffsets &Offsets,
805                            uint64_t HdrSize, const dwarf::DwarfFormat Format,
806                            const DWARFDebugNames::Header &Hdr);
807 
808 /// If `Name` is the name of a templated function that includes template
809 /// parameters, returns a substring of `Name` containing no template
810 /// parameters.
811 /// E.g.: StripTemplateParameters("foo<int>") = "foo".
812 std::optional<StringRef> StripTemplateParameters(StringRef Name);
813 
814 struct ObjCSelectorNames {
815   /// For "-[A(Category) method:]", this would be "method:"
816   StringRef Selector;
817   /// For "-[A(Category) method:]", this would be "A(category)"
818   StringRef ClassName;
819   /// For "-[A(Category) method:]", this would be "A"
820   std::optional<StringRef> ClassNameNoCategory;
821   /// For "-[A(Category) method:]", this would be "A method:"
822   std::optional<std::string> MethodNameNoCategory;
823 };
824 
825 /// If `Name` is the AT_name of a DIE which refers to an Objective-C selector,
826 /// returns an instance of ObjCSelectorNames. The Selector and ClassName fields
827 /// are guaranteed to be non-empty in the result.
828 std::optional<ObjCSelectorNames> getObjCNamesIfSelector(StringRef Name);
829 
830 } // end namespace llvm
831 
832 #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
833