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/Support/Compiler.h"
1492ac9d3eSJonas Devlieghere #include "llvm/Support/DJB.h"
15cba595daSVictor Leschuk #include "llvm/Support/Errc.h"
1682af9438SZachary Turner #include "llvm/Support/Format.h"
179025f955SPavel Labath #include "llvm/Support/FormatVariadic.h"
183c9a918cSPavel Labath #include "llvm/Support/ScopedPrinter.h"
1982af9438SZachary Turner #include "llvm/Support/raw_ostream.h"
20e94042caSEugene Zelenko #include <cstddef>
21e94042caSEugene Zelenko #include <cstdint>
22e94042caSEugene Zelenko #include <utility>
2382af9438SZachary Turner
24e94042caSEugene Zelenko using namespace llvm;
2582af9438SZachary Turner
263c9a918cSPavel Labath namespace {
279025f955SPavel Labath struct Atom {
283c9a918cSPavel Labath unsigned Value;
293c9a918cSPavel Labath };
303c9a918cSPavel Labath
operator <<(raw_ostream & OS,const Atom & A)319025f955SPavel Labath static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {
329025f955SPavel Labath StringRef Str = dwarf::AtomTypeString(A.Value);
333c9a918cSPavel Labath if (!Str.empty())
343c9a918cSPavel Labath return OS << Str;
359025f955SPavel Labath return OS << "DW_ATOM_unknown_" << format("%x", A.Value);
363c9a918cSPavel Labath }
373c9a918cSPavel Labath } // namespace
383c9a918cSPavel Labath
formatAtom(unsigned Atom)399025f955SPavel Labath static Atom formatAtom(unsigned Atom) { return {Atom}; }
403c9a918cSPavel Labath
413c9a918cSPavel Labath DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
423c9a918cSPavel Labath
extract()43a364d599SFangrui Song Error AppleAcceleratorTable::extract() {
44f26a70a5SIgor Kudrin uint64_t Offset = 0;
4582af9438SZachary Turner
4682af9438SZachary Turner // Check that we can at least read the header.
4782af9438SZachary Turner if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4))
48cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence,
49cba595daSVictor Leschuk "Section too small: cannot read header.");
5082af9438SZachary Turner
5182af9438SZachary Turner Hdr.Magic = AccelSection.getU32(&Offset);
5282af9438SZachary Turner Hdr.Version = AccelSection.getU16(&Offset);
5382af9438SZachary Turner Hdr.HashFunction = AccelSection.getU16(&Offset);
54394e8056SPavel Labath Hdr.BucketCount = AccelSection.getU32(&Offset);
55394e8056SPavel Labath Hdr.HashCount = AccelSection.getU32(&Offset);
5682af9438SZachary Turner Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
5782af9438SZachary Turner
5882af9438SZachary Turner // Check that we can read all the hashes and offsets from the
5982af9438SZachary Turner // section (see SourceLevelDebugging.rst for the structure of the index).
60ba915897SJonas Devlieghere // We need to substract one because we're checking for an *offset* which is
61ba915897SJonas Devlieghere // equal to the size for an empty table and hence pointer after the section.
6282af9438SZachary Turner if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
63394e8056SPavel Labath Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1))
64cba595daSVictor Leschuk return createStringError(
65cba595daSVictor Leschuk errc::illegal_byte_sequence,
66cba595daSVictor Leschuk "Section too small: cannot read buckets and hashes.");
6782af9438SZachary Turner
6882af9438SZachary Turner HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
6982af9438SZachary Turner uint32_t NumAtoms = AccelSection.getU32(&Offset);
7082af9438SZachary Turner
7182af9438SZachary Turner for (unsigned i = 0; i < NumAtoms; ++i) {
7282af9438SZachary Turner uint16_t AtomType = AccelSection.getU16(&Offset);
736c273763SGreg Clayton auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
7482af9438SZachary Turner HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
7582af9438SZachary Turner }
7682af9438SZachary Turner
7799fdb9d9SAdrian Prantl IsValid = true;
78ba915897SJonas Devlieghere return Error::success();
7982af9438SZachary Turner }
8082af9438SZachary Turner
getNumBuckets()81394e8056SPavel Labath uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; }
getNumHashes()82394e8056SPavel Labath uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; }
getSizeHdr()839b36fd25SPavel Labath uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
getHeaderDataLength()849b36fd25SPavel Labath uint32_t AppleAcceleratorTable::getHeaderDataLength() {
85e41823bbSSpyridoula Gravani return Hdr.HeaderDataLength;
86e41823bbSSpyridoula Gravani }
87e41823bbSSpyridoula Gravani
889b36fd25SPavel Labath ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
899b36fd25SPavel Labath AppleAcceleratorTable::HeaderData::Form>>
getAtomsDesc()909b36fd25SPavel Labath AppleAcceleratorTable::getAtomsDesc() {
91837c110cSSpyridoula Gravani return HdrData.Atoms;
92837c110cSSpyridoula Gravani }
93837c110cSSpyridoula Gravani
validateForms()949b36fd25SPavel Labath bool AppleAcceleratorTable::validateForms() {
95837c110cSSpyridoula Gravani for (auto Atom : getAtomsDesc()) {
96837c110cSSpyridoula Gravani DWARFFormValue FormValue(Atom.second);
97837c110cSSpyridoula Gravani switch (Atom.first) {
98837c110cSSpyridoula Gravani case dwarf::DW_ATOM_die_offset:
9970d35e10SSpyridoula Gravani case dwarf::DW_ATOM_die_tag:
10070d35e10SSpyridoula Gravani case dwarf::DW_ATOM_type_flags:
101837c110cSSpyridoula Gravani if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
102837c110cSSpyridoula Gravani !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
103837c110cSSpyridoula Gravani FormValue.getForm() == dwarf::DW_FORM_sdata)
104837c110cSSpyridoula Gravani return false;
1050e6694d1SAdrian Prantl break;
106837c110cSSpyridoula Gravani default:
107837c110cSSpyridoula Gravani break;
108837c110cSSpyridoula Gravani }
109837c110cSSpyridoula Gravani }
110837c110cSSpyridoula Gravani return true;
111837c110cSSpyridoula Gravani }
112837c110cSSpyridoula Gravani
113f26a70a5SIgor Kudrin std::pair<uint64_t, dwarf::Tag>
readAtoms(uint64_t * HashDataOffset)114f26a70a5SIgor Kudrin AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) {
115f26a70a5SIgor Kudrin uint64_t DieOffset = dwarf::DW_INVALID_OFFSET;
11670d35e10SSpyridoula Gravani dwarf::Tag DieTag = dwarf::DW_TAG_null;
117322711f5SPavel Labath dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
118837c110cSSpyridoula Gravani
119837c110cSSpyridoula Gravani for (auto Atom : getAtomsDesc()) {
120837c110cSSpyridoula Gravani DWARFFormValue FormValue(Atom.second);
121f26a70a5SIgor Kudrin FormValue.extractValue(AccelSection, HashDataOffset, FormParams);
122837c110cSSpyridoula Gravani switch (Atom.first) {
123837c110cSSpyridoula Gravani case dwarf::DW_ATOM_die_offset:
124837c110cSSpyridoula Gravani DieOffset = *FormValue.getAsUnsignedConstant();
125837c110cSSpyridoula Gravani break;
12670d35e10SSpyridoula Gravani case dwarf::DW_ATOM_die_tag:
12770d35e10SSpyridoula Gravani DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
12870d35e10SSpyridoula Gravani break;
129837c110cSSpyridoula Gravani default:
130837c110cSSpyridoula Gravani break;
131837c110cSSpyridoula Gravani }
132837c110cSSpyridoula Gravani }
13370d35e10SSpyridoula Gravani return {DieOffset, DieTag};
134837c110cSSpyridoula Gravani }
135837c110cSSpyridoula Gravani
dump(ScopedPrinter & W) const136394e8056SPavel Labath void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const {
137394e8056SPavel Labath DictScope HeaderScope(W, "Header");
138394e8056SPavel Labath W.printHex("Magic", Magic);
139394e8056SPavel Labath W.printHex("Version", Version);
140394e8056SPavel Labath W.printHex("Hash function", HashFunction);
141394e8056SPavel Labath W.printNumber("Bucket count", BucketCount);
142394e8056SPavel Labath W.printNumber("Hashes count", HashCount);
143394e8056SPavel Labath W.printNumber("HeaderData length", HeaderDataLength);
144394e8056SPavel Labath }
145394e8056SPavel Labath
extractOffset(Optional<DWARFFormValue> Value) const14647c3472cSPavel Labath Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset(
14747c3472cSPavel Labath Optional<DWARFFormValue> Value) const {
14847c3472cSPavel Labath if (!Value)
14947c3472cSPavel Labath return None;
15047c3472cSPavel Labath
15147c3472cSPavel Labath switch (Value->getForm()) {
15247c3472cSPavel Labath case dwarf::DW_FORM_ref1:
15347c3472cSPavel Labath case dwarf::DW_FORM_ref2:
15447c3472cSPavel Labath case dwarf::DW_FORM_ref4:
15547c3472cSPavel Labath case dwarf::DW_FORM_ref8:
15647c3472cSPavel Labath case dwarf::DW_FORM_ref_udata:
15747c3472cSPavel Labath return Value->getRawUValue() + DIEOffsetBase;
15847c3472cSPavel Labath default:
15947c3472cSPavel Labath return Value->getAsSectionOffset();
16047c3472cSPavel Labath }
16147c3472cSPavel Labath }
16247c3472cSPavel Labath
dumpName(ScopedPrinter & W,SmallVectorImpl<DWARFFormValue> & AtomForms,uint64_t * DataOffset) const163394e8056SPavel Labath bool AppleAcceleratorTable::dumpName(ScopedPrinter &W,
164394e8056SPavel Labath SmallVectorImpl<DWARFFormValue> &AtomForms,
165f26a70a5SIgor Kudrin uint64_t *DataOffset) const {
166322711f5SPavel Labath dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
167f26a70a5SIgor Kudrin uint64_t NameOffset = *DataOffset;
168394e8056SPavel Labath if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) {
169394e8056SPavel Labath W.printString("Incorrectly terminated list.");
170394e8056SPavel Labath return false;
171394e8056SPavel Labath }
172f26a70a5SIgor Kudrin uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset);
173394e8056SPavel Labath if (!StringOffset)
174394e8056SPavel Labath return false; // End of list
175394e8056SPavel Labath
176394e8056SPavel Labath DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str());
177f26a70a5SIgor Kudrin W.startLine() << format("String: 0x%08" PRIx64, StringOffset);
178394e8056SPavel Labath W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n";
179394e8056SPavel Labath
180394e8056SPavel Labath unsigned NumData = AccelSection.getU32(DataOffset);
181394e8056SPavel Labath for (unsigned Data = 0; Data < NumData; ++Data) {
182394e8056SPavel Labath ListScope DataScope(W, ("Data " + Twine(Data)).str());
183394e8056SPavel Labath unsigned i = 0;
184394e8056SPavel Labath for (auto &Atom : AtomForms) {
185327e7a16SJonas Devlieghere W.startLine() << format("Atom[%d]: ", i);
186327e7a16SJonas Devlieghere if (Atom.extractValue(AccelSection, DataOffset, FormParams)) {
187394e8056SPavel Labath Atom.dump(W.getOStream());
188327e7a16SJonas Devlieghere if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) {
189327e7a16SJonas Devlieghere StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val);
190327e7a16SJonas Devlieghere if (!Str.empty())
191327e7a16SJonas Devlieghere W.getOStream() << " (" << Str << ")";
192327e7a16SJonas Devlieghere }
193327e7a16SJonas Devlieghere } else
194394e8056SPavel Labath W.getOStream() << "Error extracting the value";
195394e8056SPavel Labath W.getOStream() << "\n";
196327e7a16SJonas Devlieghere i++;
197394e8056SPavel Labath }
198394e8056SPavel Labath }
199394e8056SPavel Labath return true; // more entries follow
200394e8056SPavel Labath }
201394e8056SPavel Labath
dump(raw_ostream & OS) const2029b36fd25SPavel Labath LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
20399fdb9d9SAdrian Prantl if (!IsValid)
20499fdb9d9SAdrian Prantl return;
20599fdb9d9SAdrian Prantl
206394e8056SPavel Labath ScopedPrinter W(OS);
20782af9438SZachary Turner
208394e8056SPavel Labath Hdr.dump(W);
209394e8056SPavel Labath
210394e8056SPavel Labath W.printNumber("DIE offset base", HdrData.DIEOffsetBase);
2113460957eSPavel Labath W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size()));
21282af9438SZachary Turner SmallVector<DWARFFormValue, 3> AtomForms;
213394e8056SPavel Labath {
214394e8056SPavel Labath ListScope AtomsScope(W, "Atoms");
215394e8056SPavel Labath unsigned i = 0;
21682af9438SZachary Turner for (const auto &Atom : HdrData.Atoms) {
217394e8056SPavel Labath DictScope AtomScope(W, ("Atom " + Twine(i++)).str());
218394e8056SPavel Labath W.startLine() << "Type: " << formatAtom(Atom.first) << '\n';
2199025f955SPavel Labath W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n';
22082af9438SZachary Turner AtomForms.push_back(DWARFFormValue(Atom.second));
22182af9438SZachary Turner }
222394e8056SPavel Labath }
22382af9438SZachary Turner
22482af9438SZachary Turner // Now go through the actual tables and dump them.
225f26a70a5SIgor Kudrin uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
226f26a70a5SIgor Kudrin uint64_t HashesBase = Offset + Hdr.BucketCount * 4;
227f26a70a5SIgor Kudrin uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;
22882af9438SZachary Turner
229394e8056SPavel Labath for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) {
23082af9438SZachary Turner unsigned Index = AccelSection.getU32(&Offset);
23182af9438SZachary Turner
232394e8056SPavel Labath ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
23382af9438SZachary Turner if (Index == UINT32_MAX) {
234394e8056SPavel Labath W.printString("EMPTY");
23582af9438SZachary Turner continue;
23682af9438SZachary Turner }
23782af9438SZachary Turner
238394e8056SPavel Labath for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
239f26a70a5SIgor Kudrin uint64_t HashOffset = HashesBase + HashIdx*4;
240f26a70a5SIgor Kudrin uint64_t OffsetsOffset = OffsetsBase + HashIdx*4;
24182af9438SZachary Turner uint32_t Hash = AccelSection.getU32(&HashOffset);
24282af9438SZachary Turner
243394e8056SPavel Labath if (Hash % Hdr.BucketCount != Bucket)
24482af9438SZachary Turner break;
24582af9438SZachary Turner
246f26a70a5SIgor Kudrin uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);
247394e8056SPavel Labath ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str());
24882af9438SZachary Turner if (!AccelSection.isValidOffset(DataOffset)) {
249394e8056SPavel Labath W.printString("Invalid section offset");
25082af9438SZachary Turner continue;
25182af9438SZachary Turner }
252394e8056SPavel Labath while (dumpName(W, AtomForms, &DataOffset))
253394e8056SPavel Labath /*empty*/;
25482af9438SZachary Turner }
25582af9438SZachary Turner }
25682af9438SZachary Turner }
25799fdb9d9SAdrian Prantl
Entry(const AppleAcceleratorTable::HeaderData & HdrData)258d99072bcSPavel Labath AppleAcceleratorTable::Entry::Entry(
259d99072bcSPavel Labath const AppleAcceleratorTable::HeaderData &HdrData)
260d99072bcSPavel Labath : HdrData(&HdrData) {
261d99072bcSPavel Labath Values.reserve(HdrData.Atoms.size());
262d99072bcSPavel Labath for (const auto &Atom : HdrData.Atoms)
263d99072bcSPavel Labath Values.push_back(DWARFFormValue(Atom.second));
264d99072bcSPavel Labath }
265d99072bcSPavel Labath
extract(const AppleAcceleratorTable & AccelTable,uint64_t * Offset)266d99072bcSPavel Labath void AppleAcceleratorTable::Entry::extract(
267f26a70a5SIgor Kudrin const AppleAcceleratorTable &AccelTable, uint64_t *Offset) {
268d99072bcSPavel Labath
269322711f5SPavel Labath dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0,
270d99072bcSPavel Labath dwarf::DwarfFormat::DWARF32};
271d99072bcSPavel Labath for (auto &Atom : Values)
272d99072bcSPavel Labath Atom.extractValue(AccelTable.AccelSection, Offset, FormParams);
273d99072bcSPavel Labath }
274d99072bcSPavel Labath
275d99072bcSPavel Labath Optional<DWARFFormValue>
lookup(HeaderData::AtomType Atom) const276d99072bcSPavel Labath AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const {
277d99072bcSPavel Labath assert(HdrData && "Dereferencing end iterator?");
278d99072bcSPavel Labath assert(HdrData->Atoms.size() == Values.size());
2798dc7b982SMark de Wever for (auto Tuple : zip_first(HdrData->Atoms, Values)) {
280d99072bcSPavel Labath if (std::get<0>(Tuple).first == Atom)
281d99072bcSPavel Labath return std::get<1>(Tuple);
282d99072bcSPavel Labath }
283d99072bcSPavel Labath return None;
284d99072bcSPavel Labath }
285d99072bcSPavel Labath
getDIESectionOffset() const28647c3472cSPavel Labath Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const {
28747c3472cSPavel Labath return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset));
288d99072bcSPavel Labath }
289d99072bcSPavel Labath
getCUOffset() const290d99072bcSPavel Labath Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
29147c3472cSPavel Labath return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset));
292d99072bcSPavel Labath }
293d99072bcSPavel Labath
getTag() const294d99072bcSPavel Labath Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {
295d99072bcSPavel Labath Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);
296d99072bcSPavel Labath if (!Tag)
297d99072bcSPavel Labath return None;
298d99072bcSPavel Labath if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant())
299d99072bcSPavel Labath return dwarf::Tag(*Value);
300d99072bcSPavel Labath return None;
301d99072bcSPavel Labath }
302d99072bcSPavel Labath
ValueIterator(const AppleAcceleratorTable & AccelTable,uint64_t Offset)3039b36fd25SPavel Labath AppleAcceleratorTable::ValueIterator::ValueIterator(
304f26a70a5SIgor Kudrin const AppleAcceleratorTable &AccelTable, uint64_t Offset)
305d99072bcSPavel Labath : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) {
30699fdb9d9SAdrian Prantl if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
30799fdb9d9SAdrian Prantl return;
30899fdb9d9SAdrian Prantl
30999fdb9d9SAdrian Prantl // Read the first entry.
31099fdb9d9SAdrian Prantl NumData = AccelTable.AccelSection.getU32(&DataOffset);
31199fdb9d9SAdrian Prantl Next();
31299fdb9d9SAdrian Prantl }
31399fdb9d9SAdrian Prantl
Next()3149b36fd25SPavel Labath void AppleAcceleratorTable::ValueIterator::Next() {
31599fdb9d9SAdrian Prantl assert(NumData > 0 && "attempted to increment iterator past the end");
31699fdb9d9SAdrian Prantl auto &AccelSection = AccelTable->AccelSection;
31799fdb9d9SAdrian Prantl if (Data >= NumData ||
31899fdb9d9SAdrian Prantl !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
31999fdb9d9SAdrian Prantl NumData = 0;
32059870af6SPavel Labath DataOffset = 0;
32199fdb9d9SAdrian Prantl return;
32299fdb9d9SAdrian Prantl }
323d99072bcSPavel Labath Current.extract(*AccelTable, &DataOffset);
32499fdb9d9SAdrian Prantl ++Data;
32599fdb9d9SAdrian Prantl }
32699fdb9d9SAdrian Prantl
3279b36fd25SPavel Labath iterator_range<AppleAcceleratorTable::ValueIterator>
equal_range(StringRef Key) const3289b36fd25SPavel Labath AppleAcceleratorTable::equal_range(StringRef Key) const {
32999fdb9d9SAdrian Prantl if (!IsValid)
33099fdb9d9SAdrian Prantl return make_range(ValueIterator(), ValueIterator());
33199fdb9d9SAdrian Prantl
33299fdb9d9SAdrian Prantl // Find the bucket.
33392ac9d3eSJonas Devlieghere unsigned HashValue = djbHash(Key);
334394e8056SPavel Labath unsigned Bucket = HashValue % Hdr.BucketCount;
335f26a70a5SIgor Kudrin uint64_t BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
336f26a70a5SIgor Kudrin uint64_t HashesBase = BucketBase + Hdr.BucketCount * 4;
337f26a70a5SIgor Kudrin uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;
33899fdb9d9SAdrian Prantl
339f26a70a5SIgor Kudrin uint64_t BucketOffset = BucketBase + Bucket * 4;
34099fdb9d9SAdrian Prantl unsigned Index = AccelSection.getU32(&BucketOffset);
34199fdb9d9SAdrian Prantl
34299fdb9d9SAdrian Prantl // Search through all hashes in the bucket.
343394e8056SPavel Labath for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
344f26a70a5SIgor Kudrin uint64_t HashOffset = HashesBase + HashIdx * 4;
345f26a70a5SIgor Kudrin uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4;
34699fdb9d9SAdrian Prantl uint32_t Hash = AccelSection.getU32(&HashOffset);
34799fdb9d9SAdrian Prantl
348394e8056SPavel Labath if (Hash % Hdr.BucketCount != Bucket)
34999fdb9d9SAdrian Prantl // We are already in the next bucket.
35099fdb9d9SAdrian Prantl break;
35199fdb9d9SAdrian Prantl
352f26a70a5SIgor Kudrin uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);
353f26a70a5SIgor Kudrin uint64_t StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
35499fdb9d9SAdrian Prantl if (!StringOffset)
35599fdb9d9SAdrian Prantl break;
35699fdb9d9SAdrian Prantl
35799fdb9d9SAdrian Prantl // Finally, compare the key.
35899fdb9d9SAdrian Prantl if (Key == StringSection.getCStr(&StringOffset))
35999fdb9d9SAdrian Prantl return make_range({*this, DataOffset}, ValueIterator());
36099fdb9d9SAdrian Prantl }
36199fdb9d9SAdrian Prantl return make_range(ValueIterator(), ValueIterator());
36299fdb9d9SAdrian Prantl }
3633c9a918cSPavel Labath
dump(ScopedPrinter & W) const3643c9a918cSPavel Labath void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
3653c9a918cSPavel Labath DictScope HeaderScope(W, "Header");
3663c9a918cSPavel Labath W.printHex("Length", UnitLength);
3676aed60c0SIgor Kudrin W.printString("Format", dwarf::FormatString(Format));
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
extract(const DWARFDataExtractor & AS,uint64_t * Offset)378a364d599SFangrui Song Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
379f26a70a5SIgor Kudrin uint64_t *Offset) {
380dba683ccSPavel Labath auto HeaderError = [Offset = *Offset](Error E) {
38116a0313eSIgor Kudrin return createStringError(errc::illegal_byte_sequence,
382dba683ccSPavel Labath "parsing .debug_names header at 0x%" PRIx64 ": %s",
383dba683ccSPavel Labath Offset, toString(std::move(E)).c_str());
384dba683ccSPavel Labath };
38516a0313eSIgor Kudrin
386dba683ccSPavel Labath DataExtractor::Cursor C(*Offset);
387dba683ccSPavel Labath std::tie(UnitLength, Format) = AS.getInitialLength(C);
3883c9a918cSPavel Labath
389dba683ccSPavel Labath Version = AS.getU16(C);
390dba683ccSPavel Labath AS.skip(C, 2); // padding
391dba683ccSPavel Labath CompUnitCount = AS.getU32(C);
392dba683ccSPavel Labath LocalTypeUnitCount = AS.getU32(C);
393dba683ccSPavel Labath ForeignTypeUnitCount = AS.getU32(C);
394dba683ccSPavel Labath BucketCount = AS.getU32(C);
395dba683ccSPavel Labath NameCount = AS.getU32(C);
396dba683ccSPavel Labath AbbrevTableSize = AS.getU32(C);
397dba683ccSPavel Labath AugmentationStringSize = alignTo(AS.getU32(C), 4);
398dba683ccSPavel Labath
399dba683ccSPavel Labath if (!C)
400dba683ccSPavel Labath return HeaderError(C.takeError());
401dba683ccSPavel Labath
402dba683ccSPavel Labath if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize))
403dba683ccSPavel Labath return HeaderError(createStringError(errc::illegal_byte_sequence,
404dba683ccSPavel Labath "cannot read header augmentation"));
4053c9a918cSPavel Labath AugmentationString.resize(AugmentationStringSize);
406dba683ccSPavel Labath AS.getU8(C, reinterpret_cast<uint8_t *>(AugmentationString.data()),
4073c9a918cSPavel Labath AugmentationStringSize);
408dba683ccSPavel Labath *Offset = C.tell();
409dba683ccSPavel Labath return C.takeError();
4103c9a918cSPavel Labath }
4113c9a918cSPavel Labath
dump(ScopedPrinter & W) const4123c9a918cSPavel Labath void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {
4133c9a918cSPavel Labath DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());
4149025f955SPavel Labath W.startLine() << formatv("Tag: {0}\n", Tag);
4153c9a918cSPavel Labath
4169025f955SPavel Labath for (const auto &Attr : Attributes)
4179025f955SPavel Labath W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form);
4183c9a918cSPavel Labath }
4193c9a918cSPavel Labath
sentinelAttrEnc()4203c9a918cSPavel Labath static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
4213c9a918cSPavel Labath return {dwarf::Index(0), dwarf::Form(0)};
4223c9a918cSPavel Labath }
4233c9a918cSPavel Labath
isSentinel(const DWARFDebugNames::AttributeEncoding & AE)4243c9a918cSPavel Labath static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
4253c9a918cSPavel Labath return AE == sentinelAttrEnc();
4263c9a918cSPavel Labath }
4273c9a918cSPavel Labath
sentinelAbbrev()4283c9a918cSPavel Labath static DWARFDebugNames::Abbrev sentinelAbbrev() {
4293c9a918cSPavel Labath return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
4303c9a918cSPavel Labath }
4313c9a918cSPavel Labath
isSentinel(const DWARFDebugNames::Abbrev & Abbr)4323c9a918cSPavel Labath static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
4333c9a918cSPavel Labath return Abbr.Code == 0;
4343c9a918cSPavel Labath }
4353c9a918cSPavel Labath
getEmptyKey()4363c9a918cSPavel Labath DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
4373c9a918cSPavel Labath return sentinelAbbrev();
4383c9a918cSPavel Labath }
4393c9a918cSPavel Labath
getTombstoneKey()4403c9a918cSPavel Labath DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
4413c9a918cSPavel Labath return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
4423c9a918cSPavel Labath }
4433c9a918cSPavel Labath
4443c9a918cSPavel Labath Expected<DWARFDebugNames::AttributeEncoding>
extractAttributeEncoding(uint64_t * Offset)445f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) {
4463c9a918cSPavel Labath if (*Offset >= EntriesBase) {
447cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence,
448cba595daSVictor Leschuk "Incorrectly terminated abbreviation table.");
4493c9a918cSPavel Labath }
4503c9a918cSPavel Labath
4513c9a918cSPavel Labath uint32_t Index = Section.AccelSection.getULEB128(Offset);
4523c9a918cSPavel Labath uint32_t Form = Section.AccelSection.getULEB128(Offset);
4533c9a918cSPavel Labath return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));
4543c9a918cSPavel Labath }
4553c9a918cSPavel Labath
4563c9a918cSPavel Labath Expected<std::vector<DWARFDebugNames::AttributeEncoding>>
extractAttributeEncodings(uint64_t * Offset)457f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) {
4583c9a918cSPavel Labath std::vector<AttributeEncoding> Result;
4593c9a918cSPavel Labath for (;;) {
4603c9a918cSPavel Labath auto AttrEncOr = extractAttributeEncoding(Offset);
4613c9a918cSPavel Labath if (!AttrEncOr)
4623c9a918cSPavel Labath return AttrEncOr.takeError();
4633c9a918cSPavel Labath if (isSentinel(*AttrEncOr))
464c55cf4afSBill Wendling return std::move(Result);
4653c9a918cSPavel Labath
4663c9a918cSPavel Labath Result.emplace_back(*AttrEncOr);
4673c9a918cSPavel Labath }
4683c9a918cSPavel Labath }
4693c9a918cSPavel Labath
4703c9a918cSPavel Labath Expected<DWARFDebugNames::Abbrev>
extractAbbrev(uint64_t * Offset)471f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) {
4723c9a918cSPavel Labath if (*Offset >= EntriesBase) {
473cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence,
474cba595daSVictor Leschuk "Incorrectly terminated abbreviation table.");
4753c9a918cSPavel Labath }
4763c9a918cSPavel Labath
4773c9a918cSPavel Labath uint32_t Code = Section.AccelSection.getULEB128(Offset);
4783c9a918cSPavel Labath if (Code == 0)
4793c9a918cSPavel Labath return sentinelAbbrev();
4803c9a918cSPavel Labath
4813c9a918cSPavel Labath uint32_t Tag = Section.AccelSection.getULEB128(Offset);
4823c9a918cSPavel Labath auto AttrEncOr = extractAttributeEncodings(Offset);
4833c9a918cSPavel Labath if (!AttrEncOr)
4843c9a918cSPavel Labath return AttrEncOr.takeError();
4853c9a918cSPavel Labath return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr));
4863c9a918cSPavel Labath }
4873c9a918cSPavel Labath
extract()4883c9a918cSPavel Labath Error DWARFDebugNames::NameIndex::extract() {
4893c9a918cSPavel Labath const DWARFDataExtractor &AS = Section.AccelSection;
490f26a70a5SIgor Kudrin uint64_t Offset = Base;
4913c9a918cSPavel Labath if (Error E = Hdr.extract(AS, &Offset))
4923c9a918cSPavel Labath return E;
4933c9a918cSPavel Labath
49416a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
4953c9a918cSPavel Labath CUsBase = Offset;
49616a0313eSIgor Kudrin Offset += Hdr.CompUnitCount * SectionOffsetSize;
49716a0313eSIgor Kudrin Offset += Hdr.LocalTypeUnitCount * SectionOffsetSize;
4983c9a918cSPavel Labath Offset += Hdr.ForeignTypeUnitCount * 8;
4993c9a918cSPavel Labath BucketsBase = Offset;
5003c9a918cSPavel Labath Offset += Hdr.BucketCount * 4;
5013c9a918cSPavel Labath HashesBase = Offset;
5023c9a918cSPavel Labath if (Hdr.BucketCount > 0)
5033c9a918cSPavel Labath Offset += Hdr.NameCount * 4;
5043c9a918cSPavel Labath StringOffsetsBase = Offset;
50516a0313eSIgor Kudrin Offset += Hdr.NameCount * SectionOffsetSize;
5063c9a918cSPavel Labath EntryOffsetsBase = Offset;
50716a0313eSIgor Kudrin Offset += Hdr.NameCount * SectionOffsetSize;
5083c9a918cSPavel Labath
5093c9a918cSPavel Labath if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))
510cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence,
511cba595daSVictor Leschuk "Section too small: cannot read abbreviations.");
5123c9a918cSPavel Labath
5133c9a918cSPavel Labath EntriesBase = Offset + Hdr.AbbrevTableSize;
5143c9a918cSPavel Labath
5153c9a918cSPavel Labath for (;;) {
5163c9a918cSPavel Labath auto AbbrevOr = extractAbbrev(&Offset);
5173c9a918cSPavel Labath if (!AbbrevOr)
5183c9a918cSPavel Labath return AbbrevOr.takeError();
5193c9a918cSPavel Labath if (isSentinel(*AbbrevOr))
5203c9a918cSPavel Labath return Error::success();
5213c9a918cSPavel Labath
522cba595daSVictor Leschuk if (!Abbrevs.insert(std::move(*AbbrevOr)).second)
523cba595daSVictor Leschuk return createStringError(errc::invalid_argument,
524cba595daSVictor Leschuk "Duplicate abbreviation code.");
5253c9a918cSPavel Labath }
5263c9a918cSPavel Labath }
527a364d599SFangrui Song
Entry(const NameIndex & NameIdx,const Abbrev & Abbr)528d99072bcSPavel Labath DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)
529d99072bcSPavel Labath : NameIdx(&NameIdx), Abbr(&Abbr) {
5303c9a918cSPavel Labath // This merely creates form values. It is up to the caller
5313c9a918cSPavel Labath // (NameIndex::getEntry) to populate them.
5323c9a918cSPavel Labath Values.reserve(Abbr.Attributes.size());
5333c9a918cSPavel Labath for (const auto &Attr : Abbr.Attributes)
5343c9a918cSPavel Labath Values.emplace_back(Attr.Form);
5353c9a918cSPavel Labath }
5363c9a918cSPavel Labath
537d99072bcSPavel Labath Optional<DWARFFormValue>
lookup(dwarf::Index Index) const538d99072bcSPavel Labath DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
539d99072bcSPavel Labath assert(Abbr->Attributes.size() == Values.size());
5408dc7b982SMark de Wever for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
541d99072bcSPavel Labath if (std::get<0>(Tuple).Index == Index)
542d99072bcSPavel Labath return std::get<1>(Tuple);
543d99072bcSPavel Labath }
544d99072bcSPavel Labath return None;
545d99072bcSPavel Labath }
5463c9a918cSPavel Labath
getDIEUnitOffset() const54747c3472cSPavel Labath Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {
548d99072bcSPavel Labath if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
5492d1fc437SPavel Labath return Off->getAsReferenceUVal();
550d99072bcSPavel Labath return None;
551d99072bcSPavel Labath }
552d99072bcSPavel Labath
getCUIndex() const553d99072bcSPavel Labath Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
554d99072bcSPavel Labath if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
555d99072bcSPavel Labath return Off->getAsUnsignedConstant();
55647c3472cSPavel Labath // In a per-CU index, the entries without a DW_IDX_compile_unit attribute
55747c3472cSPavel Labath // implicitly refer to the single CU.
55847c3472cSPavel Labath if (NameIdx->getCUCount() == 1)
55947c3472cSPavel Labath return 0;
560d99072bcSPavel Labath return None;
561d99072bcSPavel Labath }
562d99072bcSPavel Labath
getCUOffset() const563d99072bcSPavel Labath Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
564d99072bcSPavel Labath Optional<uint64_t> Index = getCUIndex();
565d99072bcSPavel Labath if (!Index || *Index >= NameIdx->getCUCount())
566d99072bcSPavel Labath return None;
567d99072bcSPavel Labath return NameIdx->getCUOffset(*Index);
568d99072bcSPavel Labath }
569d99072bcSPavel Labath
dump(ScopedPrinter & W) const570d99072bcSPavel Labath void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
571d99072bcSPavel Labath W.printHex("Abbrev", Abbr->Code);
5729025f955SPavel Labath W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
573d99072bcSPavel Labath assert(Abbr->Attributes.size() == Values.size());
5748dc7b982SMark de Wever for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
5759025f955SPavel Labath W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index);
576d99072bcSPavel Labath std::get<1>(Tuple).dump(W.getOStream());
5773c9a918cSPavel Labath W.getOStream() << '\n';
5783c9a918cSPavel Labath }
5793c9a918cSPavel Labath }
5803c9a918cSPavel Labath
5813c9a918cSPavel Labath char DWARFDebugNames::SentinelError::ID;
convertToErrorCode() const5823c9a918cSPavel Labath std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
5833c9a918cSPavel Labath return inconvertibleErrorCode();
5843c9a918cSPavel Labath }
5853c9a918cSPavel Labath
getCUOffset(uint32_t CU) const586f26a70a5SIgor Kudrin uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {
5873c9a918cSPavel Labath assert(CU < Hdr.CompUnitCount);
58816a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
58916a0313eSIgor Kudrin uint64_t Offset = CUsBase + SectionOffsetSize * CU;
59016a0313eSIgor Kudrin return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset);
5913c9a918cSPavel Labath }
5923c9a918cSPavel Labath
getLocalTUOffset(uint32_t TU) const593f26a70a5SIgor Kudrin uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
5943c9a918cSPavel Labath assert(TU < Hdr.LocalTypeUnitCount);
59516a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
59616a0313eSIgor Kudrin uint64_t Offset = CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU);
59716a0313eSIgor Kudrin return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset);
5983c9a918cSPavel Labath }
5993c9a918cSPavel Labath
getForeignTUSignature(uint32_t TU) const600d99072bcSPavel Labath uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const {
6013c9a918cSPavel Labath assert(TU < Hdr.ForeignTypeUnitCount);
60216a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
603f26a70a5SIgor Kudrin uint64_t Offset =
60416a0313eSIgor Kudrin CUsBase +
60516a0313eSIgor Kudrin SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU;
6063c9a918cSPavel Labath return Section.AccelSection.getU64(&Offset);
6073c9a918cSPavel Labath }
6083c9a918cSPavel Labath
6093c9a918cSPavel Labath Expected<DWARFDebugNames::Entry>
getEntry(uint64_t * Offset) const610f26a70a5SIgor Kudrin DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const {
6113c9a918cSPavel Labath const DWARFDataExtractor &AS = Section.AccelSection;
6123c9a918cSPavel Labath if (!AS.isValidOffset(*Offset))
613cba595daSVictor Leschuk return createStringError(errc::illegal_byte_sequence,
614cba595daSVictor Leschuk "Incorrectly terminated entry list.");
6153c9a918cSPavel Labath
6163c9a918cSPavel Labath uint32_t AbbrevCode = AS.getULEB128(Offset);
6173c9a918cSPavel Labath if (AbbrevCode == 0)
6183c9a918cSPavel Labath return make_error<SentinelError>();
6193c9a918cSPavel Labath
6203c9a918cSPavel Labath const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);
6213c9a918cSPavel Labath if (AbbrevIt == Abbrevs.end())
622cba595daSVictor Leschuk return createStringError(errc::invalid_argument, "Invalid abbreviation.");
6233c9a918cSPavel Labath
624d99072bcSPavel Labath Entry E(*this, *AbbrevIt);
6253c9a918cSPavel Labath
62616a0313eSIgor Kudrin dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format};
6273c9a918cSPavel Labath for (auto &Value : E.Values) {
6283c9a918cSPavel Labath if (!Value.extractValue(AS, Offset, FormParams))
629cba595daSVictor Leschuk return createStringError(errc::io_error,
630cba595daSVictor Leschuk "Error extracting index attribute values.");
6313c9a918cSPavel Labath }
632c55cf4afSBill Wendling return std::move(E);
6333c9a918cSPavel Labath }
6343c9a918cSPavel Labath
6353c9a918cSPavel Labath DWARFDebugNames::NameTableEntry
getNameTableEntry(uint32_t Index) const6363c9a918cSPavel Labath DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {
6373c9a918cSPavel Labath assert(0 < Index && Index <= Hdr.NameCount);
63816a0313eSIgor Kudrin const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
63916a0313eSIgor Kudrin uint64_t StringOffsetOffset =
64016a0313eSIgor Kudrin StringOffsetsBase + SectionOffsetSize * (Index - 1);
64116a0313eSIgor Kudrin uint64_t EntryOffsetOffset =
64216a0313eSIgor Kudrin EntryOffsetsBase + SectionOffsetSize * (Index - 1);
6433c9a918cSPavel Labath const DWARFDataExtractor &AS = Section.AccelSection;
6443c9a918cSPavel Labath
64516a0313eSIgor Kudrin uint64_t StringOffset =
64616a0313eSIgor Kudrin AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset);
64716a0313eSIgor Kudrin uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize);
6483c9a918cSPavel Labath EntryOffset += EntriesBase;
649d6ca0639SPavel Labath return {Section.StringSection, Index, StringOffset, EntryOffset};
6503c9a918cSPavel Labath }
6513c9a918cSPavel Labath
6523c9a918cSPavel Labath uint32_t
getBucketArrayEntry(uint32_t Bucket) const6533c9a918cSPavel Labath DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {
6543c9a918cSPavel Labath assert(Bucket < Hdr.BucketCount);
655f26a70a5SIgor Kudrin uint64_t BucketOffset = BucketsBase + 4 * Bucket;
6563c9a918cSPavel Labath return Section.AccelSection.getU32(&BucketOffset);
6573c9a918cSPavel Labath }
6583c9a918cSPavel Labath
getHashArrayEntry(uint32_t Index) const6593c9a918cSPavel Labath uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {
6603c9a918cSPavel Labath assert(0 < Index && Index <= Hdr.NameCount);
661f26a70a5SIgor Kudrin uint64_t HashOffset = HashesBase + 4 * (Index - 1);
6623c9a918cSPavel Labath return Section.AccelSection.getU32(&HashOffset);
6633c9a918cSPavel Labath }
6643c9a918cSPavel Labath
6653c9a918cSPavel Labath // Returns true if we should continue scanning for entries, false if this is the
6663c9a918cSPavel Labath // last (sentinel) entry). In case of a parsing error we also return false, as
6673c9a918cSPavel Labath // it's not possible to recover this entry list (but the other lists may still
6683c9a918cSPavel Labath // parse OK).
dumpEntry(ScopedPrinter & W,uint64_t * Offset) const6693c9a918cSPavel Labath bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
670f26a70a5SIgor Kudrin uint64_t *Offset) const {
671f26a70a5SIgor Kudrin uint64_t EntryId = *Offset;
6723c9a918cSPavel Labath auto EntryOr = getEntry(Offset);
6733c9a918cSPavel Labath if (!EntryOr) {
6743c9a918cSPavel Labath handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
6753c9a918cSPavel Labath [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
6763c9a918cSPavel Labath return false;
6773c9a918cSPavel Labath }
6783c9a918cSPavel Labath
6793c9a918cSPavel Labath DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());
6803c9a918cSPavel Labath EntryOr->dump(W);
6813c9a918cSPavel Labath return true;
6823c9a918cSPavel Labath }
6833c9a918cSPavel Labath
dumpName(ScopedPrinter & W,const NameTableEntry & NTE,Optional<uint32_t> Hash) const684d6ca0639SPavel Labath void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W,
685d6ca0639SPavel Labath const NameTableEntry &NTE,
6863c9a918cSPavel Labath Optional<uint32_t> Hash) const {
687d6ca0639SPavel Labath DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str());
6883c9a918cSPavel Labath if (Hash)
6893c9a918cSPavel Labath W.printHex("Hash", *Hash);
6903c9a918cSPavel Labath
691f26a70a5SIgor Kudrin W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset());
692d6ca0639SPavel Labath W.getOStream() << " \"" << NTE.getString() << "\"\n";
6933c9a918cSPavel Labath
694f26a70a5SIgor Kudrin uint64_t EntryOffset = NTE.getEntryOffset();
695d6ca0639SPavel Labath while (dumpEntry(W, &EntryOffset))
6963c9a918cSPavel Labath /*empty*/;
6973c9a918cSPavel Labath }
6983c9a918cSPavel Labath
dumpCUs(ScopedPrinter & W) const6993c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {
7003c9a918cSPavel Labath ListScope CUScope(W, "Compilation Unit offsets");
7013c9a918cSPavel Labath for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)
702f26a70a5SIgor Kudrin W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU));
7033c9a918cSPavel Labath }
7043c9a918cSPavel Labath
dumpLocalTUs(ScopedPrinter & W) const7053c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {
7063c9a918cSPavel Labath if (Hdr.LocalTypeUnitCount == 0)
7073c9a918cSPavel Labath return;
7083c9a918cSPavel Labath
7093c9a918cSPavel Labath ListScope TUScope(W, "Local Type Unit offsets");
7103c9a918cSPavel Labath for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)
711f26a70a5SIgor Kudrin W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU,
712f26a70a5SIgor Kudrin getLocalTUOffset(TU));
7133c9a918cSPavel Labath }
7143c9a918cSPavel Labath
dumpForeignTUs(ScopedPrinter & W) const7153c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
7163c9a918cSPavel Labath if (Hdr.ForeignTypeUnitCount == 0)
7173c9a918cSPavel Labath return;
7183c9a918cSPavel Labath
7193c9a918cSPavel Labath ListScope TUScope(W, "Foreign Type Unit signatures");
7203c9a918cSPavel Labath for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
7213c9a918cSPavel Labath W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
722d99072bcSPavel Labath getForeignTUSignature(TU));
7233c9a918cSPavel Labath }
7243c9a918cSPavel Labath }
7253c9a918cSPavel Labath
dumpAbbreviations(ScopedPrinter & W) const7263c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {
7273c9a918cSPavel Labath ListScope AbbrevsScope(W, "Abbreviations");
7283c9a918cSPavel Labath for (const auto &Abbr : Abbrevs)
7293c9a918cSPavel Labath Abbr.dump(W);
7303c9a918cSPavel Labath }
7313c9a918cSPavel Labath
dumpBucket(ScopedPrinter & W,uint32_t Bucket) const7323c9a918cSPavel Labath void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,
7333c9a918cSPavel Labath uint32_t Bucket) const {
7343c9a918cSPavel Labath ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
7353c9a918cSPavel Labath uint32_t Index = getBucketArrayEntry(Bucket);
7363c9a918cSPavel Labath if (Index == 0) {
7373c9a918cSPavel Labath W.printString("EMPTY");
7383c9a918cSPavel Labath return;
7393c9a918cSPavel Labath }
7403c9a918cSPavel Labath if (Index > Hdr.NameCount) {
7413c9a918cSPavel Labath W.printString("Name index is invalid");
7423c9a918cSPavel Labath return;
7433c9a918cSPavel Labath }
7443c9a918cSPavel Labath
7453c9a918cSPavel Labath for (; Index <= Hdr.NameCount; ++Index) {
7463c9a918cSPavel Labath uint32_t Hash = getHashArrayEntry(Index);
7473c9a918cSPavel Labath if (Hash % Hdr.BucketCount != Bucket)
7483c9a918cSPavel Labath break;
7493c9a918cSPavel Labath
750d6ca0639SPavel Labath dumpName(W, getNameTableEntry(Index), Hash);
7513c9a918cSPavel Labath }
7523c9a918cSPavel Labath }
7533c9a918cSPavel Labath
dump(ScopedPrinter & W) const7543c9a918cSPavel Labath LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {
7553c9a918cSPavel Labath DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());
7563c9a918cSPavel Labath Hdr.dump(W);
7573c9a918cSPavel Labath dumpCUs(W);
7583c9a918cSPavel Labath dumpLocalTUs(W);
7593c9a918cSPavel Labath dumpForeignTUs(W);
7603c9a918cSPavel Labath dumpAbbreviations(W);
7613c9a918cSPavel Labath
7623c9a918cSPavel Labath if (Hdr.BucketCount > 0) {
7633c9a918cSPavel Labath for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)
7643c9a918cSPavel Labath dumpBucket(W, Bucket);
7653c9a918cSPavel Labath return;
7663c9a918cSPavel Labath }
7673c9a918cSPavel Labath
7683c9a918cSPavel Labath W.startLine() << "Hash table not present\n";
769*72e57862SSimon Pilgrim for (const NameTableEntry &NTE : *this)
770d6ca0639SPavel Labath dumpName(W, NTE, None);
7713c9a918cSPavel Labath }
7723c9a918cSPavel Labath
extract()773a364d599SFangrui Song Error DWARFDebugNames::extract() {
774f26a70a5SIgor Kudrin uint64_t Offset = 0;
7753c9a918cSPavel Labath while (AccelSection.isValidOffset(Offset)) {
7763c9a918cSPavel Labath NameIndex Next(*this, Offset);
777a364d599SFangrui Song if (Error E = Next.extract())
7783c9a918cSPavel Labath return E;
7793c9a918cSPavel Labath Offset = Next.getNextUnitOffset();
7803c9a918cSPavel Labath NameIndices.push_back(std::move(Next));
7813c9a918cSPavel Labath }
7823c9a918cSPavel Labath return Error::success();
7833c9a918cSPavel Labath }
7843c9a918cSPavel Labath
78580827f10SPavel Labath iterator_range<DWARFDebugNames::ValueIterator>
equal_range(StringRef Key) const78680827f10SPavel Labath DWARFDebugNames::NameIndex::equal_range(StringRef Key) const {
78780827f10SPavel Labath return make_range(ValueIterator(*this, Key), ValueIterator());
78880827f10SPavel Labath }
78980827f10SPavel Labath
dump(raw_ostream & OS) const7903c9a918cSPavel Labath LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
7913c9a918cSPavel Labath ScopedPrinter W(OS);
7923c9a918cSPavel Labath for (const NameIndex &NI : NameIndices)
7933c9a918cSPavel Labath NI.dump(W);
7943c9a918cSPavel Labath }
795d99072bcSPavel Labath
796f26a70a5SIgor Kudrin Optional<uint64_t>
findEntryOffsetInCurrentIndex()797d99072bcSPavel Labath DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {
798d99072bcSPavel Labath const Header &Hdr = CurrentIndex->Hdr;
799d99072bcSPavel Labath if (Hdr.BucketCount == 0) {
800d99072bcSPavel Labath // No Hash Table, We need to search through all names in the Name Index.
801*72e57862SSimon Pilgrim for (const NameTableEntry &NTE : *CurrentIndex) {
802d6ca0639SPavel Labath if (NTE.getString() == Key)
803d6ca0639SPavel Labath return NTE.getEntryOffset();
804d99072bcSPavel Labath }
805d99072bcSPavel Labath return None;
806d99072bcSPavel Labath }
807d99072bcSPavel Labath
808d99072bcSPavel Labath // The Name Index has a Hash Table, so use that to speed up the search.
809d99072bcSPavel Labath // Compute the Key Hash, if it has not been done already.
810d99072bcSPavel Labath if (!Hash)
811d99072bcSPavel Labath Hash = caseFoldingDjbHash(Key);
812d99072bcSPavel Labath uint32_t Bucket = *Hash % Hdr.BucketCount;
813d99072bcSPavel Labath uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket);
814d99072bcSPavel Labath if (Index == 0)
815d99072bcSPavel Labath return None; // Empty bucket
816d99072bcSPavel Labath
817d99072bcSPavel Labath for (; Index <= Hdr.NameCount; ++Index) {
818d99072bcSPavel Labath uint32_t Hash = CurrentIndex->getHashArrayEntry(Index);
819d99072bcSPavel Labath if (Hash % Hdr.BucketCount != Bucket)
820d99072bcSPavel Labath return None; // End of bucket
821d99072bcSPavel Labath
822d99072bcSPavel Labath NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);
823d6ca0639SPavel Labath if (NTE.getString() == Key)
824d6ca0639SPavel Labath return NTE.getEntryOffset();
825d99072bcSPavel Labath }
826d99072bcSPavel Labath return None;
827d99072bcSPavel Labath }
828d99072bcSPavel Labath
getEntryAtCurrentOffset()829d99072bcSPavel Labath bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {
830d99072bcSPavel Labath auto EntryOr = CurrentIndex->getEntry(&DataOffset);
831d99072bcSPavel Labath if (!EntryOr) {
832d99072bcSPavel Labath consumeError(EntryOr.takeError());
833d99072bcSPavel Labath return false;
834d99072bcSPavel Labath }
835d99072bcSPavel Labath CurrentEntry = std::move(*EntryOr);
836d99072bcSPavel Labath return true;
837d99072bcSPavel Labath }
838d99072bcSPavel Labath
findInCurrentIndex()839d99072bcSPavel Labath bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {
840f26a70a5SIgor Kudrin Optional<uint64_t> Offset = findEntryOffsetInCurrentIndex();
841d99072bcSPavel Labath if (!Offset)
842d99072bcSPavel Labath return false;
843d99072bcSPavel Labath DataOffset = *Offset;
844d99072bcSPavel Labath return getEntryAtCurrentOffset();
845d99072bcSPavel Labath }
846d99072bcSPavel Labath
searchFromStartOfCurrentIndex()847d99072bcSPavel Labath void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {
848d99072bcSPavel Labath for (const NameIndex *End = CurrentIndex->Section.NameIndices.end();
849d99072bcSPavel Labath CurrentIndex != End; ++CurrentIndex) {
850d99072bcSPavel Labath if (findInCurrentIndex())
851d99072bcSPavel Labath return;
852d99072bcSPavel Labath }
853d99072bcSPavel Labath setEnd();
854d99072bcSPavel Labath }
855d99072bcSPavel Labath
next()856d99072bcSPavel Labath void DWARFDebugNames::ValueIterator::next() {
857d99072bcSPavel Labath assert(CurrentIndex && "Incrementing an end() iterator?");
858d99072bcSPavel Labath
859d99072bcSPavel Labath // First try the next entry in the current Index.
860d99072bcSPavel Labath if (getEntryAtCurrentOffset())
861d99072bcSPavel Labath return;
862d99072bcSPavel Labath
86359870af6SPavel Labath // If we're a local iterator or we have reached the last Index, we're done.
86459870af6SPavel Labath if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) {
86580827f10SPavel Labath setEnd();
86680827f10SPavel Labath return;
86780827f10SPavel Labath }
86880827f10SPavel Labath
86980827f10SPavel Labath // Otherwise, try the next index.
870d99072bcSPavel Labath ++CurrentIndex;
871d99072bcSPavel Labath searchFromStartOfCurrentIndex();
872d99072bcSPavel Labath }
873d99072bcSPavel Labath
ValueIterator(const DWARFDebugNames & AccelTable,StringRef Key)874d99072bcSPavel Labath DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable,
875d99072bcSPavel Labath StringRef Key)
876adcd0268SBenjamin Kramer : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false),
877adcd0268SBenjamin Kramer Key(std::string(Key)) {
878d99072bcSPavel Labath searchFromStartOfCurrentIndex();
879d99072bcSPavel Labath }
880d99072bcSPavel Labath
ValueIterator(const DWARFDebugNames::NameIndex & NI,StringRef Key)88180827f10SPavel Labath DWARFDebugNames::ValueIterator::ValueIterator(
88280827f10SPavel Labath const DWARFDebugNames::NameIndex &NI, StringRef Key)
883adcd0268SBenjamin Kramer : CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) {
88480827f10SPavel Labath if (!findInCurrentIndex())
88580827f10SPavel Labath setEnd();
88680827f10SPavel Labath }
88780827f10SPavel Labath
888d99072bcSPavel Labath iterator_range<DWARFDebugNames::ValueIterator>
equal_range(StringRef Key) const889d99072bcSPavel Labath DWARFDebugNames::equal_range(StringRef Key) const {
890d99072bcSPavel Labath if (NameIndices.empty())
891d99072bcSPavel Labath return make_range(ValueIterator(), ValueIterator());
892d99072bcSPavel Labath return make_range(ValueIterator(*this, Key), ValueIterator());
893d99072bcSPavel Labath }
89480827f10SPavel Labath
89580827f10SPavel Labath const DWARFDebugNames::NameIndex *
getCUNameIndex(uint64_t CUOffset)896f26a70a5SIgor Kudrin DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) {
89780827f10SPavel Labath if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) {
89880827f10SPavel Labath for (const auto &NI : *this) {
89980827f10SPavel Labath for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU)
90080827f10SPavel Labath CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);
90180827f10SPavel Labath }
90280827f10SPavel Labath }
90380827f10SPavel Labath return CUToNameIndex.lookup(CUOffset);
90480827f10SPavel Labath }
905