Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
35269 views
//===- DWARFAcceleratorTable.cpp ------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"910#include "llvm/ADT/SmallVector.h"11#include "llvm/BinaryFormat/Dwarf.h"12#include "llvm/Support/Compiler.h"13#include "llvm/Support/DJB.h"14#include "llvm/Support/Errc.h"15#include "llvm/Support/Format.h"16#include "llvm/Support/FormatVariadic.h"17#include "llvm/Support/ScopedPrinter.h"18#include "llvm/Support/raw_ostream.h"19#include <cstddef>20#include <cstdint>21#include <utility>2223using namespace llvm;2425namespace {26struct Atom {27unsigned Value;28};2930static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {31StringRef Str = dwarf::AtomTypeString(A.Value);32if (!Str.empty())33return OS << Str;34return OS << "DW_ATOM_unknown_" << format("%x", A.Value);35}36} // namespace3738static Atom formatAtom(unsigned Atom) { return {Atom}; }3940DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;4142Error AppleAcceleratorTable::extract() {43uint64_t Offset = 0;4445// Check that we can at least read the header.46if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4))47return createStringError(errc::illegal_byte_sequence,48"Section too small: cannot read header.");4950Hdr.Magic = AccelSection.getU32(&Offset);51Hdr.Version = AccelSection.getU16(&Offset);52Hdr.HashFunction = AccelSection.getU16(&Offset);53Hdr.BucketCount = AccelSection.getU32(&Offset);54Hdr.HashCount = AccelSection.getU32(&Offset);55Hdr.HeaderDataLength = AccelSection.getU32(&Offset);56FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};5758// Check that we can read all the hashes and offsets from the59// section (see SourceLevelDebugging.rst for the structure of the index).60if (!AccelSection.isValidOffset(getIthBucketBase(Hdr.BucketCount - 1)))61return createStringError(62errc::illegal_byte_sequence,63"Section too small: cannot read buckets and hashes.");6465HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);66uint32_t NumAtoms = AccelSection.getU32(&Offset);6768HashDataEntryLength = 0;69auto MakeUnsupportedFormError = [](dwarf::Form Form) {70return createStringError(errc::not_supported,71"Unsupported form:" +72dwarf::FormEncodingString(Form));73};7475for (unsigned i = 0; i < NumAtoms; ++i) {76uint16_t AtomType = AccelSection.getU16(&Offset);77auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));78HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));7980std::optional<uint8_t> FormSize =81dwarf::getFixedFormByteSize(AtomForm, FormParams);82if (!FormSize)83return MakeUnsupportedFormError(AtomForm);84HashDataEntryLength += *FormSize;85}8687IsValid = true;88return Error::success();89}9091uint32_t AppleAcceleratorTable::getNumBuckets() const {92return Hdr.BucketCount;93}94uint32_t AppleAcceleratorTable::getNumHashes() const { return Hdr.HashCount; }95uint32_t AppleAcceleratorTable::getSizeHdr() const { return sizeof(Hdr); }96uint32_t AppleAcceleratorTable::getHeaderDataLength() const {97return Hdr.HeaderDataLength;98}99100ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,101AppleAcceleratorTable::HeaderData::Form>>102AppleAcceleratorTable::getAtomsDesc() {103return HdrData.Atoms;104}105106bool AppleAcceleratorTable::validateForms() {107for (auto Atom : getAtomsDesc()) {108DWARFFormValue FormValue(Atom.second);109switch (Atom.first) {110case dwarf::DW_ATOM_die_offset:111case dwarf::DW_ATOM_die_tag:112case dwarf::DW_ATOM_type_flags:113if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&114!FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||115FormValue.getForm() == dwarf::DW_FORM_sdata)116return false;117break;118default:119break;120}121}122return true;123}124125std::pair<uint64_t, dwarf::Tag>126AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) {127uint64_t DieOffset = dwarf::DW_INVALID_OFFSET;128dwarf::Tag DieTag = dwarf::DW_TAG_null;129130for (auto Atom : getAtomsDesc()) {131DWARFFormValue FormValue(Atom.second);132FormValue.extractValue(AccelSection, HashDataOffset, FormParams);133switch (Atom.first) {134case dwarf::DW_ATOM_die_offset:135DieOffset = *FormValue.getAsUnsignedConstant();136break;137case dwarf::DW_ATOM_die_tag:138DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();139break;140default:141break;142}143}144return {DieOffset, DieTag};145}146147void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const {148DictScope HeaderScope(W, "Header");149W.printHex("Magic", Magic);150W.printHex("Version", Version);151W.printHex("Hash function", HashFunction);152W.printNumber("Bucket count", BucketCount);153W.printNumber("Hashes count", HashCount);154W.printNumber("HeaderData length", HeaderDataLength);155}156157std::optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset(158std::optional<DWARFFormValue> Value) const {159if (!Value)160return std::nullopt;161162switch (Value->getForm()) {163case dwarf::DW_FORM_ref1:164case dwarf::DW_FORM_ref2:165case dwarf::DW_FORM_ref4:166case dwarf::DW_FORM_ref8:167case dwarf::DW_FORM_ref_udata:168return Value->getRawUValue() + DIEOffsetBase;169default:170return Value->getAsSectionOffset();171}172}173174bool AppleAcceleratorTable::dumpName(ScopedPrinter &W,175SmallVectorImpl<DWARFFormValue> &AtomForms,176uint64_t *DataOffset) const {177uint64_t NameOffset = *DataOffset;178if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) {179W.printString("Incorrectly terminated list.");180return false;181}182uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset);183if (!StringOffset)184return false; // End of list185186DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str());187W.startLine() << format("String: 0x%08" PRIx64, StringOffset);188W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n";189190unsigned NumData = AccelSection.getU32(DataOffset);191for (unsigned Data = 0; Data < NumData; ++Data) {192ListScope DataScope(W, ("Data " + Twine(Data)).str());193unsigned i = 0;194for (auto &Atom : AtomForms) {195W.startLine() << format("Atom[%d]: ", i);196if (Atom.extractValue(AccelSection, DataOffset, FormParams)) {197Atom.dump(W.getOStream());198if (std::optional<uint64_t> Val = Atom.getAsUnsignedConstant()) {199StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val);200if (!Str.empty())201W.getOStream() << " (" << Str << ")";202}203} else204W.getOStream() << "Error extracting the value";205W.getOStream() << "\n";206i++;207}208}209return true; // more entries follow210}211212LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {213if (!IsValid)214return;215216ScopedPrinter W(OS);217218Hdr.dump(W);219220W.printNumber("DIE offset base", HdrData.DIEOffsetBase);221W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size()));222W.printNumber("Size of each hash data entry", getHashDataEntryLength());223SmallVector<DWARFFormValue, 3> AtomForms;224{225ListScope AtomsScope(W, "Atoms");226unsigned i = 0;227for (const auto &Atom : HdrData.Atoms) {228DictScope AtomScope(W, ("Atom " + Twine(i++)).str());229W.startLine() << "Type: " << formatAtom(Atom.first) << '\n';230W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n';231AtomForms.push_back(DWARFFormValue(Atom.second));232}233}234235// Now go through the actual tables and dump them.236uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;237uint64_t HashesBase = Offset + Hdr.BucketCount * 4;238uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;239240for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) {241unsigned Index = AccelSection.getU32(&Offset);242243ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());244if (Index == UINT32_MAX) {245W.printString("EMPTY");246continue;247}248249for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {250uint64_t HashOffset = HashesBase + HashIdx*4;251uint64_t OffsetsOffset = OffsetsBase + HashIdx*4;252uint32_t Hash = AccelSection.getU32(&HashOffset);253254if (Hash % Hdr.BucketCount != Bucket)255break;256257uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);258ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str());259if (!AccelSection.isValidOffset(DataOffset)) {260W.printString("Invalid section offset");261continue;262}263while (dumpName(W, AtomForms, &DataOffset))264/*empty*/;265}266}267}268269AppleAcceleratorTable::Entry::Entry(const AppleAcceleratorTable &Table)270: Table(Table) {271Values.reserve(Table.HdrData.Atoms.size());272for (const auto &Atom : Table.HdrData.Atoms)273Values.push_back(DWARFFormValue(Atom.second));274}275276void AppleAcceleratorTable::Entry::extract(uint64_t *Offset) {277for (auto &FormValue : Values)278FormValue.extractValue(Table.AccelSection, Offset, Table.FormParams);279}280281std::optional<DWARFFormValue>282AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType AtomToFind) const {283for (auto [Atom, FormValue] : zip_equal(Table.HdrData.Atoms, Values))284if (Atom.first == AtomToFind)285return FormValue;286return std::nullopt;287}288289std::optional<uint64_t>290AppleAcceleratorTable::Entry::getDIESectionOffset() const {291return Table.HdrData.extractOffset(lookup(dwarf::DW_ATOM_die_offset));292}293294std::optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {295return Table.HdrData.extractOffset(lookup(dwarf::DW_ATOM_cu_offset));296}297298std::optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {299std::optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);300if (!Tag)301return std::nullopt;302if (std::optional<uint64_t> Value = Tag->getAsUnsignedConstant())303return dwarf::Tag(*Value);304return std::nullopt;305}306307AppleAcceleratorTable::SameNameIterator::SameNameIterator(308const AppleAcceleratorTable &AccelTable, uint64_t DataOffset)309: Current(AccelTable), Offset(DataOffset) {}310311void AppleAcceleratorTable::Iterator::prepareNextEntryOrEnd() {312if (NumEntriesToCome == 0)313prepareNextStringOrEnd();314if (isEnd())315return;316uint64_t OffsetCopy = Offset;317Current.BaseEntry.extract(&OffsetCopy);318NumEntriesToCome--;319Offset += getTable().getHashDataEntryLength();320}321322void AppleAcceleratorTable::Iterator::prepareNextStringOrEnd() {323std::optional<uint32_t> StrOffset = getTable().readStringOffsetAt(Offset);324if (!StrOffset)325return setToEnd();326327// A zero denotes the end of the collision list. Read the next string328// again.329if (*StrOffset == 0)330return prepareNextStringOrEnd();331Current.StrOffset = *StrOffset;332333std::optional<uint32_t> MaybeNumEntries = getTable().readU32FromAccel(Offset);334if (!MaybeNumEntries || *MaybeNumEntries == 0)335return setToEnd();336NumEntriesToCome = *MaybeNumEntries;337}338339AppleAcceleratorTable::Iterator::Iterator(const AppleAcceleratorTable &Table,340bool SetEnd)341: Current(Table), Offset(Table.getEntriesBase()), NumEntriesToCome(0) {342if (SetEnd)343setToEnd();344else345prepareNextEntryOrEnd();346}347348iterator_range<AppleAcceleratorTable::SameNameIterator>349AppleAcceleratorTable::equal_range(StringRef Key) const {350const auto EmptyRange =351make_range(SameNameIterator(*this, 0), SameNameIterator(*this, 0));352if (!IsValid)353return EmptyRange;354355// Find the bucket.356uint32_t SearchHash = djbHash(Key);357uint32_t BucketIdx = hashToBucketIdx(SearchHash);358std::optional<uint32_t> HashIdx = idxOfHashInBucket(SearchHash, BucketIdx);359if (!HashIdx)360return EmptyRange;361362std::optional<uint64_t> MaybeDataOffset = readIthOffset(*HashIdx);363if (!MaybeDataOffset)364return EmptyRange;365366uint64_t DataOffset = *MaybeDataOffset;367if (DataOffset >= AccelSection.size())368return EmptyRange;369370std::optional<uint32_t> StrOffset = readStringOffsetAt(DataOffset);371// Valid input and still have strings in this hash.372while (StrOffset && *StrOffset) {373std::optional<StringRef> MaybeStr = readStringFromStrSection(*StrOffset);374std::optional<uint32_t> NumEntries = this->readU32FromAccel(DataOffset);375if (!MaybeStr || !NumEntries)376return EmptyRange;377uint64_t EndOffset = DataOffset + *NumEntries * getHashDataEntryLength();378if (Key == *MaybeStr)379return make_range({*this, DataOffset},380SameNameIterator{*this, EndOffset});381DataOffset = EndOffset;382StrOffset = readStringOffsetAt(DataOffset);383}384385return EmptyRange;386}387388std::optional<uint32_t>389AppleAcceleratorTable::idxOfHashInBucket(uint32_t HashToFind,390uint32_t BucketIdx) const {391std::optional<uint32_t> HashStartIdx = readIthBucket(BucketIdx);392if (!HashStartIdx)393return std::nullopt;394395for (uint32_t HashIdx = *HashStartIdx; HashIdx < getNumHashes(); HashIdx++) {396std::optional<uint32_t> MaybeHash = readIthHash(HashIdx);397if (!MaybeHash || !wouldHashBeInBucket(*MaybeHash, BucketIdx))398break;399if (*MaybeHash == HashToFind)400return HashIdx;401}402return std::nullopt;403}404405std::optional<StringRef> AppleAcceleratorTable::readStringFromStrSection(406uint64_t StringSectionOffset) const {407Error E = Error::success();408StringRef Str = StringSection.getCStrRef(&StringSectionOffset, &E);409if (E) {410consumeError(std::move(E));411return std::nullopt;412}413return Str;414}415416std::optional<uint32_t>417AppleAcceleratorTable::readU32FromAccel(uint64_t &Offset,418bool UseRelocation) const {419Error E = Error::success();420uint32_t Data = UseRelocation421? AccelSection.getRelocatedValue(4, &Offset, nullptr, &E)422: AccelSection.getU32(&Offset, &E);423if (E) {424consumeError(std::move(E));425return std::nullopt;426}427return Data;428}429430void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {431DictScope HeaderScope(W, "Header");432W.printHex("Length", UnitLength);433W.printString("Format", dwarf::FormatString(Format));434W.printNumber("Version", Version);435W.printNumber("CU count", CompUnitCount);436W.printNumber("Local TU count", LocalTypeUnitCount);437W.printNumber("Foreign TU count", ForeignTypeUnitCount);438W.printNumber("Bucket count", BucketCount);439W.printNumber("Name count", NameCount);440W.printHex("Abbreviations table size", AbbrevTableSize);441W.startLine() << "Augmentation: '" << AugmentationString << "'\n";442}443444Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,445uint64_t *Offset) {446auto HeaderError = [Offset = *Offset](Error E) {447return createStringError(errc::illegal_byte_sequence,448"parsing .debug_names header at 0x%" PRIx64 ": %s",449Offset, toString(std::move(E)).c_str());450};451452DataExtractor::Cursor C(*Offset);453std::tie(UnitLength, Format) = AS.getInitialLength(C);454455Version = AS.getU16(C);456AS.skip(C, 2); // padding457CompUnitCount = AS.getU32(C);458LocalTypeUnitCount = AS.getU32(C);459ForeignTypeUnitCount = AS.getU32(C);460BucketCount = AS.getU32(C);461NameCount = AS.getU32(C);462AbbrevTableSize = AS.getU32(C);463AugmentationStringSize = alignTo(AS.getU32(C), 4);464465if (!C)466return HeaderError(C.takeError());467468if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize))469return HeaderError(createStringError(errc::illegal_byte_sequence,470"cannot read header augmentation"));471AugmentationString.resize(AugmentationStringSize);472AS.getU8(C, reinterpret_cast<uint8_t *>(AugmentationString.data()),473AugmentationStringSize);474*Offset = C.tell();475return C.takeError();476}477478void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {479DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());480W.startLine() << formatv("Tag: {0}\n", Tag);481482for (const auto &Attr : Attributes)483W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form);484}485486static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {487return {dwarf::Index(0), dwarf::Form(0)};488}489490static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {491return AE == sentinelAttrEnc();492}493494static DWARFDebugNames::Abbrev sentinelAbbrev() {495return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), 0, {});496}497498static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {499return Abbr.Code == 0;500}501502DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {503return sentinelAbbrev();504}505506DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {507return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), 0, {});508}509510Expected<DWARFDebugNames::AttributeEncoding>511DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) {512if (*Offset >= Offsets.EntriesBase) {513return createStringError(errc::illegal_byte_sequence,514"Incorrectly terminated abbreviation table.");515}516517uint32_t Index = Section.AccelSection.getULEB128(Offset);518uint32_t Form = Section.AccelSection.getULEB128(Offset);519return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));520}521522Expected<std::vector<DWARFDebugNames::AttributeEncoding>>523DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) {524std::vector<AttributeEncoding> Result;525for (;;) {526auto AttrEncOr = extractAttributeEncoding(Offset);527if (!AttrEncOr)528return AttrEncOr.takeError();529if (isSentinel(*AttrEncOr))530return std::move(Result);531532Result.emplace_back(*AttrEncOr);533}534}535536Expected<DWARFDebugNames::Abbrev>537DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) {538if (*Offset >= Offsets.EntriesBase) {539return createStringError(errc::illegal_byte_sequence,540"Incorrectly terminated abbreviation table.");541}542const uint64_t AbbrevOffset = *Offset;543uint32_t Code = Section.AccelSection.getULEB128(Offset);544if (Code == 0)545return sentinelAbbrev();546547uint32_t Tag = Section.AccelSection.getULEB128(Offset);548auto AttrEncOr = extractAttributeEncodings(Offset);549if (!AttrEncOr)550return AttrEncOr.takeError();551return Abbrev(Code, dwarf::Tag(Tag), AbbrevOffset, std::move(*AttrEncOr));552}553554DWARFDebugNames::DWARFDebugNamesOffsets555dwarf::findDebugNamesOffsets(uint64_t EndOfHeaderOffset,556const DWARFDebugNames::Header &Hdr) {557uint64_t DwarfSize = getDwarfOffsetByteSize(Hdr.Format);558DWARFDebugNames::DWARFDebugNamesOffsets Ret;559Ret.CUsBase = EndOfHeaderOffset;560Ret.BucketsBase = Ret.CUsBase + Hdr.CompUnitCount * DwarfSize +561Hdr.LocalTypeUnitCount * DwarfSize +562Hdr.ForeignTypeUnitCount * 8;563Ret.HashesBase = Ret.BucketsBase + Hdr.BucketCount * 4;564Ret.StringOffsetsBase =565Ret.HashesBase + (Hdr.BucketCount > 0 ? Hdr.NameCount * 4 : 0);566Ret.EntryOffsetsBase = Ret.StringOffsetsBase + Hdr.NameCount * DwarfSize;567Ret.EntriesBase =568Ret.EntryOffsetsBase + Hdr.NameCount * DwarfSize + Hdr.AbbrevTableSize;569return Ret;570}571572Error DWARFDebugNames::NameIndex::extract() {573const DWARFDataExtractor &AS = Section.AccelSection;574uint64_t EndOfHeaderOffset = Base;575if (Error E = Hdr.extract(AS, &EndOfHeaderOffset))576return E;577578const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);579Offsets = dwarf::findDebugNamesOffsets(EndOfHeaderOffset, Hdr);580581uint64_t Offset =582Offsets.EntryOffsetsBase + (Hdr.NameCount * SectionOffsetSize);583584if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))585return createStringError(errc::illegal_byte_sequence,586"Section too small: cannot read abbreviations.");587588Offsets.EntriesBase = Offset + Hdr.AbbrevTableSize;589590for (;;) {591auto AbbrevOr = extractAbbrev(&Offset);592if (!AbbrevOr)593return AbbrevOr.takeError();594if (isSentinel(*AbbrevOr))595return Error::success();596597if (!Abbrevs.insert(std::move(*AbbrevOr)).second)598return createStringError(errc::invalid_argument,599"Duplicate abbreviation code.");600}601}602603DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)604: NameIdx(&NameIdx), Abbr(&Abbr) {605// This merely creates form values. It is up to the caller606// (NameIndex::getEntry) to populate them.607Values.reserve(Abbr.Attributes.size());608for (const auto &Attr : Abbr.Attributes)609Values.emplace_back(Attr.Form);610}611612std::optional<DWARFFormValue>613DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {614assert(Abbr->Attributes.size() == Values.size());615for (auto Tuple : zip_first(Abbr->Attributes, Values)) {616if (std::get<0>(Tuple).Index == Index)617return std::get<1>(Tuple);618}619return std::nullopt;620}621622bool DWARFDebugNames::Entry::hasParentInformation() const {623return lookup(dwarf::DW_IDX_parent).has_value();624}625626std::optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {627if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))628return Off->getAsReferenceUVal();629return std::nullopt;630}631632std::optional<uint64_t> DWARFDebugNames::Entry::getRelatedCUIndex() const {633// Return the DW_IDX_compile_unit attribute value if it is specified.634if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))635return Off->getAsUnsignedConstant();636// In a per-CU index, the entries without a DW_IDX_compile_unit attribute637// implicitly refer to the single CU.638if (NameIdx->getCUCount() == 1)639return 0;640return std::nullopt;641}642643std::optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {644// Return the DW_IDX_compile_unit attribute value but only if we don't have a645// DW_IDX_type_unit attribute. Use Entry::getRelatedCUIndex() to get the646// associated CU index if this behaviour is not desired.647if (lookup(dwarf::DW_IDX_type_unit).has_value())648return std::nullopt;649return getRelatedCUIndex();650}651652std::optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {653std::optional<uint64_t> Index = getCUIndex();654if (!Index || *Index >= NameIdx->getCUCount())655return std::nullopt;656return NameIdx->getCUOffset(*Index);657}658659std::optional<uint64_t> DWARFDebugNames::Entry::getRelatedCUOffset() const {660std::optional<uint64_t> Index = getRelatedCUIndex();661if (!Index || *Index >= NameIdx->getCUCount())662return std::nullopt;663return NameIdx->getCUOffset(*Index);664}665666std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const {667std::optional<uint64_t> Index = getLocalTUIndex();668if (!Index || *Index >= NameIdx->getLocalTUCount())669return std::nullopt;670return NameIdx->getLocalTUOffset(*Index);671}672673std::optional<uint64_t>674DWARFDebugNames::Entry::getForeignTUTypeSignature() const {675std::optional<uint64_t> Index = getLocalTUIndex();676const uint32_t NumLocalTUs = NameIdx->getLocalTUCount();677if (!Index || *Index < NumLocalTUs)678return std::nullopt; // Invalid TU index or TU index is for a local TU679// The foreign TU index is the TU index minus the number of local TUs.680const uint64_t ForeignTUIndex = *Index - NumLocalTUs;681if (ForeignTUIndex >= NameIdx->getForeignTUCount())682return std::nullopt; // Invalid foreign TU index.683return NameIdx->getForeignTUSignature(ForeignTUIndex);684}685686std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {687if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit))688return Off->getAsUnsignedConstant();689return std::nullopt;690}691692Expected<std::optional<DWARFDebugNames::Entry>>693DWARFDebugNames::Entry::getParentDIEEntry() const {694// The offset of the accelerator table entry for the parent.695std::optional<DWARFFormValue> ParentEntryOff = lookup(dwarf::DW_IDX_parent);696assert(ParentEntryOff.has_value() && "hasParentInformation() must be called");697698if (ParentEntryOff->getForm() == dwarf::Form::DW_FORM_flag_present)699return std::nullopt;700return NameIdx->getEntryAtRelativeOffset(ParentEntryOff->getRawUValue());701}702703void DWARFDebugNames::Entry::dumpParentIdx(704ScopedPrinter &W, const DWARFFormValue &FormValue) const {705Expected<std::optional<Entry>> ParentEntry = getParentDIEEntry();706if (!ParentEntry) {707W.getOStream() << "<invalid offset data>";708consumeError(ParentEntry.takeError());709return;710}711712if (!ParentEntry->has_value()) {713W.getOStream() << "<parent not indexed>";714return;715}716717auto AbsoluteOffset = NameIdx->Offsets.EntriesBase + FormValue.getRawUValue();718W.getOStream() << "Entry @ 0x" + Twine::utohexstr(AbsoluteOffset);719}720721void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {722W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code);723W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);724assert(Abbr->Attributes.size() == Values.size());725for (auto Tuple : zip_first(Abbr->Attributes, Values)) {726auto Index = std::get<0>(Tuple).Index;727W.startLine() << formatv("{0}: ", Index);728729auto FormValue = std::get<1>(Tuple);730if (Index == dwarf::Index::DW_IDX_parent)731dumpParentIdx(W, FormValue);732else733FormValue.dump(W.getOStream());734W.getOStream() << '\n';735}736}737738char DWARFDebugNames::SentinelError::ID;739std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {740return inconvertibleErrorCode();741}742743uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {744assert(CU < Hdr.CompUnitCount);745const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);746uint64_t Offset = Offsets.CUsBase + SectionOffsetSize * CU;747return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset);748}749750uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {751assert(TU < Hdr.LocalTypeUnitCount);752const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);753uint64_t Offset =754Offsets.CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU);755return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset);756}757758uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const {759assert(TU < Hdr.ForeignTypeUnitCount);760const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);761uint64_t Offset =762Offsets.CUsBase +763SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU;764return Section.AccelSection.getU64(&Offset);765}766767Expected<DWARFDebugNames::Entry>768DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const {769const DWARFDataExtractor &AS = Section.AccelSection;770if (!AS.isValidOffset(*Offset))771return createStringError(errc::illegal_byte_sequence,772"Incorrectly terminated entry list.");773774uint32_t AbbrevCode = AS.getULEB128(Offset);775if (AbbrevCode == 0)776return make_error<SentinelError>();777778const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);779if (AbbrevIt == Abbrevs.end())780return createStringError(errc::invalid_argument, "Invalid abbreviation.");781782Entry E(*this, *AbbrevIt);783784dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format};785for (auto &Value : E.Values) {786if (!Value.extractValue(AS, Offset, FormParams))787return createStringError(errc::io_error,788"Error extracting index attribute values.");789}790return std::move(E);791}792793DWARFDebugNames::NameTableEntry794DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {795assert(0 < Index && Index <= Hdr.NameCount);796const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);797uint64_t StringOffsetOffset =798Offsets.StringOffsetsBase + SectionOffsetSize * (Index - 1);799uint64_t EntryOffsetOffset =800Offsets.EntryOffsetsBase + SectionOffsetSize * (Index - 1);801const DWARFDataExtractor &AS = Section.AccelSection;802803uint64_t StringOffset =804AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset);805uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize);806EntryOffset += Offsets.EntriesBase;807return {Section.StringSection, Index, StringOffset, EntryOffset};808}809810uint32_t811DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {812assert(Bucket < Hdr.BucketCount);813uint64_t BucketOffset = Offsets.BucketsBase + 4 * Bucket;814return Section.AccelSection.getU32(&BucketOffset);815}816817uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {818assert(0 < Index && Index <= Hdr.NameCount);819uint64_t HashOffset = Offsets.HashesBase + 4 * (Index - 1);820return Section.AccelSection.getU32(&HashOffset);821}822823// Returns true if we should continue scanning for entries, false if this is the824// last (sentinel) entry). In case of a parsing error we also return false, as825// it's not possible to recover this entry list (but the other lists may still826// parse OK).827bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,828uint64_t *Offset) const {829uint64_t EntryId = *Offset;830auto EntryOr = getEntry(Offset);831if (!EntryOr) {832handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},833[&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });834return false;835}836837DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());838EntryOr->dump(W);839return true;840}841842void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W,843const NameTableEntry &NTE,844std::optional<uint32_t> Hash) const {845DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str());846if (Hash)847W.printHex("Hash", *Hash);848849W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset());850W.getOStream() << " \"" << NTE.getString() << "\"\n";851852uint64_t EntryOffset = NTE.getEntryOffset();853while (dumpEntry(W, &EntryOffset))854/*empty*/;855}856857void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {858ListScope CUScope(W, "Compilation Unit offsets");859for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)860W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU));861}862863void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {864if (Hdr.LocalTypeUnitCount == 0)865return;866867ListScope TUScope(W, "Local Type Unit offsets");868for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)869W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU,870getLocalTUOffset(TU));871}872873void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {874if (Hdr.ForeignTypeUnitCount == 0)875return;876877ListScope TUScope(W, "Foreign Type Unit signatures");878for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {879W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,880getForeignTUSignature(TU));881}882}883884void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {885ListScope AbbrevsScope(W, "Abbreviations");886std::vector<const Abbrev *> AbbrevsVect;887for (const DWARFDebugNames::Abbrev &Abbr : Abbrevs)888AbbrevsVect.push_back(&Abbr);889llvm::sort(AbbrevsVect, [](const Abbrev *LHS, const Abbrev *RHS) {890return LHS->AbbrevOffset < RHS->AbbrevOffset;891});892for (const DWARFDebugNames::Abbrev *Abbr : AbbrevsVect)893Abbr->dump(W);894}895896void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,897uint32_t Bucket) const {898ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());899uint32_t Index = getBucketArrayEntry(Bucket);900if (Index == 0) {901W.printString("EMPTY");902return;903}904if (Index > Hdr.NameCount) {905W.printString("Name index is invalid");906return;907}908909for (; Index <= Hdr.NameCount; ++Index) {910uint32_t Hash = getHashArrayEntry(Index);911if (Hash % Hdr.BucketCount != Bucket)912break;913914dumpName(W, getNameTableEntry(Index), Hash);915}916}917918LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {919DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());920Hdr.dump(W);921dumpCUs(W);922dumpLocalTUs(W);923dumpForeignTUs(W);924dumpAbbreviations(W);925926if (Hdr.BucketCount > 0) {927for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)928dumpBucket(W, Bucket);929return;930}931932W.startLine() << "Hash table not present\n";933for (const NameTableEntry &NTE : *this)934dumpName(W, NTE, std::nullopt);935}936937Error DWARFDebugNames::extract() {938uint64_t Offset = 0;939while (AccelSection.isValidOffset(Offset)) {940NameIndex Next(*this, Offset);941if (Error E = Next.extract())942return E;943Offset = Next.getNextUnitOffset();944NameIndices.push_back(std::move(Next));945}946return Error::success();947}948949iterator_range<DWARFDebugNames::ValueIterator>950DWARFDebugNames::NameIndex::equal_range(StringRef Key) const {951return make_range(ValueIterator(*this, Key), ValueIterator());952}953954LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {955ScopedPrinter W(OS);956for (const NameIndex &NI : NameIndices)957NI.dump(W);958}959960std::optional<uint64_t>961DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {962const Header &Hdr = CurrentIndex->Hdr;963if (Hdr.BucketCount == 0) {964// No Hash Table, We need to search through all names in the Name Index.965for (const NameTableEntry &NTE : *CurrentIndex) {966if (NTE.sameNameAs(Key))967return NTE.getEntryOffset();968}969return std::nullopt;970}971972// The Name Index has a Hash Table, so use that to speed up the search.973// Compute the Key Hash, if it has not been done already.974if (!Hash)975Hash = caseFoldingDjbHash(Key);976uint32_t Bucket = *Hash % Hdr.BucketCount;977uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket);978if (Index == 0)979return std::nullopt; // Empty bucket980981for (; Index <= Hdr.NameCount; ++Index) {982uint32_t HashAtIndex = CurrentIndex->getHashArrayEntry(Index);983if (HashAtIndex % Hdr.BucketCount != Bucket)984return std::nullopt; // End of bucket985// Only compare names if the hashes match.986if (HashAtIndex != Hash)987continue;988989NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);990if (NTE.sameNameAs(Key))991return NTE.getEntryOffset();992}993return std::nullopt;994}995996bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {997auto EntryOr = CurrentIndex->getEntry(&DataOffset);998if (!EntryOr) {999consumeError(EntryOr.takeError());1000return false;1001}1002CurrentEntry = std::move(*EntryOr);1003return true;1004}10051006bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {1007std::optional<uint64_t> Offset = findEntryOffsetInCurrentIndex();1008if (!Offset)1009return false;1010DataOffset = *Offset;1011return getEntryAtCurrentOffset();1012}10131014void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {1015for (const NameIndex *End = CurrentIndex->Section.NameIndices.end();1016CurrentIndex != End; ++CurrentIndex) {1017if (findInCurrentIndex())1018return;1019}1020setEnd();1021}10221023void DWARFDebugNames::ValueIterator::next() {1024assert(CurrentIndex && "Incrementing an end() iterator?");10251026// First try the next entry in the current Index.1027if (getEntryAtCurrentOffset())1028return;10291030// If we're a local iterator or we have reached the last Index, we're done.1031if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) {1032setEnd();1033return;1034}10351036// Otherwise, try the next index.1037++CurrentIndex;1038searchFromStartOfCurrentIndex();1039}10401041DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable,1042StringRef Key)1043: CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false),1044Key(std::string(Key)) {1045searchFromStartOfCurrentIndex();1046}10471048DWARFDebugNames::ValueIterator::ValueIterator(1049const DWARFDebugNames::NameIndex &NI, StringRef Key)1050: CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) {1051if (!findInCurrentIndex())1052setEnd();1053}10541055iterator_range<DWARFDebugNames::ValueIterator>1056DWARFDebugNames::equal_range(StringRef Key) const {1057if (NameIndices.empty())1058return make_range(ValueIterator(), ValueIterator());1059return make_range(ValueIterator(*this, Key), ValueIterator());1060}10611062const DWARFDebugNames::NameIndex *1063DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) {1064if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) {1065for (const auto &NI : *this) {1066for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU)1067CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);1068}1069}1070return CUToNameIndex.lookup(CUOffset);1071}10721073static bool isObjCSelector(StringRef Name) {1074return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') &&1075(Name[1] == '[');1076}10771078std::optional<ObjCSelectorNames> llvm::getObjCNamesIfSelector(StringRef Name) {1079if (!isObjCSelector(Name))1080return std::nullopt;1081// "-[Atom setMass:]"1082StringRef ClassNameStart(Name.drop_front(2));1083size_t FirstSpace = ClassNameStart.find(' ');1084if (FirstSpace == StringRef::npos)1085return std::nullopt;10861087StringRef SelectorStart = ClassNameStart.drop_front(FirstSpace + 1);1088if (!SelectorStart.size())1089return std::nullopt;10901091ObjCSelectorNames Ans;1092Ans.ClassName = ClassNameStart.take_front(FirstSpace);1093Ans.Selector = SelectorStart.drop_back(); // drop ']';10941095// "-[Class(Category) selector :withArg ...]"1096if (Ans.ClassName.back() == ')') {1097size_t OpenParens = Ans.ClassName.find('(');1098if (OpenParens != StringRef::npos) {1099Ans.ClassNameNoCategory = Ans.ClassName.take_front(OpenParens);11001101Ans.MethodNameNoCategory = Name.take_front(OpenParens + 2);1102// FIXME: The missing space here may be a bug, but dsymutil-classic also1103// does it this way.1104append_range(*Ans.MethodNameNoCategory, SelectorStart);1105}1106}1107return Ans;1108}11091110std::optional<StringRef> llvm::StripTemplateParameters(StringRef Name) {1111// We are looking for template parameters to strip from Name. e.g.1112//1113// operator<<B>1114//1115// We look for > at the end but if it does not contain any < then we1116// have something like operator>>. We check for the operator<=> case.1117if (!Name.ends_with(">") || Name.count("<") == 0 || Name.ends_with("<=>"))1118return {};11191120// How many < until we have the start of the template parameters.1121size_t NumLeftAnglesToSkip = 1;11221123// If we have operator<=> then we need to skip its < as well.1124NumLeftAnglesToSkip += Name.count("<=>");11251126size_t RightAngleCount = Name.count('>');1127size_t LeftAngleCount = Name.count('<');11281129// If we have more < than > we have operator< or operator<<1130// we to account for their < as well.1131if (LeftAngleCount > RightAngleCount)1132NumLeftAnglesToSkip += LeftAngleCount - RightAngleCount;11331134size_t StartOfTemplate = 0;1135while (NumLeftAnglesToSkip--)1136StartOfTemplate = Name.find('<', StartOfTemplate) + 1;11371138return Name.substr(0, StartOfTemplate - 1);1139}114011411142