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