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