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
operator <<(raw_ostream & OS,const Atom & A)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
formatAtom(unsigned Atom)390b57cec5SDimitry Andric static Atom formatAtom(unsigned Atom) { return {Atom}; }
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
420b57cec5SDimitry Andric
extract()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
getNumBuckets() const9206c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getNumBuckets() const {
9306c3fb27SDimitry Andric return Hdr.BucketCount;
9406c3fb27SDimitry Andric }
getNumHashes() const9506c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getNumHashes() const { return Hdr.HashCount; }
getSizeHdr() const9606c3fb27SDimitry Andric uint32_t AppleAcceleratorTable::getSizeHdr() const { return sizeof(Hdr); }
getHeaderDataLength() const9706c3fb27SDimitry 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>>
getAtomsDesc()1030b57cec5SDimitry Andric AppleAcceleratorTable::getAtomsDesc() {
1040b57cec5SDimitry Andric return HdrData.Atoms;
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
validateForms()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>
readAtoms(uint64_t * HashDataOffset)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
dump(ScopedPrinter & W) const1480b57cec5SDimitry 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
extractOffset(std::optional<DWARFFormValue> Value) const158bdd1243dSDimitry 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
dumpName(ScopedPrinter & W,SmallVectorImpl<DWARFFormValue> & AtomForms,uint64_t * DataOffset) const1750b57cec5SDimitry 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
dump(raw_ostream & OS) const2130b57cec5SDimitry 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
Entry(const AppleAcceleratorTable & Table)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
extract(uint64_t * Offset)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>
lookup(HeaderData::AtomType AtomToFind) const28306c3fb27SDimitry 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>
getDIESectionOffset() const291bdd1243dSDimitry Andric AppleAcceleratorTable::Entry::getDIESectionOffset() const {
29206c3fb27SDimitry Andric return Table.HdrData.extractOffset(lookup(dwarf::DW_ATOM_die_offset));
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric
getCUOffset() const295bdd1243dSDimitry 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
getTag() const299bdd1243dSDimitry 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
SameNameIterator(const AppleAcceleratorTable & AccelTable,uint64_t DataOffset)30806c3fb27SDimitry Andric AppleAcceleratorTable::SameNameIterator::SameNameIterator(
30906c3fb27SDimitry Andric const AppleAcceleratorTable &AccelTable, uint64_t DataOffset)
31006c3fb27SDimitry Andric : Current(AccelTable), Offset(DataOffset) {}
31106c3fb27SDimitry Andric
prepareNextEntryOrEnd()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
prepareNextStringOrEnd()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
Iterator(const AppleAcceleratorTable & Table,bool SetEnd)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>
equal_range(StringRef Key) const3500b57cec5SDimitry 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>
idxOfHashInBucket(uint32_t HashToFind,uint32_t BucketIdx) const39006c3fb27SDimitry 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
readStringFromStrSection(uint64_t StringSectionOffset) const40606c3fb27SDimitry 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>
readU32FromAccel(uint64_t & Offset,bool UseRelocation) const41806c3fb27SDimitry 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
dump(ScopedPrinter & W) const4310b57cec5SDimitry 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
extract(const DWARFDataExtractor & AS,uint64_t * Offset)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
dump(ScopedPrinter & W) const4790b57cec5SDimitry 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
sentinelAttrEnc()4870b57cec5SDimitry Andric static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
4880b57cec5SDimitry Andric return {dwarf::Index(0), dwarf::Form(0)};
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric
isSentinel(const DWARFDebugNames::AttributeEncoding & AE)4910b57cec5SDimitry Andric static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
4920b57cec5SDimitry Andric return AE == sentinelAttrEnc();
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric
sentinelAbbrev()4950b57cec5SDimitry Andric static DWARFDebugNames::Abbrev sentinelAbbrev() {
496*0fca6ea1SDimitry Andric return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), 0, {});
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric
isSentinel(const DWARFDebugNames::Abbrev & Abbr)4990b57cec5SDimitry Andric static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
5000b57cec5SDimitry Andric return Abbr.Code == 0;
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric
getEmptyKey()5030b57cec5SDimitry Andric DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
5040b57cec5SDimitry Andric return sentinelAbbrev();
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric
getTombstoneKey()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>
extractAttributeEncoding(uint64_t * Offset)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>>
extractAttributeEncodings(uint64_t * Offset)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>
extractAbbrev(uint64_t * Offset)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
findDebugNamesOffsets(uint64_t EndOfHeaderOffset,const DWARFDebugNames::Header & Hdr)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
extract()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
Entry(const NameIndex & NameIdx,const Abbrev & Abbr)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>
lookup(dwarf::Index Index) const6140b57cec5SDimitry 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
hasParentInformation() const623*0fca6ea1SDimitry Andric bool DWARFDebugNames::Entry::hasParentInformation() const {
624*0fca6ea1SDimitry Andric return lookup(dwarf::DW_IDX_parent).has_value();
625*0fca6ea1SDimitry Andric }
626*0fca6ea1SDimitry Andric
getDIEUnitOffset() const627bdd1243dSDimitry 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
getRelatedCUIndex() const633*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
getCUIndex() const644*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
getCUOffset() const653bdd1243dSDimitry 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
getRelatedCUOffset() const660*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
getLocalTUOffset() const6675f757f3fSDimitry 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>
getForeignTUTypeSignature() const675*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
getLocalTUIndex() const6875f757f3fSDimitry 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>>
getParentDIEEntry() const694*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
dumpParentIdx(ScopedPrinter & W,const DWARFFormValue & FormValue) const704*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
dump(ScopedPrinter & W) const7220b57cec5SDimitry 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;
convertToErrorCode() const7400b57cec5SDimitry Andric std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
7410b57cec5SDimitry Andric return inconvertibleErrorCode();
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric
getCUOffset(uint32_t CU) const7448bcb0991SDimitry 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
getLocalTUOffset(uint32_t TU) const7518bcb0991SDimitry 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
getForeignTUSignature(uint32_t TU) const7590b57cec5SDimitry 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>
getEntry(uint64_t * Offset) const7698bcb0991SDimitry 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
getNameTableEntry(uint32_t Index) const7950b57cec5SDimitry 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
getBucketArrayEntry(uint32_t Bucket) const8120b57cec5SDimitry 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
getHashArrayEntry(uint32_t Index) const8180b57cec5SDimitry 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).
dumpEntry(ScopedPrinter & W,uint64_t * Offset) const8280b57cec5SDimitry 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
dumpName(ScopedPrinter & W,const NameTableEntry & NTE,std::optional<uint32_t> Hash) const8430b57cec5SDimitry 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
dumpCUs(ScopedPrinter & W) const8580b57cec5SDimitry 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
dumpLocalTUs(ScopedPrinter & W) const8640b57cec5SDimitry 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
dumpForeignTUs(ScopedPrinter & W) const8740b57cec5SDimitry 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
dumpAbbreviations(ScopedPrinter & W) const8850b57cec5SDimitry 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
dumpBucket(ScopedPrinter & W,uint32_t Bucket) const8970b57cec5SDimitry 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
dump(ScopedPrinter & W) const9190b57cec5SDimitry 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
extract()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>
equal_range(StringRef Key) const9510b57cec5SDimitry Andric DWARFDebugNames::NameIndex::equal_range(StringRef Key) const {
9520b57cec5SDimitry Andric return make_range(ValueIterator(*this, Key), ValueIterator());
9530b57cec5SDimitry Andric }
9540b57cec5SDimitry Andric
dump(raw_ostream & OS) const9550b57cec5SDimitry 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>
findEntryOffsetInCurrentIndex()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
getEntryAtCurrentOffset()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
findInCurrentIndex()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
searchFromStartOfCurrentIndex()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
next()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
ValueIterator(const DWARFDebugNames & AccelTable,StringRef Key)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
ValueIterator(const DWARFDebugNames::NameIndex & NI,StringRef Key)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>
equal_range(StringRef Key) const10570b57cec5SDimitry 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 *
getCUNameIndex(uint64_t CUOffset)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
isObjCSelector(StringRef Name)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
getObjCNamesIfSelector(StringRef Name)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
StripTemplateParameters(StringRef Name)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