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     uint32_t Code;  ///< Abbreviation code
416     dwarf::Tag Tag; ///< Dwarf Tag of the described entity.
417     std::vector<AttributeEncoding> Attributes; ///< List of index attributes.
418 
AbbrevAbbrev419     Abbrev(uint32_t Code, dwarf::Tag Tag,
420            std::vector<AttributeEncoding> Attributes)
421         : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {}
422 
423     void dump(ScopedPrinter &W) const;
424   };
425 
426   /// DWARF v5-specific implementation of an Accelerator Entry.
427   class Entry final : public DWARFAcceleratorTable::Entry {
428     const NameIndex *NameIdx;
429     const Abbrev *Abbr;
430 
431     Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
432 
433   public:
434     std::optional<uint64_t> getCUOffset() const override;
435     std::optional<uint64_t> getLocalTUOffset() const override;
getTag()436     std::optional<dwarf::Tag> getTag() const override { return tag(); }
437 
438     /// Returns the Index into the Compilation Unit list of the owning Name
439     /// Index or std::nullopt if this Accelerator Entry does not have an
440     /// associated Compilation Unit. It is up to the user to verify that the
441     /// returned Index is valid in the owning NameIndex (or use getCUOffset(),
442     /// which will handle that check itself). Note that entries in NameIndexes
443     /// which index just a single Compilation Unit are implicitly associated
444     /// with that unit, so this function will return 0 even without an explicit
445     /// DW_IDX_compile_unit attribute, unless there is a DW_IDX_type_unit
446     /// attribute.
447     std::optional<uint64_t> getCUIndex() const;
448 
449     /// Returns the Index into the Local Type Unit list of the owning Name
450     /// Index or std::nullopt if this Accelerator Entry does not have an
451     /// associated Type Unit. It is up to the user to verify that the
452     /// returned Index is valid in the owning NameIndex (or use
453     /// getLocalTUOffset(), which will handle that check itself).
454     std::optional<uint64_t> getLocalTUIndex() const;
455 
456     /// .debug_names-specific getter, which always succeeds (DWARF v5 index
457     /// entries always have a tag).
tag()458     dwarf::Tag tag() const { return Abbr->Tag; }
459 
460     /// Returns the Offset of the DIE within the containing CU or TU.
461     std::optional<uint64_t> getDIEUnitOffset() const;
462 
463     /// Return the Abbreviation that can be used to interpret the raw values of
464     /// this Accelerator Entry.
getAbbrev()465     const Abbrev &getAbbrev() const { return *Abbr; }
466 
467     /// Returns the value of the Index Attribute in this Accelerator Entry, if
468     /// the Entry contains such Attribute.
469     std::optional<DWARFFormValue> lookup(dwarf::Index Index) const;
470 
471     void dump(ScopedPrinter &W) const;
472 
473     friend class NameIndex;
474     friend class ValueIterator;
475   };
476 
477   /// Error returned by NameIndex::getEntry to report it has reached the end of
478   /// the entry list.
479   class SentinelError : public ErrorInfo<SentinelError> {
480   public:
481     static char ID;
482 
log(raw_ostream & OS)483     void log(raw_ostream &OS) const override { OS << "Sentinel"; }
484     std::error_code convertToErrorCode() const override;
485   };
486 
487 private:
488   /// DenseMapInfo for struct Abbrev.
489   struct AbbrevMapInfo {
490     static Abbrev getEmptyKey();
491     static Abbrev getTombstoneKey();
getHashValueAbbrevMapInfo492     static unsigned getHashValue(uint32_t Code) {
493       return DenseMapInfo<uint32_t>::getHashValue(Code);
494     }
getHashValueAbbrevMapInfo495     static unsigned getHashValue(const Abbrev &Abbr) {
496       return getHashValue(Abbr.Code);
497     }
isEqualAbbrevMapInfo498     static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
499       return LHS == RHS.Code;
500     }
isEqualAbbrevMapInfo501     static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
502       return LHS.Code == RHS.Code;
503     }
504   };
505 
506 public:
507   /// A single entry in the Name Table (DWARF v5 sect. 6.1.1.4.6) of the Name
508   /// Index.
509   class NameTableEntry {
510     DataExtractor StrData;
511 
512     uint32_t Index;
513     uint64_t StringOffset;
514     uint64_t EntryOffset;
515 
516   public:
NameTableEntry(const DataExtractor & StrData,uint32_t Index,uint64_t StringOffset,uint64_t EntryOffset)517     NameTableEntry(const DataExtractor &StrData, uint32_t Index,
518                    uint64_t StringOffset, uint64_t EntryOffset)
519         : StrData(StrData), Index(Index), StringOffset(StringOffset),
520           EntryOffset(EntryOffset) {}
521 
522     /// Return the index of this name in the parent Name Index.
getIndex()523     uint32_t getIndex() const { return Index; }
524 
525     /// Returns the offset of the name of the described entities.
getStringOffset()526     uint64_t getStringOffset() const { return StringOffset; }
527 
528     /// Return the string referenced by this name table entry or nullptr if the
529     /// string offset is not valid.
getString()530     const char *getString() const {
531       uint64_t Off = StringOffset;
532       return StrData.getCStr(&Off);
533     }
534 
535     /// Returns the offset of the first Entry in the list.
getEntryOffset()536     uint64_t getEntryOffset() const { return EntryOffset; }
537   };
538 
539   /// Represents a single accelerator table within the DWARF v5 .debug_names
540   /// section.
541   class NameIndex {
542     DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
543     struct Header Hdr;
544     const DWARFDebugNames &Section;
545 
546     // Base of the whole unit and of various important tables, as offsets from
547     // the start of the section.
548     uint64_t Base;
549     uint64_t CUsBase;
550     uint64_t BucketsBase;
551     uint64_t HashesBase;
552     uint64_t StringOffsetsBase;
553     uint64_t EntryOffsetsBase;
554     uint64_t EntriesBase;
555 
556     void dumpCUs(ScopedPrinter &W) const;
557     void dumpLocalTUs(ScopedPrinter &W) const;
558     void dumpForeignTUs(ScopedPrinter &W) const;
559     void dumpAbbreviations(ScopedPrinter &W) const;
560     bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const;
561     void dumpName(ScopedPrinter &W, const NameTableEntry &NTE,
562                   std::optional<uint32_t> Hash) const;
563     void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
564 
565     Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset);
566 
567     Expected<std::vector<AttributeEncoding>>
568     extractAttributeEncodings(uint64_t *Offset);
569 
570     Expected<Abbrev> extractAbbrev(uint64_t *Offset);
571 
572   public:
NameIndex(const DWARFDebugNames & Section,uint64_t Base)573     NameIndex(const DWARFDebugNames &Section, uint64_t Base)
574         : Section(Section), Base(Base) {}
575 
576     /// Reads offset of compilation unit CU. CU is 0-based.
577     uint64_t getCUOffset(uint32_t CU) const;
getCUCount()578     uint32_t getCUCount() const { return Hdr.CompUnitCount; }
579 
580     /// Reads offset of local type unit TU, TU is 0-based.
581     uint64_t getLocalTUOffset(uint32_t TU) const;
getLocalTUCount()582     uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
583 
584     /// Reads signature of foreign type unit TU. TU is 0-based.
585     uint64_t getForeignTUSignature(uint32_t TU) const;
getForeignTUCount()586     uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
587 
588     /// Reads an entry in the Bucket Array for the given Bucket. The returned
589     /// value is a (1-based) index into the Names, StringOffsets and
590     /// EntryOffsets arrays. The input Bucket index is 0-based.
591     uint32_t getBucketArrayEntry(uint32_t Bucket) const;
getBucketCount()592     uint32_t getBucketCount() const { return Hdr.BucketCount; }
593 
594     /// Reads an entry in the Hash Array for the given Index. The input Index
595     /// is 1-based.
596     uint32_t getHashArrayEntry(uint32_t Index) const;
597 
598     /// Reads an entry in the Name Table for the given Index. The Name Table
599     /// consists of two arrays -- String Offsets and Entry Offsets. The returned
600     /// offsets are relative to the starts of respective sections. Input Index
601     /// is 1-based.
602     NameTableEntry getNameTableEntry(uint32_t Index) const;
603 
getNameCount()604     uint32_t getNameCount() const { return Hdr.NameCount; }
605 
getAbbrevs()606     const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
607       return Abbrevs;
608     }
609 
610     Expected<Entry> getEntry(uint64_t *Offset) const;
611 
612     /// Look up all entries in this Name Index matching \c Key.
613     iterator_range<ValueIterator> equal_range(StringRef Key) const;
614 
begin()615     NameIterator begin() const { return NameIterator(this, 1); }
end()616     NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
617 
618     Error extract();
getUnitOffset()619     uint64_t getUnitOffset() const { return Base; }
getNextUnitOffset()620     uint64_t getNextUnitOffset() const {
621       return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) +
622              Hdr.UnitLength;
623     }
624     void dump(ScopedPrinter &W) const;
625 
626     friend class DWARFDebugNames;
627   };
628 
629   class ValueIterator {
630   public:
631     using iterator_category = std::input_iterator_tag;
632     using value_type = Entry;
633     using difference_type = std::ptrdiff_t;
634     using pointer = value_type *;
635     using reference = value_type &;
636 
637   private:
638     /// The Name Index we are currently iterating through. The implementation
639     /// relies on the fact that this can also be used as an iterator into the
640     /// "NameIndices" vector in the Accelerator section.
641     const NameIndex *CurrentIndex = nullptr;
642 
643     /// Whether this is a local iterator (searches in CurrentIndex only) or not
644     /// (searches all name indices).
645     bool IsLocal;
646 
647     std::optional<Entry> CurrentEntry;
648     uint64_t DataOffset = 0; ///< Offset into the section.
649     std::string Key;         ///< The Key we are searching for.
650     std::optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
651 
652     bool getEntryAtCurrentOffset();
653     std::optional<uint64_t> findEntryOffsetInCurrentIndex();
654     bool findInCurrentIndex();
655     void searchFromStartOfCurrentIndex();
656     void next();
657 
658     /// Set the iterator to the "end" state.
setEnd()659     void setEnd() { *this = ValueIterator(); }
660 
661   public:
662     /// Create a "begin" iterator for looping over all entries in the
663     /// accelerator table matching Key. The iterator will run through all Name
664     /// Indexes in the section in sequence.
665     ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
666 
667     /// Create a "begin" iterator for looping over all entries in a specific
668     /// Name Index. Other indices in the section will not be visited.
669     ValueIterator(const NameIndex &NI, StringRef Key);
670 
671     /// End marker.
672     ValueIterator() = default;
673 
674     const Entry &operator*() const { return *CurrentEntry; }
675     ValueIterator &operator++() {
676       next();
677       return *this;
678     }
679     ValueIterator operator++(int) {
680       ValueIterator I = *this;
681       next();
682       return I;
683     }
684 
685     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
686       return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
687     }
688     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
689       return !(A == B);
690     }
691   };
692 
693   class NameIterator {
694 
695     /// The Name Index we are iterating through.
696     const NameIndex *CurrentIndex;
697 
698     /// The current name in the Name Index.
699     uint32_t CurrentName;
700 
next()701     void next() {
702       assert(CurrentName <= CurrentIndex->getNameCount());
703       ++CurrentName;
704     }
705 
706   public:
707     using iterator_category = std::input_iterator_tag;
708     using value_type = NameTableEntry;
709     using difference_type = uint32_t;
710     using pointer = NameTableEntry *;
711     using reference = NameTableEntry; // We return entries by value.
712 
713     /// Creates an iterator whose initial position is name CurrentName in
714     /// CurrentIndex.
NameIterator(const NameIndex * CurrentIndex,uint32_t CurrentName)715     NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
716         : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
717 
718     NameTableEntry operator*() const {
719       return CurrentIndex->getNameTableEntry(CurrentName);
720     }
721     NameIterator &operator++() {
722       next();
723       return *this;
724     }
725     NameIterator operator++(int) {
726       NameIterator I = *this;
727       next();
728       return I;
729     }
730 
731     friend bool operator==(const NameIterator &A, const NameIterator &B) {
732       return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
733     }
734     friend bool operator!=(const NameIterator &A, const NameIterator &B) {
735       return !(A == B);
736     }
737   };
738 
739 private:
740   SmallVector<NameIndex, 0> NameIndices;
741   DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
742 
743 public:
DWARFDebugNames(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)744   DWARFDebugNames(const DWARFDataExtractor &AccelSection,
745                   DataExtractor StringSection)
746       : DWARFAcceleratorTable(AccelSection, StringSection) {}
747 
748   Error extract() override;
749   void dump(raw_ostream &OS) const override;
750 
751   /// Look up all entries in the accelerator table matching \c Key.
752   iterator_range<ValueIterator> equal_range(StringRef Key) const;
753 
754   using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
begin()755   const_iterator begin() const { return NameIndices.begin(); }
end()756   const_iterator end() const { return NameIndices.end(); }
757 
758   /// Return the Name Index covering the compile unit at CUOffset, or nullptr if
759   /// there is no Name Index covering that unit.
760   const NameIndex *getCUNameIndex(uint64_t CUOffset);
761 };
762 
763 /// If `Name` is the name of a templated function that includes template
764 /// parameters, returns a substring of `Name` containing no template
765 /// parameters.
766 /// E.g.: StripTemplateParameters("foo<int>") = "foo".
767 std::optional<StringRef> StripTemplateParameters(StringRef Name);
768 
769 struct ObjCSelectorNames {
770   /// For "-[A(Category) method:]", this would be "method:"
771   StringRef Selector;
772   /// For "-[A(Category) method:]", this would be "A(category)"
773   StringRef ClassName;
774   /// For "-[A(Category) method:]", this would be "A"
775   std::optional<StringRef> ClassNameNoCategory;
776   /// For "-[A(Category) method:]", this would be "A method:"
777   std::optional<std::string> MethodNameNoCategory;
778 };
779 
780 /// If `Name` is the AT_name of a DIE which refers to an Objective-C selector,
781 /// returns an instance of ObjCSelectorNames. The Selector and ClassName fields
782 /// are guaranteed to be non-empty in the result.
783 std::optional<ObjCSelectorNames> getObjCNamesIfSelector(StringRef Name);
784 
785 } // end namespace llvm
786 
787 #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
788