xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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