1 //===- DWARFAcceleratorTable.cpp ------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/BinaryFormat/Dwarf.h"
13 #include "llvm/Support/Compiler.h"
14 #include "llvm/Support/DJB.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/Format.h"
17 #include "llvm/Support/FormatVariadic.h"
18 #include "llvm/Support/ScopedPrinter.h"
19 #include "llvm/Support/raw_ostream.h"
31 static raw_ostream
&operator<<(raw_ostream
&OS
, const Atom
&A
) {
32 StringRef Str
= dwarf::AtomTypeString(A
.Value
);
35 return OS
<< "DW_ATOM_unknown_" << format("%x", A
.Value
);
39 static Atom
formatAtom(unsigned Atom
) { return {Atom
}; }
41 DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
43 Error
AppleAcceleratorTable::extract() {
46 // Check that we can at least read the header.
47 if (!AccelSection
.isValidOffset(offsetof(Header
, HeaderDataLength
) + 4))
48 return createStringError(errc::illegal_byte_sequence
,
49 "Section too small: cannot read header.");
51 Hdr
.Magic
= AccelSection
.getU32(&Offset
);
52 Hdr
.Version
= AccelSection
.getU16(&Offset
);
53 Hdr
.HashFunction
= AccelSection
.getU16(&Offset
);
54 Hdr
.BucketCount
= AccelSection
.getU32(&Offset
);
55 Hdr
.HashCount
= AccelSection
.getU32(&Offset
);
56 Hdr
.HeaderDataLength
= AccelSection
.getU32(&Offset
);
57 FormParams
= {Hdr
.Version
, 0, dwarf::DwarfFormat::DWARF32
};
59 // Check that we can read all the hashes and offsets from the
60 // section (see SourceLevelDebugging.rst for the structure of the index).
61 if (!AccelSection
.isValidOffset(getIthBucketBase(Hdr
.BucketCount
- 1)))
62 return createStringError(
63 errc::illegal_byte_sequence
,
64 "Section too small: cannot read buckets and hashes.");
66 HdrData
.DIEOffsetBase
= AccelSection
.getU32(&Offset
);
67 uint32_t NumAtoms
= AccelSection
.getU32(&Offset
);
69 HashDataEntryLength
= 0;
70 auto MakeUnsupportedFormError
= [](dwarf::Form Form
) {
71 return createStringError(errc::not_supported
,
73 dwarf::FormEncodingString(Form
));
76 for (unsigned i
= 0; i
< NumAtoms
; ++i
) {
77 uint16_t AtomType
= AccelSection
.getU16(&Offset
);
78 auto AtomForm
= static_cast<dwarf::Form
>(AccelSection
.getU16(&Offset
));
79 HdrData
.Atoms
.push_back(std::make_pair(AtomType
, AtomForm
));
81 std::optional
<uint8_t> FormSize
=
82 dwarf::getFixedFormByteSize(AtomForm
, FormParams
);
84 return MakeUnsupportedFormError(AtomForm
);
85 HashDataEntryLength
+= *FormSize
;
89 return Error::success();
92 uint32_t AppleAcceleratorTable::getNumBuckets() const {
93 return Hdr
.BucketCount
;
95 uint32_t AppleAcceleratorTable::getNumHashes() const { return Hdr
.HashCount
; }
96 uint32_t AppleAcceleratorTable::getSizeHdr() const { return sizeof(Hdr
); }
97 uint32_t AppleAcceleratorTable::getHeaderDataLength() const {
98 return Hdr
.HeaderDataLength
;
101 ArrayRef
<std::pair
<AppleAcceleratorTable::HeaderData::AtomType
,
102 AppleAcceleratorTable::HeaderData::Form
>>
103 AppleAcceleratorTable::getAtomsDesc() {
104 return HdrData
.Atoms
;
107 bool AppleAcceleratorTable::validateForms() {
108 for (auto Atom
: getAtomsDesc()) {
109 DWARFFormValue
FormValue(Atom
.second
);
110 switch (Atom
.first
) {
111 case dwarf::DW_ATOM_die_offset
:
112 case dwarf::DW_ATOM_die_tag
:
113 case dwarf::DW_ATOM_type_flags
:
114 if ((!FormValue
.isFormClass(DWARFFormValue::FC_Constant
) &&
115 !FormValue
.isFormClass(DWARFFormValue::FC_Flag
)) ||
116 FormValue
.getForm() == dwarf::DW_FORM_sdata
)
126 std::pair
<uint64_t, dwarf::Tag
>
127 AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset
) {
128 uint64_t DieOffset
= dwarf::DW_INVALID_OFFSET
;
129 dwarf::Tag DieTag
= dwarf::DW_TAG_null
;
131 for (auto Atom
: getAtomsDesc()) {
132 DWARFFormValue
FormValue(Atom
.second
);
133 FormValue
.extractValue(AccelSection
, HashDataOffset
, FormParams
);
134 switch (Atom
.first
) {
135 case dwarf::DW_ATOM_die_offset
:
136 DieOffset
= *FormValue
.getAsUnsignedConstant();
138 case dwarf::DW_ATOM_die_tag
:
139 DieTag
= (dwarf::Tag
)*FormValue
.getAsUnsignedConstant();
145 return {DieOffset
, DieTag
};
148 void AppleAcceleratorTable::Header::dump(ScopedPrinter
&W
) const {
149 DictScope
HeaderScope(W
, "Header");
150 W
.printHex("Magic", Magic
);
151 W
.printHex("Version", Version
);
152 W
.printHex("Hash function", HashFunction
);
153 W
.printNumber("Bucket count", BucketCount
);
154 W
.printNumber("Hashes count", HashCount
);
155 W
.printNumber("HeaderData length", HeaderDataLength
);
158 std::optional
<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset(
159 std::optional
<DWARFFormValue
> Value
) const {
163 switch (Value
->getForm()) {
164 case dwarf::DW_FORM_ref1
:
165 case dwarf::DW_FORM_ref2
:
166 case dwarf::DW_FORM_ref4
:
167 case dwarf::DW_FORM_ref8
:
168 case dwarf::DW_FORM_ref_udata
:
169 return Value
->getRawUValue() + DIEOffsetBase
;
171 return Value
->getAsSectionOffset();
175 bool AppleAcceleratorTable::dumpName(ScopedPrinter
&W
,
176 SmallVectorImpl
<DWARFFormValue
> &AtomForms
,
177 uint64_t *DataOffset
) const {
178 uint64_t NameOffset
= *DataOffset
;
179 if (!AccelSection
.isValidOffsetForDataOfSize(*DataOffset
, 4)) {
180 W
.printString("Incorrectly terminated list.");
183 uint64_t StringOffset
= AccelSection
.getRelocatedValue(4, DataOffset
);
185 return false; // End of list
187 DictScope
NameScope(W
, ("Name@0x" + Twine::utohexstr(NameOffset
)).str());
188 W
.startLine() << format("String: 0x%08" PRIx64
, StringOffset
);
189 W
.getOStream() << " \"" << StringSection
.getCStr(&StringOffset
) << "\"\n";
191 unsigned NumData
= AccelSection
.getU32(DataOffset
);
192 for (unsigned Data
= 0; Data
< NumData
; ++Data
) {
193 ListScope
DataScope(W
, ("Data " + Twine(Data
)).str());
195 for (auto &Atom
: AtomForms
) {
196 W
.startLine() << format("Atom[%d]: ", i
);
197 if (Atom
.extractValue(AccelSection
, DataOffset
, FormParams
)) {
198 Atom
.dump(W
.getOStream());
199 if (std::optional
<uint64_t> Val
= Atom
.getAsUnsignedConstant()) {
200 StringRef Str
= dwarf::AtomValueString(HdrData
.Atoms
[i
].first
, *Val
);
202 W
.getOStream() << " (" << Str
<< ")";
205 W
.getOStream() << "Error extracting the value";
206 W
.getOStream() << "\n";
210 return true; // more entries follow
213 LLVM_DUMP_METHOD
void AppleAcceleratorTable::dump(raw_ostream
&OS
) const {
221 W
.printNumber("DIE offset base", HdrData
.DIEOffsetBase
);
222 W
.printNumber("Number of atoms", uint64_t(HdrData
.Atoms
.size()));
223 W
.printNumber("Size of each hash data entry", getHashDataEntryLength());
224 SmallVector
<DWARFFormValue
, 3> AtomForms
;
226 ListScope
AtomsScope(W
, "Atoms");
228 for (const auto &Atom
: HdrData
.Atoms
) {
229 DictScope
AtomScope(W
, ("Atom " + Twine(i
++)).str());
230 W
.startLine() << "Type: " << formatAtom(Atom
.first
) << '\n';
231 W
.startLine() << "Form: " << formatv("{0}", Atom
.second
) << '\n';
232 AtomForms
.push_back(DWARFFormValue(Atom
.second
));
236 // Now go through the actual tables and dump them.
237 uint64_t Offset
= sizeof(Hdr
) + Hdr
.HeaderDataLength
;
238 uint64_t HashesBase
= Offset
+ Hdr
.BucketCount
* 4;
239 uint64_t OffsetsBase
= HashesBase
+ Hdr
.HashCount
* 4;
241 for (unsigned Bucket
= 0; Bucket
< Hdr
.BucketCount
; ++Bucket
) {
242 unsigned Index
= AccelSection
.getU32(&Offset
);
244 ListScope
BucketScope(W
, ("Bucket " + Twine(Bucket
)).str());
245 if (Index
== UINT32_MAX
) {
246 W
.printString("EMPTY");
250 for (unsigned HashIdx
= Index
; HashIdx
< Hdr
.HashCount
; ++HashIdx
) {
251 uint64_t HashOffset
= HashesBase
+ HashIdx
*4;
252 uint64_t OffsetsOffset
= OffsetsBase
+ HashIdx
*4;
253 uint32_t Hash
= AccelSection
.getU32(&HashOffset
);
255 if (Hash
% Hdr
.BucketCount
!= Bucket
)
258 uint64_t DataOffset
= AccelSection
.getU32(&OffsetsOffset
);
259 ListScope
HashScope(W
, ("Hash 0x" + Twine::utohexstr(Hash
)).str());
260 if (!AccelSection
.isValidOffset(DataOffset
)) {
261 W
.printString("Invalid section offset");
264 while (dumpName(W
, AtomForms
, &DataOffset
))
270 AppleAcceleratorTable::Entry::Entry(const AppleAcceleratorTable
&Table
)
272 Values
.reserve(Table
.HdrData
.Atoms
.size());
273 for (const auto &Atom
: Table
.HdrData
.Atoms
)
274 Values
.push_back(DWARFFormValue(Atom
.second
));
277 void AppleAcceleratorTable::Entry::extract(uint64_t *Offset
) {
278 for (auto &FormValue
: Values
)
279 FormValue
.extractValue(Table
.AccelSection
, Offset
, Table
.FormParams
);
282 std::optional
<DWARFFormValue
>
283 AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType AtomToFind
) const {
284 for (auto [Atom
, FormValue
] : zip_equal(Table
.HdrData
.Atoms
, Values
))
285 if (Atom
.first
== AtomToFind
)
290 std::optional
<uint64_t>
291 AppleAcceleratorTable::Entry::getDIESectionOffset() const {
292 return Table
.HdrData
.extractOffset(lookup(dwarf::DW_ATOM_die_offset
));
295 std::optional
<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
296 return Table
.HdrData
.extractOffset(lookup(dwarf::DW_ATOM_cu_offset
));
299 std::optional
<dwarf::Tag
> AppleAcceleratorTable::Entry::getTag() const {
300 std::optional
<DWARFFormValue
> Tag
= lookup(dwarf::DW_ATOM_die_tag
);
303 if (std::optional
<uint64_t> Value
= Tag
->getAsUnsignedConstant())
304 return dwarf::Tag(*Value
);
308 AppleAcceleratorTable::SameNameIterator::SameNameIterator(
309 const AppleAcceleratorTable
&AccelTable
, uint64_t DataOffset
)
310 : Current(AccelTable
), Offset(DataOffset
) {}
312 void AppleAcceleratorTable::Iterator::prepareNextEntryOrEnd() {
313 if (NumEntriesToCome
== 0)
314 prepareNextStringOrEnd();
317 uint64_t OffsetCopy
= Offset
;
318 Current
.BaseEntry
.extract(&OffsetCopy
);
320 Offset
+= getTable().getHashDataEntryLength();
323 void AppleAcceleratorTable::Iterator::prepareNextStringOrEnd() {
324 std::optional
<uint32_t> StrOffset
= getTable().readStringOffsetAt(Offset
);
328 // A zero denotes the end of the collision list. Read the next string
331 return prepareNextStringOrEnd();
332 Current
.StrOffset
= *StrOffset
;
334 std::optional
<uint32_t> MaybeNumEntries
= getTable().readU32FromAccel(Offset
);
335 if (!MaybeNumEntries
|| *MaybeNumEntries
== 0)
337 NumEntriesToCome
= *MaybeNumEntries
;
340 AppleAcceleratorTable::Iterator::Iterator(const AppleAcceleratorTable
&Table
,
342 : Current(Table
), Offset(Table
.getEntriesBase()), NumEntriesToCome(0) {
346 prepareNextEntryOrEnd();
349 iterator_range
<AppleAcceleratorTable::SameNameIterator
>
350 AppleAcceleratorTable::equal_range(StringRef Key
) const {
351 const auto EmptyRange
=
352 make_range(SameNameIterator(*this, 0), SameNameIterator(*this, 0));
357 uint32_t SearchHash
= djbHash(Key
);
358 uint32_t BucketIdx
= hashToBucketIdx(SearchHash
);
359 std::optional
<uint32_t> HashIdx
= idxOfHashInBucket(SearchHash
, BucketIdx
);
363 std::optional
<uint64_t> MaybeDataOffset
= readIthOffset(*HashIdx
);
364 if (!MaybeDataOffset
)
367 uint64_t DataOffset
= *MaybeDataOffset
;
368 if (DataOffset
>= AccelSection
.size())
371 std::optional
<uint32_t> StrOffset
= readStringOffsetAt(DataOffset
);
372 // Valid input and still have strings in this hash.
373 while (StrOffset
&& *StrOffset
) {
374 std::optional
<StringRef
> MaybeStr
= readStringFromStrSection(*StrOffset
);
375 std::optional
<uint32_t> NumEntries
= this->readU32FromAccel(DataOffset
);
376 if (!MaybeStr
|| !NumEntries
)
378 uint64_t EndOffset
= DataOffset
+ *NumEntries
* getHashDataEntryLength();
379 if (Key
== *MaybeStr
)
380 return make_range({*this, DataOffset
},
381 SameNameIterator
{*this, EndOffset
});
382 DataOffset
= EndOffset
;
383 StrOffset
= readStringOffsetAt(DataOffset
);
389 std::optional
<uint32_t>
390 AppleAcceleratorTable::idxOfHashInBucket(uint32_t HashToFind
,
391 uint32_t BucketIdx
) const {
392 std::optional
<uint32_t> HashStartIdx
= readIthBucket(BucketIdx
);
396 for (uint32_t HashIdx
= *HashStartIdx
; HashIdx
< getNumHashes(); HashIdx
++) {
397 std::optional
<uint32_t> MaybeHash
= readIthHash(HashIdx
);
398 if (!MaybeHash
|| !wouldHashBeInBucket(*MaybeHash
, BucketIdx
))
400 if (*MaybeHash
== HashToFind
)
406 std::optional
<StringRef
> AppleAcceleratorTable::readStringFromStrSection(
407 uint64_t StringSectionOffset
) const {
408 Error E
= Error::success();
409 StringRef Str
= StringSection
.getCStrRef(&StringSectionOffset
, &E
);
411 consumeError(std::move(E
));
417 std::optional
<uint32_t>
418 AppleAcceleratorTable::readU32FromAccel(uint64_t &Offset
,
419 bool UseRelocation
) const {
420 Error E
= Error::success();
421 uint32_t Data
= UseRelocation
422 ? AccelSection
.getRelocatedValue(4, &Offset
, nullptr, &E
)
423 : AccelSection
.getU32(&Offset
, &E
);
425 consumeError(std::move(E
));
431 void DWARFDebugNames::Header::dump(ScopedPrinter
&W
) const {
432 DictScope
HeaderScope(W
, "Header");
433 W
.printHex("Length", UnitLength
);
434 W
.printString("Format", dwarf::FormatString(Format
));
435 W
.printNumber("Version", Version
);
436 W
.printNumber("CU count", CompUnitCount
);
437 W
.printNumber("Local TU count", LocalTypeUnitCount
);
438 W
.printNumber("Foreign TU count", ForeignTypeUnitCount
);
439 W
.printNumber("Bucket count", BucketCount
);
440 W
.printNumber("Name count", NameCount
);
441 W
.printHex("Abbreviations table size", AbbrevTableSize
);
442 W
.startLine() << "Augmentation: '" << AugmentationString
<< "'\n";
445 Error
DWARFDebugNames::Header::extract(const DWARFDataExtractor
&AS
,
447 auto HeaderError
= [Offset
= *Offset
](Error E
) {
448 return createStringError(errc::illegal_byte_sequence
,
449 "parsing .debug_names header at 0x%" PRIx64
": %s",
450 Offset
, toString(std::move(E
)).c_str());
453 DataExtractor::Cursor
C(*Offset
);
454 std::tie(UnitLength
, Format
) = AS
.getInitialLength(C
);
456 Version
= AS
.getU16(C
);
457 AS
.skip(C
, 2); // padding
458 CompUnitCount
= AS
.getU32(C
);
459 LocalTypeUnitCount
= AS
.getU32(C
);
460 ForeignTypeUnitCount
= AS
.getU32(C
);
461 BucketCount
= AS
.getU32(C
);
462 NameCount
= AS
.getU32(C
);
463 AbbrevTableSize
= AS
.getU32(C
);
464 AugmentationStringSize
= alignTo(AS
.getU32(C
), 4);
467 return HeaderError(C
.takeError());
469 if (!AS
.isValidOffsetForDataOfSize(C
.tell(), AugmentationStringSize
))
470 return HeaderError(createStringError(errc::illegal_byte_sequence
,
471 "cannot read header augmentation"));
472 AugmentationString
.resize(AugmentationStringSize
);
473 AS
.getU8(C
, reinterpret_cast<uint8_t *>(AugmentationString
.data()),
474 AugmentationStringSize
);
476 return C
.takeError();
479 void DWARFDebugNames::Abbrev::dump(ScopedPrinter
&W
) const {
480 DictScope
AbbrevScope(W
, ("Abbreviation 0x" + Twine::utohexstr(Code
)).str());
481 W
.startLine() << formatv("Tag: {0}\n", Tag
);
483 for (const auto &Attr
: Attributes
)
484 W
.startLine() << formatv("{0}: {1}\n", Attr
.Index
, Attr
.Form
);
487 static constexpr DWARFDebugNames::AttributeEncoding
sentinelAttrEnc() {
488 return {dwarf::Index(0), dwarf::Form(0)};
491 static bool isSentinel(const DWARFDebugNames::AttributeEncoding
&AE
) {
492 return AE
== sentinelAttrEnc();
495 static DWARFDebugNames::Abbrev
sentinelAbbrev() {
496 return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
499 static bool isSentinel(const DWARFDebugNames::Abbrev
&Abbr
) {
500 return Abbr
.Code
== 0;
503 DWARFDebugNames::Abbrev
DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
504 return sentinelAbbrev();
507 DWARFDebugNames::Abbrev
DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
508 return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
511 Expected
<DWARFDebugNames::AttributeEncoding
>
512 DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset
) {
513 if (*Offset
>= EntriesBase
) {
514 return createStringError(errc::illegal_byte_sequence
,
515 "Incorrectly terminated abbreviation table.");
518 uint32_t Index
= Section
.AccelSection
.getULEB128(Offset
);
519 uint32_t Form
= Section
.AccelSection
.getULEB128(Offset
);
520 return AttributeEncoding(dwarf::Index(Index
), dwarf::Form(Form
));
523 Expected
<std::vector
<DWARFDebugNames::AttributeEncoding
>>
524 DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset
) {
525 std::vector
<AttributeEncoding
> Result
;
527 auto AttrEncOr
= extractAttributeEncoding(Offset
);
529 return AttrEncOr
.takeError();
530 if (isSentinel(*AttrEncOr
))
531 return std::move(Result
);
533 Result
.emplace_back(*AttrEncOr
);
537 Expected
<DWARFDebugNames::Abbrev
>
538 DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset
) {
539 if (*Offset
>= EntriesBase
) {
540 return createStringError(errc::illegal_byte_sequence
,
541 "Incorrectly terminated abbreviation table.");
544 uint32_t Code
= Section
.AccelSection
.getULEB128(Offset
);
546 return sentinelAbbrev();
548 uint32_t Tag
= Section
.AccelSection
.getULEB128(Offset
);
549 auto AttrEncOr
= extractAttributeEncodings(Offset
);
551 return AttrEncOr
.takeError();
552 return Abbrev(Code
, dwarf::Tag(Tag
), std::move(*AttrEncOr
));
555 Error
DWARFDebugNames::NameIndex::extract() {
556 const DWARFDataExtractor
&AS
= Section
.AccelSection
;
557 uint64_t Offset
= Base
;
558 if (Error E
= Hdr
.extract(AS
, &Offset
))
561 const unsigned SectionOffsetSize
= dwarf::getDwarfOffsetByteSize(Hdr
.Format
);
563 Offset
+= Hdr
.CompUnitCount
* SectionOffsetSize
;
564 Offset
+= Hdr
.LocalTypeUnitCount
* SectionOffsetSize
;
565 Offset
+= Hdr
.ForeignTypeUnitCount
* 8;
566 BucketsBase
= Offset
;
567 Offset
+= Hdr
.BucketCount
* 4;
569 if (Hdr
.BucketCount
> 0)
570 Offset
+= Hdr
.NameCount
* 4;
571 StringOffsetsBase
= Offset
;
572 Offset
+= Hdr
.NameCount
* SectionOffsetSize
;
573 EntryOffsetsBase
= Offset
;
574 Offset
+= Hdr
.NameCount
* SectionOffsetSize
;
576 if (!AS
.isValidOffsetForDataOfSize(Offset
, Hdr
.AbbrevTableSize
))
577 return createStringError(errc::illegal_byte_sequence
,
578 "Section too small: cannot read abbreviations.");
580 EntriesBase
= Offset
+ Hdr
.AbbrevTableSize
;
583 auto AbbrevOr
= extractAbbrev(&Offset
);
585 return AbbrevOr
.takeError();
586 if (isSentinel(*AbbrevOr
))
587 return Error::success();
589 if (!Abbrevs
.insert(std::move(*AbbrevOr
)).second
)
590 return createStringError(errc::invalid_argument
,
591 "Duplicate abbreviation code.");
595 DWARFDebugNames::Entry::Entry(const NameIndex
&NameIdx
, const Abbrev
&Abbr
)
596 : NameIdx(&NameIdx
), Abbr(&Abbr
) {
597 // This merely creates form values. It is up to the caller
598 // (NameIndex::getEntry) to populate them.
599 Values
.reserve(Abbr
.Attributes
.size());
600 for (const auto &Attr
: Abbr
.Attributes
)
601 Values
.emplace_back(Attr
.Form
);
604 std::optional
<DWARFFormValue
>
605 DWARFDebugNames::Entry::lookup(dwarf::Index Index
) const {
606 assert(Abbr
->Attributes
.size() == Values
.size());
607 for (auto Tuple
: zip_first(Abbr
->Attributes
, Values
)) {
608 if (std::get
<0>(Tuple
).Index
== Index
)
609 return std::get
<1>(Tuple
);
614 std::optional
<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {
615 if (std::optional
<DWARFFormValue
> Off
= lookup(dwarf::DW_IDX_die_offset
))
616 return Off
->getAsReferenceUVal();
620 std::optional
<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
621 if (std::optional
<DWARFFormValue
> Off
= lookup(dwarf::DW_IDX_compile_unit
))
622 return Off
->getAsUnsignedConstant();
623 // In a per-CU index, the entries without a DW_IDX_compile_unit attribute
624 // implicitly refer to the single CU, but only if we don't have a
626 if (lookup(dwarf::DW_IDX_type_unit
).has_value())
628 if (NameIdx
->getCUCount() == 1)
633 std::optional
<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
634 std::optional
<uint64_t> Index
= getCUIndex();
635 if (!Index
|| *Index
>= NameIdx
->getCUCount())
637 return NameIdx
->getCUOffset(*Index
);
640 std::optional
<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const {
641 std::optional
<uint64_t> Index
= getLocalTUIndex();
642 if (!Index
|| *Index
>= NameIdx
->getLocalTUCount())
644 return NameIdx
->getLocalTUOffset(*Index
);
647 std::optional
<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
648 if (std::optional
<DWARFFormValue
> Off
= lookup(dwarf::DW_IDX_type_unit
))
649 return Off
->getAsUnsignedConstant();
653 void DWARFDebugNames::Entry::dump(ScopedPrinter
&W
) const {
654 W
.startLine() << formatv("Abbrev: {0:x}\n", Abbr
->Code
);
655 W
.startLine() << formatv("Tag: {0}\n", Abbr
->Tag
);
656 assert(Abbr
->Attributes
.size() == Values
.size());
657 for (auto Tuple
: zip_first(Abbr
->Attributes
, Values
)) {
658 W
.startLine() << formatv("{0}: ", std::get
<0>(Tuple
).Index
);
659 std::get
<1>(Tuple
).dump(W
.getOStream());
660 W
.getOStream() << '\n';
664 char DWARFDebugNames::SentinelError::ID
;
665 std::error_code
DWARFDebugNames::SentinelError::convertToErrorCode() const {
666 return inconvertibleErrorCode();
669 uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU
) const {
670 assert(CU
< Hdr
.CompUnitCount
);
671 const unsigned SectionOffsetSize
= dwarf::getDwarfOffsetByteSize(Hdr
.Format
);
672 uint64_t Offset
= CUsBase
+ SectionOffsetSize
* CU
;
673 return Section
.AccelSection
.getRelocatedValue(SectionOffsetSize
, &Offset
);
676 uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU
) const {
677 assert(TU
< Hdr
.LocalTypeUnitCount
);
678 const unsigned SectionOffsetSize
= dwarf::getDwarfOffsetByteSize(Hdr
.Format
);
679 uint64_t Offset
= CUsBase
+ SectionOffsetSize
* (Hdr
.CompUnitCount
+ TU
);
680 return Section
.AccelSection
.getRelocatedValue(SectionOffsetSize
, &Offset
);
683 uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU
) const {
684 assert(TU
< Hdr
.ForeignTypeUnitCount
);
685 const unsigned SectionOffsetSize
= dwarf::getDwarfOffsetByteSize(Hdr
.Format
);
688 SectionOffsetSize
* (Hdr
.CompUnitCount
+ Hdr
.LocalTypeUnitCount
) + 8 * TU
;
689 return Section
.AccelSection
.getU64(&Offset
);
692 Expected
<DWARFDebugNames::Entry
>
693 DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset
) const {
694 const DWARFDataExtractor
&AS
= Section
.AccelSection
;
695 if (!AS
.isValidOffset(*Offset
))
696 return createStringError(errc::illegal_byte_sequence
,
697 "Incorrectly terminated entry list.");
699 uint32_t AbbrevCode
= AS
.getULEB128(Offset
);
701 return make_error
<SentinelError
>();
703 const auto AbbrevIt
= Abbrevs
.find_as(AbbrevCode
);
704 if (AbbrevIt
== Abbrevs
.end())
705 return createStringError(errc::invalid_argument
, "Invalid abbreviation.");
707 Entry
E(*this, *AbbrevIt
);
709 dwarf::FormParams FormParams
= {Hdr
.Version
, 0, Hdr
.Format
};
710 for (auto &Value
: E
.Values
) {
711 if (!Value
.extractValue(AS
, Offset
, FormParams
))
712 return createStringError(errc::io_error
,
713 "Error extracting index attribute values.");
718 DWARFDebugNames::NameTableEntry
719 DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index
) const {
720 assert(0 < Index
&& Index
<= Hdr
.NameCount
);
721 const unsigned SectionOffsetSize
= dwarf::getDwarfOffsetByteSize(Hdr
.Format
);
722 uint64_t StringOffsetOffset
=
723 StringOffsetsBase
+ SectionOffsetSize
* (Index
- 1);
724 uint64_t EntryOffsetOffset
=
725 EntryOffsetsBase
+ SectionOffsetSize
* (Index
- 1);
726 const DWARFDataExtractor
&AS
= Section
.AccelSection
;
728 uint64_t StringOffset
=
729 AS
.getRelocatedValue(SectionOffsetSize
, &StringOffsetOffset
);
730 uint64_t EntryOffset
= AS
.getUnsigned(&EntryOffsetOffset
, SectionOffsetSize
);
731 EntryOffset
+= EntriesBase
;
732 return {Section
.StringSection
, Index
, StringOffset
, EntryOffset
};
736 DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket
) const {
737 assert(Bucket
< Hdr
.BucketCount
);
738 uint64_t BucketOffset
= BucketsBase
+ 4 * Bucket
;
739 return Section
.AccelSection
.getU32(&BucketOffset
);
742 uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index
) const {
743 assert(0 < Index
&& Index
<= Hdr
.NameCount
);
744 uint64_t HashOffset
= HashesBase
+ 4 * (Index
- 1);
745 return Section
.AccelSection
.getU32(&HashOffset
);
748 // Returns true if we should continue scanning for entries, false if this is the
749 // last (sentinel) entry). In case of a parsing error we also return false, as
750 // it's not possible to recover this entry list (but the other lists may still
752 bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter
&W
,
753 uint64_t *Offset
) const {
754 uint64_t EntryId
= *Offset
;
755 auto EntryOr
= getEntry(Offset
);
757 handleAllErrors(EntryOr
.takeError(), [](const SentinelError
&) {},
758 [&W
](const ErrorInfoBase
&EI
) { EI
.log(W
.startLine()); });
762 DictScope
EntryScope(W
, ("Entry @ 0x" + Twine::utohexstr(EntryId
)).str());
767 void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter
&W
,
768 const NameTableEntry
&NTE
,
769 std::optional
<uint32_t> Hash
) const {
770 DictScope
NameScope(W
, ("Name " + Twine(NTE
.getIndex())).str());
772 W
.printHex("Hash", *Hash
);
774 W
.startLine() << format("String: 0x%08" PRIx64
, NTE
.getStringOffset());
775 W
.getOStream() << " \"" << NTE
.getString() << "\"\n";
777 uint64_t EntryOffset
= NTE
.getEntryOffset();
778 while (dumpEntry(W
, &EntryOffset
))
782 void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter
&W
) const {
783 ListScope
CUScope(W
, "Compilation Unit offsets");
784 for (uint32_t CU
= 0; CU
< Hdr
.CompUnitCount
; ++CU
)
785 W
.startLine() << format("CU[%u]: 0x%08" PRIx64
"\n", CU
, getCUOffset(CU
));
788 void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter
&W
) const {
789 if (Hdr
.LocalTypeUnitCount
== 0)
792 ListScope
TUScope(W
, "Local Type Unit offsets");
793 for (uint32_t TU
= 0; TU
< Hdr
.LocalTypeUnitCount
; ++TU
)
794 W
.startLine() << format("LocalTU[%u]: 0x%08" PRIx64
"\n", TU
,
795 getLocalTUOffset(TU
));
798 void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter
&W
) const {
799 if (Hdr
.ForeignTypeUnitCount
== 0)
802 ListScope
TUScope(W
, "Foreign Type Unit signatures");
803 for (uint32_t TU
= 0; TU
< Hdr
.ForeignTypeUnitCount
; ++TU
) {
804 W
.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64
"\n", TU
,
805 getForeignTUSignature(TU
));
809 void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter
&W
) const {
810 ListScope
AbbrevsScope(W
, "Abbreviations");
811 for (const auto &Abbr
: Abbrevs
)
815 void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter
&W
,
816 uint32_t Bucket
) const {
817 ListScope
BucketScope(W
, ("Bucket " + Twine(Bucket
)).str());
818 uint32_t Index
= getBucketArrayEntry(Bucket
);
820 W
.printString("EMPTY");
823 if (Index
> Hdr
.NameCount
) {
824 W
.printString("Name index is invalid");
828 for (; Index
<= Hdr
.NameCount
; ++Index
) {
829 uint32_t Hash
= getHashArrayEntry(Index
);
830 if (Hash
% Hdr
.BucketCount
!= Bucket
)
833 dumpName(W
, getNameTableEntry(Index
), Hash
);
837 LLVM_DUMP_METHOD
void DWARFDebugNames::NameIndex::dump(ScopedPrinter
&W
) const {
838 DictScope
UnitScope(W
, ("Name Index @ 0x" + Twine::utohexstr(Base
)).str());
843 dumpAbbreviations(W
);
845 if (Hdr
.BucketCount
> 0) {
846 for (uint32_t Bucket
= 0; Bucket
< Hdr
.BucketCount
; ++Bucket
)
847 dumpBucket(W
, Bucket
);
851 W
.startLine() << "Hash table not present\n";
852 for (const NameTableEntry
&NTE
: *this)
853 dumpName(W
, NTE
, std::nullopt
);
856 Error
DWARFDebugNames::extract() {
858 while (AccelSection
.isValidOffset(Offset
)) {
859 NameIndex
Next(*this, Offset
);
860 if (Error E
= Next
.extract())
862 Offset
= Next
.getNextUnitOffset();
863 NameIndices
.push_back(std::move(Next
));
865 return Error::success();
868 iterator_range
<DWARFDebugNames::ValueIterator
>
869 DWARFDebugNames::NameIndex::equal_range(StringRef Key
) const {
870 return make_range(ValueIterator(*this, Key
), ValueIterator());
873 LLVM_DUMP_METHOD
void DWARFDebugNames::dump(raw_ostream
&OS
) const {
875 for (const NameIndex
&NI
: NameIndices
)
879 std::optional
<uint64_t>
880 DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {
881 const Header
&Hdr
= CurrentIndex
->Hdr
;
882 if (Hdr
.BucketCount
== 0) {
883 // No Hash Table, We need to search through all names in the Name Index.
884 for (const NameTableEntry
&NTE
: *CurrentIndex
) {
885 if (NTE
.getString() == Key
)
886 return NTE
.getEntryOffset();
891 // The Name Index has a Hash Table, so use that to speed up the search.
892 // Compute the Key Hash, if it has not been done already.
894 Hash
= caseFoldingDjbHash(Key
);
895 uint32_t Bucket
= *Hash
% Hdr
.BucketCount
;
896 uint32_t Index
= CurrentIndex
->getBucketArrayEntry(Bucket
);
898 return std::nullopt
; // Empty bucket
900 for (; Index
<= Hdr
.NameCount
; ++Index
) {
901 uint32_t Hash
= CurrentIndex
->getHashArrayEntry(Index
);
902 if (Hash
% Hdr
.BucketCount
!= Bucket
)
903 return std::nullopt
; // End of bucket
905 NameTableEntry NTE
= CurrentIndex
->getNameTableEntry(Index
);
906 if (NTE
.getString() == Key
)
907 return NTE
.getEntryOffset();
912 bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {
913 auto EntryOr
= CurrentIndex
->getEntry(&DataOffset
);
915 consumeError(EntryOr
.takeError());
918 CurrentEntry
= std::move(*EntryOr
);
922 bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {
923 std::optional
<uint64_t> Offset
= findEntryOffsetInCurrentIndex();
926 DataOffset
= *Offset
;
927 return getEntryAtCurrentOffset();
930 void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {
931 for (const NameIndex
*End
= CurrentIndex
->Section
.NameIndices
.end();
932 CurrentIndex
!= End
; ++CurrentIndex
) {
933 if (findInCurrentIndex())
939 void DWARFDebugNames::ValueIterator::next() {
940 assert(CurrentIndex
&& "Incrementing an end() iterator?");
942 // First try the next entry in the current Index.
943 if (getEntryAtCurrentOffset())
946 // If we're a local iterator or we have reached the last Index, we're done.
947 if (IsLocal
|| CurrentIndex
== &CurrentIndex
->Section
.NameIndices
.back()) {
952 // Otherwise, try the next index.
954 searchFromStartOfCurrentIndex();
957 DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames
&AccelTable
,
959 : CurrentIndex(AccelTable
.NameIndices
.begin()), IsLocal(false),
960 Key(std::string(Key
)) {
961 searchFromStartOfCurrentIndex();
964 DWARFDebugNames::ValueIterator::ValueIterator(
965 const DWARFDebugNames::NameIndex
&NI
, StringRef Key
)
966 : CurrentIndex(&NI
), IsLocal(true), Key(std::string(Key
)) {
967 if (!findInCurrentIndex())
971 iterator_range
<DWARFDebugNames::ValueIterator
>
972 DWARFDebugNames::equal_range(StringRef Key
) const {
973 if (NameIndices
.empty())
974 return make_range(ValueIterator(), ValueIterator());
975 return make_range(ValueIterator(*this, Key
), ValueIterator());
978 const DWARFDebugNames::NameIndex
*
979 DWARFDebugNames::getCUNameIndex(uint64_t CUOffset
) {
980 if (CUToNameIndex
.size() == 0 && NameIndices
.size() > 0) {
981 for (const auto &NI
: *this) {
982 for (uint32_t CU
= 0; CU
< NI
.getCUCount(); ++CU
)
983 CUToNameIndex
.try_emplace(NI
.getCUOffset(CU
), &NI
);
986 return CUToNameIndex
.lookup(CUOffset
);
989 static bool isObjCSelector(StringRef Name
) {
990 return Name
.size() > 2 && (Name
[0] == '-' || Name
[0] == '+') &&
994 std::optional
<ObjCSelectorNames
> llvm::getObjCNamesIfSelector(StringRef Name
) {
995 if (!isObjCSelector(Name
))
997 // "-[Atom setMass:]"
998 StringRef
ClassNameStart(Name
.drop_front(2));
999 size_t FirstSpace
= ClassNameStart
.find(' ');
1000 if (FirstSpace
== StringRef::npos
)
1001 return std::nullopt
;
1003 StringRef SelectorStart
= ClassNameStart
.drop_front(FirstSpace
+ 1);
1004 if (!SelectorStart
.size())
1005 return std::nullopt
;
1007 ObjCSelectorNames Ans
;
1008 Ans
.ClassName
= ClassNameStart
.take_front(FirstSpace
);
1009 Ans
.Selector
= SelectorStart
.drop_back(); // drop ']';
1011 // "-[Class(Category) selector :withArg ...]"
1012 if (Ans
.ClassName
.back() == ')') {
1013 size_t OpenParens
= Ans
.ClassName
.find('(');
1014 if (OpenParens
!= StringRef::npos
) {
1015 Ans
.ClassNameNoCategory
= Ans
.ClassName
.take_front(OpenParens
);
1017 Ans
.MethodNameNoCategory
= Name
.take_front(OpenParens
+ 2);
1018 // FIXME: The missing space here may be a bug, but dsymutil-classic also
1019 // does it this way.
1020 append_range(*Ans
.MethodNameNoCategory
, SelectorStart
);
1026 std::optional
<StringRef
> llvm::StripTemplateParameters(StringRef Name
) {
1027 // We are looking for template parameters to strip from Name. e.g.
1031 // We look for > at the end but if it does not contain any < then we
1032 // have something like operator>>. We check for the operator<=> case.
1033 if (!Name
.ends_with(">") || Name
.count("<") == 0 || Name
.ends_with("<=>"))
1036 // How many < until we have the start of the template parameters.
1037 size_t NumLeftAnglesToSkip
= 1;
1039 // If we have operator<=> then we need to skip its < as well.
1040 NumLeftAnglesToSkip
+= Name
.count("<=>");
1042 size_t RightAngleCount
= Name
.count('>');
1043 size_t LeftAngleCount
= Name
.count('<');
1045 // If we have more < than > we have operator< or operator<<
1046 // we to account for their < as well.
1047 if (LeftAngleCount
> RightAngleCount
)
1048 NumLeftAnglesToSkip
+= LeftAngleCount
- RightAngleCount
;
1050 size_t StartOfTemplate
= 0;
1051 while (NumLeftAnglesToSkip
--)
1052 StartOfTemplate
= Name
.find('<', StartOfTemplate
) + 1;
1054 return Name
.substr(0, StartOfTemplate
- 1);