10b57cec5SDimitry Andric //===- DWARFAcceleratorTable.cpp ------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 120b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 130b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 140b57cec5SDimitry Andric #include "llvm/Support/DJB.h" 150b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 160b57cec5SDimitry Andric #include "llvm/Support/Format.h" 170b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 180b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h" 190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 200b57cec5SDimitry Andric #include <cstddef> 210b57cec5SDimitry Andric #include <cstdint> 220b57cec5SDimitry Andric #include <utility> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric using namespace llvm; 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric namespace { 270b57cec5SDimitry Andric struct Atom { 280b57cec5SDimitry Andric unsigned Value; 290b57cec5SDimitry Andric }; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) { 320b57cec5SDimitry Andric StringRef Str = dwarf::AtomTypeString(A.Value); 330b57cec5SDimitry Andric if (!Str.empty()) 340b57cec5SDimitry Andric return OS << Str; 350b57cec5SDimitry Andric return OS << "DW_ATOM_unknown_" << format("%x", A.Value); 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric } // namespace 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric static Atom formatAtom(unsigned Atom) { return {Atom}; } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric Error AppleAcceleratorTable::extract() { 448bcb0991SDimitry Andric uint64_t Offset = 0; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // Check that we can at least read the header. 470b57cec5SDimitry Andric if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4)) 480b57cec5SDimitry Andric return createStringError(errc::illegal_byte_sequence, 490b57cec5SDimitry Andric "Section too small: cannot read header."); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric Hdr.Magic = AccelSection.getU32(&Offset); 520b57cec5SDimitry Andric Hdr.Version = AccelSection.getU16(&Offset); 530b57cec5SDimitry Andric Hdr.HashFunction = AccelSection.getU16(&Offset); 540b57cec5SDimitry Andric Hdr.BucketCount = AccelSection.getU32(&Offset); 550b57cec5SDimitry Andric Hdr.HashCount = AccelSection.getU32(&Offset); 560b57cec5SDimitry Andric Hdr.HeaderDataLength = AccelSection.getU32(&Offset); 5706c3fb27SDimitry Andric FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // Check that we can read all the hashes and offsets from the 600b57cec5SDimitry Andric // section (see SourceLevelDebugging.rst for the structure of the index). 6106c3fb27SDimitry Andric if (!AccelSection.isValidOffset(getIthBucketBase(Hdr.BucketCount - 1))) 620b57cec5SDimitry Andric return createStringError( 630b57cec5SDimitry Andric errc::illegal_byte_sequence, 640b57cec5SDimitry Andric "Section too small: cannot read buckets and hashes."); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); 670b57cec5SDimitry Andric uint32_t NumAtoms = AccelSection.getU32(&Offset); 680b57cec5SDimitry Andric 6906c3fb27SDimitry Andric HashDataEntryLength = 0; 7006c3fb27SDimitry Andric auto MakeUnsupportedFormError = [](dwarf::Form Form) { 7106c3fb27SDimitry Andric return createStringError(errc::not_supported, 7206c3fb27SDimitry Andric "Unsupported form:" + 7306c3fb27SDimitry Andric dwarf::FormEncodingString(Form)); 7406c3fb27SDimitry Andric }; 7506c3fb27SDimitry Andric 760b57cec5SDimitry Andric for (unsigned i = 0; i < NumAtoms; ++i) { 770b57cec5SDimitry Andric uint16_t AtomType = AccelSection.getU16(&Offset); 780b57cec5SDimitry Andric auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); 790b57cec5SDimitry Andric HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); 8006c3fb27SDimitry Andric 8106c3fb27SDimitry Andric std::optional<uint8_t> FormSize = 8206c3fb27SDimitry Andric dwarf::getFixedFormByteSize(AtomForm, FormParams); 8306c3fb27SDimitry Andric if (!FormSize) 8406c3fb27SDimitry Andric return MakeUnsupportedFormError(AtomForm); 8506c3fb27SDimitry Andric HashDataEntryLength += *FormSize; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric IsValid = true; 890b57cec5SDimitry Andric return Error::success(); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 9206c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getNumBuckets() const { 9306c3fb27SDimitry Andric return Hdr.BucketCount; 9406c3fb27SDimitry Andric } 9506c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getNumHashes() const { return Hdr.HashCount; } 9606c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getSizeHdr() const { return sizeof(Hdr); } 9706c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getHeaderDataLength() const { 980b57cec5SDimitry Andric return Hdr.HeaderDataLength; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType, 1020b57cec5SDimitry Andric AppleAcceleratorTable::HeaderData::Form>> 1030b57cec5SDimitry Andric AppleAcceleratorTable::getAtomsDesc() { 1040b57cec5SDimitry Andric return HdrData.Atoms; 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric bool AppleAcceleratorTable::validateForms() { 1080b57cec5SDimitry Andric for (auto Atom : getAtomsDesc()) { 1090b57cec5SDimitry Andric DWARFFormValue FormValue(Atom.second); 1100b57cec5SDimitry Andric switch (Atom.first) { 1110b57cec5SDimitry Andric case dwarf::DW_ATOM_die_offset: 1120b57cec5SDimitry Andric case dwarf::DW_ATOM_die_tag: 1130b57cec5SDimitry Andric case dwarf::DW_ATOM_type_flags: 1140b57cec5SDimitry Andric if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && 1150b57cec5SDimitry Andric !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || 1160b57cec5SDimitry Andric FormValue.getForm() == dwarf::DW_FORM_sdata) 1170b57cec5SDimitry Andric return false; 1180b57cec5SDimitry Andric break; 1190b57cec5SDimitry Andric default: 1200b57cec5SDimitry Andric break; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric return true; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1268bcb0991SDimitry Andric std::pair<uint64_t, dwarf::Tag> 1278bcb0991SDimitry Andric AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) { 1288bcb0991SDimitry Andric uint64_t DieOffset = dwarf::DW_INVALID_OFFSET; 1290b57cec5SDimitry Andric dwarf::Tag DieTag = dwarf::DW_TAG_null; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric for (auto Atom : getAtomsDesc()) { 1320b57cec5SDimitry Andric DWARFFormValue FormValue(Atom.second); 1338bcb0991SDimitry Andric FormValue.extractValue(AccelSection, HashDataOffset, FormParams); 1340b57cec5SDimitry Andric switch (Atom.first) { 1350b57cec5SDimitry Andric case dwarf::DW_ATOM_die_offset: 1360b57cec5SDimitry Andric DieOffset = *FormValue.getAsUnsignedConstant(); 1370b57cec5SDimitry Andric break; 1380b57cec5SDimitry Andric case dwarf::DW_ATOM_die_tag: 1390b57cec5SDimitry Andric DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); 1400b57cec5SDimitry Andric break; 1410b57cec5SDimitry Andric default: 1420b57cec5SDimitry Andric break; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric return {DieOffset, DieTag}; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const { 1490b57cec5SDimitry Andric DictScope HeaderScope(W, "Header"); 1500b57cec5SDimitry Andric W.printHex("Magic", Magic); 1510b57cec5SDimitry Andric W.printHex("Version", Version); 1520b57cec5SDimitry Andric W.printHex("Hash function", HashFunction); 1530b57cec5SDimitry Andric W.printNumber("Bucket count", BucketCount); 1540b57cec5SDimitry Andric W.printNumber("Hashes count", HashCount); 1550b57cec5SDimitry Andric W.printNumber("HeaderData length", HeaderDataLength); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 158bdd1243dSDimitry Andric std::optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset( 159bdd1243dSDimitry Andric std::optional<DWARFFormValue> Value) const { 1600b57cec5SDimitry Andric if (!Value) 161bdd1243dSDimitry Andric return std::nullopt; 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric switch (Value->getForm()) { 1640b57cec5SDimitry Andric case dwarf::DW_FORM_ref1: 1650b57cec5SDimitry Andric case dwarf::DW_FORM_ref2: 1660b57cec5SDimitry Andric case dwarf::DW_FORM_ref4: 1670b57cec5SDimitry Andric case dwarf::DW_FORM_ref8: 1680b57cec5SDimitry Andric case dwarf::DW_FORM_ref_udata: 1690b57cec5SDimitry Andric return Value->getRawUValue() + DIEOffsetBase; 1700b57cec5SDimitry Andric default: 1710b57cec5SDimitry Andric return Value->getAsSectionOffset(); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric bool AppleAcceleratorTable::dumpName(ScopedPrinter &W, 1760b57cec5SDimitry Andric SmallVectorImpl<DWARFFormValue> &AtomForms, 1778bcb0991SDimitry Andric uint64_t *DataOffset) const { 1788bcb0991SDimitry Andric uint64_t NameOffset = *DataOffset; 1790b57cec5SDimitry Andric if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) { 1800b57cec5SDimitry Andric W.printString("Incorrectly terminated list."); 1810b57cec5SDimitry Andric return false; 1820b57cec5SDimitry Andric } 1838bcb0991SDimitry Andric uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset); 1840b57cec5SDimitry Andric if (!StringOffset) 1850b57cec5SDimitry Andric return false; // End of list 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str()); 1888bcb0991SDimitry Andric W.startLine() << format("String: 0x%08" PRIx64, StringOffset); 1890b57cec5SDimitry Andric W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n"; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric unsigned NumData = AccelSection.getU32(DataOffset); 1920b57cec5SDimitry Andric for (unsigned Data = 0; Data < NumData; ++Data) { 1930b57cec5SDimitry Andric ListScope DataScope(W, ("Data " + Twine(Data)).str()); 1940b57cec5SDimitry Andric unsigned i = 0; 1950b57cec5SDimitry Andric for (auto &Atom : AtomForms) { 1960b57cec5SDimitry Andric W.startLine() << format("Atom[%d]: ", i); 1970b57cec5SDimitry Andric if (Atom.extractValue(AccelSection, DataOffset, FormParams)) { 1980b57cec5SDimitry Andric Atom.dump(W.getOStream()); 199bdd1243dSDimitry Andric if (std::optional<uint64_t> Val = Atom.getAsUnsignedConstant()) { 2000b57cec5SDimitry Andric StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val); 2010b57cec5SDimitry Andric if (!Str.empty()) 2020b57cec5SDimitry Andric W.getOStream() << " (" << Str << ")"; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric } else 2050b57cec5SDimitry Andric W.getOStream() << "Error extracting the value"; 2060b57cec5SDimitry Andric W.getOStream() << "\n"; 2070b57cec5SDimitry Andric i++; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric return true; // more entries follow 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { 2140b57cec5SDimitry Andric if (!IsValid) 2150b57cec5SDimitry Andric return; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric ScopedPrinter W(OS); 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric Hdr.dump(W); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric W.printNumber("DIE offset base", HdrData.DIEOffsetBase); 2220b57cec5SDimitry Andric W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size())); 22306c3fb27SDimitry Andric W.printNumber("Size of each hash data entry", getHashDataEntryLength()); 2240b57cec5SDimitry Andric SmallVector<DWARFFormValue, 3> AtomForms; 2250b57cec5SDimitry Andric { 2260b57cec5SDimitry Andric ListScope AtomsScope(W, "Atoms"); 2270b57cec5SDimitry Andric unsigned i = 0; 2280b57cec5SDimitry Andric for (const auto &Atom : HdrData.Atoms) { 2290b57cec5SDimitry Andric DictScope AtomScope(W, ("Atom " + Twine(i++)).str()); 2300b57cec5SDimitry Andric W.startLine() << "Type: " << formatAtom(Atom.first) << '\n'; 2310b57cec5SDimitry Andric W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n'; 2320b57cec5SDimitry Andric AtomForms.push_back(DWARFFormValue(Atom.second)); 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Now go through the actual tables and dump them. 2378bcb0991SDimitry Andric uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; 2388bcb0991SDimitry Andric uint64_t HashesBase = Offset + Hdr.BucketCount * 4; 2398bcb0991SDimitry Andric uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) { 2420b57cec5SDimitry Andric unsigned Index = AccelSection.getU32(&Offset); 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); 2450b57cec5SDimitry Andric if (Index == UINT32_MAX) { 2460b57cec5SDimitry Andric W.printString("EMPTY"); 2470b57cec5SDimitry Andric continue; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { 2518bcb0991SDimitry Andric uint64_t HashOffset = HashesBase + HashIdx*4; 2528bcb0991SDimitry Andric uint64_t OffsetsOffset = OffsetsBase + HashIdx*4; 2530b57cec5SDimitry Andric uint32_t Hash = AccelSection.getU32(&HashOffset); 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric if (Hash % Hdr.BucketCount != Bucket) 2560b57cec5SDimitry Andric break; 2570b57cec5SDimitry Andric 2588bcb0991SDimitry Andric uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); 2590b57cec5SDimitry Andric ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str()); 2600b57cec5SDimitry Andric if (!AccelSection.isValidOffset(DataOffset)) { 2610b57cec5SDimitry Andric W.printString("Invalid section offset"); 2620b57cec5SDimitry Andric continue; 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric while (dumpName(W, AtomForms, &DataOffset)) 2650b57cec5SDimitry Andric /*empty*/; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 27006c3fb27SDimitry Andric AppleAcceleratorTable::Entry::Entry(const AppleAcceleratorTable &Table) 27106c3fb27SDimitry Andric : Table(Table) { 27206c3fb27SDimitry Andric Values.reserve(Table.HdrData.Atoms.size()); 27306c3fb27SDimitry Andric for (const auto &Atom : Table.HdrData.Atoms) 2740b57cec5SDimitry Andric Values.push_back(DWARFFormValue(Atom.second)); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 27706c3fb27SDimitry Andric void AppleAcceleratorTable::Entry::extract(uint64_t *Offset) { 27806c3fb27SDimitry Andric for (auto &FormValue : Values) 27906c3fb27SDimitry Andric FormValue.extractValue(Table.AccelSection, Offset, Table.FormParams); 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 282bdd1243dSDimitry Andric std::optional<DWARFFormValue> 28306c3fb27SDimitry Andric AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType AtomToFind) const { 28406c3fb27SDimitry Andric for (auto [Atom, FormValue] : zip_equal(Table.HdrData.Atoms, Values)) 28506c3fb27SDimitry Andric if (Atom.first == AtomToFind) 28606c3fb27SDimitry Andric return FormValue; 287bdd1243dSDimitry Andric return std::nullopt; 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 290bdd1243dSDimitry Andric std::optional<uint64_t> 291bdd1243dSDimitry Andric AppleAcceleratorTable::Entry::getDIESectionOffset() const { 29206c3fb27SDimitry Andric return Table.HdrData.extractOffset(lookup(dwarf::DW_ATOM_die_offset)); 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 295bdd1243dSDimitry Andric std::optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const { 29606c3fb27SDimitry Andric return Table.HdrData.extractOffset(lookup(dwarf::DW_ATOM_cu_offset)); 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric 299bdd1243dSDimitry Andric std::optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const { 300bdd1243dSDimitry Andric std::optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag); 3010b57cec5SDimitry Andric if (!Tag) 302bdd1243dSDimitry Andric return std::nullopt; 303bdd1243dSDimitry Andric if (std::optional<uint64_t> Value = Tag->getAsUnsignedConstant()) 3040b57cec5SDimitry Andric return dwarf::Tag(*Value); 305bdd1243dSDimitry Andric return std::nullopt; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 30806c3fb27SDimitry Andric AppleAcceleratorTable::SameNameIterator::SameNameIterator( 30906c3fb27SDimitry Andric const AppleAcceleratorTable &AccelTable, uint64_t DataOffset) 31006c3fb27SDimitry Andric : Current(AccelTable), Offset(DataOffset) {} 31106c3fb27SDimitry Andric 31206c3fb27SDimitry Andric void AppleAcceleratorTable::Iterator::prepareNextEntryOrEnd() { 31306c3fb27SDimitry Andric if (NumEntriesToCome == 0) 31406c3fb27SDimitry Andric prepareNextStringOrEnd(); 31506c3fb27SDimitry Andric if (isEnd()) 3160b57cec5SDimitry Andric return; 31706c3fb27SDimitry Andric uint64_t OffsetCopy = Offset; 31806c3fb27SDimitry Andric Current.BaseEntry.extract(&OffsetCopy); 31906c3fb27SDimitry Andric NumEntriesToCome--; 32006c3fb27SDimitry Andric Offset += getTable().getHashDataEntryLength(); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 32306c3fb27SDimitry Andric void AppleAcceleratorTable::Iterator::prepareNextStringOrEnd() { 32406c3fb27SDimitry Andric std::optional<uint32_t> StrOffset = getTable().readStringOffsetAt(Offset); 32506c3fb27SDimitry Andric if (!StrOffset) 32606c3fb27SDimitry Andric return setToEnd(); 32706c3fb27SDimitry Andric 32806c3fb27SDimitry Andric // A zero denotes the end of the collision list. Read the next string 32906c3fb27SDimitry Andric // again. 33006c3fb27SDimitry Andric if (*StrOffset == 0) 33106c3fb27SDimitry Andric return prepareNextStringOrEnd(); 33206c3fb27SDimitry Andric Current.StrOffset = *StrOffset; 33306c3fb27SDimitry Andric 33406c3fb27SDimitry Andric std::optional<uint32_t> MaybeNumEntries = getTable().readU32FromAccel(Offset); 33506c3fb27SDimitry Andric if (!MaybeNumEntries || *MaybeNumEntries == 0) 33606c3fb27SDimitry Andric return setToEnd(); 33706c3fb27SDimitry Andric NumEntriesToCome = *MaybeNumEntries; 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 34006c3fb27SDimitry Andric AppleAcceleratorTable::Iterator::Iterator(const AppleAcceleratorTable &Table, 34106c3fb27SDimitry Andric bool SetEnd) 34206c3fb27SDimitry Andric : Current(Table), Offset(Table.getEntriesBase()), NumEntriesToCome(0) { 34306c3fb27SDimitry Andric if (SetEnd) 34406c3fb27SDimitry Andric setToEnd(); 34506c3fb27SDimitry Andric else 34606c3fb27SDimitry Andric prepareNextEntryOrEnd(); 34706c3fb27SDimitry Andric } 34806c3fb27SDimitry Andric 34906c3fb27SDimitry Andric iterator_range<AppleAcceleratorTable::SameNameIterator> 3500b57cec5SDimitry Andric AppleAcceleratorTable::equal_range(StringRef Key) const { 35106c3fb27SDimitry Andric const auto EmptyRange = 35206c3fb27SDimitry Andric make_range(SameNameIterator(*this, 0), SameNameIterator(*this, 0)); 3530b57cec5SDimitry Andric if (!IsValid) 35406c3fb27SDimitry Andric return EmptyRange; 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric // Find the bucket. 35706c3fb27SDimitry Andric uint32_t SearchHash = djbHash(Key); 35806c3fb27SDimitry Andric uint32_t BucketIdx = hashToBucketIdx(SearchHash); 35906c3fb27SDimitry Andric std::optional<uint32_t> HashIdx = idxOfHashInBucket(SearchHash, BucketIdx); 36006c3fb27SDimitry Andric if (!HashIdx) 36106c3fb27SDimitry Andric return EmptyRange; 3620b57cec5SDimitry Andric 36306c3fb27SDimitry Andric std::optional<uint64_t> MaybeDataOffset = readIthOffset(*HashIdx); 36406c3fb27SDimitry Andric if (!MaybeDataOffset) 36506c3fb27SDimitry Andric return EmptyRange; 3660b57cec5SDimitry Andric 36706c3fb27SDimitry Andric uint64_t DataOffset = *MaybeDataOffset; 36806c3fb27SDimitry Andric if (DataOffset >= AccelSection.size()) 36906c3fb27SDimitry Andric return EmptyRange; 3700b57cec5SDimitry Andric 37106c3fb27SDimitry Andric std::optional<uint32_t> StrOffset = readStringOffsetAt(DataOffset); 37206c3fb27SDimitry Andric // Valid input and still have strings in this hash. 37306c3fb27SDimitry Andric while (StrOffset && *StrOffset) { 37406c3fb27SDimitry Andric std::optional<StringRef> MaybeStr = readStringFromStrSection(*StrOffset); 37506c3fb27SDimitry Andric std::optional<uint32_t> NumEntries = this->readU32FromAccel(DataOffset); 37606c3fb27SDimitry Andric if (!MaybeStr || !NumEntries) 37706c3fb27SDimitry Andric return EmptyRange; 37806c3fb27SDimitry Andric uint64_t EndOffset = DataOffset + *NumEntries * getHashDataEntryLength(); 37906c3fb27SDimitry Andric if (Key == *MaybeStr) 38006c3fb27SDimitry Andric return make_range({*this, DataOffset}, 38106c3fb27SDimitry Andric SameNameIterator{*this, EndOffset}); 38206c3fb27SDimitry Andric DataOffset = EndOffset; 38306c3fb27SDimitry Andric StrOffset = readStringOffsetAt(DataOffset); 3840b57cec5SDimitry Andric } 38506c3fb27SDimitry Andric 38606c3fb27SDimitry Andric return EmptyRange; 38706c3fb27SDimitry Andric } 38806c3fb27SDimitry Andric 38906c3fb27SDimitry Andric std::optional<uint32_t> 39006c3fb27SDimitry Andric AppleAcceleratorTable::idxOfHashInBucket(uint32_t HashToFind, 39106c3fb27SDimitry Andric uint32_t BucketIdx) const { 39206c3fb27SDimitry Andric std::optional<uint32_t> HashStartIdx = readIthBucket(BucketIdx); 39306c3fb27SDimitry Andric if (!HashStartIdx) 39406c3fb27SDimitry Andric return std::nullopt; 39506c3fb27SDimitry Andric 39606c3fb27SDimitry Andric for (uint32_t HashIdx = *HashStartIdx; HashIdx < getNumHashes(); HashIdx++) { 39706c3fb27SDimitry Andric std::optional<uint32_t> MaybeHash = readIthHash(HashIdx); 39806c3fb27SDimitry Andric if (!MaybeHash || !wouldHashBeInBucket(*MaybeHash, BucketIdx)) 39906c3fb27SDimitry Andric break; 40006c3fb27SDimitry Andric if (*MaybeHash == HashToFind) 40106c3fb27SDimitry Andric return HashIdx; 40206c3fb27SDimitry Andric } 40306c3fb27SDimitry Andric return std::nullopt; 40406c3fb27SDimitry Andric } 40506c3fb27SDimitry Andric 40606c3fb27SDimitry Andric std::optional<StringRef> AppleAcceleratorTable::readStringFromStrSection( 40706c3fb27SDimitry Andric uint64_t StringSectionOffset) const { 40806c3fb27SDimitry Andric Error E = Error::success(); 40906c3fb27SDimitry Andric StringRef Str = StringSection.getCStrRef(&StringSectionOffset, &E); 41006c3fb27SDimitry Andric if (E) { 41106c3fb27SDimitry Andric consumeError(std::move(E)); 41206c3fb27SDimitry Andric return std::nullopt; 41306c3fb27SDimitry Andric } 41406c3fb27SDimitry Andric return Str; 41506c3fb27SDimitry Andric } 41606c3fb27SDimitry Andric 41706c3fb27SDimitry Andric std::optional<uint32_t> 41806c3fb27SDimitry Andric AppleAcceleratorTable::readU32FromAccel(uint64_t &Offset, 41906c3fb27SDimitry Andric bool UseRelocation) const { 42006c3fb27SDimitry Andric Error E = Error::success(); 42106c3fb27SDimitry Andric uint32_t Data = UseRelocation 42206c3fb27SDimitry Andric ? AccelSection.getRelocatedValue(4, &Offset, nullptr, &E) 42306c3fb27SDimitry Andric : AccelSection.getU32(&Offset, &E); 42406c3fb27SDimitry Andric if (E) { 42506c3fb27SDimitry Andric consumeError(std::move(E)); 42606c3fb27SDimitry Andric return std::nullopt; 42706c3fb27SDimitry Andric } 42806c3fb27SDimitry Andric return Data; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric void DWARFDebugNames::Header::dump(ScopedPrinter &W) const { 4320b57cec5SDimitry Andric DictScope HeaderScope(W, "Header"); 4330b57cec5SDimitry Andric W.printHex("Length", UnitLength); 4345ffd83dbSDimitry Andric W.printString("Format", dwarf::FormatString(Format)); 4350b57cec5SDimitry Andric W.printNumber("Version", Version); 4360b57cec5SDimitry Andric W.printNumber("CU count", CompUnitCount); 4370b57cec5SDimitry Andric W.printNumber("Local TU count", LocalTypeUnitCount); 4380b57cec5SDimitry Andric W.printNumber("Foreign TU count", ForeignTypeUnitCount); 4390b57cec5SDimitry Andric W.printNumber("Bucket count", BucketCount); 4400b57cec5SDimitry Andric W.printNumber("Name count", NameCount); 4410b57cec5SDimitry Andric W.printHex("Abbreviations table size", AbbrevTableSize); 4420b57cec5SDimitry Andric W.startLine() << "Augmentation: '" << AugmentationString << "'\n"; 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, 4468bcb0991SDimitry Andric uint64_t *Offset) { 4475ffd83dbSDimitry Andric auto HeaderError = [Offset = *Offset](Error E) { 4480b57cec5SDimitry Andric return createStringError(errc::illegal_byte_sequence, 4495ffd83dbSDimitry Andric "parsing .debug_names header at 0x%" PRIx64 ": %s", 4505ffd83dbSDimitry Andric Offset, toString(std::move(E)).c_str()); 4515ffd83dbSDimitry Andric }; 4520b57cec5SDimitry Andric 4535ffd83dbSDimitry Andric DataExtractor::Cursor C(*Offset); 4545ffd83dbSDimitry Andric std::tie(UnitLength, Format) = AS.getInitialLength(C); 4550b57cec5SDimitry Andric 4565ffd83dbSDimitry Andric Version = AS.getU16(C); 4575ffd83dbSDimitry Andric AS.skip(C, 2); // padding 4585ffd83dbSDimitry Andric CompUnitCount = AS.getU32(C); 4595ffd83dbSDimitry Andric LocalTypeUnitCount = AS.getU32(C); 4605ffd83dbSDimitry Andric ForeignTypeUnitCount = AS.getU32(C); 4615ffd83dbSDimitry Andric BucketCount = AS.getU32(C); 4625ffd83dbSDimitry Andric NameCount = AS.getU32(C); 4635ffd83dbSDimitry Andric AbbrevTableSize = AS.getU32(C); 4645ffd83dbSDimitry Andric AugmentationStringSize = alignTo(AS.getU32(C), 4); 4655ffd83dbSDimitry Andric 4665ffd83dbSDimitry Andric if (!C) 4675ffd83dbSDimitry Andric return HeaderError(C.takeError()); 4685ffd83dbSDimitry Andric 4695ffd83dbSDimitry Andric if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize)) 4705ffd83dbSDimitry Andric return HeaderError(createStringError(errc::illegal_byte_sequence, 4715ffd83dbSDimitry Andric "cannot read header augmentation")); 4720b57cec5SDimitry Andric AugmentationString.resize(AugmentationStringSize); 4735ffd83dbSDimitry Andric AS.getU8(C, reinterpret_cast<uint8_t *>(AugmentationString.data()), 4740b57cec5SDimitry Andric AugmentationStringSize); 4755ffd83dbSDimitry Andric *Offset = C.tell(); 4765ffd83dbSDimitry Andric return C.takeError(); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { 4800b57cec5SDimitry Andric DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str()); 4810b57cec5SDimitry Andric W.startLine() << formatv("Tag: {0}\n", Tag); 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric for (const auto &Attr : Attributes) 4840b57cec5SDimitry Andric W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() { 4880b57cec5SDimitry Andric return {dwarf::Index(0), dwarf::Form(0)}; 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) { 4920b57cec5SDimitry Andric return AE == sentinelAttrEnc(); 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric static DWARFDebugNames::Abbrev sentinelAbbrev() { 496*0fca6ea1SDimitry Andric return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), 0, {}); 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) { 5000b57cec5SDimitry Andric return Abbr.Code == 0; 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() { 5040b57cec5SDimitry Andric return sentinelAbbrev(); 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() { 508*0fca6ea1SDimitry Andric return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), 0, {}); 5090b57cec5SDimitry Andric } 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric Expected<DWARFDebugNames::AttributeEncoding> 5128bcb0991SDimitry Andric DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) { 513*0fca6ea1SDimitry Andric if (*Offset >= Offsets.EntriesBase) { 5140b57cec5SDimitry Andric return createStringError(errc::illegal_byte_sequence, 5150b57cec5SDimitry Andric "Incorrectly terminated abbreviation table."); 5160b57cec5SDimitry Andric } 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric uint32_t Index = Section.AccelSection.getULEB128(Offset); 5190b57cec5SDimitry Andric uint32_t Form = Section.AccelSection.getULEB128(Offset); 5200b57cec5SDimitry Andric return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form)); 5210b57cec5SDimitry Andric } 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric Expected<std::vector<DWARFDebugNames::AttributeEncoding>> 5248bcb0991SDimitry Andric DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) { 5250b57cec5SDimitry Andric std::vector<AttributeEncoding> Result; 5260b57cec5SDimitry Andric for (;;) { 5270b57cec5SDimitry Andric auto AttrEncOr = extractAttributeEncoding(Offset); 5280b57cec5SDimitry Andric if (!AttrEncOr) 5290b57cec5SDimitry Andric return AttrEncOr.takeError(); 5300b57cec5SDimitry Andric if (isSentinel(*AttrEncOr)) 5310b57cec5SDimitry Andric return std::move(Result); 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric Result.emplace_back(*AttrEncOr); 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric } 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric Expected<DWARFDebugNames::Abbrev> 5388bcb0991SDimitry Andric DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) { 539*0fca6ea1SDimitry Andric if (*Offset >= Offsets.EntriesBase) { 5400b57cec5SDimitry Andric return createStringError(errc::illegal_byte_sequence, 5410b57cec5SDimitry Andric "Incorrectly terminated abbreviation table."); 5420b57cec5SDimitry Andric } 543*0fca6ea1SDimitry Andric const uint64_t AbbrevOffset = *Offset; 5440b57cec5SDimitry Andric uint32_t Code = Section.AccelSection.getULEB128(Offset); 5450b57cec5SDimitry Andric if (Code == 0) 5460b57cec5SDimitry Andric return sentinelAbbrev(); 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric uint32_t Tag = Section.AccelSection.getULEB128(Offset); 5490b57cec5SDimitry Andric auto AttrEncOr = extractAttributeEncodings(Offset); 5500b57cec5SDimitry Andric if (!AttrEncOr) 5510b57cec5SDimitry Andric return AttrEncOr.takeError(); 552*0fca6ea1SDimitry Andric return Abbrev(Code, dwarf::Tag(Tag), AbbrevOffset, std::move(*AttrEncOr)); 553*0fca6ea1SDimitry Andric } 554*0fca6ea1SDimitry Andric 555*0fca6ea1SDimitry Andric DWARFDebugNames::DWARFDebugNamesOffsets 556*0fca6ea1SDimitry Andric dwarf::findDebugNamesOffsets(uint64_t EndOfHeaderOffset, 557*0fca6ea1SDimitry Andric const DWARFDebugNames::Header &Hdr) { 558*0fca6ea1SDimitry Andric uint64_t DwarfSize = getDwarfOffsetByteSize(Hdr.Format); 559*0fca6ea1SDimitry Andric DWARFDebugNames::DWARFDebugNamesOffsets Ret; 560*0fca6ea1SDimitry Andric Ret.CUsBase = EndOfHeaderOffset; 561*0fca6ea1SDimitry Andric Ret.BucketsBase = Ret.CUsBase + Hdr.CompUnitCount * DwarfSize + 562*0fca6ea1SDimitry Andric Hdr.LocalTypeUnitCount * DwarfSize + 563*0fca6ea1SDimitry Andric Hdr.ForeignTypeUnitCount * 8; 564*0fca6ea1SDimitry Andric Ret.HashesBase = Ret.BucketsBase + Hdr.BucketCount * 4; 565*0fca6ea1SDimitry Andric Ret.StringOffsetsBase = 566*0fca6ea1SDimitry Andric Ret.HashesBase + (Hdr.BucketCount > 0 ? Hdr.NameCount * 4 : 0); 567*0fca6ea1SDimitry Andric Ret.EntryOffsetsBase = Ret.StringOffsetsBase + Hdr.NameCount * DwarfSize; 568*0fca6ea1SDimitry Andric Ret.EntriesBase = 569*0fca6ea1SDimitry Andric Ret.EntryOffsetsBase + Hdr.NameCount * DwarfSize + Hdr.AbbrevTableSize; 570*0fca6ea1SDimitry Andric return Ret; 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric Error DWARFDebugNames::NameIndex::extract() { 5740b57cec5SDimitry Andric const DWARFDataExtractor &AS = Section.AccelSection; 575*0fca6ea1SDimitry Andric uint64_t EndOfHeaderOffset = Base; 576*0fca6ea1SDimitry Andric if (Error E = Hdr.extract(AS, &EndOfHeaderOffset)) 5770b57cec5SDimitry Andric return E; 5780b57cec5SDimitry Andric 5795ffd83dbSDimitry Andric const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 580*0fca6ea1SDimitry Andric Offsets = dwarf::findDebugNamesOffsets(EndOfHeaderOffset, Hdr); 581*0fca6ea1SDimitry Andric 582*0fca6ea1SDimitry Andric uint64_t Offset = 583*0fca6ea1SDimitry Andric Offsets.EntryOffsetsBase + (Hdr.NameCount * SectionOffsetSize); 5840b57cec5SDimitry Andric 5850b57cec5SDimitry Andric if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize)) 5860b57cec5SDimitry Andric return createStringError(errc::illegal_byte_sequence, 5870b57cec5SDimitry Andric "Section too small: cannot read abbreviations."); 5880b57cec5SDimitry Andric 589*0fca6ea1SDimitry Andric Offsets.EntriesBase = Offset + Hdr.AbbrevTableSize; 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric for (;;) { 5920b57cec5SDimitry Andric auto AbbrevOr = extractAbbrev(&Offset); 5930b57cec5SDimitry Andric if (!AbbrevOr) 5940b57cec5SDimitry Andric return AbbrevOr.takeError(); 5950b57cec5SDimitry Andric if (isSentinel(*AbbrevOr)) 5960b57cec5SDimitry Andric return Error::success(); 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric if (!Abbrevs.insert(std::move(*AbbrevOr)).second) 5990b57cec5SDimitry Andric return createStringError(errc::invalid_argument, 6000b57cec5SDimitry Andric "Duplicate abbreviation code."); 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr) 6050b57cec5SDimitry Andric : NameIdx(&NameIdx), Abbr(&Abbr) { 6060b57cec5SDimitry Andric // This merely creates form values. It is up to the caller 6070b57cec5SDimitry Andric // (NameIndex::getEntry) to populate them. 6080b57cec5SDimitry Andric Values.reserve(Abbr.Attributes.size()); 6090b57cec5SDimitry Andric for (const auto &Attr : Abbr.Attributes) 6100b57cec5SDimitry Andric Values.emplace_back(Attr.Form); 6110b57cec5SDimitry Andric } 6120b57cec5SDimitry Andric 613bdd1243dSDimitry Andric std::optional<DWARFFormValue> 6140b57cec5SDimitry Andric DWARFDebugNames::Entry::lookup(dwarf::Index Index) const { 6150b57cec5SDimitry Andric assert(Abbr->Attributes.size() == Values.size()); 616480093f4SDimitry Andric for (auto Tuple : zip_first(Abbr->Attributes, Values)) { 6170b57cec5SDimitry Andric if (std::get<0>(Tuple).Index == Index) 6180b57cec5SDimitry Andric return std::get<1>(Tuple); 6190b57cec5SDimitry Andric } 620bdd1243dSDimitry Andric return std::nullopt; 6210b57cec5SDimitry Andric } 6220b57cec5SDimitry Andric 623*0fca6ea1SDimitry Andric bool DWARFDebugNames::Entry::hasParentInformation() const { 624*0fca6ea1SDimitry Andric return lookup(dwarf::DW_IDX_parent).has_value(); 625*0fca6ea1SDimitry Andric } 626*0fca6ea1SDimitry Andric 627bdd1243dSDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const { 628bdd1243dSDimitry Andric if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset)) 6290b57cec5SDimitry Andric return Off->getAsReferenceUVal(); 630bdd1243dSDimitry Andric return std::nullopt; 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric 633*0fca6ea1SDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getRelatedCUIndex() const { 634*0fca6ea1SDimitry Andric // Return the DW_IDX_compile_unit attribute value if it is specified. 635bdd1243dSDimitry Andric if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit)) 6360b57cec5SDimitry Andric return Off->getAsUnsignedConstant(); 6370b57cec5SDimitry Andric // In a per-CU index, the entries without a DW_IDX_compile_unit attribute 638*0fca6ea1SDimitry Andric // implicitly refer to the single CU. 6390b57cec5SDimitry Andric if (NameIdx->getCUCount() == 1) 6400b57cec5SDimitry Andric return 0; 641bdd1243dSDimitry Andric return std::nullopt; 6420b57cec5SDimitry Andric } 6430b57cec5SDimitry Andric 644*0fca6ea1SDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const { 645*0fca6ea1SDimitry Andric // Return the DW_IDX_compile_unit attribute value but only if we don't have a 646*0fca6ea1SDimitry Andric // DW_IDX_type_unit attribute. Use Entry::getRelatedCUIndex() to get the 647*0fca6ea1SDimitry Andric // associated CU index if this behaviour is not desired. 648*0fca6ea1SDimitry Andric if (lookup(dwarf::DW_IDX_type_unit).has_value()) 649*0fca6ea1SDimitry Andric return std::nullopt; 650*0fca6ea1SDimitry Andric return getRelatedCUIndex(); 651*0fca6ea1SDimitry Andric } 652*0fca6ea1SDimitry Andric 653bdd1243dSDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const { 654bdd1243dSDimitry Andric std::optional<uint64_t> Index = getCUIndex(); 6550b57cec5SDimitry Andric if (!Index || *Index >= NameIdx->getCUCount()) 656bdd1243dSDimitry Andric return std::nullopt; 6570b57cec5SDimitry Andric return NameIdx->getCUOffset(*Index); 6580b57cec5SDimitry Andric } 6590b57cec5SDimitry Andric 660*0fca6ea1SDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getRelatedCUOffset() const { 661*0fca6ea1SDimitry Andric std::optional<uint64_t> Index = getRelatedCUIndex(); 662*0fca6ea1SDimitry Andric if (!Index || *Index >= NameIdx->getCUCount()) 663*0fca6ea1SDimitry Andric return std::nullopt; 664*0fca6ea1SDimitry Andric return NameIdx->getCUOffset(*Index); 665*0fca6ea1SDimitry Andric } 666*0fca6ea1SDimitry Andric 6675f757f3fSDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const { 6685f757f3fSDimitry Andric std::optional<uint64_t> Index = getLocalTUIndex(); 6695f757f3fSDimitry Andric if (!Index || *Index >= NameIdx->getLocalTUCount()) 6705f757f3fSDimitry Andric return std::nullopt; 6715f757f3fSDimitry Andric return NameIdx->getLocalTUOffset(*Index); 6725f757f3fSDimitry Andric } 6735f757f3fSDimitry Andric 674*0fca6ea1SDimitry Andric std::optional<uint64_t> 675*0fca6ea1SDimitry Andric DWARFDebugNames::Entry::getForeignTUTypeSignature() const { 676*0fca6ea1SDimitry Andric std::optional<uint64_t> Index = getLocalTUIndex(); 677*0fca6ea1SDimitry Andric const uint32_t NumLocalTUs = NameIdx->getLocalTUCount(); 678*0fca6ea1SDimitry Andric if (!Index || *Index < NumLocalTUs) 679*0fca6ea1SDimitry Andric return std::nullopt; // Invalid TU index or TU index is for a local TU 680*0fca6ea1SDimitry Andric // The foreign TU index is the TU index minus the number of local TUs. 681*0fca6ea1SDimitry Andric const uint64_t ForeignTUIndex = *Index - NumLocalTUs; 682*0fca6ea1SDimitry Andric if (ForeignTUIndex >= NameIdx->getForeignTUCount()) 683*0fca6ea1SDimitry Andric return std::nullopt; // Invalid foreign TU index. 684*0fca6ea1SDimitry Andric return NameIdx->getForeignTUSignature(ForeignTUIndex); 685*0fca6ea1SDimitry Andric } 686*0fca6ea1SDimitry Andric 6875f757f3fSDimitry Andric std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const { 6885f757f3fSDimitry Andric if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit)) 6895f757f3fSDimitry Andric return Off->getAsUnsignedConstant(); 6905f757f3fSDimitry Andric return std::nullopt; 6915f757f3fSDimitry Andric } 6925f757f3fSDimitry Andric 693*0fca6ea1SDimitry Andric Expected<std::optional<DWARFDebugNames::Entry>> 694*0fca6ea1SDimitry Andric DWARFDebugNames::Entry::getParentDIEEntry() const { 695*0fca6ea1SDimitry Andric // The offset of the accelerator table entry for the parent. 696*0fca6ea1SDimitry Andric std::optional<DWARFFormValue> ParentEntryOff = lookup(dwarf::DW_IDX_parent); 697*0fca6ea1SDimitry Andric assert(ParentEntryOff.has_value() && "hasParentInformation() must be called"); 698*0fca6ea1SDimitry Andric 699*0fca6ea1SDimitry Andric if (ParentEntryOff->getForm() == dwarf::Form::DW_FORM_flag_present) 700*0fca6ea1SDimitry Andric return std::nullopt; 701*0fca6ea1SDimitry Andric return NameIdx->getEntryAtRelativeOffset(ParentEntryOff->getRawUValue()); 702*0fca6ea1SDimitry Andric } 703*0fca6ea1SDimitry Andric 704*0fca6ea1SDimitry Andric void DWARFDebugNames::Entry::dumpParentIdx( 705*0fca6ea1SDimitry Andric ScopedPrinter &W, const DWARFFormValue &FormValue) const { 706*0fca6ea1SDimitry Andric Expected<std::optional<Entry>> ParentEntry = getParentDIEEntry(); 707*0fca6ea1SDimitry Andric if (!ParentEntry) { 708*0fca6ea1SDimitry Andric W.getOStream() << "<invalid offset data>"; 709*0fca6ea1SDimitry Andric consumeError(ParentEntry.takeError()); 710*0fca6ea1SDimitry Andric return; 711*0fca6ea1SDimitry Andric } 712*0fca6ea1SDimitry Andric 713*0fca6ea1SDimitry Andric if (!ParentEntry->has_value()) { 714*0fca6ea1SDimitry Andric W.getOStream() << "<parent not indexed>"; 715*0fca6ea1SDimitry Andric return; 716*0fca6ea1SDimitry Andric } 717*0fca6ea1SDimitry Andric 718*0fca6ea1SDimitry Andric auto AbsoluteOffset = NameIdx->Offsets.EntriesBase + FormValue.getRawUValue(); 719*0fca6ea1SDimitry Andric W.getOStream() << "Entry @ 0x" + Twine::utohexstr(AbsoluteOffset); 720*0fca6ea1SDimitry Andric } 721*0fca6ea1SDimitry Andric 7220b57cec5SDimitry Andric void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { 7235f757f3fSDimitry Andric W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code); 7240b57cec5SDimitry Andric W.startLine() << formatv("Tag: {0}\n", Abbr->Tag); 7250b57cec5SDimitry Andric assert(Abbr->Attributes.size() == Values.size()); 726480093f4SDimitry Andric for (auto Tuple : zip_first(Abbr->Attributes, Values)) { 727*0fca6ea1SDimitry Andric auto Index = std::get<0>(Tuple).Index; 728*0fca6ea1SDimitry Andric W.startLine() << formatv("{0}: ", Index); 729*0fca6ea1SDimitry Andric 730*0fca6ea1SDimitry Andric auto FormValue = std::get<1>(Tuple); 731*0fca6ea1SDimitry Andric if (Index == dwarf::Index::DW_IDX_parent) 732*0fca6ea1SDimitry Andric dumpParentIdx(W, FormValue); 733*0fca6ea1SDimitry Andric else 734*0fca6ea1SDimitry Andric FormValue.dump(W.getOStream()); 7350b57cec5SDimitry Andric W.getOStream() << '\n'; 7360b57cec5SDimitry Andric } 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric char DWARFDebugNames::SentinelError::ID; 7400b57cec5SDimitry Andric std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const { 7410b57cec5SDimitry Andric return inconvertibleErrorCode(); 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric 7448bcb0991SDimitry Andric uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const { 7450b57cec5SDimitry Andric assert(CU < Hdr.CompUnitCount); 7465ffd83dbSDimitry Andric const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 747*0fca6ea1SDimitry Andric uint64_t Offset = Offsets.CUsBase + SectionOffsetSize * CU; 7485ffd83dbSDimitry Andric return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric 7518bcb0991SDimitry Andric uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const { 7520b57cec5SDimitry Andric assert(TU < Hdr.LocalTypeUnitCount); 7535ffd83dbSDimitry Andric const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 754*0fca6ea1SDimitry Andric uint64_t Offset = 755*0fca6ea1SDimitry Andric Offsets.CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU); 7565ffd83dbSDimitry Andric return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); 7570b57cec5SDimitry Andric } 7580b57cec5SDimitry Andric 7590b57cec5SDimitry Andric uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const { 7600b57cec5SDimitry Andric assert(TU < Hdr.ForeignTypeUnitCount); 7615ffd83dbSDimitry Andric const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 7628bcb0991SDimitry Andric uint64_t Offset = 763*0fca6ea1SDimitry Andric Offsets.CUsBase + 7645ffd83dbSDimitry Andric SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU; 7650b57cec5SDimitry Andric return Section.AccelSection.getU64(&Offset); 7660b57cec5SDimitry Andric } 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric Expected<DWARFDebugNames::Entry> 7698bcb0991SDimitry Andric DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const { 7700b57cec5SDimitry Andric const DWARFDataExtractor &AS = Section.AccelSection; 7710b57cec5SDimitry Andric if (!AS.isValidOffset(*Offset)) 7720b57cec5SDimitry Andric return createStringError(errc::illegal_byte_sequence, 7730b57cec5SDimitry Andric "Incorrectly terminated entry list."); 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric uint32_t AbbrevCode = AS.getULEB128(Offset); 7760b57cec5SDimitry Andric if (AbbrevCode == 0) 7770b57cec5SDimitry Andric return make_error<SentinelError>(); 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric const auto AbbrevIt = Abbrevs.find_as(AbbrevCode); 7800b57cec5SDimitry Andric if (AbbrevIt == Abbrevs.end()) 7810b57cec5SDimitry Andric return createStringError(errc::invalid_argument, "Invalid abbreviation."); 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric Entry E(*this, *AbbrevIt); 7840b57cec5SDimitry Andric 7855ffd83dbSDimitry Andric dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format}; 7860b57cec5SDimitry Andric for (auto &Value : E.Values) { 7870b57cec5SDimitry Andric if (!Value.extractValue(AS, Offset, FormParams)) 7880b57cec5SDimitry Andric return createStringError(errc::io_error, 7890b57cec5SDimitry Andric "Error extracting index attribute values."); 7900b57cec5SDimitry Andric } 7910b57cec5SDimitry Andric return std::move(E); 7920b57cec5SDimitry Andric } 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric DWARFDebugNames::NameTableEntry 7950b57cec5SDimitry Andric DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const { 7960b57cec5SDimitry Andric assert(0 < Index && Index <= Hdr.NameCount); 7975ffd83dbSDimitry Andric const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 7985ffd83dbSDimitry Andric uint64_t StringOffsetOffset = 799*0fca6ea1SDimitry Andric Offsets.StringOffsetsBase + SectionOffsetSize * (Index - 1); 8005ffd83dbSDimitry Andric uint64_t EntryOffsetOffset = 801*0fca6ea1SDimitry Andric Offsets.EntryOffsetsBase + SectionOffsetSize * (Index - 1); 8020b57cec5SDimitry Andric const DWARFDataExtractor &AS = Section.AccelSection; 8030b57cec5SDimitry Andric 8045ffd83dbSDimitry Andric uint64_t StringOffset = 8055ffd83dbSDimitry Andric AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset); 8065ffd83dbSDimitry Andric uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize); 807*0fca6ea1SDimitry Andric EntryOffset += Offsets.EntriesBase; 8080b57cec5SDimitry Andric return {Section.StringSection, Index, StringOffset, EntryOffset}; 8090b57cec5SDimitry Andric } 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric uint32_t 8120b57cec5SDimitry Andric DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const { 8130b57cec5SDimitry Andric assert(Bucket < Hdr.BucketCount); 814*0fca6ea1SDimitry Andric uint64_t BucketOffset = Offsets.BucketsBase + 4 * Bucket; 8150b57cec5SDimitry Andric return Section.AccelSection.getU32(&BucketOffset); 8160b57cec5SDimitry Andric } 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const { 8190b57cec5SDimitry Andric assert(0 < Index && Index <= Hdr.NameCount); 820*0fca6ea1SDimitry Andric uint64_t HashOffset = Offsets.HashesBase + 4 * (Index - 1); 8210b57cec5SDimitry Andric return Section.AccelSection.getU32(&HashOffset); 8220b57cec5SDimitry Andric } 8230b57cec5SDimitry Andric 8240b57cec5SDimitry Andric // Returns true if we should continue scanning for entries, false if this is the 8250b57cec5SDimitry Andric // last (sentinel) entry). In case of a parsing error we also return false, as 8260b57cec5SDimitry Andric // it's not possible to recover this entry list (but the other lists may still 8270b57cec5SDimitry Andric // parse OK). 8280b57cec5SDimitry Andric bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W, 8298bcb0991SDimitry Andric uint64_t *Offset) const { 8308bcb0991SDimitry Andric uint64_t EntryId = *Offset; 8310b57cec5SDimitry Andric auto EntryOr = getEntry(Offset); 8320b57cec5SDimitry Andric if (!EntryOr) { 8330b57cec5SDimitry Andric handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {}, 8340b57cec5SDimitry Andric [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); }); 8350b57cec5SDimitry Andric return false; 8360b57cec5SDimitry Andric } 8370b57cec5SDimitry Andric 8380b57cec5SDimitry Andric DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str()); 8390b57cec5SDimitry Andric EntryOr->dump(W); 8400b57cec5SDimitry Andric return true; 8410b57cec5SDimitry Andric } 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W, 8440b57cec5SDimitry Andric const NameTableEntry &NTE, 845bdd1243dSDimitry Andric std::optional<uint32_t> Hash) const { 8460b57cec5SDimitry Andric DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str()); 8470b57cec5SDimitry Andric if (Hash) 8480b57cec5SDimitry Andric W.printHex("Hash", *Hash); 8490b57cec5SDimitry Andric 8508bcb0991SDimitry Andric W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset()); 8510b57cec5SDimitry Andric W.getOStream() << " \"" << NTE.getString() << "\"\n"; 8520b57cec5SDimitry Andric 8538bcb0991SDimitry Andric uint64_t EntryOffset = NTE.getEntryOffset(); 8540b57cec5SDimitry Andric while (dumpEntry(W, &EntryOffset)) 8550b57cec5SDimitry Andric /*empty*/; 8560b57cec5SDimitry Andric } 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const { 8590b57cec5SDimitry Andric ListScope CUScope(W, "Compilation Unit offsets"); 8600b57cec5SDimitry Andric for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU) 8618bcb0991SDimitry Andric W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU)); 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const { 8650b57cec5SDimitry Andric if (Hdr.LocalTypeUnitCount == 0) 8660b57cec5SDimitry Andric return; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric ListScope TUScope(W, "Local Type Unit offsets"); 8690b57cec5SDimitry Andric for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU) 8708bcb0991SDimitry Andric W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU, 8718bcb0991SDimitry Andric getLocalTUOffset(TU)); 8720b57cec5SDimitry Andric } 8730b57cec5SDimitry Andric 8740b57cec5SDimitry Andric void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const { 8750b57cec5SDimitry Andric if (Hdr.ForeignTypeUnitCount == 0) 8760b57cec5SDimitry Andric return; 8770b57cec5SDimitry Andric 8780b57cec5SDimitry Andric ListScope TUScope(W, "Foreign Type Unit signatures"); 8790b57cec5SDimitry Andric for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) { 8800b57cec5SDimitry Andric W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU, 8810b57cec5SDimitry Andric getForeignTUSignature(TU)); 8820b57cec5SDimitry Andric } 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 8850b57cec5SDimitry Andric void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const { 8860b57cec5SDimitry Andric ListScope AbbrevsScope(W, "Abbreviations"); 887*0fca6ea1SDimitry Andric std::vector<const Abbrev *> AbbrevsVect; 888*0fca6ea1SDimitry Andric for (const DWARFDebugNames::Abbrev &Abbr : Abbrevs) 889*0fca6ea1SDimitry Andric AbbrevsVect.push_back(&Abbr); 890*0fca6ea1SDimitry Andric llvm::sort(AbbrevsVect, [](const Abbrev *LHS, const Abbrev *RHS) { 891*0fca6ea1SDimitry Andric return LHS->AbbrevOffset < RHS->AbbrevOffset; 892*0fca6ea1SDimitry Andric }); 893*0fca6ea1SDimitry Andric for (const DWARFDebugNames::Abbrev *Abbr : AbbrevsVect) 894*0fca6ea1SDimitry Andric Abbr->dump(W); 8950b57cec5SDimitry Andric } 8960b57cec5SDimitry Andric 8970b57cec5SDimitry Andric void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W, 8980b57cec5SDimitry Andric uint32_t Bucket) const { 8990b57cec5SDimitry Andric ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); 9000b57cec5SDimitry Andric uint32_t Index = getBucketArrayEntry(Bucket); 9010b57cec5SDimitry Andric if (Index == 0) { 9020b57cec5SDimitry Andric W.printString("EMPTY"); 9030b57cec5SDimitry Andric return; 9040b57cec5SDimitry Andric } 9050b57cec5SDimitry Andric if (Index > Hdr.NameCount) { 9060b57cec5SDimitry Andric W.printString("Name index is invalid"); 9070b57cec5SDimitry Andric return; 9080b57cec5SDimitry Andric } 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric for (; Index <= Hdr.NameCount; ++Index) { 9110b57cec5SDimitry Andric uint32_t Hash = getHashArrayEntry(Index); 9120b57cec5SDimitry Andric if (Hash % Hdr.BucketCount != Bucket) 9130b57cec5SDimitry Andric break; 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric dumpName(W, getNameTableEntry(Index), Hash); 9160b57cec5SDimitry Andric } 9170b57cec5SDimitry Andric } 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const { 9200b57cec5SDimitry Andric DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str()); 9210b57cec5SDimitry Andric Hdr.dump(W); 9220b57cec5SDimitry Andric dumpCUs(W); 9230b57cec5SDimitry Andric dumpLocalTUs(W); 9240b57cec5SDimitry Andric dumpForeignTUs(W); 9250b57cec5SDimitry Andric dumpAbbreviations(W); 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric if (Hdr.BucketCount > 0) { 9280b57cec5SDimitry Andric for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) 9290b57cec5SDimitry Andric dumpBucket(W, Bucket); 9300b57cec5SDimitry Andric return; 9310b57cec5SDimitry Andric } 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric W.startLine() << "Hash table not present\n"; 934349cc55cSDimitry Andric for (const NameTableEntry &NTE : *this) 935bdd1243dSDimitry Andric dumpName(W, NTE, std::nullopt); 9360b57cec5SDimitry Andric } 9370b57cec5SDimitry Andric 9380b57cec5SDimitry Andric Error DWARFDebugNames::extract() { 9398bcb0991SDimitry Andric uint64_t Offset = 0; 9400b57cec5SDimitry Andric while (AccelSection.isValidOffset(Offset)) { 9410b57cec5SDimitry Andric NameIndex Next(*this, Offset); 9420b57cec5SDimitry Andric if (Error E = Next.extract()) 9430b57cec5SDimitry Andric return E; 9440b57cec5SDimitry Andric Offset = Next.getNextUnitOffset(); 9450b57cec5SDimitry Andric NameIndices.push_back(std::move(Next)); 9460b57cec5SDimitry Andric } 9470b57cec5SDimitry Andric return Error::success(); 9480b57cec5SDimitry Andric } 9490b57cec5SDimitry Andric 9500b57cec5SDimitry Andric iterator_range<DWARFDebugNames::ValueIterator> 9510b57cec5SDimitry Andric DWARFDebugNames::NameIndex::equal_range(StringRef Key) const { 9520b57cec5SDimitry Andric return make_range(ValueIterator(*this, Key), ValueIterator()); 9530b57cec5SDimitry Andric } 9540b57cec5SDimitry Andric 9550b57cec5SDimitry Andric LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const { 9560b57cec5SDimitry Andric ScopedPrinter W(OS); 9570b57cec5SDimitry Andric for (const NameIndex &NI : NameIndices) 9580b57cec5SDimitry Andric NI.dump(W); 9590b57cec5SDimitry Andric } 9600b57cec5SDimitry Andric 961bdd1243dSDimitry Andric std::optional<uint64_t> 9620b57cec5SDimitry Andric DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { 9630b57cec5SDimitry Andric const Header &Hdr = CurrentIndex->Hdr; 9640b57cec5SDimitry Andric if (Hdr.BucketCount == 0) { 9650b57cec5SDimitry Andric // No Hash Table, We need to search through all names in the Name Index. 966349cc55cSDimitry Andric for (const NameTableEntry &NTE : *CurrentIndex) { 967*0fca6ea1SDimitry Andric if (NTE.sameNameAs(Key)) 9680b57cec5SDimitry Andric return NTE.getEntryOffset(); 9690b57cec5SDimitry Andric } 970bdd1243dSDimitry Andric return std::nullopt; 9710b57cec5SDimitry Andric } 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric // The Name Index has a Hash Table, so use that to speed up the search. 9740b57cec5SDimitry Andric // Compute the Key Hash, if it has not been done already. 9750b57cec5SDimitry Andric if (!Hash) 9760b57cec5SDimitry Andric Hash = caseFoldingDjbHash(Key); 9770b57cec5SDimitry Andric uint32_t Bucket = *Hash % Hdr.BucketCount; 9780b57cec5SDimitry Andric uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket); 9790b57cec5SDimitry Andric if (Index == 0) 980bdd1243dSDimitry Andric return std::nullopt; // Empty bucket 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric for (; Index <= Hdr.NameCount; ++Index) { 983*0fca6ea1SDimitry Andric uint32_t HashAtIndex = CurrentIndex->getHashArrayEntry(Index); 984*0fca6ea1SDimitry Andric if (HashAtIndex % Hdr.BucketCount != Bucket) 985bdd1243dSDimitry Andric return std::nullopt; // End of bucket 986*0fca6ea1SDimitry Andric // Only compare names if the hashes match. 987*0fca6ea1SDimitry Andric if (HashAtIndex != Hash) 988*0fca6ea1SDimitry Andric continue; 9890b57cec5SDimitry Andric 9900b57cec5SDimitry Andric NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); 991*0fca6ea1SDimitry Andric if (NTE.sameNameAs(Key)) 9920b57cec5SDimitry Andric return NTE.getEntryOffset(); 9930b57cec5SDimitry Andric } 994bdd1243dSDimitry Andric return std::nullopt; 9950b57cec5SDimitry Andric } 9960b57cec5SDimitry Andric 9970b57cec5SDimitry Andric bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() { 9980b57cec5SDimitry Andric auto EntryOr = CurrentIndex->getEntry(&DataOffset); 9990b57cec5SDimitry Andric if (!EntryOr) { 10000b57cec5SDimitry Andric consumeError(EntryOr.takeError()); 10010b57cec5SDimitry Andric return false; 10020b57cec5SDimitry Andric } 10030b57cec5SDimitry Andric CurrentEntry = std::move(*EntryOr); 10040b57cec5SDimitry Andric return true; 10050b57cec5SDimitry Andric } 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric bool DWARFDebugNames::ValueIterator::findInCurrentIndex() { 1008bdd1243dSDimitry Andric std::optional<uint64_t> Offset = findEntryOffsetInCurrentIndex(); 10090b57cec5SDimitry Andric if (!Offset) 10100b57cec5SDimitry Andric return false; 10110b57cec5SDimitry Andric DataOffset = *Offset; 10120b57cec5SDimitry Andric return getEntryAtCurrentOffset(); 10130b57cec5SDimitry Andric } 10140b57cec5SDimitry Andric 10150b57cec5SDimitry Andric void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() { 10160b57cec5SDimitry Andric for (const NameIndex *End = CurrentIndex->Section.NameIndices.end(); 10170b57cec5SDimitry Andric CurrentIndex != End; ++CurrentIndex) { 10180b57cec5SDimitry Andric if (findInCurrentIndex()) 10190b57cec5SDimitry Andric return; 10200b57cec5SDimitry Andric } 10210b57cec5SDimitry Andric setEnd(); 10220b57cec5SDimitry Andric } 10230b57cec5SDimitry Andric 10240b57cec5SDimitry Andric void DWARFDebugNames::ValueIterator::next() { 10250b57cec5SDimitry Andric assert(CurrentIndex && "Incrementing an end() iterator?"); 10260b57cec5SDimitry Andric 10270b57cec5SDimitry Andric // First try the next entry in the current Index. 10280b57cec5SDimitry Andric if (getEntryAtCurrentOffset()) 10290b57cec5SDimitry Andric return; 10300b57cec5SDimitry Andric 10310b57cec5SDimitry Andric // If we're a local iterator or we have reached the last Index, we're done. 10320b57cec5SDimitry Andric if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) { 10330b57cec5SDimitry Andric setEnd(); 10340b57cec5SDimitry Andric return; 10350b57cec5SDimitry Andric } 10360b57cec5SDimitry Andric 10370b57cec5SDimitry Andric // Otherwise, try the next index. 10380b57cec5SDimitry Andric ++CurrentIndex; 10390b57cec5SDimitry Andric searchFromStartOfCurrentIndex(); 10400b57cec5SDimitry Andric } 10410b57cec5SDimitry Andric 10420b57cec5SDimitry Andric DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable, 10430b57cec5SDimitry Andric StringRef Key) 10445ffd83dbSDimitry Andric : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false), 10455ffd83dbSDimitry Andric Key(std::string(Key)) { 10460b57cec5SDimitry Andric searchFromStartOfCurrentIndex(); 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric DWARFDebugNames::ValueIterator::ValueIterator( 10500b57cec5SDimitry Andric const DWARFDebugNames::NameIndex &NI, StringRef Key) 10515ffd83dbSDimitry Andric : CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) { 10520b57cec5SDimitry Andric if (!findInCurrentIndex()) 10530b57cec5SDimitry Andric setEnd(); 10540b57cec5SDimitry Andric } 10550b57cec5SDimitry Andric 10560b57cec5SDimitry Andric iterator_range<DWARFDebugNames::ValueIterator> 10570b57cec5SDimitry Andric DWARFDebugNames::equal_range(StringRef Key) const { 10580b57cec5SDimitry Andric if (NameIndices.empty()) 10590b57cec5SDimitry Andric return make_range(ValueIterator(), ValueIterator()); 10600b57cec5SDimitry Andric return make_range(ValueIterator(*this, Key), ValueIterator()); 10610b57cec5SDimitry Andric } 10620b57cec5SDimitry Andric 10630b57cec5SDimitry Andric const DWARFDebugNames::NameIndex * 10648bcb0991SDimitry Andric DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) { 10650b57cec5SDimitry Andric if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) { 10660b57cec5SDimitry Andric for (const auto &NI : *this) { 10670b57cec5SDimitry Andric for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU) 10680b57cec5SDimitry Andric CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI); 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric return CUToNameIndex.lookup(CUOffset); 10720b57cec5SDimitry Andric } 10735f757f3fSDimitry Andric 10745f757f3fSDimitry Andric static bool isObjCSelector(StringRef Name) { 10755f757f3fSDimitry Andric return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') && 10765f757f3fSDimitry Andric (Name[1] == '['); 10775f757f3fSDimitry Andric } 10785f757f3fSDimitry Andric 10795f757f3fSDimitry Andric std::optional<ObjCSelectorNames> llvm::getObjCNamesIfSelector(StringRef Name) { 10805f757f3fSDimitry Andric if (!isObjCSelector(Name)) 10815f757f3fSDimitry Andric return std::nullopt; 10825f757f3fSDimitry Andric // "-[Atom setMass:]" 10835f757f3fSDimitry Andric StringRef ClassNameStart(Name.drop_front(2)); 10845f757f3fSDimitry Andric size_t FirstSpace = ClassNameStart.find(' '); 10855f757f3fSDimitry Andric if (FirstSpace == StringRef::npos) 10865f757f3fSDimitry Andric return std::nullopt; 10875f757f3fSDimitry Andric 10885f757f3fSDimitry Andric StringRef SelectorStart = ClassNameStart.drop_front(FirstSpace + 1); 10895f757f3fSDimitry Andric if (!SelectorStart.size()) 10905f757f3fSDimitry Andric return std::nullopt; 10915f757f3fSDimitry Andric 10925f757f3fSDimitry Andric ObjCSelectorNames Ans; 10935f757f3fSDimitry Andric Ans.ClassName = ClassNameStart.take_front(FirstSpace); 10945f757f3fSDimitry Andric Ans.Selector = SelectorStart.drop_back(); // drop ']'; 10955f757f3fSDimitry Andric 10965f757f3fSDimitry Andric // "-[Class(Category) selector :withArg ...]" 10975f757f3fSDimitry Andric if (Ans.ClassName.back() == ')') { 10985f757f3fSDimitry Andric size_t OpenParens = Ans.ClassName.find('('); 10995f757f3fSDimitry Andric if (OpenParens != StringRef::npos) { 11005f757f3fSDimitry Andric Ans.ClassNameNoCategory = Ans.ClassName.take_front(OpenParens); 11015f757f3fSDimitry Andric 11025f757f3fSDimitry Andric Ans.MethodNameNoCategory = Name.take_front(OpenParens + 2); 11035f757f3fSDimitry Andric // FIXME: The missing space here may be a bug, but dsymutil-classic also 11045f757f3fSDimitry Andric // does it this way. 11055f757f3fSDimitry Andric append_range(*Ans.MethodNameNoCategory, SelectorStart); 11065f757f3fSDimitry Andric } 11075f757f3fSDimitry Andric } 11085f757f3fSDimitry Andric return Ans; 11095f757f3fSDimitry Andric } 11105f757f3fSDimitry Andric 11115f757f3fSDimitry Andric std::optional<StringRef> llvm::StripTemplateParameters(StringRef Name) { 11125f757f3fSDimitry Andric // We are looking for template parameters to strip from Name. e.g. 11135f757f3fSDimitry Andric // 11145f757f3fSDimitry Andric // operator<<B> 11155f757f3fSDimitry Andric // 11165f757f3fSDimitry Andric // We look for > at the end but if it does not contain any < then we 11175f757f3fSDimitry Andric // have something like operator>>. We check for the operator<=> case. 11185f757f3fSDimitry Andric if (!Name.ends_with(">") || Name.count("<") == 0 || Name.ends_with("<=>")) 11195f757f3fSDimitry Andric return {}; 11205f757f3fSDimitry Andric 11215f757f3fSDimitry Andric // How many < until we have the start of the template parameters. 11225f757f3fSDimitry Andric size_t NumLeftAnglesToSkip = 1; 11235f757f3fSDimitry Andric 11245f757f3fSDimitry Andric // If we have operator<=> then we need to skip its < as well. 11255f757f3fSDimitry Andric NumLeftAnglesToSkip += Name.count("<=>"); 11265f757f3fSDimitry Andric 11275f757f3fSDimitry Andric size_t RightAngleCount = Name.count('>'); 11285f757f3fSDimitry Andric size_t LeftAngleCount = Name.count('<'); 11295f757f3fSDimitry Andric 11305f757f3fSDimitry Andric // If we have more < than > we have operator< or operator<< 11315f757f3fSDimitry Andric // we to account for their < as well. 11325f757f3fSDimitry Andric if (LeftAngleCount > RightAngleCount) 11335f757f3fSDimitry Andric NumLeftAnglesToSkip += LeftAngleCount - RightAngleCount; 11345f757f3fSDimitry Andric 11355f757f3fSDimitry Andric size_t StartOfTemplate = 0; 11365f757f3fSDimitry Andric while (NumLeftAnglesToSkip--) 11375f757f3fSDimitry Andric StartOfTemplate = Name.find('<', StartOfTemplate) + 1; 11385f757f3fSDimitry Andric 11395f757f3fSDimitry Andric return Name.substr(0, StartOfTemplate - 1); 11405f757f3fSDimitry Andric } 1141