Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
35271 views
1
//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file contains support for writing accelerator tables.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/CodeGen/AccelTable.h"
14
#include "DwarfCompileUnit.h"
15
#include "DwarfUnit.h"
16
#include "llvm/ADT/DenseSet.h"
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/Twine.h"
19
#include "llvm/BinaryFormat/Dwarf.h"
20
#include "llvm/CodeGen/AsmPrinter.h"
21
#include "llvm/CodeGen/DIE.h"
22
#include "llvm/MC/MCStreamer.h"
23
#include "llvm/MC/MCSymbol.h"
24
#include "llvm/Support/raw_ostream.h"
25
#include "llvm/Target/TargetLoweringObjectFile.h"
26
#include <algorithm>
27
#include <cstddef>
28
#include <cstdint>
29
#include <limits>
30
#include <vector>
31
32
using namespace llvm;
33
34
void AccelTableBase::computeBucketCount() {
35
SmallVector<uint32_t, 0> Uniques;
36
Uniques.reserve(Entries.size());
37
for (const auto &E : Entries)
38
Uniques.push_back(E.second.HashValue);
39
llvm::sort(Uniques);
40
UniqueHashCount = llvm::unique(Uniques) - Uniques.begin();
41
BucketCount = dwarf::getDebugNamesBucketCount(UniqueHashCount);
42
}
43
44
void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
45
// Create the individual hash data outputs.
46
for (auto &E : Entries) {
47
// Unique the entries.
48
llvm::stable_sort(E.second.Values,
49
[](const AccelTableData *A, const AccelTableData *B) {
50
return *A < *B;
51
});
52
E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end());
53
}
54
55
// Figure out how many buckets we need, then compute the bucket contents and
56
// the final ordering. The hashes and offsets can be emitted by walking these
57
// data structures. We add temporary symbols to the data so they can be
58
// referenced when emitting the offsets.
59
computeBucketCount();
60
61
// Compute bucket contents and final ordering.
62
Buckets.resize(BucketCount);
63
for (auto &E : Entries) {
64
uint32_t Bucket = E.second.HashValue % BucketCount;
65
Buckets[Bucket].push_back(&E.second);
66
E.second.Sym = Asm->createTempSymbol(Prefix);
67
}
68
69
// Sort the contents of the buckets by hash value so that hash collisions end
70
// up together. Stable sort makes testing easier and doesn't cost much more.
71
for (auto &Bucket : Buckets)
72
llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
73
return LHS->HashValue < RHS->HashValue;
74
});
75
}
76
77
namespace {
78
/// Base class for writing out Accelerator tables. It holds the common
79
/// functionality for the two Accelerator table types.
80
class AccelTableWriter {
81
protected:
82
AsmPrinter *const Asm; ///< Destination.
83
const AccelTableBase &Contents; ///< Data to emit.
84
85
/// Controls whether to emit duplicate hash and offset table entries for names
86
/// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
87
/// tables do.
88
const bool SkipIdenticalHashes;
89
90
void emitHashes() const;
91
92
/// Emit offsets to lists of entries with identical names. The offsets are
93
/// relative to the Base argument.
94
void emitOffsets(const MCSymbol *Base) const;
95
96
public:
97
AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
98
bool SkipIdenticalHashes)
99
: Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
100
}
101
};
102
103
class AppleAccelTableWriter : public AccelTableWriter {
104
using Atom = AppleAccelTableData::Atom;
105
106
/// The fixed header of an Apple Accelerator Table.
107
struct Header {
108
uint32_t Magic = MagicHash;
109
uint16_t Version = 1;
110
uint16_t HashFunction = dwarf::DW_hash_function_djb;
111
uint32_t BucketCount;
112
uint32_t HashCount;
113
uint32_t HeaderDataLength;
114
115
/// 'HASH' magic value to detect endianness.
116
static const uint32_t MagicHash = 0x48415348;
117
118
Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
119
: BucketCount(BucketCount), HashCount(UniqueHashCount),
120
HeaderDataLength(DataLength) {}
121
122
void emit(AsmPrinter *Asm) const;
123
#ifndef NDEBUG
124
void print(raw_ostream &OS) const;
125
void dump() const { print(dbgs()); }
126
#endif
127
};
128
129
/// The HeaderData describes the structure of an Apple accelerator table
130
/// through a list of Atoms.
131
struct HeaderData {
132
/// In the case of data that is referenced via DW_FORM_ref_* the offset
133
/// base is used to describe the offset for all forms in the list of atoms.
134
uint32_t DieOffsetBase;
135
136
const SmallVector<Atom, 4> Atoms;
137
138
HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
139
: DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
140
141
void emit(AsmPrinter *Asm) const;
142
#ifndef NDEBUG
143
void print(raw_ostream &OS) const;
144
void dump() const { print(dbgs()); }
145
#endif
146
};
147
148
Header Header;
149
HeaderData HeaderData;
150
const MCSymbol *SecBegin;
151
152
void emitBuckets() const;
153
void emitData() const;
154
155
public:
156
AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
157
ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
158
: AccelTableWriter(Asm, Contents, true),
159
Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
160
8 + (Atoms.size() * 4)),
161
HeaderData(Atoms), SecBegin(SecBegin) {}
162
163
void emit() const;
164
165
#ifndef NDEBUG
166
void print(raw_ostream &OS) const;
167
void dump() const { print(dbgs()); }
168
#endif
169
};
170
171
/// Class responsible for emitting a DWARF v5 Accelerator Table. The only
172
/// public function is emit(), which performs the actual emission.
173
///
174
/// A callback abstracts the logic to provide a CU index for a given entry.
175
class Dwarf5AccelTableWriter : public AccelTableWriter {
176
struct Header {
177
uint16_t Version = 5;
178
uint16_t Padding = 0;
179
uint32_t CompUnitCount;
180
uint32_t LocalTypeUnitCount = 0;
181
uint32_t ForeignTypeUnitCount = 0;
182
uint32_t BucketCount = 0;
183
uint32_t NameCount = 0;
184
uint32_t AbbrevTableSize = 0;
185
uint32_t AugmentationStringSize = sizeof(AugmentationString);
186
char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
187
188
Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
189
uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
190
uint32_t NameCount)
191
: CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
192
ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
193
NameCount(NameCount) {}
194
195
void emit(Dwarf5AccelTableWriter &Ctx);
196
};
197
198
Header Header;
199
/// FoldingSet that uniques the abbreviations.
200
FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
201
/// Vector containing DebugNames abbreviations for iteration in order.
202
SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
203
/// The bump allocator to use when creating DIEAbbrev objects in the uniqued
204
/// storage container.
205
BumpPtrAllocator Alloc;
206
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
207
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
208
llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
209
const DWARF5AccelTableData &)>
210
getIndexForEntry;
211
MCSymbol *ContributionEnd = nullptr;
212
MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
213
MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
214
MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
215
// Indicates if this module is built with Split Dwarf enabled.
216
bool IsSplitDwarf = false;
217
/// Stores the DIE offsets which are indexed by this table.
218
DenseSet<OffsetAndUnitID> IndexedOffsets;
219
220
void populateAbbrevsMap();
221
222
void emitCUList() const;
223
void emitTUList() const;
224
void emitBuckets() const;
225
void emitStringOffsets() const;
226
void emitAbbrevs() const;
227
void emitEntry(
228
const DWARF5AccelTableData &Entry,
229
const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
230
DenseSet<MCSymbol *> &EmittedAccelEntrySymbols);
231
void emitData();
232
233
public:
234
Dwarf5AccelTableWriter(
235
AsmPrinter *Asm, const AccelTableBase &Contents,
236
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
237
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
238
llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
239
const DWARF5AccelTableData &)>
240
getIndexForEntry,
241
bool IsSplitDwarf);
242
~Dwarf5AccelTableWriter() {
243
for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
244
Abbrev->~DebugNamesAbbrev();
245
}
246
void emit();
247
};
248
} // namespace
249
250
void AccelTableWriter::emitHashes() const {
251
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
252
unsigned BucketIdx = 0;
253
for (const auto &Bucket : Contents.getBuckets()) {
254
for (const auto &Hash : Bucket) {
255
uint32_t HashValue = Hash->HashValue;
256
if (SkipIdenticalHashes && PrevHash == HashValue)
257
continue;
258
Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
259
Asm->emitInt32(HashValue);
260
PrevHash = HashValue;
261
}
262
BucketIdx++;
263
}
264
}
265
266
void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
267
const auto &Buckets = Contents.getBuckets();
268
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
269
for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
270
for (auto *Hash : Buckets[i]) {
271
uint32_t HashValue = Hash->HashValue;
272
if (SkipIdenticalHashes && PrevHash == HashValue)
273
continue;
274
PrevHash = HashValue;
275
Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
276
Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
277
}
278
}
279
}
280
281
void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
282
Asm->OutStreamer->AddComment("Header Magic");
283
Asm->emitInt32(Magic);
284
Asm->OutStreamer->AddComment("Header Version");
285
Asm->emitInt16(Version);
286
Asm->OutStreamer->AddComment("Header Hash Function");
287
Asm->emitInt16(HashFunction);
288
Asm->OutStreamer->AddComment("Header Bucket Count");
289
Asm->emitInt32(BucketCount);
290
Asm->OutStreamer->AddComment("Header Hash Count");
291
Asm->emitInt32(HashCount);
292
Asm->OutStreamer->AddComment("Header Data Length");
293
Asm->emitInt32(HeaderDataLength);
294
}
295
296
void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
297
Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
298
Asm->emitInt32(DieOffsetBase);
299
Asm->OutStreamer->AddComment("HeaderData Atom Count");
300
Asm->emitInt32(Atoms.size());
301
302
for (const Atom &A : Atoms) {
303
Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
304
Asm->emitInt16(A.Type);
305
Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
306
Asm->emitInt16(A.Form);
307
}
308
}
309
310
void AppleAccelTableWriter::emitBuckets() const {
311
const auto &Buckets = Contents.getBuckets();
312
unsigned index = 0;
313
for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
314
Asm->OutStreamer->AddComment("Bucket " + Twine(i));
315
if (!Buckets[i].empty())
316
Asm->emitInt32(index);
317
else
318
Asm->emitInt32(std::numeric_limits<uint32_t>::max());
319
// Buckets point in the list of hashes, not to the data. Do not increment
320
// the index multiple times in case of hash collisions.
321
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
322
for (auto *HD : Buckets[i]) {
323
uint32_t HashValue = HD->HashValue;
324
if (PrevHash != HashValue)
325
++index;
326
PrevHash = HashValue;
327
}
328
}
329
}
330
331
void AppleAccelTableWriter::emitData() const {
332
const auto &Buckets = Contents.getBuckets();
333
for (const AccelTableBase::HashList &Bucket : Buckets) {
334
uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
335
for (const auto &Hash : Bucket) {
336
// Terminate the previous entry if there is no hash collision with the
337
// current one.
338
if (PrevHash != std::numeric_limits<uint64_t>::max() &&
339
PrevHash != Hash->HashValue)
340
Asm->emitInt32(0);
341
// Remember to emit the label for our offset.
342
Asm->OutStreamer->emitLabel(Hash->Sym);
343
Asm->OutStreamer->AddComment(Hash->Name.getString());
344
Asm->emitDwarfStringOffset(Hash->Name);
345
Asm->OutStreamer->AddComment("Num DIEs");
346
Asm->emitInt32(Hash->Values.size());
347
for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
348
V->emit(Asm);
349
PrevHash = Hash->HashValue;
350
}
351
// Emit the final end marker for the bucket.
352
if (!Bucket.empty())
353
Asm->emitInt32(0);
354
}
355
}
356
357
void AppleAccelTableWriter::emit() const {
358
Header.emit(Asm);
359
HeaderData.emit(Asm);
360
emitBuckets();
361
emitHashes();
362
emitOffsets(SecBegin);
363
emitData();
364
}
365
366
DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
367
const uint32_t UnitID,
368
const bool IsTU)
369
: OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
370
UnitID(UnitID) {}
371
372
void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
373
assert(CompUnitCount > 0 && "Index must have at least one CU.");
374
375
AsmPrinter *Asm = Ctx.Asm;
376
Ctx.ContributionEnd =
377
Asm->emitDwarfUnitLength("names", "Header: unit length");
378
Asm->OutStreamer->AddComment("Header: version");
379
Asm->emitInt16(Version);
380
Asm->OutStreamer->AddComment("Header: padding");
381
Asm->emitInt16(Padding);
382
Asm->OutStreamer->AddComment("Header: compilation unit count");
383
Asm->emitInt32(CompUnitCount);
384
Asm->OutStreamer->AddComment("Header: local type unit count");
385
Asm->emitInt32(LocalTypeUnitCount);
386
Asm->OutStreamer->AddComment("Header: foreign type unit count");
387
Asm->emitInt32(ForeignTypeUnitCount);
388
Asm->OutStreamer->AddComment("Header: bucket count");
389
Asm->emitInt32(BucketCount);
390
Asm->OutStreamer->AddComment("Header: name count");
391
Asm->emitInt32(NameCount);
392
Asm->OutStreamer->AddComment("Header: abbreviation table size");
393
Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
394
Asm->OutStreamer->AddComment("Header: augmentation string size");
395
assert(AugmentationStringSize % 4 == 0);
396
Asm->emitInt32(AugmentationStringSize);
397
Asm->OutStreamer->AddComment("Header: augmentation string");
398
Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
399
}
400
401
std::optional<uint64_t>
402
DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
403
if (auto *Parent = Die.getParent();
404
Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
405
return Parent->getOffset();
406
return {};
407
}
408
409
static std::optional<dwarf::Form>
410
getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
411
std::optional<OffsetAndUnitID> ParentOffset) {
412
// No parent information
413
if (!ParentOffset)
414
return std::nullopt;
415
// Parent is indexed by this table.
416
if (IndexedOffsets.contains(*ParentOffset))
417
return dwarf::Form::DW_FORM_ref4;
418
// Parent is not indexed by this table.
419
return dwarf::Form::DW_FORM_flag_present;
420
}
421
422
void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const {
423
ID.AddInteger(DieTag);
424
for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
425
ID.AddInteger(Enc.Index);
426
ID.AddInteger(Enc.Form);
427
}
428
}
429
430
void Dwarf5AccelTableWriter::populateAbbrevsMap() {
431
for (auto &Bucket : Contents.getBuckets()) {
432
for (auto *Hash : Bucket) {
433
for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
434
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
435
getIndexForEntry(*Value);
436
std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
437
IndexedOffsets, Value->getParentDieOffsetAndUnitID());
438
DebugNamesAbbrev Abbrev(Value->getDieTag());
439
if (EntryRet)
440
Abbrev.addAttribute(EntryRet->Encoding);
441
Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
442
if (MaybeParentForm)
443
Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
444
FoldingSetNodeID ID;
445
Abbrev.Profile(ID);
446
void *InsertPos;
447
if (DebugNamesAbbrev *Existing =
448
AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
449
Value->setAbbrevNumber(Existing->getNumber());
450
continue;
451
}
452
DebugNamesAbbrev *NewAbbrev =
453
new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
454
AbbreviationsVector.push_back(NewAbbrev);
455
NewAbbrev->setNumber(AbbreviationsVector.size());
456
AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);
457
Value->setAbbrevNumber(NewAbbrev->getNumber());
458
}
459
}
460
}
461
}
462
463
void Dwarf5AccelTableWriter::emitCUList() const {
464
for (const auto &CU : enumerate(CompUnits)) {
465
Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
466
if (std::holds_alternative<MCSymbol *>(CU.value()))
467
Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
468
else
469
Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
470
}
471
}
472
473
void Dwarf5AccelTableWriter::emitTUList() const {
474
for (const auto &TU : enumerate(TypeUnits)) {
475
Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
476
if (std::holds_alternative<MCSymbol *>(TU.value()))
477
Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
478
else if (IsSplitDwarf)
479
Asm->emitInt64(std::get<uint64_t>(TU.value()));
480
else
481
Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
482
}
483
}
484
485
void Dwarf5AccelTableWriter::emitBuckets() const {
486
uint32_t Index = 1;
487
for (const auto &Bucket : enumerate(Contents.getBuckets())) {
488
Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
489
Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
490
Index += Bucket.value().size();
491
}
492
}
493
494
void Dwarf5AccelTableWriter::emitStringOffsets() const {
495
for (const auto &Bucket : enumerate(Contents.getBuckets())) {
496
for (auto *Hash : Bucket.value()) {
497
DwarfStringPoolEntryRef String = Hash->Name;
498
Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
499
": " + String.getString());
500
Asm->emitDwarfStringOffset(String);
501
}
502
}
503
}
504
505
void Dwarf5AccelTableWriter::emitAbbrevs() const {
506
Asm->OutStreamer->emitLabel(AbbrevStart);
507
for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
508
Asm->OutStreamer->AddComment("Abbrev code");
509
Asm->emitULEB128(Abbrev->getNumber());
510
Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
511
Asm->emitULEB128(Abbrev->getDieTag());
512
for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
513
Abbrev->getAttributes()) {
514
Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
515
Asm->emitULEB128(AttrEnc.Form,
516
dwarf::FormEncodingString(AttrEnc.Form).data());
517
}
518
Asm->emitULEB128(0, "End of abbrev");
519
Asm->emitULEB128(0, "End of abbrev");
520
}
521
Asm->emitULEB128(0, "End of abbrev list");
522
Asm->OutStreamer->emitLabel(AbbrevEnd);
523
}
524
525
void Dwarf5AccelTableWriter::emitEntry(
526
const DWARF5AccelTableData &Entry,
527
const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
528
DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) {
529
unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
530
assert(AbbrevIndex < AbbreviationsVector.size() &&
531
"Entry abbrev index is outside of abbreviations vector range.");
532
DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
533
std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
534
getIndexForEntry(Entry);
535
std::optional<OffsetAndUnitID> MaybeParentOffset =
536
Entry.getParentDieOffsetAndUnitID();
537
auto EntrySymbolIt =
538
DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
539
assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
540
MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
541
542
// Emit the label for this Entry, so that IDX_parents may refer to it.
543
// Note: a DIE may have multiple accelerator Entries; this check avoids
544
// creating/emitting multiple labels for the same DIE.
545
if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
546
Asm->OutStreamer->emitLabel(EntrySymbol);
547
548
Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
549
550
for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
551
Abbrev->getAttributes()) {
552
Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
553
switch (AttrEnc.Index) {
554
case dwarf::DW_IDX_compile_unit:
555
case dwarf::DW_IDX_type_unit: {
556
DIEInteger ID(EntryRet->Index);
557
ID.emitValue(Asm, AttrEnc.Form);
558
break;
559
}
560
case dwarf::DW_IDX_die_offset:
561
assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
562
Asm->emitInt32(Entry.getDieOffset());
563
break;
564
case dwarf::DW_IDX_parent: {
565
if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
566
break;
567
auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
568
assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
569
Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
570
break;
571
}
572
default:
573
llvm_unreachable("Unexpected index attribute!");
574
}
575
}
576
}
577
578
void Dwarf5AccelTableWriter::emitData() {
579
DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
580
581
for (OffsetAndUnitID Offset : IndexedOffsets)
582
DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
583
584
Asm->OutStreamer->emitLabel(EntryPool);
585
DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
586
for (auto &Bucket : Contents.getBuckets()) {
587
for (auto *Hash : Bucket) {
588
// Remember to emit the label for our offset.
589
Asm->OutStreamer->emitLabel(Hash->Sym);
590
for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
591
emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
592
Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
593
Asm->emitInt8(0);
594
}
595
}
596
}
597
598
Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
599
AsmPrinter *Asm, const AccelTableBase &Contents,
600
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
601
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
602
llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
603
const DWARF5AccelTableData &)>
604
getIndexForEntry,
605
bool IsSplitDwarf)
606
: AccelTableWriter(Asm, Contents, false),
607
Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
608
IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
609
Contents.getUniqueNameCount()),
610
CompUnits(CompUnits), TypeUnits(TypeUnits),
611
getIndexForEntry(std::move(getIndexForEntry)),
612
IsSplitDwarf(IsSplitDwarf) {
613
614
for (auto &Bucket : Contents.getBuckets())
615
for (auto *Hash : Bucket)
616
for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
617
IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
618
619
populateAbbrevsMap();
620
}
621
622
void Dwarf5AccelTableWriter::emit() {
623
Header.emit(*this);
624
emitCUList();
625
emitTUList();
626
emitBuckets();
627
emitHashes();
628
emitStringOffsets();
629
emitOffsets(EntryPool);
630
emitAbbrevs();
631
emitData();
632
Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
633
Asm->OutStreamer->emitLabel(ContributionEnd);
634
}
635
636
void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
637
StringRef Prefix, const MCSymbol *SecBegin,
638
ArrayRef<AppleAccelTableData::Atom> Atoms) {
639
Contents.finalize(Asm, Prefix);
640
AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
641
}
642
643
void llvm::emitDWARF5AccelTable(
644
AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
645
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
646
TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
647
std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
648
std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
649
SmallVector<unsigned, 1> CUIndex(CUs.size());
650
DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
651
int CUCount = 0;
652
int TUCount = 0;
653
for (const auto &CU : enumerate(CUs)) {
654
switch (CU.value()->getCUNode()->getNameTableKind()) {
655
case DICompileUnit::DebugNameTableKind::Default:
656
case DICompileUnit::DebugNameTableKind::Apple:
657
break;
658
default:
659
continue;
660
}
661
CUIndex[CU.index()] = CUCount++;
662
assert(CU.index() == CU.value()->getUniqueID());
663
const DwarfCompileUnit *MainCU =
664
DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
665
CompUnits.push_back(MainCU->getLabelBegin());
666
}
667
668
for (const auto &TU : TUSymbols) {
669
TUIndex[TU.UniqueID] = TUCount++;
670
if (DD.useSplitDwarf())
671
TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
672
else
673
TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
674
}
675
676
if (CompUnits.empty())
677
return;
678
679
Asm->OutStreamer->switchSection(
680
Asm->getObjFileLowering().getDwarfDebugNamesSection());
681
682
Contents.finalize(Asm, "names");
683
dwarf::Form CUIndexForm =
684
DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
685
dwarf::Form TUIndexForm =
686
DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
687
Dwarf5AccelTableWriter(
688
Asm, Contents, CompUnits, TypeUnits,
689
[&](const DWARF5AccelTableData &Entry)
690
-> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
691
if (Entry.isTU())
692
return {{TUIndex[Entry.getUnitID()],
693
{dwarf::DW_IDX_type_unit, TUIndexForm}}};
694
if (CUIndex.size() > 1)
695
return {{CUIndex[Entry.getUnitID()],
696
{dwarf::DW_IDX_compile_unit, CUIndexForm}}};
697
return std::nullopt;
698
},
699
DD.useSplitDwarf())
700
.emit();
701
}
702
703
void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
704
TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
705
}
706
707
void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
708
TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
709
}
710
711
void llvm::emitDWARF5AccelTable(
712
AsmPrinter *Asm, DWARF5AccelTable &Contents,
713
ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
714
llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
715
const DWARF5AccelTableData &)>
716
getIndexForEntry) {
717
std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
718
Contents.finalize(Asm, "names");
719
Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
720
.emit();
721
}
722
723
void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
724
assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
725
"The section offset exceeds the limit.");
726
Asm->emitInt32(Die.getDebugSectionOffset());
727
}
728
729
void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
730
assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
731
"The section offset exceeds the limit.");
732
Asm->emitInt32(Die.getDebugSectionOffset());
733
Asm->emitInt16(Die.getTag());
734
Asm->emitInt8(0);
735
}
736
737
void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
738
Asm->emitInt32(Offset);
739
}
740
741
void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
742
Asm->emitInt32(Offset);
743
Asm->emitInt16(Tag);
744
Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
745
: 0);
746
Asm->emitInt32(QualifiedNameHash);
747
}
748
749
constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
750
constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
751
constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
752
constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
753
754
#ifndef NDEBUG
755
void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
756
OS << "Magic: " << format("0x%x", Magic) << "\n"
757
<< "Version: " << Version << "\n"
758
<< "Hash Function: " << HashFunction << "\n"
759
<< "Bucket Count: " << BucketCount << "\n"
760
<< "Header Data Length: " << HeaderDataLength << "\n";
761
}
762
763
void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
764
OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
765
<< "Form: " << dwarf::FormEncodingString(Form) << "\n";
766
}
767
768
void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
769
OS << "DIE Offset Base: " << DieOffsetBase << "\n";
770
for (auto Atom : Atoms)
771
Atom.print(OS);
772
}
773
774
void AppleAccelTableWriter::print(raw_ostream &OS) const {
775
Header.print(OS);
776
HeaderData.print(OS);
777
Contents.print(OS);
778
SecBegin->print(OS, nullptr);
779
}
780
781
void AccelTableBase::HashData::print(raw_ostream &OS) const {
782
OS << "Name: " << Name.getString() << "\n";
783
OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
784
OS << " Symbol: ";
785
if (Sym)
786
OS << *Sym;
787
else
788
OS << "<none>";
789
OS << "\n";
790
for (auto *Value : Values)
791
Value->print(OS);
792
}
793
794
void AccelTableBase::print(raw_ostream &OS) const {
795
// Print Content.
796
OS << "Entries: \n";
797
for (const auto &[Name, Data] : Entries) {
798
OS << "Name: " << Name << "\n";
799
for (auto *V : Data.Values)
800
V->print(OS);
801
}
802
803
OS << "Buckets and Hashes: \n";
804
for (const auto &Bucket : Buckets)
805
for (const auto &Hash : Bucket)
806
Hash->print(OS);
807
808
OS << "Data: \n";
809
for (const auto &E : Entries)
810
E.second.print(OS);
811
}
812
813
void DWARF5AccelTableData::print(raw_ostream &OS) const {
814
OS << " Offset: " << getDieOffset() << "\n";
815
OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
816
}
817
818
void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
819
OS << " Offset: " << Die.getOffset() << "\n";
820
}
821
822
void AppleAccelTableTypeData::print(raw_ostream &OS) const {
823
OS << " Offset: " << Die.getOffset() << "\n";
824
OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
825
}
826
827
void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
828
OS << " Static Offset: " << Offset << "\n";
829
}
830
831
void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
832
OS << " Static Offset: " << Offset << "\n";
833
OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
834
OS << " Tag: " << dwarf::TagString(Tag) << "\n";
835
OS << " ObjCClassIsImplementation: "
836
<< (ObjCClassIsImplementation ? "true" : "false");
837
OS << "\n";
838
}
839
#endif
840
841