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