Home | History | Annotate | Download | only in DWARF
      1 //===- DWARFAcceleratorTable.h ----------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
     11 #define LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
     12 
     13 #include "llvm/ADT/DenseSet.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 None if the Compilation Unit offset is not recorded
     56     /// in this Accelerator Entry.
     57     virtual Optional<uint64_t> getCUOffset() const = 0;
     58 
     59     /// Returns the Tag of the Debug Info Entry associated with this
     60     /// Accelerator Entry or None if the Tag is not recorded in this
     61     /// Accelerator Entry.
     62     virtual Optional<dwarf::Tag> getTag() const = 0;
     63 
     64     /// Returns the raw values of fields in the Accelerator Entry. In general,
     65     /// these can only be interpreted with the help of the metadata in the
     66     /// owning Accelerator Table.
     67     ArrayRef<DWARFFormValue> getValues() const { return Values; }
     68   };
     69 
     70   DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
     71                         DataExtractor StringSection)
     72       : AccelSection(AccelSection), StringSection(StringSection) {}
     73   virtual ~DWARFAcceleratorTable();
     74 
     75   virtual llvm::Error extract() = 0;
     76   virtual void dump(raw_ostream &OS) const = 0;
     77 
     78   DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete;
     79   void operator=(const DWARFAcceleratorTable &) = delete;
     80 };
     81 
     82 /// This implements the Apple accelerator table format, a precursor of the
     83 /// DWARF 5 accelerator table format.
     84 class AppleAcceleratorTable : public DWARFAcceleratorTable {
     85   struct Header {
     86     uint32_t Magic;
     87     uint16_t Version;
     88     uint16_t HashFunction;
     89     uint32_t BucketCount;
     90     uint32_t HashCount;
     91     uint32_t HeaderDataLength;
     92 
     93     void dump(ScopedPrinter &W) const;
     94   };
     95 
     96   struct HeaderData {
     97     using AtomType = uint16_t;
     98     using Form = dwarf::Form;
     99 
    100     uint32_t DIEOffsetBase;
    101     SmallVector<std::pair<AtomType, Form>, 3> Atoms;
    102 
    103     Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const;
    104   };
    105 
    106   struct Header Hdr;
    107   struct HeaderData HdrData;
    108   bool IsValid = false;
    109 
    110   /// Returns true if we should continue scanning for entries or false if we've
    111   /// reached the last (sentinel) entry of encountered a parsing error.
    112   bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms,
    113                 uint32_t *DataOffset) const;
    114 
    115 public:
    116   /// Apple-specific implementation of an Accelerator Entry.
    117   class Entry final : public DWARFAcceleratorTable::Entry {
    118     const HeaderData *HdrData = nullptr;
    119 
    120     Entry(const HeaderData &Data);
    121     Entry() = default;
    122 
    123     void extract(const AppleAcceleratorTable &AccelTable, uint32_t *Offset);
    124 
    125   public:
    126     Optional<uint64_t> getCUOffset() const override;
    127 
    128     /// Returns the Section Offset of the Debug Info Entry associated with this
    129     /// Accelerator Entry or None if the DIE offset is not recorded in this
    130     /// Accelerator Entry. The returned offset is relative to the start of the
    131     /// Section containing the DIE.
    132     Optional<uint64_t> getDIESectionOffset() const;
    133 
    134     Optional<dwarf::Tag> getTag() const override;
    135 
    136     /// Returns the value of the Atom in this Accelerator Entry, if the Entry
    137     /// contains such Atom.
    138     Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
    139 
    140     friend class AppleAcceleratorTable;
    141     friend class ValueIterator;
    142   };
    143 
    144   class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
    145     const AppleAcceleratorTable *AccelTable = nullptr;
    146     Entry Current;           ///< The current entry.
    147     unsigned DataOffset = 0; ///< Offset into the section.
    148     unsigned Data = 0; ///< Current data entry.
    149     unsigned NumData = 0; ///< Number of data entries.
    150 
    151     /// Advance the iterator.
    152     void Next();
    153   public:
    154     /// Construct a new iterator for the entries at \p DataOffset.
    155     ValueIterator(const AppleAcceleratorTable &AccelTable, unsigned DataOffset);
    156     /// End marker.
    157     ValueIterator() = default;
    158 
    159     const Entry &operator*() const { return Current; }
    160     ValueIterator &operator++() { Next(); return *this; }
    161     ValueIterator operator++(int) {
    162       ValueIterator I = *this;
    163       Next();
    164       return I;
    165     }
    166     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
    167       return A.NumData == B.NumData && A.DataOffset == B.DataOffset;
    168     }
    169     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
    170       return !(A == B);
    171     }
    172   };
    173 
    174   AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
    175                         DataExtractor StringSection)
    176       : DWARFAcceleratorTable(AccelSection, StringSection) {}
    177 
    178   llvm::Error extract() override;
    179   uint32_t getNumBuckets();
    180   uint32_t getNumHashes();
    181   uint32_t getSizeHdr();
    182   uint32_t getHeaderDataLength();
    183 
    184   /// Return the Atom description, which can be used to interpret the raw values
    185   /// of the Accelerator Entries in this table.
    186   ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
    187   bool validateForms();
    188 
    189   /// Return information related to the DWARF DIE we're looking for when
    190   /// performing a lookup by name.
    191   ///
    192   /// \param HashDataOffset an offset into the hash data table
    193   /// \returns <DieOffset, DieTag>
    194   /// DieOffset is the offset into the .debug_info section for the DIE
    195   /// related to the input hash data offset.
    196   /// DieTag is the tag of the DIE
    197   std::pair<uint32_t, dwarf::Tag> readAtoms(uint32_t &HashDataOffset);
    198   void dump(raw_ostream &OS) const override;
    199 
    200   /// Look up all entries in the accelerator table matching \c Key.
    201   iterator_range<ValueIterator> equal_range(StringRef Key) const;
    202 };
    203 
    204 /// .debug_names section consists of one or more units. Each unit starts with a
    205 /// header, which is followed by a list of compilation units, local and foreign
    206 /// type units.
    207 ///
    208 /// These may be followed by an (optional) hash lookup table, which consists of
    209 /// an array of buckets and hashes similar to the apple tables above. The only
    210 /// difference is that the hashes array is 1-based, and consequently an empty
    211 /// bucket is denoted by 0 and not UINT32_MAX.
    212 ///
    213 /// Next is the name table, which consists of an array of names and array of
    214 /// entry offsets. This is different from the apple tables, which store names
    215 /// next to the actual entries.
    216 ///
    217 /// The structure of the entries is described by an abbreviations table, which
    218 /// comes after the name table. Unlike the apple tables, which have a uniform
    219 /// entry structure described in the header, each .debug_names entry may have
    220 /// different index attributes (DW_IDX_???) attached to it.
    221 ///
    222 /// The last segment consists of a list of entries, which is a 0-terminated list
    223 /// referenced by the name table and interpreted with the help of the
    224 /// abbreviation table.
    225 class DWARFDebugNames : public DWARFAcceleratorTable {
    226   /// The fixed-size part of a Dwarf 5 Name Index header
    227   struct HeaderPOD {
    228     uint32_t UnitLength;
    229     uint16_t Version;
    230     uint16_t Padding;
    231     uint32_t CompUnitCount;
    232     uint32_t LocalTypeUnitCount;
    233     uint32_t ForeignTypeUnitCount;
    234     uint32_t BucketCount;
    235     uint32_t NameCount;
    236     uint32_t AbbrevTableSize;
    237     uint32_t AugmentationStringSize;
    238   };
    239 
    240 public:
    241   class NameIndex;
    242   class NameIterator;
    243   class ValueIterator;
    244 
    245   /// Dwarf 5 Name Index header.
    246   struct Header : public HeaderPOD {
    247     SmallString<8> AugmentationString;
    248 
    249     Error extract(const DWARFDataExtractor &AS, uint32_t *Offset);
    250     void dump(ScopedPrinter &W) const;
    251   };
    252 
    253   /// Index attribute and its encoding.
    254   struct AttributeEncoding {
    255     dwarf::Index Index;
    256     dwarf::Form Form;
    257 
    258     constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form)
    259         : Index(Index), Form(Form) {}
    260 
    261     friend bool operator==(const AttributeEncoding &LHS,
    262                            const AttributeEncoding &RHS) {
    263       return LHS.Index == RHS.Index && LHS.Form == RHS.Form;
    264     }
    265   };
    266 
    267   /// Abbreviation describing the encoding of Name Index entries.
    268   struct Abbrev {
    269     uint32_t Code;  ///< Abbreviation code
    270     dwarf::Tag Tag; ///< Dwarf Tag of the described entity.
    271     std::vector<AttributeEncoding> Attributes; ///< List of index attributes.
    272 
    273     Abbrev(uint32_t Code, dwarf::Tag Tag,
    274            std::vector<AttributeEncoding> Attributes)
    275         : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {}
    276 
    277     void dump(ScopedPrinter &W) const;
    278   };
    279 
    280   /// DWARF v5-specific implementation of an Accelerator Entry.
    281   class Entry final : public DWARFAcceleratorTable::Entry {
    282     const NameIndex *NameIdx;
    283     const Abbrev *Abbr;
    284 
    285     Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
    286 
    287   public:
    288     Optional<uint64_t> getCUOffset() const override;
    289     Optional<dwarf::Tag> getTag() const override { return tag(); }
    290 
    291     /// Returns the Index into the Compilation Unit list of the owning Name
    292     /// Index or None if this Accelerator Entry does not have an associated
    293     /// Compilation Unit. It is up to the user to verify that the returned Index
    294     /// is valid in the owning NameIndex (or use getCUOffset(), which will
    295     /// handle that check itself). Note that entries in NameIndexes which index
    296     /// just a single Compilation Unit are implicitly associated with that unit,
    297     /// so this function will return 0 even without an explicit
    298     /// DW_IDX_compile_unit attribute.
    299     Optional<uint64_t> getCUIndex() const;
    300 
    301     /// .debug_names-specific getter, which always succeeds (DWARF v5 index
    302     /// entries always have a tag).
    303     dwarf::Tag tag() const { return Abbr->Tag; }
    304 
    305     /// Returns the Offset of the DIE within the containing CU or TU.
    306     Optional<uint64_t> getDIEUnitOffset() const;
    307 
    308     /// Return the Abbreviation that can be used to interpret the raw values of
    309     /// this Accelerator Entry.
    310     const Abbrev &getAbbrev() const { return *Abbr; }
    311 
    312     /// Returns the value of the Index Attribute in this Accelerator Entry, if
    313     /// the Entry contains such Attribute.
    314     Optional<DWARFFormValue> lookup(dwarf::Index Index) const;
    315 
    316     void dump(ScopedPrinter &W) const;
    317 
    318     friend class NameIndex;
    319     friend class ValueIterator;
    320   };
    321 
    322   /// Error returned by NameIndex::getEntry to report it has reached the end of
    323   /// the entry list.
    324   class SentinelError : public ErrorInfo<SentinelError> {
    325   public:
    326     static char ID;
    327 
    328     void log(raw_ostream &OS) const override { OS << "Sentinel"; }
    329     std::error_code convertToErrorCode() const override;
    330   };
    331 
    332 private:
    333   /// DenseMapInfo for struct Abbrev.
    334   struct AbbrevMapInfo {
    335     static Abbrev getEmptyKey();
    336     static Abbrev getTombstoneKey();
    337     static unsigned getHashValue(uint32_t Code) {
    338       return DenseMapInfo<uint32_t>::getHashValue(Code);
    339     }
    340     static unsigned getHashValue(const Abbrev &Abbr) {
    341       return getHashValue(Abbr.Code);
    342     }
    343     static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
    344       return LHS == RHS.Code;
    345     }
    346     static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
    347       return LHS.Code == RHS.Code;
    348     }
    349   };
    350 
    351 public:
    352   /// A single entry in the Name Table (Dwarf 5 sect. 6.1.1.4.6) of the Name
    353   /// Index.
    354   class NameTableEntry {
    355     DataExtractor StrData;
    356 
    357     uint32_t Index;
    358     uint32_t StringOffset;
    359     uint32_t EntryOffset;
    360 
    361   public:
    362     NameTableEntry(const DataExtractor &StrData, uint32_t Index,
    363                    uint32_t StringOffset, uint32_t EntryOffset)
    364         : StrData(StrData), Index(Index), StringOffset(StringOffset),
    365           EntryOffset(EntryOffset) {}
    366 
    367     /// Return the index of this name in the parent Name Index.
    368     uint32_t getIndex() const { return Index; }
    369 
    370     /// Returns the offset of the name of the described entities.
    371     uint32_t getStringOffset() const { return StringOffset; }
    372 
    373     /// Return the string referenced by this name table entry or nullptr if the
    374     /// string offset is not valid.
    375     const char *getString() const {
    376       uint32_t Off = StringOffset;
    377       return StrData.getCStr(&Off);
    378     }
    379 
    380     /// Returns the offset of the first Entry in the list.
    381     uint32_t getEntryOffset() const { return EntryOffset; }
    382   };
    383 
    384   /// Represents a single accelerator table within the Dwarf 5 .debug_names
    385   /// section.
    386   class NameIndex {
    387     DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
    388     struct Header Hdr;
    389     const DWARFDebugNames &Section;
    390 
    391     // Base of the whole unit and of various important tables, as offsets from
    392     // the start of the section.
    393     uint32_t Base;
    394     uint32_t CUsBase;
    395     uint32_t BucketsBase;
    396     uint32_t HashesBase;
    397     uint32_t StringOffsetsBase;
    398     uint32_t EntryOffsetsBase;
    399     uint32_t EntriesBase;
    400 
    401     void dumpCUs(ScopedPrinter &W) const;
    402     void dumpLocalTUs(ScopedPrinter &W) const;
    403     void dumpForeignTUs(ScopedPrinter &W) const;
    404     void dumpAbbreviations(ScopedPrinter &W) const;
    405     bool dumpEntry(ScopedPrinter &W, uint32_t *Offset) const;
    406     void dumpName(ScopedPrinter &W, const NameTableEntry &NTE,
    407                   Optional<uint32_t> Hash) const;
    408     void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
    409 
    410     Expected<AttributeEncoding> extractAttributeEncoding(uint32_t *Offset);
    411 
    412     Expected<std::vector<AttributeEncoding>>
    413     extractAttributeEncodings(uint32_t *Offset);
    414 
    415     Expected<Abbrev> extractAbbrev(uint32_t *Offset);
    416 
    417   public:
    418     NameIndex(const DWARFDebugNames &Section, uint32_t Base)
    419         : Section(Section), Base(Base) {}
    420 
    421     /// Reads offset of compilation unit CU. CU is 0-based.
    422     uint32_t getCUOffset(uint32_t CU) const;
    423     uint32_t getCUCount() const { return Hdr.CompUnitCount; }
    424 
    425     /// Reads offset of local type unit TU, TU is 0-based.
    426     uint32_t getLocalTUOffset(uint32_t TU) const;
    427     uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
    428 
    429     /// Reads signature of foreign type unit TU. TU is 0-based.
    430     uint64_t getForeignTUSignature(uint32_t TU) const;
    431     uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
    432 
    433     /// Reads an entry in the Bucket Array for the given Bucket. The returned
    434     /// value is a (1-based) index into the Names, StringOffsets and
    435     /// EntryOffsets arrays. The input Bucket index is 0-based.
    436     uint32_t getBucketArrayEntry(uint32_t Bucket) const;
    437     uint32_t getBucketCount() const { return Hdr.BucketCount; }
    438 
    439     /// Reads an entry in the Hash Array for the given Index. The input Index
    440     /// is 1-based.
    441     uint32_t getHashArrayEntry(uint32_t Index) const;
    442 
    443     /// Reads an entry in the Name Table for the given Index. The Name Table
    444     /// consists of two arrays -- String Offsets and Entry Offsets. The returned
    445     /// offsets are relative to the starts of respective sections. Input Index
    446     /// is 1-based.
    447     NameTableEntry getNameTableEntry(uint32_t Index) const;
    448 
    449     uint32_t getNameCount() const { return Hdr.NameCount; }
    450 
    451     const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
    452       return Abbrevs;
    453     }
    454 
    455     Expected<Entry> getEntry(uint32_t *Offset) const;
    456 
    457     /// Look up all entries in this Name Index matching \c Key.
    458     iterator_range<ValueIterator> equal_range(StringRef Key) const;
    459 
    460     NameIterator begin() const { return NameIterator(this, 1); }
    461     NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
    462 
    463     llvm::Error extract();
    464     uint32_t getUnitOffset() const { return Base; }
    465     uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; }
    466     void dump(ScopedPrinter &W) const;
    467 
    468     friend class DWARFDebugNames;
    469   };
    470 
    471   class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
    472 
    473     /// The Name Index we are currently iterating through. The implementation
    474     /// relies on the fact that this can also be used as an iterator into the
    475     /// "NameIndices" vector in the Accelerator section.
    476     const NameIndex *CurrentIndex = nullptr;
    477 
    478     /// Whether this is a local iterator (searches in CurrentIndex only) or not
    479     /// (searches all name indices).
    480     bool IsLocal;
    481 
    482     Optional<Entry> CurrentEntry;
    483     unsigned DataOffset = 0; ///< Offset into the section.
    484     std::string Key;         ///< The Key we are searching for.
    485     Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
    486 
    487     bool getEntryAtCurrentOffset();
    488     Optional<uint32_t> findEntryOffsetInCurrentIndex();
    489     bool findInCurrentIndex();
    490     void searchFromStartOfCurrentIndex();
    491     void next();
    492 
    493     /// Set the iterator to the "end" state.
    494     void setEnd() { *this = ValueIterator(); }
    495 
    496   public:
    497     /// Create a "begin" iterator for looping over all entries in the
    498     /// accelerator table matching Key. The iterator will run through all Name
    499     /// Indexes in the section in sequence.
    500     ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
    501 
    502     /// Create a "begin" iterator for looping over all entries in a specific
    503     /// Name Index. Other indices in the section will not be visited.
    504     ValueIterator(const NameIndex &NI, StringRef Key);
    505 
    506     /// End marker.
    507     ValueIterator() = default;
    508 
    509     const Entry &operator*() const { return *CurrentEntry; }
    510     ValueIterator &operator++() {
    511       next();
    512       return *this;
    513     }
    514     ValueIterator operator++(int) {
    515       ValueIterator I = *this;
    516       next();
    517       return I;
    518     }
    519 
    520     friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
    521       return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
    522     }
    523     friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
    524       return !(A == B);
    525     }
    526   };
    527 
    528   class NameIterator {
    529 
    530     /// The Name Index we are iterating through.
    531     const NameIndex *CurrentIndex;
    532 
    533     /// The current name in the Name Index.
    534     uint32_t CurrentName;
    535 
    536     void next() {
    537       assert(CurrentName <= CurrentIndex->getNameCount());
    538       ++CurrentName;
    539     }
    540 
    541   public:
    542     using iterator_category = std::input_iterator_tag;
    543     using value_type = NameTableEntry;
    544     using difference_type = uint32_t;
    545     using pointer = NameTableEntry *;
    546     using reference = NameTableEntry; // We return entries by value.
    547 
    548     /// Creates an iterator whose initial position is name CurrentName in
    549     /// CurrentIndex.
    550     NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
    551         : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
    552 
    553     NameTableEntry operator*() const {
    554       return CurrentIndex->getNameTableEntry(CurrentName);
    555     }
    556     NameIterator &operator++() {
    557       next();
    558       return *this;
    559     }
    560     NameIterator operator++(int) {
    561       NameIterator I = *this;
    562       next();
    563       return I;
    564     }
    565 
    566     friend bool operator==(const NameIterator &A, const NameIterator &B) {
    567       return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
    568     }
    569     friend bool operator!=(const NameIterator &A, const NameIterator &B) {
    570       return !(A == B);
    571     }
    572   };
    573 
    574 private:
    575   SmallVector<NameIndex, 0> NameIndices;
    576   DenseMap<uint32_t, const NameIndex *> CUToNameIndex;
    577 
    578 public:
    579   DWARFDebugNames(const DWARFDataExtractor &AccelSection,
    580                   DataExtractor StringSection)
    581       : DWARFAcceleratorTable(AccelSection, StringSection) {}
    582 
    583   llvm::Error extract() override;
    584   void dump(raw_ostream &OS) const override;
    585 
    586   /// Look up all entries in the accelerator table matching \c Key.
    587   iterator_range<ValueIterator> equal_range(StringRef Key) const;
    588 
    589   using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
    590   const_iterator begin() const { return NameIndices.begin(); }
    591   const_iterator end() const { return NameIndices.end(); }
    592 
    593   /// Return the Name Index covering the compile unit at CUOffset, or nullptr if
    594   /// there is no Name Index covering that unit.
    595   const NameIndex *getCUNameIndex(uint32_t CUOffset);
    596 };
    597 
    598 } // end namespace llvm
    599 
    600 #endif // LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
    601