1e94042caSEugene Zelenko //===- DWARFAcceleratorTable.cpp ------------------------------------------===// 282af9438SZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 682af9438SZachary Turner // 782af9438SZachary Turner //===----------------------------------------------------------------------===// 882af9438SZachary Turner 982af9438SZachary Turner #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" 10264b5d9eSZachary Turner 116bda14b3SChandler Carruth #include "llvm/ADT/SmallVector.h" 12264b5d9eSZachary Turner #include "llvm/BinaryFormat/Dwarf.h" 13e94042caSEugene Zelenko #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" 14e94042caSEugene Zelenko #include "llvm/Support/Compiler.h" 1592ac9d3eSJonas Devlieghere #include "llvm/Support/DJB.h" 16cba595daSVictor Leschuk #include "llvm/Support/Errc.h" 1782af9438SZachary Turner #include "llvm/Support/Format.h" 189025f955SPavel Labath #include "llvm/Support/FormatVariadic.h" 193c9a918cSPavel Labath #include "llvm/Support/ScopedPrinter.h" 2082af9438SZachary Turner #include "llvm/Support/raw_ostream.h" 21e94042caSEugene Zelenko #include <cstddef> 22e94042caSEugene Zelenko #include <cstdint> 23e94042caSEugene Zelenko #include <utility> 2482af9438SZachary Turner 25e94042caSEugene Zelenko using namespace llvm; 2682af9438SZachary Turner 273c9a918cSPavel Labath namespace { 289025f955SPavel Labath struct Atom { 293c9a918cSPavel Labath unsigned Value; 303c9a918cSPavel Labath }; 313c9a918cSPavel Labath 329025f955SPavel Labath static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) { 339025f955SPavel Labath StringRef Str = dwarf::AtomTypeString(A.Value); 343c9a918cSPavel Labath if (!Str.empty()) 353c9a918cSPavel Labath return OS << Str; 369025f955SPavel Labath return OS << "DW_ATOM_unknown_" << format("%x", A.Value); 373c9a918cSPavel Labath } 383c9a918cSPavel Labath } // namespace 393c9a918cSPavel Labath 409025f955SPavel Labath static Atom formatAtom(unsigned Atom) { return {Atom}; } 413c9a918cSPavel Labath 423c9a918cSPavel Labath DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; 433c9a918cSPavel Labath 44a364d599SFangrui Song Error AppleAcceleratorTable::extract() { 45f26a70a5SIgor Kudrin uint64_t Offset = 0; 4682af9438SZachary Turner 4782af9438SZachary Turner // Check that we can at least read the header. 4882af9438SZachary Turner if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4)) 49cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence, 50cba595daSVictor Leschuk "Section too small: cannot read header."); 5182af9438SZachary Turner 5282af9438SZachary Turner Hdr.Magic = AccelSection.getU32(&Offset); 5382af9438SZachary Turner Hdr.Version = AccelSection.getU16(&Offset); 5482af9438SZachary Turner Hdr.HashFunction = AccelSection.getU16(&Offset); 55394e8056SPavel Labath Hdr.BucketCount = AccelSection.getU32(&Offset); 56394e8056SPavel Labath Hdr.HashCount = AccelSection.getU32(&Offset); 5782af9438SZachary Turner Hdr.HeaderDataLength = AccelSection.getU32(&Offset); 5882af9438SZachary Turner 5982af9438SZachary Turner // Check that we can read all the hashes and offsets from the 6082af9438SZachary Turner // section (see SourceLevelDebugging.rst for the structure of the index). 61ba915897SJonas Devlieghere // We need to substract one because we're checking for an *offset* which is 62ba915897SJonas Devlieghere // equal to the size for an empty table and hence pointer after the section. 6382af9438SZachary Turner if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength + 64394e8056SPavel Labath Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1)) 65cba595daSVictor Leschuk return createStringError( 66cba595daSVictor Leschuk errc::illegal_byte_sequence, 67cba595daSVictor Leschuk "Section too small: cannot read buckets and hashes."); 6882af9438SZachary Turner 6982af9438SZachary Turner HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); 7082af9438SZachary Turner uint32_t NumAtoms = AccelSection.getU32(&Offset); 7182af9438SZachary Turner 7282af9438SZachary Turner for (unsigned i = 0; i < NumAtoms; ++i) { 7382af9438SZachary Turner uint16_t AtomType = AccelSection.getU16(&Offset); 746c273763SGreg Clayton auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); 7582af9438SZachary Turner HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); 7682af9438SZachary Turner } 7782af9438SZachary Turner 7899fdb9d9SAdrian Prantl IsValid = true; 79ba915897SJonas Devlieghere return Error::success(); 8082af9438SZachary Turner } 8182af9438SZachary Turner 82394e8056SPavel Labath uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; } 83394e8056SPavel Labath uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; } 849b36fd25SPavel Labath uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } 859b36fd25SPavel Labath uint32_t AppleAcceleratorTable::getHeaderDataLength() { 86e41823bbSSpyridoula Gravani return Hdr.HeaderDataLength; 87e41823bbSSpyridoula Gravani } 88e41823bbSSpyridoula Gravani 899b36fd25SPavel Labath ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType, 909b36fd25SPavel Labath AppleAcceleratorTable::HeaderData::Form>> 919b36fd25SPavel Labath AppleAcceleratorTable::getAtomsDesc() { 92837c110cSSpyridoula Gravani return HdrData.Atoms; 93837c110cSSpyridoula Gravani } 94837c110cSSpyridoula Gravani 959b36fd25SPavel Labath bool AppleAcceleratorTable::validateForms() { 96837c110cSSpyridoula Gravani for (auto Atom : getAtomsDesc()) { 97837c110cSSpyridoula Gravani DWARFFormValue FormValue(Atom.second); 98837c110cSSpyridoula Gravani switch (Atom.first) { 99837c110cSSpyridoula Gravani case dwarf::DW_ATOM_die_offset: 10070d35e10SSpyridoula Gravani case dwarf::DW_ATOM_die_tag: 10170d35e10SSpyridoula Gravani case dwarf::DW_ATOM_type_flags: 102837c110cSSpyridoula Gravani if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && 103837c110cSSpyridoula Gravani !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || 104837c110cSSpyridoula Gravani FormValue.getForm() == dwarf::DW_FORM_sdata) 105837c110cSSpyridoula Gravani return false; 1060e6694d1SAdrian Prantl break; 107837c110cSSpyridoula Gravani default: 108837c110cSSpyridoula Gravani break; 109837c110cSSpyridoula Gravani } 110837c110cSSpyridoula Gravani } 111837c110cSSpyridoula Gravani return true; 112837c110cSSpyridoula Gravani } 113837c110cSSpyridoula Gravani 114f26a70a5SIgor Kudrin std::pair<uint64_t, dwarf::Tag> 115f26a70a5SIgor Kudrin AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) { 116f26a70a5SIgor Kudrin uint64_t DieOffset = dwarf::DW_INVALID_OFFSET; 11770d35e10SSpyridoula Gravani dwarf::Tag DieTag = dwarf::DW_TAG_null; 118322711f5SPavel Labath dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; 119837c110cSSpyridoula Gravani 120837c110cSSpyridoula Gravani for (auto Atom : getAtomsDesc()) { 121837c110cSSpyridoula Gravani DWARFFormValue FormValue(Atom.second); 122f26a70a5SIgor Kudrin FormValue.extractValue(AccelSection, HashDataOffset, FormParams); 123837c110cSSpyridoula Gravani switch (Atom.first) { 124837c110cSSpyridoula Gravani case dwarf::DW_ATOM_die_offset: 125837c110cSSpyridoula Gravani DieOffset = *FormValue.getAsUnsignedConstant(); 126837c110cSSpyridoula Gravani break; 12770d35e10SSpyridoula Gravani case dwarf::DW_ATOM_die_tag: 12870d35e10SSpyridoula Gravani DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); 12970d35e10SSpyridoula Gravani break; 130837c110cSSpyridoula Gravani default: 131837c110cSSpyridoula Gravani break; 132837c110cSSpyridoula Gravani } 133837c110cSSpyridoula Gravani } 13470d35e10SSpyridoula Gravani return {DieOffset, DieTag}; 135837c110cSSpyridoula Gravani } 136837c110cSSpyridoula Gravani 137394e8056SPavel Labath void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const { 138394e8056SPavel Labath DictScope HeaderScope(W, "Header"); 139394e8056SPavel Labath W.printHex("Magic", Magic); 140394e8056SPavel Labath W.printHex("Version", Version); 141394e8056SPavel Labath W.printHex("Hash function", HashFunction); 142394e8056SPavel Labath W.printNumber("Bucket count", BucketCount); 143394e8056SPavel Labath W.printNumber("Hashes count", HashCount); 144394e8056SPavel Labath W.printNumber("HeaderData length", HeaderDataLength); 145394e8056SPavel Labath } 146394e8056SPavel Labath 14747c3472cSPavel Labath Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset( 14847c3472cSPavel Labath Optional<DWARFFormValue> Value) const { 14947c3472cSPavel Labath if (!Value) 15047c3472cSPavel Labath return None; 15147c3472cSPavel Labath 15247c3472cSPavel Labath switch (Value->getForm()) { 15347c3472cSPavel Labath case dwarf::DW_FORM_ref1: 15447c3472cSPavel Labath case dwarf::DW_FORM_ref2: 15547c3472cSPavel Labath case dwarf::DW_FORM_ref4: 15647c3472cSPavel Labath case dwarf::DW_FORM_ref8: 15747c3472cSPavel Labath case dwarf::DW_FORM_ref_udata: 15847c3472cSPavel Labath return Value->getRawUValue() + DIEOffsetBase; 15947c3472cSPavel Labath default: 16047c3472cSPavel Labath return Value->getAsSectionOffset(); 16147c3472cSPavel Labath } 16247c3472cSPavel Labath } 16347c3472cSPavel Labath 164394e8056SPavel Labath bool AppleAcceleratorTable::dumpName(ScopedPrinter &W, 165394e8056SPavel Labath SmallVectorImpl<DWARFFormValue> &AtomForms, 166f26a70a5SIgor Kudrin uint64_t *DataOffset) const { 167322711f5SPavel Labath dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; 168f26a70a5SIgor Kudrin uint64_t NameOffset = *DataOffset; 169394e8056SPavel Labath if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) { 170394e8056SPavel Labath W.printString("Incorrectly terminated list."); 171394e8056SPavel Labath return false; 172394e8056SPavel Labath } 173f26a70a5SIgor Kudrin uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset); 174394e8056SPavel Labath if (!StringOffset) 175394e8056SPavel Labath return false; // End of list 176394e8056SPavel Labath 177394e8056SPavel Labath DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str()); 178f26a70a5SIgor Kudrin W.startLine() << format("String: 0x%08" PRIx64, StringOffset); 179394e8056SPavel Labath W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n"; 180394e8056SPavel Labath 181394e8056SPavel Labath unsigned NumData = AccelSection.getU32(DataOffset); 182394e8056SPavel Labath for (unsigned Data = 0; Data < NumData; ++Data) { 183394e8056SPavel Labath ListScope DataScope(W, ("Data " + Twine(Data)).str()); 184394e8056SPavel Labath unsigned i = 0; 185394e8056SPavel Labath for (auto &Atom : AtomForms) { 186327e7a16SJonas Devlieghere W.startLine() << format("Atom[%d]: ", i); 187327e7a16SJonas Devlieghere if (Atom.extractValue(AccelSection, DataOffset, FormParams)) { 188394e8056SPavel Labath Atom.dump(W.getOStream()); 189327e7a16SJonas Devlieghere if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) { 190327e7a16SJonas Devlieghere StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val); 191327e7a16SJonas Devlieghere if (!Str.empty()) 192327e7a16SJonas Devlieghere W.getOStream() << " (" << Str << ")"; 193327e7a16SJonas Devlieghere } 194327e7a16SJonas Devlieghere } else 195394e8056SPavel Labath W.getOStream() << "Error extracting the value"; 196394e8056SPavel Labath W.getOStream() << "\n"; 197327e7a16SJonas Devlieghere i++; 198394e8056SPavel Labath } 199394e8056SPavel Labath } 200394e8056SPavel Labath return true; // more entries follow 201394e8056SPavel Labath } 202394e8056SPavel Labath 2039b36fd25SPavel Labath LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { 20499fdb9d9SAdrian Prantl if (!IsValid) 20599fdb9d9SAdrian Prantl return; 20699fdb9d9SAdrian Prantl 207394e8056SPavel Labath ScopedPrinter W(OS); 20882af9438SZachary Turner 209394e8056SPavel Labath Hdr.dump(W); 210394e8056SPavel Labath 211394e8056SPavel Labath W.printNumber("DIE offset base", HdrData.DIEOffsetBase); 2123460957eSPavel Labath W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size())); 21382af9438SZachary Turner SmallVector<DWARFFormValue, 3> AtomForms; 214394e8056SPavel Labath { 215394e8056SPavel Labath ListScope AtomsScope(W, "Atoms"); 216394e8056SPavel Labath unsigned i = 0; 21782af9438SZachary Turner for (const auto &Atom : HdrData.Atoms) { 218394e8056SPavel Labath DictScope AtomScope(W, ("Atom " + Twine(i++)).str()); 219394e8056SPavel Labath W.startLine() << "Type: " << formatAtom(Atom.first) << '\n'; 2209025f955SPavel Labath W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n'; 22182af9438SZachary Turner AtomForms.push_back(DWARFFormValue(Atom.second)); 22282af9438SZachary Turner } 223394e8056SPavel Labath } 22482af9438SZachary Turner 22582af9438SZachary Turner // Now go through the actual tables and dump them. 226f26a70a5SIgor Kudrin uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; 227f26a70a5SIgor Kudrin uint64_t HashesBase = Offset + Hdr.BucketCount * 4; 228f26a70a5SIgor Kudrin uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; 22982af9438SZachary Turner 230394e8056SPavel Labath for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) { 23182af9438SZachary Turner unsigned Index = AccelSection.getU32(&Offset); 23282af9438SZachary Turner 233394e8056SPavel Labath ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); 23482af9438SZachary Turner if (Index == UINT32_MAX) { 235394e8056SPavel Labath W.printString("EMPTY"); 23682af9438SZachary Turner continue; 23782af9438SZachary Turner } 23882af9438SZachary Turner 239394e8056SPavel Labath for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { 240f26a70a5SIgor Kudrin uint64_t HashOffset = HashesBase + HashIdx*4; 241f26a70a5SIgor Kudrin uint64_t OffsetsOffset = OffsetsBase + HashIdx*4; 24282af9438SZachary Turner uint32_t Hash = AccelSection.getU32(&HashOffset); 24382af9438SZachary Turner 244394e8056SPavel Labath if (Hash % Hdr.BucketCount != Bucket) 24582af9438SZachary Turner break; 24682af9438SZachary Turner 247f26a70a5SIgor Kudrin uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); 248394e8056SPavel Labath ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str()); 24982af9438SZachary Turner if (!AccelSection.isValidOffset(DataOffset)) { 250394e8056SPavel Labath W.printString("Invalid section offset"); 25182af9438SZachary Turner continue; 25282af9438SZachary Turner } 253394e8056SPavel Labath while (dumpName(W, AtomForms, &DataOffset)) 254394e8056SPavel Labath /*empty*/; 25582af9438SZachary Turner } 25682af9438SZachary Turner } 25782af9438SZachary Turner } 25899fdb9d9SAdrian Prantl 259d99072bcSPavel Labath AppleAcceleratorTable::Entry::Entry( 260d99072bcSPavel Labath const AppleAcceleratorTable::HeaderData &HdrData) 261d99072bcSPavel Labath : HdrData(&HdrData) { 262d99072bcSPavel Labath Values.reserve(HdrData.Atoms.size()); 263d99072bcSPavel Labath for (const auto &Atom : HdrData.Atoms) 264d99072bcSPavel Labath Values.push_back(DWARFFormValue(Atom.second)); 265d99072bcSPavel Labath } 266d99072bcSPavel Labath 267d99072bcSPavel Labath void AppleAcceleratorTable::Entry::extract( 268f26a70a5SIgor Kudrin const AppleAcceleratorTable &AccelTable, uint64_t *Offset) { 269d99072bcSPavel Labath 270322711f5SPavel Labath dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0, 271d99072bcSPavel Labath dwarf::DwarfFormat::DWARF32}; 272d99072bcSPavel Labath for (auto &Atom : Values) 273d99072bcSPavel Labath Atom.extractValue(AccelTable.AccelSection, Offset, FormParams); 274d99072bcSPavel Labath } 275d99072bcSPavel Labath 276d99072bcSPavel Labath Optional<DWARFFormValue> 277d99072bcSPavel Labath AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const { 278d99072bcSPavel Labath assert(HdrData && "Dereferencing end iterator?"); 279d99072bcSPavel Labath assert(HdrData->Atoms.size() == Values.size()); 2808dc7b982SMark de Wever for (auto Tuple : zip_first(HdrData->Atoms, Values)) { 281d99072bcSPavel Labath if (std::get<0>(Tuple).first == Atom) 282d99072bcSPavel Labath return std::get<1>(Tuple); 283d99072bcSPavel Labath } 284d99072bcSPavel Labath return None; 285d99072bcSPavel Labath } 286d99072bcSPavel Labath 28747c3472cSPavel Labath Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const { 28847c3472cSPavel Labath return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset)); 289d99072bcSPavel Labath } 290d99072bcSPavel Labath 291d99072bcSPavel Labath Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const { 29247c3472cSPavel Labath return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset)); 293d99072bcSPavel Labath } 294d99072bcSPavel Labath 295d99072bcSPavel Labath Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const { 296d99072bcSPavel Labath Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag); 297d99072bcSPavel Labath if (!Tag) 298d99072bcSPavel Labath return None; 299d99072bcSPavel Labath if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant()) 300d99072bcSPavel Labath return dwarf::Tag(*Value); 301d99072bcSPavel Labath return None; 302d99072bcSPavel Labath } 303d99072bcSPavel Labath 3049b36fd25SPavel Labath AppleAcceleratorTable::ValueIterator::ValueIterator( 305f26a70a5SIgor Kudrin const AppleAcceleratorTable &AccelTable, uint64_t Offset) 306d99072bcSPavel Labath : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) { 30799fdb9d9SAdrian Prantl if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) 30899fdb9d9SAdrian Prantl return; 30999fdb9d9SAdrian Prantl 31099fdb9d9SAdrian Prantl // Read the first entry. 31199fdb9d9SAdrian Prantl NumData = AccelTable.AccelSection.getU32(&DataOffset); 31299fdb9d9SAdrian Prantl Next(); 31399fdb9d9SAdrian Prantl } 31499fdb9d9SAdrian Prantl 3159b36fd25SPavel Labath void AppleAcceleratorTable::ValueIterator::Next() { 31699fdb9d9SAdrian Prantl assert(NumData > 0 && "attempted to increment iterator past the end"); 31799fdb9d9SAdrian Prantl auto &AccelSection = AccelTable->AccelSection; 31899fdb9d9SAdrian Prantl if (Data >= NumData || 31999fdb9d9SAdrian Prantl !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { 32099fdb9d9SAdrian Prantl NumData = 0; 32159870af6SPavel Labath DataOffset = 0; 32299fdb9d9SAdrian Prantl return; 32399fdb9d9SAdrian Prantl } 324d99072bcSPavel Labath Current.extract(*AccelTable, &DataOffset); 32599fdb9d9SAdrian Prantl ++Data; 32699fdb9d9SAdrian Prantl } 32799fdb9d9SAdrian Prantl 3289b36fd25SPavel Labath iterator_range<AppleAcceleratorTable::ValueIterator> 3299b36fd25SPavel Labath AppleAcceleratorTable::equal_range(StringRef Key) const { 33099fdb9d9SAdrian Prantl if (!IsValid) 33199fdb9d9SAdrian Prantl return make_range(ValueIterator(), ValueIterator()); 33299fdb9d9SAdrian Prantl 33399fdb9d9SAdrian Prantl // Find the bucket. 33492ac9d3eSJonas Devlieghere unsigned HashValue = djbHash(Key); 335394e8056SPavel Labath unsigned Bucket = HashValue % Hdr.BucketCount; 336f26a70a5SIgor Kudrin uint64_t BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength; 337f26a70a5SIgor Kudrin uint64_t HashesBase = BucketBase + Hdr.BucketCount * 4; 338f26a70a5SIgor Kudrin uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; 33999fdb9d9SAdrian Prantl 340f26a70a5SIgor Kudrin uint64_t BucketOffset = BucketBase + Bucket * 4; 34199fdb9d9SAdrian Prantl unsigned Index = AccelSection.getU32(&BucketOffset); 34299fdb9d9SAdrian Prantl 34399fdb9d9SAdrian Prantl // Search through all hashes in the bucket. 344394e8056SPavel Labath for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { 345f26a70a5SIgor Kudrin uint64_t HashOffset = HashesBase + HashIdx * 4; 346f26a70a5SIgor Kudrin uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4; 34799fdb9d9SAdrian Prantl uint32_t Hash = AccelSection.getU32(&HashOffset); 34899fdb9d9SAdrian Prantl 349394e8056SPavel Labath if (Hash % Hdr.BucketCount != Bucket) 35099fdb9d9SAdrian Prantl // We are already in the next bucket. 35199fdb9d9SAdrian Prantl break; 35299fdb9d9SAdrian Prantl 353f26a70a5SIgor Kudrin uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); 354f26a70a5SIgor Kudrin uint64_t StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); 35599fdb9d9SAdrian Prantl if (!StringOffset) 35699fdb9d9SAdrian Prantl break; 35799fdb9d9SAdrian Prantl 35899fdb9d9SAdrian Prantl // Finally, compare the key. 35999fdb9d9SAdrian Prantl if (Key == StringSection.getCStr(&StringOffset)) 36099fdb9d9SAdrian Prantl return make_range({*this, DataOffset}, ValueIterator()); 36199fdb9d9SAdrian Prantl } 36299fdb9d9SAdrian Prantl return make_range(ValueIterator(), ValueIterator()); 36399fdb9d9SAdrian Prantl } 3643c9a918cSPavel Labath 3653c9a918cSPavel Labath void DWARFDebugNames::Header::dump(ScopedPrinter &W) const { 3663c9a918cSPavel Labath DictScope HeaderScope(W, "Header"); 3673c9a918cSPavel Labath W.printHex("Length", UnitLength); 3683c9a918cSPavel Labath W.printNumber("Version", Version); 3693c9a918cSPavel Labath W.printNumber("CU count", CompUnitCount); 3703c9a918cSPavel Labath W.printNumber("Local TU count", LocalTypeUnitCount); 3713c9a918cSPavel Labath W.printNumber("Foreign TU count", ForeignTypeUnitCount); 3723c9a918cSPavel Labath W.printNumber("Bucket count", BucketCount); 3733c9a918cSPavel Labath W.printNumber("Name count", NameCount); 3743c9a918cSPavel Labath W.printHex("Abbreviations table size", AbbrevTableSize); 3753c9a918cSPavel Labath W.startLine() << "Augmentation: '" << AugmentationString << "'\n"; 3763c9a918cSPavel Labath } 3773c9a918cSPavel Labath 378a364d599SFangrui Song Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, 379f26a70a5SIgor Kudrin uint64_t *Offset) { 380*16a0313eSIgor Kudrin uint64_t StartingOffset = *Offset; 381*16a0313eSIgor Kudrin // Check that we can read the unit length field. 382*16a0313eSIgor Kudrin if (!AS.isValidOffsetForDataOfSize(StartingOffset, 4)) 383*16a0313eSIgor Kudrin return createStringError(errc::illegal_byte_sequence, 384*16a0313eSIgor Kudrin "Section too small: cannot read header."); 385*16a0313eSIgor Kudrin UnitLength = AS.getU32(Offset); 386*16a0313eSIgor Kudrin if (UnitLength >= dwarf::DW_LENGTH_lo_reserved && 387*16a0313eSIgor Kudrin UnitLength != dwarf::DW_LENGTH_DWARF64) 388*16a0313eSIgor Kudrin return createStringError(errc::illegal_byte_sequence, 389*16a0313eSIgor Kudrin "Unsupported reserved unit length value"); 390*16a0313eSIgor Kudrin Format = (UnitLength == dwarf::DW_LENGTH_DWARF64) ? dwarf::DWARF64 391*16a0313eSIgor Kudrin : dwarf::DWARF32; 392*16a0313eSIgor Kudrin 39399960de7SIgor Kudrin // These fields are the same for 32-bit and 64-bit DWARF formats. 39499960de7SIgor Kudrin constexpr unsigned CommonHeaderSize = 2 + // Version 39599960de7SIgor Kudrin 2 + // Padding 39699960de7SIgor Kudrin 4 + // CU count 39799960de7SIgor Kudrin 4 + // Local TU count 39899960de7SIgor Kudrin 4 + // Foreign TU count 39999960de7SIgor Kudrin 4 + // Bucket count 40099960de7SIgor Kudrin 4 + // Name count 40199960de7SIgor Kudrin 4 + // Abbreviations table size 40299960de7SIgor Kudrin 4; // Augmentation string size 4033c9a918cSPavel Labath // Check that we can read the fixed-size part. 404*16a0313eSIgor Kudrin if (!AS.isValidOffsetForDataOfSize( 405*16a0313eSIgor Kudrin StartingOffset, 406*16a0313eSIgor Kudrin CommonHeaderSize + dwarf::getUnitLengthFieldByteSize(Format))) 407cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence, 408cba595daSVictor Leschuk "Section too small: cannot read header."); 409*16a0313eSIgor Kudrin if (Format == dwarf::DWARF64) 410*16a0313eSIgor Kudrin UnitLength = AS.getU64(Offset); 4113c9a918cSPavel Labath Version = AS.getU16(Offset); 4128306f55bSIgor Kudrin // Skip padding 4138306f55bSIgor Kudrin *Offset += 2; 4143c9a918cSPavel Labath CompUnitCount = AS.getU32(Offset); 4153c9a918cSPavel Labath LocalTypeUnitCount = AS.getU32(Offset); 4163c9a918cSPavel Labath ForeignTypeUnitCount = AS.getU32(Offset); 4173c9a918cSPavel Labath BucketCount = AS.getU32(Offset); 4183c9a918cSPavel Labath NameCount = AS.getU32(Offset); 4193c9a918cSPavel Labath AbbrevTableSize = AS.getU32(Offset); 420ea0f841cSPavel Labath AugmentationStringSize = alignTo(AS.getU32(Offset), 4); 4213c9a918cSPavel Labath 4223c9a918cSPavel Labath if (!AS.isValidOffsetForDataOfSize(*Offset, AugmentationStringSize)) 423cba595daSVictor Leschuk return createStringError( 424cba595daSVictor Leschuk errc::illegal_byte_sequence, 425cba595daSVictor Leschuk "Section too small: cannot read header augmentation."); 4263c9a918cSPavel Labath AugmentationString.resize(AugmentationStringSize); 4273c9a918cSPavel Labath AS.getU8(Offset, reinterpret_cast<uint8_t *>(AugmentationString.data()), 4283c9a918cSPavel Labath AugmentationStringSize); 4293c9a918cSPavel Labath return Error::success(); 4303c9a918cSPavel Labath } 4313c9a918cSPavel Labath 4323c9a918cSPavel Labath void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { 4333c9a918cSPavel Labath DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str()); 4349025f955SPavel Labath W.startLine() << formatv("Tag: {0}\n", Tag); 4353c9a918cSPavel Labath 4369025f955SPavel Labath for (const auto &Attr : Attributes) 4379025f955SPavel Labath W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form); 4383c9a918cSPavel Labath } 4393c9a918cSPavel Labath 4403c9a918cSPavel Labath static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() { 4413c9a918cSPavel Labath return {dwarf::Index(0), dwarf::Form(0)}; 4423c9a918cSPavel Labath } 4433c9a918cSPavel Labath 4443c9a918cSPavel Labath static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) { 4453c9a918cSPavel Labath return AE == sentinelAttrEnc(); 4463c9a918cSPavel Labath } 4473c9a918cSPavel Labath 4483c9a918cSPavel Labath static DWARFDebugNames::Abbrev sentinelAbbrev() { 4493c9a918cSPavel Labath return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {}); 4503c9a918cSPavel Labath } 4513c9a918cSPavel Labath 4523c9a918cSPavel Labath static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) { 4533c9a918cSPavel Labath return Abbr.Code == 0; 4543c9a918cSPavel Labath } 4553c9a918cSPavel Labath 4563c9a918cSPavel Labath DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() { 4573c9a918cSPavel Labath return sentinelAbbrev(); 4583c9a918cSPavel Labath } 4593c9a918cSPavel Labath 4603c9a918cSPavel Labath DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() { 4613c9a918cSPavel Labath return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {}); 4623c9a918cSPavel Labath } 4633c9a918cSPavel Labath 4643c9a918cSPavel Labath Expected<DWARFDebugNames::AttributeEncoding> 465f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) { 4663c9a918cSPavel Labath if (*Offset >= EntriesBase) { 467cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence, 468cba595daSVictor Leschuk "Incorrectly terminated abbreviation table."); 4693c9a918cSPavel Labath } 4703c9a918cSPavel Labath 4713c9a918cSPavel Labath uint32_t Index = Section.AccelSection.getULEB128(Offset); 4723c9a918cSPavel Labath uint32_t Form = Section.AccelSection.getULEB128(Offset); 4733c9a918cSPavel Labath return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form)); 4743c9a918cSPavel Labath } 4753c9a918cSPavel Labath 4763c9a918cSPavel Labath Expected<std::vector<DWARFDebugNames::AttributeEncoding>> 477f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) { 4783c9a918cSPavel Labath std::vector<AttributeEncoding> Result; 4793c9a918cSPavel Labath for (;;) { 4803c9a918cSPavel Labath auto AttrEncOr = extractAttributeEncoding(Offset); 4813c9a918cSPavel Labath if (!AttrEncOr) 4823c9a918cSPavel Labath return AttrEncOr.takeError(); 4833c9a918cSPavel Labath if (isSentinel(*AttrEncOr)) 4843c9a918cSPavel Labath return std::move(Result); 4853c9a918cSPavel Labath 4863c9a918cSPavel Labath Result.emplace_back(*AttrEncOr); 4873c9a918cSPavel Labath } 4883c9a918cSPavel Labath } 4893c9a918cSPavel Labath 4903c9a918cSPavel Labath Expected<DWARFDebugNames::Abbrev> 491f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) { 4923c9a918cSPavel Labath if (*Offset >= EntriesBase) { 493cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence, 494cba595daSVictor Leschuk "Incorrectly terminated abbreviation table."); 4953c9a918cSPavel Labath } 4963c9a918cSPavel Labath 4973c9a918cSPavel Labath uint32_t Code = Section.AccelSection.getULEB128(Offset); 4983c9a918cSPavel Labath if (Code == 0) 4993c9a918cSPavel Labath return sentinelAbbrev(); 5003c9a918cSPavel Labath 5013c9a918cSPavel Labath uint32_t Tag = Section.AccelSection.getULEB128(Offset); 5023c9a918cSPavel Labath auto AttrEncOr = extractAttributeEncodings(Offset); 5033c9a918cSPavel Labath if (!AttrEncOr) 5043c9a918cSPavel Labath return AttrEncOr.takeError(); 5053c9a918cSPavel Labath return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr)); 5063c9a918cSPavel Labath } 5073c9a918cSPavel Labath 5083c9a918cSPavel Labath Error DWARFDebugNames::NameIndex::extract() { 5093c9a918cSPavel Labath const DWARFDataExtractor &AS = Section.AccelSection; 510f26a70a5SIgor Kudrin uint64_t Offset = Base; 5113c9a918cSPavel Labath if (Error E = Hdr.extract(AS, &Offset)) 5123c9a918cSPavel Labath return E; 5133c9a918cSPavel Labath 514*16a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 5153c9a918cSPavel Labath CUsBase = Offset; 516*16a0313eSIgor Kudrin Offset += Hdr.CompUnitCount * SectionOffsetSize; 517*16a0313eSIgor Kudrin Offset += Hdr.LocalTypeUnitCount * SectionOffsetSize; 5183c9a918cSPavel Labath Offset += Hdr.ForeignTypeUnitCount * 8; 5193c9a918cSPavel Labath BucketsBase = Offset; 5203c9a918cSPavel Labath Offset += Hdr.BucketCount * 4; 5213c9a918cSPavel Labath HashesBase = Offset; 5223c9a918cSPavel Labath if (Hdr.BucketCount > 0) 5233c9a918cSPavel Labath Offset += Hdr.NameCount * 4; 5243c9a918cSPavel Labath StringOffsetsBase = Offset; 525*16a0313eSIgor Kudrin Offset += Hdr.NameCount * SectionOffsetSize; 5263c9a918cSPavel Labath EntryOffsetsBase = Offset; 527*16a0313eSIgor Kudrin Offset += Hdr.NameCount * SectionOffsetSize; 5283c9a918cSPavel Labath 5293c9a918cSPavel Labath if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize)) 530cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence, 531cba595daSVictor Leschuk "Section too small: cannot read abbreviations."); 5323c9a918cSPavel Labath 5333c9a918cSPavel Labath EntriesBase = Offset + Hdr.AbbrevTableSize; 5343c9a918cSPavel Labath 5353c9a918cSPavel Labath for (;;) { 5363c9a918cSPavel Labath auto AbbrevOr = extractAbbrev(&Offset); 5373c9a918cSPavel Labath if (!AbbrevOr) 5383c9a918cSPavel Labath return AbbrevOr.takeError(); 5393c9a918cSPavel Labath if (isSentinel(*AbbrevOr)) 5403c9a918cSPavel Labath return Error::success(); 5413c9a918cSPavel Labath 542cba595daSVictor Leschuk if (!Abbrevs.insert(std::move(*AbbrevOr)).second) 543cba595daSVictor Leschuk return createStringError(errc::invalid_argument, 544cba595daSVictor Leschuk "Duplicate abbreviation code."); 5453c9a918cSPavel Labath } 5463c9a918cSPavel Labath } 547a364d599SFangrui Song 548d99072bcSPavel Labath DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr) 549d99072bcSPavel Labath : NameIdx(&NameIdx), Abbr(&Abbr) { 5503c9a918cSPavel Labath // This merely creates form values. It is up to the caller 5513c9a918cSPavel Labath // (NameIndex::getEntry) to populate them. 5523c9a918cSPavel Labath Values.reserve(Abbr.Attributes.size()); 5533c9a918cSPavel Labath for (const auto &Attr : Abbr.Attributes) 5543c9a918cSPavel Labath Values.emplace_back(Attr.Form); 5553c9a918cSPavel Labath } 5563c9a918cSPavel Labath 557d99072bcSPavel Labath Optional<DWARFFormValue> 558d99072bcSPavel Labath DWARFDebugNames::Entry::lookup(dwarf::Index Index) const { 559d99072bcSPavel Labath assert(Abbr->Attributes.size() == Values.size()); 5608dc7b982SMark de Wever for (auto Tuple : zip_first(Abbr->Attributes, Values)) { 561d99072bcSPavel Labath if (std::get<0>(Tuple).Index == Index) 562d99072bcSPavel Labath return std::get<1>(Tuple); 563d99072bcSPavel Labath } 564d99072bcSPavel Labath return None; 565d99072bcSPavel Labath } 5663c9a918cSPavel Labath 56747c3472cSPavel Labath Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const { 568d99072bcSPavel Labath if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset)) 5692d1fc437SPavel Labath return Off->getAsReferenceUVal(); 570d99072bcSPavel Labath return None; 571d99072bcSPavel Labath } 572d99072bcSPavel Labath 573d99072bcSPavel Labath Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const { 574d99072bcSPavel Labath if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit)) 575d99072bcSPavel Labath return Off->getAsUnsignedConstant(); 57647c3472cSPavel Labath // In a per-CU index, the entries without a DW_IDX_compile_unit attribute 57747c3472cSPavel Labath // implicitly refer to the single CU. 57847c3472cSPavel Labath if (NameIdx->getCUCount() == 1) 57947c3472cSPavel Labath return 0; 580d99072bcSPavel Labath return None; 581d99072bcSPavel Labath } 582d99072bcSPavel Labath 583d99072bcSPavel Labath Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const { 584d99072bcSPavel Labath Optional<uint64_t> Index = getCUIndex(); 585d99072bcSPavel Labath if (!Index || *Index >= NameIdx->getCUCount()) 586d99072bcSPavel Labath return None; 587d99072bcSPavel Labath return NameIdx->getCUOffset(*Index); 588d99072bcSPavel Labath } 589d99072bcSPavel Labath 590d99072bcSPavel Labath void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { 591d99072bcSPavel Labath W.printHex("Abbrev", Abbr->Code); 5929025f955SPavel Labath W.startLine() << formatv("Tag: {0}\n", Abbr->Tag); 593d99072bcSPavel Labath assert(Abbr->Attributes.size() == Values.size()); 5948dc7b982SMark de Wever for (auto Tuple : zip_first(Abbr->Attributes, Values)) { 5959025f955SPavel Labath W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index); 596d99072bcSPavel Labath std::get<1>(Tuple).dump(W.getOStream()); 5973c9a918cSPavel Labath W.getOStream() << '\n'; 5983c9a918cSPavel Labath } 5993c9a918cSPavel Labath } 6003c9a918cSPavel Labath 6013c9a918cSPavel Labath char DWARFDebugNames::SentinelError::ID; 6023c9a918cSPavel Labath std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const { 6033c9a918cSPavel Labath return inconvertibleErrorCode(); 6043c9a918cSPavel Labath } 6053c9a918cSPavel Labath 606f26a70a5SIgor Kudrin uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const { 6073c9a918cSPavel Labath assert(CU < Hdr.CompUnitCount); 608*16a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 609*16a0313eSIgor Kudrin uint64_t Offset = CUsBase + SectionOffsetSize * CU; 610*16a0313eSIgor Kudrin return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); 6113c9a918cSPavel Labath } 6123c9a918cSPavel Labath 613f26a70a5SIgor Kudrin uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const { 6143c9a918cSPavel Labath assert(TU < Hdr.LocalTypeUnitCount); 615*16a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 616*16a0313eSIgor Kudrin uint64_t Offset = CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU); 617*16a0313eSIgor Kudrin return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); 6183c9a918cSPavel Labath } 6193c9a918cSPavel Labath 620d99072bcSPavel Labath uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const { 6213c9a918cSPavel Labath assert(TU < Hdr.ForeignTypeUnitCount); 622*16a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 623f26a70a5SIgor Kudrin uint64_t Offset = 624*16a0313eSIgor Kudrin CUsBase + 625*16a0313eSIgor Kudrin SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU; 6263c9a918cSPavel Labath return Section.AccelSection.getU64(&Offset); 6273c9a918cSPavel Labath } 6283c9a918cSPavel Labath 6293c9a918cSPavel Labath Expected<DWARFDebugNames::Entry> 630f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const { 6313c9a918cSPavel Labath const DWARFDataExtractor &AS = Section.AccelSection; 6323c9a918cSPavel Labath if (!AS.isValidOffset(*Offset)) 633cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence, 634cba595daSVictor Leschuk "Incorrectly terminated entry list."); 6353c9a918cSPavel Labath 6363c9a918cSPavel Labath uint32_t AbbrevCode = AS.getULEB128(Offset); 6373c9a918cSPavel Labath if (AbbrevCode == 0) 6383c9a918cSPavel Labath return make_error<SentinelError>(); 6393c9a918cSPavel Labath 6403c9a918cSPavel Labath const auto AbbrevIt = Abbrevs.find_as(AbbrevCode); 6413c9a918cSPavel Labath if (AbbrevIt == Abbrevs.end()) 642cba595daSVictor Leschuk return createStringError(errc::invalid_argument, "Invalid abbreviation."); 6433c9a918cSPavel Labath 644d99072bcSPavel Labath Entry E(*this, *AbbrevIt); 6453c9a918cSPavel Labath 646*16a0313eSIgor Kudrin dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format}; 6473c9a918cSPavel Labath for (auto &Value : E.Values) { 6483c9a918cSPavel Labath if (!Value.extractValue(AS, Offset, FormParams)) 649cba595daSVictor Leschuk return createStringError(errc::io_error, 650cba595daSVictor Leschuk "Error extracting index attribute values."); 6513c9a918cSPavel Labath } 6523c9a918cSPavel Labath return std::move(E); 6533c9a918cSPavel Labath } 6543c9a918cSPavel Labath 6553c9a918cSPavel Labath DWARFDebugNames::NameTableEntry 6563c9a918cSPavel Labath DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const { 6573c9a918cSPavel Labath assert(0 < Index && Index <= Hdr.NameCount); 658*16a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); 659*16a0313eSIgor Kudrin uint64_t StringOffsetOffset = 660*16a0313eSIgor Kudrin StringOffsetsBase + SectionOffsetSize * (Index - 1); 661*16a0313eSIgor Kudrin uint64_t EntryOffsetOffset = 662*16a0313eSIgor Kudrin EntryOffsetsBase + SectionOffsetSize * (Index - 1); 6633c9a918cSPavel Labath const DWARFDataExtractor &AS = Section.AccelSection; 6643c9a918cSPavel Labath 665*16a0313eSIgor Kudrin uint64_t StringOffset = 666*16a0313eSIgor Kudrin AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset); 667*16a0313eSIgor Kudrin uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize); 6683c9a918cSPavel Labath EntryOffset += EntriesBase; 669d6ca0639SPavel Labath return {Section.StringSection, Index, StringOffset, EntryOffset}; 6703c9a918cSPavel Labath } 6713c9a918cSPavel Labath 6723c9a918cSPavel Labath uint32_t 6733c9a918cSPavel Labath DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const { 6743c9a918cSPavel Labath assert(Bucket < Hdr.BucketCount); 675f26a70a5SIgor Kudrin uint64_t BucketOffset = BucketsBase + 4 * Bucket; 6763c9a918cSPavel Labath return Section.AccelSection.getU32(&BucketOffset); 6773c9a918cSPavel Labath } 6783c9a918cSPavel Labath 6793c9a918cSPavel Labath uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const { 6803c9a918cSPavel Labath assert(0 < Index && Index <= Hdr.NameCount); 681f26a70a5SIgor Kudrin uint64_t HashOffset = HashesBase + 4 * (Index - 1); 6823c9a918cSPavel Labath return Section.AccelSection.getU32(&HashOffset); 6833c9a918cSPavel Labath } 6843c9a918cSPavel Labath 6853c9a918cSPavel Labath // Returns true if we should continue scanning for entries, false if this is the 6863c9a918cSPavel Labath // last (sentinel) entry). In case of a parsing error we also return false, as 6873c9a918cSPavel Labath // it's not possible to recover this entry list (but the other lists may still 6883c9a918cSPavel Labath // parse OK). 6893c9a918cSPavel Labath bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W, 690f26a70a5SIgor Kudrin uint64_t *Offset) const { 691f26a70a5SIgor Kudrin uint64_t EntryId = *Offset; 6923c9a918cSPavel Labath auto EntryOr = getEntry(Offset); 6933c9a918cSPavel Labath if (!EntryOr) { 6943c9a918cSPavel Labath handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {}, 6953c9a918cSPavel Labath [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); }); 6963c9a918cSPavel Labath return false; 6973c9a918cSPavel Labath } 6983c9a918cSPavel Labath 6993c9a918cSPavel Labath DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str()); 7003c9a918cSPavel Labath EntryOr->dump(W); 7013c9a918cSPavel Labath return true; 7023c9a918cSPavel Labath } 7033c9a918cSPavel Labath 704d6ca0639SPavel Labath void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W, 705d6ca0639SPavel Labath const NameTableEntry &NTE, 7063c9a918cSPavel Labath Optional<uint32_t> Hash) const { 707d6ca0639SPavel Labath DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str()); 7083c9a918cSPavel Labath if (Hash) 7093c9a918cSPavel Labath W.printHex("Hash", *Hash); 7103c9a918cSPavel Labath 711f26a70a5SIgor Kudrin W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset()); 712d6ca0639SPavel Labath W.getOStream() << " \"" << NTE.getString() << "\"\n"; 7133c9a918cSPavel Labath 714f26a70a5SIgor Kudrin uint64_t EntryOffset = NTE.getEntryOffset(); 715d6ca0639SPavel Labath while (dumpEntry(W, &EntryOffset)) 7163c9a918cSPavel Labath /*empty*/; 7173c9a918cSPavel Labath } 7183c9a918cSPavel Labath 7193c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const { 7203c9a918cSPavel Labath ListScope CUScope(W, "Compilation Unit offsets"); 7213c9a918cSPavel Labath for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU) 722f26a70a5SIgor Kudrin W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU)); 7233c9a918cSPavel Labath } 7243c9a918cSPavel Labath 7253c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const { 7263c9a918cSPavel Labath if (Hdr.LocalTypeUnitCount == 0) 7273c9a918cSPavel Labath return; 7283c9a918cSPavel Labath 7293c9a918cSPavel Labath ListScope TUScope(W, "Local Type Unit offsets"); 7303c9a918cSPavel Labath for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU) 731f26a70a5SIgor Kudrin W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU, 732f26a70a5SIgor Kudrin getLocalTUOffset(TU)); 7333c9a918cSPavel Labath } 7343c9a918cSPavel Labath 7353c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const { 7363c9a918cSPavel Labath if (Hdr.ForeignTypeUnitCount == 0) 7373c9a918cSPavel Labath return; 7383c9a918cSPavel Labath 7393c9a918cSPavel Labath ListScope TUScope(W, "Foreign Type Unit signatures"); 7403c9a918cSPavel Labath for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) { 7413c9a918cSPavel Labath W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU, 742d99072bcSPavel Labath getForeignTUSignature(TU)); 7433c9a918cSPavel Labath } 7443c9a918cSPavel Labath } 7453c9a918cSPavel Labath 7463c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const { 7473c9a918cSPavel Labath ListScope AbbrevsScope(W, "Abbreviations"); 7483c9a918cSPavel Labath for (const auto &Abbr : Abbrevs) 7493c9a918cSPavel Labath Abbr.dump(W); 7503c9a918cSPavel Labath } 7513c9a918cSPavel Labath 7523c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W, 7533c9a918cSPavel Labath uint32_t Bucket) const { 7543c9a918cSPavel Labath ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); 7553c9a918cSPavel Labath uint32_t Index = getBucketArrayEntry(Bucket); 7563c9a918cSPavel Labath if (Index == 0) { 7573c9a918cSPavel Labath W.printString("EMPTY"); 7583c9a918cSPavel Labath return; 7593c9a918cSPavel Labath } 7603c9a918cSPavel Labath if (Index > Hdr.NameCount) { 7613c9a918cSPavel Labath W.printString("Name index is invalid"); 7623c9a918cSPavel Labath return; 7633c9a918cSPavel Labath } 7643c9a918cSPavel Labath 7653c9a918cSPavel Labath for (; Index <= Hdr.NameCount; ++Index) { 7663c9a918cSPavel Labath uint32_t Hash = getHashArrayEntry(Index); 7673c9a918cSPavel Labath if (Hash % Hdr.BucketCount != Bucket) 7683c9a918cSPavel Labath break; 7693c9a918cSPavel Labath 770d6ca0639SPavel Labath dumpName(W, getNameTableEntry(Index), Hash); 7713c9a918cSPavel Labath } 7723c9a918cSPavel Labath } 7733c9a918cSPavel Labath 7743c9a918cSPavel Labath LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const { 7753c9a918cSPavel Labath DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str()); 7763c9a918cSPavel Labath Hdr.dump(W); 7773c9a918cSPavel Labath dumpCUs(W); 7783c9a918cSPavel Labath dumpLocalTUs(W); 7793c9a918cSPavel Labath dumpForeignTUs(W); 7803c9a918cSPavel Labath dumpAbbreviations(W); 7813c9a918cSPavel Labath 7823c9a918cSPavel Labath if (Hdr.BucketCount > 0) { 7833c9a918cSPavel Labath for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) 7843c9a918cSPavel Labath dumpBucket(W, Bucket); 7853c9a918cSPavel Labath return; 7863c9a918cSPavel Labath } 7873c9a918cSPavel Labath 7883c9a918cSPavel Labath W.startLine() << "Hash table not present\n"; 789d6ca0639SPavel Labath for (NameTableEntry NTE : *this) 790d6ca0639SPavel Labath dumpName(W, NTE, None); 7913c9a918cSPavel Labath } 7923c9a918cSPavel Labath 793a364d599SFangrui Song Error DWARFDebugNames::extract() { 794f26a70a5SIgor Kudrin uint64_t Offset = 0; 7953c9a918cSPavel Labath while (AccelSection.isValidOffset(Offset)) { 7963c9a918cSPavel Labath NameIndex Next(*this, Offset); 797a364d599SFangrui Song if (Error E = Next.extract()) 7983c9a918cSPavel Labath return E; 7993c9a918cSPavel Labath Offset = Next.getNextUnitOffset(); 8003c9a918cSPavel Labath NameIndices.push_back(std::move(Next)); 8013c9a918cSPavel Labath } 8023c9a918cSPavel Labath return Error::success(); 8033c9a918cSPavel Labath } 8043c9a918cSPavel Labath 80580827f10SPavel Labath iterator_range<DWARFDebugNames::ValueIterator> 80680827f10SPavel Labath DWARFDebugNames::NameIndex::equal_range(StringRef Key) const { 80780827f10SPavel Labath return make_range(ValueIterator(*this, Key), ValueIterator()); 80880827f10SPavel Labath } 80980827f10SPavel Labath 8103c9a918cSPavel Labath LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const { 8113c9a918cSPavel Labath ScopedPrinter W(OS); 8123c9a918cSPavel Labath for (const NameIndex &NI : NameIndices) 8133c9a918cSPavel Labath NI.dump(W); 8143c9a918cSPavel Labath } 815d99072bcSPavel Labath 816f26a70a5SIgor Kudrin Optional<uint64_t> 817d99072bcSPavel Labath DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { 818d99072bcSPavel Labath const Header &Hdr = CurrentIndex->Hdr; 819d99072bcSPavel Labath if (Hdr.BucketCount == 0) { 820d99072bcSPavel Labath // No Hash Table, We need to search through all names in the Name Index. 821d6ca0639SPavel Labath for (NameTableEntry NTE : *CurrentIndex) { 822d6ca0639SPavel Labath if (NTE.getString() == Key) 823d6ca0639SPavel Labath return NTE.getEntryOffset(); 824d99072bcSPavel Labath } 825d99072bcSPavel Labath return None; 826d99072bcSPavel Labath } 827d99072bcSPavel Labath 828d99072bcSPavel Labath // The Name Index has a Hash Table, so use that to speed up the search. 829d99072bcSPavel Labath // Compute the Key Hash, if it has not been done already. 830d99072bcSPavel Labath if (!Hash) 831d99072bcSPavel Labath Hash = caseFoldingDjbHash(Key); 832d99072bcSPavel Labath uint32_t Bucket = *Hash % Hdr.BucketCount; 833d99072bcSPavel Labath uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket); 834d99072bcSPavel Labath if (Index == 0) 835d99072bcSPavel Labath return None; // Empty bucket 836d99072bcSPavel Labath 837d99072bcSPavel Labath for (; Index <= Hdr.NameCount; ++Index) { 838d99072bcSPavel Labath uint32_t Hash = CurrentIndex->getHashArrayEntry(Index); 839d99072bcSPavel Labath if (Hash % Hdr.BucketCount != Bucket) 840d99072bcSPavel Labath return None; // End of bucket 841d99072bcSPavel Labath 842d99072bcSPavel Labath NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); 843d6ca0639SPavel Labath if (NTE.getString() == Key) 844d6ca0639SPavel Labath return NTE.getEntryOffset(); 845d99072bcSPavel Labath } 846d99072bcSPavel Labath return None; 847d99072bcSPavel Labath } 848d99072bcSPavel Labath 849d99072bcSPavel Labath bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() { 850d99072bcSPavel Labath auto EntryOr = CurrentIndex->getEntry(&DataOffset); 851d99072bcSPavel Labath if (!EntryOr) { 852d99072bcSPavel Labath consumeError(EntryOr.takeError()); 853d99072bcSPavel Labath return false; 854d99072bcSPavel Labath } 855d99072bcSPavel Labath CurrentEntry = std::move(*EntryOr); 856d99072bcSPavel Labath return true; 857d99072bcSPavel Labath } 858d99072bcSPavel Labath 859d99072bcSPavel Labath bool DWARFDebugNames::ValueIterator::findInCurrentIndex() { 860f26a70a5SIgor Kudrin Optional<uint64_t> Offset = findEntryOffsetInCurrentIndex(); 861d99072bcSPavel Labath if (!Offset) 862d99072bcSPavel Labath return false; 863d99072bcSPavel Labath DataOffset = *Offset; 864d99072bcSPavel Labath return getEntryAtCurrentOffset(); 865d99072bcSPavel Labath } 866d99072bcSPavel Labath 867d99072bcSPavel Labath void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() { 868d99072bcSPavel Labath for (const NameIndex *End = CurrentIndex->Section.NameIndices.end(); 869d99072bcSPavel Labath CurrentIndex != End; ++CurrentIndex) { 870d99072bcSPavel Labath if (findInCurrentIndex()) 871d99072bcSPavel Labath return; 872d99072bcSPavel Labath } 873d99072bcSPavel Labath setEnd(); 874d99072bcSPavel Labath } 875d99072bcSPavel Labath 876d99072bcSPavel Labath void DWARFDebugNames::ValueIterator::next() { 877d99072bcSPavel Labath assert(CurrentIndex && "Incrementing an end() iterator?"); 878d99072bcSPavel Labath 879d99072bcSPavel Labath // First try the next entry in the current Index. 880d99072bcSPavel Labath if (getEntryAtCurrentOffset()) 881d99072bcSPavel Labath return; 882d99072bcSPavel Labath 88359870af6SPavel Labath // If we're a local iterator or we have reached the last Index, we're done. 88459870af6SPavel Labath if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) { 88580827f10SPavel Labath setEnd(); 88680827f10SPavel Labath return; 88780827f10SPavel Labath } 88880827f10SPavel Labath 88980827f10SPavel Labath // Otherwise, try the next index. 890d99072bcSPavel Labath ++CurrentIndex; 891d99072bcSPavel Labath searchFromStartOfCurrentIndex(); 892d99072bcSPavel Labath } 893d99072bcSPavel Labath 894d99072bcSPavel Labath DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable, 895d99072bcSPavel Labath StringRef Key) 896adcd0268SBenjamin Kramer : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false), 897adcd0268SBenjamin Kramer Key(std::string(Key)) { 898d99072bcSPavel Labath searchFromStartOfCurrentIndex(); 899d99072bcSPavel Labath } 900d99072bcSPavel Labath 90180827f10SPavel Labath DWARFDebugNames::ValueIterator::ValueIterator( 90280827f10SPavel Labath const DWARFDebugNames::NameIndex &NI, StringRef Key) 903adcd0268SBenjamin Kramer : CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) { 90480827f10SPavel Labath if (!findInCurrentIndex()) 90580827f10SPavel Labath setEnd(); 90680827f10SPavel Labath } 90780827f10SPavel Labath 908d99072bcSPavel Labath iterator_range<DWARFDebugNames::ValueIterator> 909d99072bcSPavel Labath DWARFDebugNames::equal_range(StringRef Key) const { 910d99072bcSPavel Labath if (NameIndices.empty()) 911d99072bcSPavel Labath return make_range(ValueIterator(), ValueIterator()); 912d99072bcSPavel Labath return make_range(ValueIterator(*this, Key), ValueIterator()); 913d99072bcSPavel Labath } 91480827f10SPavel Labath 91580827f10SPavel Labath const DWARFDebugNames::NameIndex * 916f26a70a5SIgor Kudrin DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) { 91780827f10SPavel Labath if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) { 91880827f10SPavel Labath for (const auto &NI : *this) { 91980827f10SPavel Labath for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU) 92080827f10SPavel Labath CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI); 92180827f10SPavel Labath } 92280827f10SPavel Labath } 92380827f10SPavel Labath return CUToNameIndex.lookup(CUOffset); 92480827f10SPavel Labath } 925