blob: 86879ea0fd2761c59151cd948d1b3ae7b44880f0 [file] [log] [blame]
Eugene Zelenkoe94042c2017-02-27 23:43:14 +00001//===- DWARFAcceleratorTable.cpp ------------------------------------------===//
Frederic Riss7c41c642014-11-20 16:21:06 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turner82af9432015-01-30 18:07:45 +000010#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000011
Chandler Carruth6bda14b2017-06-06 11:49:48 +000012#include "llvm/ADT/SmallVector.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000013#include "llvm/BinaryFormat/Dwarf.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000014#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000015#include "llvm/Support/Compiler.h"
Jonas Devlieghere92ac9d32018-01-28 11:05:10 +000016#include "llvm/Support/DJB.h"
Frederic Risse837ec22014-11-14 16:15:53 +000017#include "llvm/Support/Format.h"
Pavel Labath3c9a9182018-01-29 11:08:32 +000018#include "llvm/Support/ScopedPrinter.h"
Frederic Risse837ec22014-11-14 16:15:53 +000019#include "llvm/Support/raw_ostream.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000020#include <cstddef>
21#include <cstdint>
22#include <utility>
Frederic Risse837ec22014-11-14 16:15:53 +000023
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000024using namespace llvm;
Frederic Risse837ec22014-11-14 16:15:53 +000025
Pavel Labath3c9a9182018-01-29 11:08:32 +000026namespace {
27struct DwarfConstant {
28 StringRef (*StringFn)(unsigned);
29 StringRef Type;
30 unsigned Value;
31};
32
33static raw_ostream &operator<<(raw_ostream &OS, const DwarfConstant &C) {
34 StringRef Str = C.StringFn(C.Value);
35 if (!Str.empty())
36 return OS << Str;
37 return OS << "DW_" << C.Type << "_Unknown_0x" << format("%x", C.Value);
38}
39} // namespace
40
41static DwarfConstant formatTag(unsigned Tag) {
42 return {dwarf::TagString, "TAG", Tag};
43}
44
45static DwarfConstant formatForm(unsigned Form) {
46 return {dwarf::FormEncodingString, "FORM", Form};
47}
48
49static DwarfConstant formatIndex(unsigned Idx) {
50 return {dwarf::IndexString, "IDX", Idx};
51}
52
53static DwarfConstant formatAtom(unsigned Atom) {
54 return {dwarf::AtomTypeString, "ATOM", Atom};
55}
56
57DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
58
Pavel Labath9b36fd22018-01-22 13:17:23 +000059llvm::Error AppleAcceleratorTable::extract() {
Frederic Risse837ec22014-11-14 16:15:53 +000060 uint32_t Offset = 0;
61
62 // Check that we can at least read the header.
63 if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
Jonas Devlieghereba915892017-12-11 18:22:47 +000064 return make_error<StringError>("Section too small: cannot read header.",
65 inconvertibleErrorCode());
Frederic Risse837ec22014-11-14 16:15:53 +000066
67 Hdr.Magic = AccelSection.getU32(&Offset);
68 Hdr.Version = AccelSection.getU16(&Offset);
69 Hdr.HashFunction = AccelSection.getU16(&Offset);
70 Hdr.NumBuckets = AccelSection.getU32(&Offset);
71 Hdr.NumHashes = AccelSection.getU32(&Offset);
72 Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
73
74 // Check that we can read all the hashes and offsets from the
75 // section (see SourceLevelDebugging.rst for the structure of the index).
Jonas Devlieghereba915892017-12-11 18:22:47 +000076 // We need to substract one because we're checking for an *offset* which is
77 // equal to the size for an empty table and hence pointer after the section.
Frederic Risse837ec22014-11-14 16:15:53 +000078 if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
Jonas Devlieghereba915892017-12-11 18:22:47 +000079 Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1))
80 return make_error<StringError>(
81 "Section too small: cannot read buckets and hashes.",
82 inconvertibleErrorCode());
Frederic Risse837ec22014-11-14 16:15:53 +000083
84 HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
85 uint32_t NumAtoms = AccelSection.getU32(&Offset);
86
87 for (unsigned i = 0; i < NumAtoms; ++i) {
88 uint16_t AtomType = AccelSection.getU16(&Offset);
Greg Clayton6c273762016-10-27 16:32:04 +000089 auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
Frederic Risse837ec22014-11-14 16:15:53 +000090 HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
91 }
92
Adrian Prantl99fdb9d2017-09-28 18:10:52 +000093 IsValid = true;
Jonas Devlieghereba915892017-12-11 18:22:47 +000094 return Error::success();
Frederic Risse837ec22014-11-14 16:15:53 +000095}
96
Pavel Labath9b36fd22018-01-22 13:17:23 +000097uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; }
98uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.NumHashes; }
99uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
100uint32_t AppleAcceleratorTable::getHeaderDataLength() {
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000101 return Hdr.HeaderDataLength;
102}
103
Pavel Labath9b36fd22018-01-22 13:17:23 +0000104ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
105 AppleAcceleratorTable::HeaderData::Form>>
106AppleAcceleratorTable::getAtomsDesc() {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000107 return HdrData.Atoms;
108}
109
Pavel Labath9b36fd22018-01-22 13:17:23 +0000110bool AppleAcceleratorTable::validateForms() {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000111 for (auto Atom : getAtomsDesc()) {
112 DWARFFormValue FormValue(Atom.second);
113 switch (Atom.first) {
114 case dwarf::DW_ATOM_die_offset:
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000115 case dwarf::DW_ATOM_die_tag:
116 case dwarf::DW_ATOM_type_flags:
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000117 if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
118 !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
119 FormValue.getForm() == dwarf::DW_FORM_sdata)
120 return false;
Adrian Prantl0e6694d2017-12-19 22:05:25 +0000121 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000122 default:
123 break;
124 }
125 }
126 return true;
127}
128
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000129std::pair<uint32_t, dwarf::Tag>
Pavel Labath9b36fd22018-01-22 13:17:23 +0000130AppleAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000131 uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000132 dwarf::Tag DieTag = dwarf::DW_TAG_null;
Paul Robinsone5400f82017-11-07 19:57:12 +0000133 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000134
135 for (auto Atom : getAtomsDesc()) {
136 DWARFFormValue FormValue(Atom.second);
Paul Robinsone5400f82017-11-07 19:57:12 +0000137 FormValue.extractValue(AccelSection, &HashDataOffset, FormParams);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000138 switch (Atom.first) {
139 case dwarf::DW_ATOM_die_offset:
140 DieOffset = *FormValue.getAsUnsignedConstant();
141 break;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000142 case dwarf::DW_ATOM_die_tag:
143 DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
144 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000145 default:
146 break;
147 }
148 }
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000149 return {DieOffset, DieTag};
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000150}
151
Pavel Labath9b36fd22018-01-22 13:17:23 +0000152LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000153 if (!IsValid)
154 return;
155
Frederic Risse837ec22014-11-14 16:15:53 +0000156 // Dump the header.
157 OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
158 << "Version = " << format("0x%04x", Hdr.Version) << '\n'
159 << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
160 << "Bucket count = " << Hdr.NumBuckets << '\n'
161 << "Hashes count = " << Hdr.NumHashes << '\n'
162 << "HeaderData length = " << Hdr.HeaderDataLength << '\n'
163 << "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
164 << "Number of atoms = " << HdrData.Atoms.size() << '\n';
165
166 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000167 SmallVector<DWARFFormValue, 3> AtomForms;
Frederic Risse837ec22014-11-14 16:15:53 +0000168 for (const auto &Atom: HdrData.Atoms) {
Pavel Labath3c9a9182018-01-29 11:08:32 +0000169 OS << format("Atom[%d] Type: ", i++) << formatAtom(Atom.first)
170 << " Form: " << formatForm(Atom.second) << '\n';
Frederic Riss77a07432014-11-20 16:21:11 +0000171 AtomForms.push_back(DWARFFormValue(Atom.second));
Frederic Risse837ec22014-11-14 16:15:53 +0000172 }
173
174 // Now go through the actual tables and dump them.
175 uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
176 unsigned HashesBase = Offset + Hdr.NumBuckets * 4;
177 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
Paul Robinsone5400f82017-11-07 19:57:12 +0000178 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Frederic Risse837ec22014-11-14 16:15:53 +0000179
180 for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
181 unsigned Index = AccelSection.getU32(&Offset);
182
183 OS << format("Bucket[%d]\n", Bucket);
184 if (Index == UINT32_MAX) {
185 OS << " EMPTY\n";
186 continue;
187 }
188
189 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
190 unsigned HashOffset = HashesBase + HashIdx*4;
191 unsigned OffsetsOffset = OffsetsBase + HashIdx*4;
192 uint32_t Hash = AccelSection.getU32(&HashOffset);
193
194 if (Hash % Hdr.NumBuckets != Bucket)
195 break;
196
197 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
198 OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
199 if (!AccelSection.isValidOffset(DataOffset)) {
200 OS << " Invalid section offset\n";
201 continue;
202 }
Frederic Riss7c500472014-11-14 19:30:08 +0000203 while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
Paul Robinson17536b92017-06-29 16:52:08 +0000204 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
Frederic Riss7c500472014-11-14 19:30:08 +0000205 if (!StringOffset)
206 break;
Frederic Risse837ec22014-11-14 16:15:53 +0000207 OS << format(" Name: %08x \"%s\"\n", StringOffset,
208 StringSection.getCStr(&StringOffset));
209 unsigned NumData = AccelSection.getU32(&DataOffset);
210 for (unsigned Data = 0; Data < NumData; ++Data) {
211 OS << format(" Data[%d] => ", Data);
212 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000213 for (auto &Atom : AtomForms) {
Frederic Risse837ec22014-11-14 16:15:53 +0000214 OS << format("{Atom[%d]: ", i++);
Paul Robinsone5400f82017-11-07 19:57:12 +0000215 if (Atom.extractValue(AccelSection, &DataOffset, FormParams))
Greg Claytoncddab272016-10-31 16:46:02 +0000216 Atom.dump(OS);
Frederic Risse837ec22014-11-14 16:15:53 +0000217 else
218 OS << "Error extracting the value";
219 OS << "} ";
220 }
221 OS << '\n';
222 }
223 }
224 }
225 }
226}
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000227
Pavel Labath9b36fd22018-01-22 13:17:23 +0000228AppleAcceleratorTable::ValueIterator::ValueIterator(
229 const AppleAcceleratorTable &AccelTable, unsigned Offset)
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000230 : AccelTable(&AccelTable), DataOffset(Offset) {
231 if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
232 return;
233
234 for (const auto &Atom : AccelTable.HdrData.Atoms)
235 AtomForms.push_back(DWARFFormValue(Atom.second));
236
237 // Read the first entry.
238 NumData = AccelTable.AccelSection.getU32(&DataOffset);
239 Next();
240}
241
Pavel Labath9b36fd22018-01-22 13:17:23 +0000242void AppleAcceleratorTable::ValueIterator::Next() {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000243 assert(NumData > 0 && "attempted to increment iterator past the end");
244 auto &AccelSection = AccelTable->AccelSection;
245 if (Data >= NumData ||
246 !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
247 NumData = 0;
248 return;
249 }
Paul Robinsone5400f82017-11-07 19:57:12 +0000250 DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
251 dwarf::DwarfFormat::DWARF32};
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000252 for (auto &Atom : AtomForms)
Paul Robinsone5400f82017-11-07 19:57:12 +0000253 Atom.extractValue(AccelSection, &DataOffset, FormParams);
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000254 ++Data;
255}
256
Pavel Labath9b36fd22018-01-22 13:17:23 +0000257iterator_range<AppleAcceleratorTable::ValueIterator>
258AppleAcceleratorTable::equal_range(StringRef Key) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000259 if (!IsValid)
260 return make_range(ValueIterator(), ValueIterator());
261
262 // Find the bucket.
Jonas Devlieghere92ac9d32018-01-28 11:05:10 +0000263 unsigned HashValue = djbHash(Key);
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000264 unsigned Bucket = HashValue % Hdr.NumBuckets;
265 unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
266 unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
267 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
268
269 unsigned BucketOffset = BucketBase + Bucket * 4;
270 unsigned Index = AccelSection.getU32(&BucketOffset);
271
272 // Search through all hashes in the bucket.
273 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
274 unsigned HashOffset = HashesBase + HashIdx * 4;
275 unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
276 uint32_t Hash = AccelSection.getU32(&HashOffset);
277
278 if (Hash % Hdr.NumBuckets != Bucket)
279 // We are already in the next bucket.
280 break;
281
282 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
283 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
284 if (!StringOffset)
285 break;
286
287 // Finally, compare the key.
288 if (Key == StringSection.getCStr(&StringOffset))
289 return make_range({*this, DataOffset}, ValueIterator());
290 }
291 return make_range(ValueIterator(), ValueIterator());
292}
Pavel Labath3c9a9182018-01-29 11:08:32 +0000293
294void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
295 DictScope HeaderScope(W, "Header");
296 W.printHex("Length", UnitLength);
297 W.printNumber("Version", Version);
298 W.printHex("Padding", Padding);
299 W.printNumber("CU count", CompUnitCount);
300 W.printNumber("Local TU count", LocalTypeUnitCount);
301 W.printNumber("Foreign TU count", ForeignTypeUnitCount);
302 W.printNumber("Bucket count", BucketCount);
303 W.printNumber("Name count", NameCount);
304 W.printHex("Abbreviations table size", AbbrevTableSize);
305 W.startLine() << "Augmentation: '" << AugmentationString << "'\n";
306}
307
308llvm::Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
309 uint32_t *Offset) {
310 // Check that we can read the fixed-size part.
311 if (!AS.isValidOffset(*Offset + sizeof(Header) - 1))
312 return make_error<StringError>("Section too small: cannot read header.",
313 inconvertibleErrorCode());
314
315 UnitLength = AS.getU32(Offset);
316 Version = AS.getU16(Offset);
317 Padding = AS.getU16(Offset);
318 CompUnitCount = AS.getU32(Offset);
319 LocalTypeUnitCount = AS.getU32(Offset);
320 ForeignTypeUnitCount = AS.getU32(Offset);
321 BucketCount = AS.getU32(Offset);
322 NameCount = AS.getU32(Offset);
323 AbbrevTableSize = AS.getU32(Offset);
324 AugmentationStringSize = AS.getU32(Offset);
325
326 if (!AS.isValidOffsetForDataOfSize(*Offset, AugmentationStringSize))
327 return make_error<StringError>(
328 "Section too small: cannot read header augmentation.",
329 inconvertibleErrorCode());
330 AugmentationString.resize(AugmentationStringSize);
331 AS.getU8(Offset, reinterpret_cast<uint8_t *>(AugmentationString.data()),
332 AugmentationStringSize);
333 *Offset = alignTo(*Offset, 4);
334 return Error::success();
335}
336
337void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {
338 DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());
339 W.startLine() << "Tag: " << formatTag(Tag) << '\n';
340
341 for (const auto &Attr : Attributes) {
342 W.startLine() << formatIndex(Attr.Index) << ": " << formatForm(Attr.Form)
343 << '\n';
344 }
345}
346
347static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
348 return {dwarf::Index(0), dwarf::Form(0)};
349}
350
351static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
352 return AE == sentinelAttrEnc();
353}
354
355static DWARFDebugNames::Abbrev sentinelAbbrev() {
356 return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
357}
358
359static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
360 return Abbr.Code == 0;
361}
362
363DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
364 return sentinelAbbrev();
365}
366
367DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
368 return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
369}
370
371Expected<DWARFDebugNames::AttributeEncoding>
372DWARFDebugNames::NameIndex::extractAttributeEncoding(uint32_t *Offset) {
373 if (*Offset >= EntriesBase) {
374 return make_error<StringError>("Incorrectly terminated abbreviation table.",
375 inconvertibleErrorCode());
376 }
377
378 uint32_t Index = Section.AccelSection.getULEB128(Offset);
379 uint32_t Form = Section.AccelSection.getULEB128(Offset);
380 return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));
381}
382
383Expected<std::vector<DWARFDebugNames::AttributeEncoding>>
384DWARFDebugNames::NameIndex::extractAttributeEncodings(uint32_t *Offset) {
385 std::vector<AttributeEncoding> Result;
386 for (;;) {
387 auto AttrEncOr = extractAttributeEncoding(Offset);
388 if (!AttrEncOr)
389 return AttrEncOr.takeError();
390 if (isSentinel(*AttrEncOr))
391 return std::move(Result);
392
393 Result.emplace_back(*AttrEncOr);
394 }
395}
396
397Expected<DWARFDebugNames::Abbrev>
398DWARFDebugNames::NameIndex::extractAbbrev(uint32_t *Offset) {
399 if (*Offset >= EntriesBase) {
400 return make_error<StringError>("Incorrectly terminated abbreviation table.",
401 inconvertibleErrorCode());
402 }
403
404 uint32_t Code = Section.AccelSection.getULEB128(Offset);
405 if (Code == 0)
406 return sentinelAbbrev();
407
408 uint32_t Tag = Section.AccelSection.getULEB128(Offset);
409 auto AttrEncOr = extractAttributeEncodings(Offset);
410 if (!AttrEncOr)
411 return AttrEncOr.takeError();
412 return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr));
413}
414
415Error DWARFDebugNames::NameIndex::extract() {
416 const DWARFDataExtractor &AS = Section.AccelSection;
417 uint32_t Offset = Base;
418 if (Error E = Hdr.extract(AS, &Offset))
419 return E;
420
421 CUsBase = Offset;
422 Offset += Hdr.CompUnitCount * 4;
423 Offset += Hdr.LocalTypeUnitCount * 4;
424 Offset += Hdr.ForeignTypeUnitCount * 8;
425 BucketsBase = Offset;
426 Offset += Hdr.BucketCount * 4;
427 HashesBase = Offset;
428 if (Hdr.BucketCount > 0)
429 Offset += Hdr.NameCount * 4;
430 StringOffsetsBase = Offset;
431 Offset += Hdr.NameCount * 4;
432 EntryOffsetsBase = Offset;
433 Offset += Hdr.NameCount * 4;
434
435 if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))
436 return make_error<StringError>(
437 "Section too small: cannot read abbreviations.",
438 inconvertibleErrorCode());
439
440 EntriesBase = Offset + Hdr.AbbrevTableSize;
441
442 for (;;) {
443 auto AbbrevOr = extractAbbrev(&Offset);
444 if (!AbbrevOr)
445 return AbbrevOr.takeError();
446 if (isSentinel(*AbbrevOr))
447 return Error::success();
448
449 if (!Abbrevs.insert(std::move(*AbbrevOr)).second) {
450 return make_error<StringError>("Duplicate abbreviation code.",
451 inconvertibleErrorCode());
452 }
453 }
454}
455
456DWARFDebugNames::Entry::Entry(const Abbrev &Abbr) : Abbr(Abbr) {
457 // This merely creates form values. It is up to the caller
458 // (NameIndex::getEntry) to populate them.
459 Values.reserve(Abbr.Attributes.size());
460 for (const auto &Attr : Abbr.Attributes)
461 Values.emplace_back(Attr.Form);
462}
463
464void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
465 W.printHex("Abbrev", Abbr.Code);
466 W.startLine() << "Tag: " << formatTag(Abbr.Tag) << "\n";
467
468 assert(Abbr.Attributes.size() == Values.size());
469 for (uint32_t I = 0, E = Values.size(); I < E; ++I) {
470 W.startLine() << formatIndex(Abbr.Attributes[I].Index) << ": ";
471 Values[I].dump(W.getOStream());
472 W.getOStream() << '\n';
473 }
474}
475
476char DWARFDebugNames::SentinelError::ID;
477std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
478 return inconvertibleErrorCode();
479}
480
481uint32_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {
482 assert(CU < Hdr.CompUnitCount);
483 uint32_t Offset = CUsBase + 4 * CU;
484 return Section.AccelSection.getRelocatedValue(4, &Offset);
485}
486
487uint32_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
488 assert(TU < Hdr.LocalTypeUnitCount);
489 uint32_t Offset = CUsBase + Hdr.CompUnitCount * 4;
490 return Section.AccelSection.getRelocatedValue(4, &Offset);
491}
492
493uint64_t DWARFDebugNames::NameIndex::getForeignTUOffset(uint32_t TU) const {
494 assert(TU < Hdr.ForeignTypeUnitCount);
495 uint32_t Offset = CUsBase + (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) * 4;
496 return Section.AccelSection.getU64(&Offset);
497}
498
499Expected<DWARFDebugNames::Entry>
500DWARFDebugNames::NameIndex::getEntry(uint32_t *Offset) const {
501 const DWARFDataExtractor &AS = Section.AccelSection;
502 if (!AS.isValidOffset(*Offset))
503 return make_error<StringError>("Incorrectly terminated entry list",
504 inconvertibleErrorCode());
505
506 uint32_t AbbrevCode = AS.getULEB128(Offset);
507 if (AbbrevCode == 0)
508 return make_error<SentinelError>();
509
510 const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);
511 if (AbbrevIt == Abbrevs.end())
512 return make_error<StringError>("Invalid abbreviation",
513 inconvertibleErrorCode());
514
515 Entry E(*AbbrevIt);
516
517 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
518 for (auto &Value : E.Values) {
519 if (!Value.extractValue(AS, Offset, FormParams))
520 return make_error<StringError>("Error extracting index attribute values",
521 inconvertibleErrorCode());
522 }
523 return std::move(E);
524}
525
526DWARFDebugNames::NameTableEntry
527DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {
528 assert(0 < Index && Index <= Hdr.NameCount);
529 uint32_t StringOffsetOffset = StringOffsetsBase + 4 * (Index - 1);
530 uint32_t EntryOffsetOffset = EntryOffsetsBase + 4 * (Index - 1);
531 const DWARFDataExtractor &AS = Section.AccelSection;
532
533 uint32_t StringOffset = AS.getRelocatedValue(4, &StringOffsetOffset);
534 uint32_t EntryOffset = AS.getU32(&EntryOffsetOffset);
535 EntryOffset += EntriesBase;
536 return {StringOffset, EntryOffset};
537}
538
539uint32_t
540DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {
541 assert(Bucket < Hdr.BucketCount);
542 uint32_t BucketOffset = BucketsBase + 4 * Bucket;
543 return Section.AccelSection.getU32(&BucketOffset);
544}
545
546uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {
547 assert(0 < Index && Index <= Hdr.NameCount);
548 uint32_t HashOffset = HashesBase + 4 * (Index - 1);
549 return Section.AccelSection.getU32(&HashOffset);
550}
551
552// Returns true if we should continue scanning for entries, false if this is the
553// last (sentinel) entry). In case of a parsing error we also return false, as
554// it's not possible to recover this entry list (but the other lists may still
555// parse OK).
556bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
557 uint32_t *Offset) const {
558 uint32_t EntryId = *Offset;
559 auto EntryOr = getEntry(Offset);
560 if (!EntryOr) {
561 handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
562 [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
563 return false;
564 }
565
566 DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());
567 EntryOr->dump(W);
568 return true;
569}
570
571void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W, uint32_t Index,
572 Optional<uint32_t> Hash) const {
573 const DataExtractor &SS = Section.StringSection;
574 NameTableEntry NTE = getNameTableEntry(Index);
575
576 DictScope NameScope(W, ("Name " + Twine(Index)).str());
577 if (Hash)
578 W.printHex("Hash", *Hash);
579
580 W.startLine() << format("String: 0x%08x", NTE.StringOffset);
581 W.getOStream() << " \"" << SS.getCStr(&NTE.StringOffset) << "\"\n";
582
583 while (dumpEntry(W, &NTE.EntryOffset))
584 /*empty*/;
585}
586
587void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {
588 ListScope CUScope(W, "Compilation Unit offsets");
589 for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)
590 W.startLine() << format("CU[%u]: 0x%08x\n", CU, getCUOffset(CU));
591}
592
593void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {
594 if (Hdr.LocalTypeUnitCount == 0)
595 return;
596
597 ListScope TUScope(W, "Local Type Unit offsets");
598 for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)
599 W.startLine() << format("LocalTU[%u]: 0x%08x\n", TU, getLocalTUOffset(TU));
600}
601
602void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
603 if (Hdr.ForeignTypeUnitCount == 0)
604 return;
605
606 ListScope TUScope(W, "Foreign Type Unit signatures");
607 for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
608 W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
609 getForeignTUOffset(TU));
610 }
611}
612
613void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {
614 ListScope AbbrevsScope(W, "Abbreviations");
615 for (const auto &Abbr : Abbrevs)
616 Abbr.dump(W);
617}
618
619void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,
620 uint32_t Bucket) const {
621 ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
622 uint32_t Index = getBucketArrayEntry(Bucket);
623 if (Index == 0) {
624 W.printString("EMPTY");
625 return;
626 }
627 if (Index > Hdr.NameCount) {
628 W.printString("Name index is invalid");
629 return;
630 }
631
632 for (; Index <= Hdr.NameCount; ++Index) {
633 uint32_t Hash = getHashArrayEntry(Index);
634 if (Hash % Hdr.BucketCount != Bucket)
635 break;
636
637 dumpName(W, Index, Hash);
638 }
639}
640
641LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {
642 DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());
643 Hdr.dump(W);
644 dumpCUs(W);
645 dumpLocalTUs(W);
646 dumpForeignTUs(W);
647 dumpAbbreviations(W);
648
649 if (Hdr.BucketCount > 0) {
650 for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)
651 dumpBucket(W, Bucket);
652 return;
653 }
654
655 W.startLine() << "Hash table not present\n";
656 for (uint32_t Index = 1; Index <= Hdr.NameCount; ++Index)
657 dumpName(W, Index, None);
658}
659
660llvm::Error DWARFDebugNames::extract() {
661 uint32_t Offset = 0;
662 while (AccelSection.isValidOffset(Offset)) {
663 NameIndex Next(*this, Offset);
664 if (llvm::Error E = Next.extract())
665 return E;
666 Offset = Next.getNextUnitOffset();
667 NameIndices.push_back(std::move(Next));
668 }
669 return Error::success();
670}
671
672LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
673 ScopedPrinter W(OS);
674 for (const NameIndex &NI : NameIndices)
675 NI.dump(W);
676}