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