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 /// The class is templated in its data type. This allows us to emit both dyamic 186 /// and static data entries. A callback abstract the logic to provide a CU 187 /// index for a given entry, which is different per data type, but identical 188 /// for every entry in the same table. 189 template <typename DataT> 190 class Dwarf5AccelTableWriter : public AccelTableWriter { 191 struct Header { 192 uint16_t Version = 5; 193 uint16_t Padding = 0; 194 uint32_t CompUnitCount; 195 uint32_t LocalTypeUnitCount = 0; 196 uint32_t ForeignTypeUnitCount = 0; 197 uint32_t BucketCount = 0; 198 uint32_t NameCount = 0; 199 uint32_t AbbrevTableSize = 0; 200 uint32_t AugmentationStringSize = sizeof(AugmentationString); 201 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; 202 203 Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount, 204 uint32_t BucketCount, uint32_t NameCount) 205 : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount), 206 BucketCount(BucketCount), NameCount(NameCount) {} 207 208 void emit(Dwarf5AccelTableWriter &Ctx); 209 }; 210 211 Header Header; 212 DenseMap<uint32_t, SmallVector<DWARF5AccelTableData::AttributeEncoding, 2>> 213 Abbreviations; 214 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits; 215 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits; 216 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>( 217 const DataT &)> 218 getIndexForEntry; 219 MCSymbol *ContributionEnd = nullptr; 220 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); 221 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); 222 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); 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 DataT &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< 240 std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(const DataT &)> 241 getIndexForEntry); 242 243 void emit(); 244 }; 245 } // namespace 246 247 void AccelTableWriter::emitHashes() const { 248 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 249 unsigned BucketIdx = 0; 250 for (const auto &Bucket : Contents.getBuckets()) { 251 for (const auto &Hash : Bucket) { 252 uint32_t HashValue = Hash->HashValue; 253 if (SkipIdenticalHashes && PrevHash == HashValue) 254 continue; 255 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx)); 256 Asm->emitInt32(HashValue); 257 PrevHash = HashValue; 258 } 259 BucketIdx++; 260 } 261 } 262 263 void AccelTableWriter::emitOffsets(const MCSymbol *Base) const { 264 const auto &Buckets = Contents.getBuckets(); 265 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 266 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 267 for (auto *Hash : Buckets[i]) { 268 uint32_t HashValue = Hash->HashValue; 269 if (SkipIdenticalHashes && PrevHash == HashValue) 270 continue; 271 PrevHash = HashValue; 272 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); 273 Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize()); 274 } 275 } 276 } 277 278 void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const { 279 Asm->OutStreamer->AddComment("Header Magic"); 280 Asm->emitInt32(Magic); 281 Asm->OutStreamer->AddComment("Header Version"); 282 Asm->emitInt16(Version); 283 Asm->OutStreamer->AddComment("Header Hash Function"); 284 Asm->emitInt16(HashFunction); 285 Asm->OutStreamer->AddComment("Header Bucket Count"); 286 Asm->emitInt32(BucketCount); 287 Asm->OutStreamer->AddComment("Header Hash Count"); 288 Asm->emitInt32(HashCount); 289 Asm->OutStreamer->AddComment("Header Data Length"); 290 Asm->emitInt32(HeaderDataLength); 291 } 292 293 void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const { 294 Asm->OutStreamer->AddComment("HeaderData Die Offset Base"); 295 Asm->emitInt32(DieOffsetBase); 296 Asm->OutStreamer->AddComment("HeaderData Atom Count"); 297 Asm->emitInt32(Atoms.size()); 298 299 for (const Atom &A : Atoms) { 300 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type)); 301 Asm->emitInt16(A.Type); 302 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form)); 303 Asm->emitInt16(A.Form); 304 } 305 } 306 307 void AppleAccelTableWriter::emitBuckets() const { 308 const auto &Buckets = Contents.getBuckets(); 309 unsigned index = 0; 310 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 311 Asm->OutStreamer->AddComment("Bucket " + Twine(i)); 312 if (!Buckets[i].empty()) 313 Asm->emitInt32(index); 314 else 315 Asm->emitInt32(std::numeric_limits<uint32_t>::max()); 316 // Buckets point in the list of hashes, not to the data. Do not increment 317 // the index multiple times in case of hash collisions. 318 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 319 for (auto *HD : Buckets[i]) { 320 uint32_t HashValue = HD->HashValue; 321 if (PrevHash != HashValue) 322 ++index; 323 PrevHash = HashValue; 324 } 325 } 326 } 327 328 void AppleAccelTableWriter::emitData() const { 329 const auto &Buckets = Contents.getBuckets(); 330 for (const AccelTableBase::HashList &Bucket : Buckets) { 331 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 332 for (const auto &Hash : Bucket) { 333 // Terminate the previous entry if there is no hash collision with the 334 // current one. 335 if (PrevHash != std::numeric_limits<uint64_t>::max() && 336 PrevHash != Hash->HashValue) 337 Asm->emitInt32(0); 338 // Remember to emit the label for our offset. 339 Asm->OutStreamer->emitLabel(Hash->Sym); 340 Asm->OutStreamer->AddComment(Hash->Name.getString()); 341 Asm->emitDwarfStringOffset(Hash->Name); 342 Asm->OutStreamer->AddComment("Num DIEs"); 343 Asm->emitInt32(Hash->Values.size()); 344 for (const auto *V : Hash->Values) 345 static_cast<const AppleAccelTableData *>(V)->emit(Asm); 346 PrevHash = Hash->HashValue; 347 } 348 // Emit the final end marker for the bucket. 349 if (!Bucket.empty()) 350 Asm->emitInt32(0); 351 } 352 } 353 354 void AppleAccelTableWriter::emit() const { 355 Header.emit(Asm); 356 HeaderData.emit(Asm); 357 emitBuckets(); 358 emitHashes(); 359 emitOffsets(SecBegin); 360 emitData(); 361 } 362 363 DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die, 364 const uint32_t UnitID, 365 const bool IsTU) 366 : OffsetVal(&Die), DieTag(Die.getTag()), UnitID(UnitID), IsTU(IsTU) {} 367 368 template <typename DataT> 369 void Dwarf5AccelTableWriter<DataT>::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->Endoding.Index; 411 AbbrvTag |= 1 << dwarf::DW_IDX_die_offset; 412 AbbrvTag |= Tag << LowerBitSize; 413 return AbbrvTag; 414 } 415 template <typename DataT> 416 void Dwarf5AccelTableWriter<DataT>::populateAbbrevsMap() { 417 for (auto &Bucket : Contents.getBuckets()) { 418 for (auto *Hash : Bucket) { 419 for (auto *Value : Hash->Values) { 420 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet = 421 getIndexForEntry(*static_cast<const DataT *>(Value)); 422 unsigned Tag = static_cast<const DataT *>(Value)->getDieTag(); 423 uint32_t AbbrvTag = constructAbbreviationTag(Tag, EntryRet); 424 if (Abbreviations.count(AbbrvTag) == 0) { 425 SmallVector<DWARF5AccelTableData::AttributeEncoding, 2> UA; 426 if (EntryRet) 427 UA.push_back(EntryRet->Endoding); 428 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); 429 Abbreviations.try_emplace(AbbrvTag, UA); 430 } 431 } 432 } 433 } 434 } 435 436 template <typename DataT> 437 void Dwarf5AccelTableWriter<DataT>::emitCUList() const { 438 for (const auto &CU : enumerate(CompUnits)) { 439 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index())); 440 if (std::holds_alternative<MCSymbol *>(CU.value())) 441 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value())); 442 else 443 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value())); 444 } 445 } 446 447 template <typename DataT> 448 void Dwarf5AccelTableWriter<DataT>::emitTUList() const { 449 for (const auto &TU : enumerate(TypeUnits)) { 450 Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index())); 451 if (std::holds_alternative<MCSymbol *>(TU.value())) 452 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value())); 453 else 454 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value())); 455 } 456 } 457 458 template <typename DataT> 459 void Dwarf5AccelTableWriter<DataT>::emitBuckets() const { 460 uint32_t Index = 1; 461 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 462 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); 463 Asm->emitInt32(Bucket.value().empty() ? 0 : Index); 464 Index += Bucket.value().size(); 465 } 466 } 467 468 template <typename DataT> 469 void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const { 470 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 471 for (auto *Hash : Bucket.value()) { 472 DwarfStringPoolEntryRef String = Hash->Name; 473 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + 474 ": " + String.getString()); 475 Asm->emitDwarfStringOffset(String); 476 } 477 } 478 } 479 480 template <typename DataT> 481 void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const { 482 Asm->OutStreamer->emitLabel(AbbrevStart); 483 for (const auto &Abbrev : Abbreviations) { 484 Asm->OutStreamer->AddComment("Abbrev code"); 485 uint32_t Tag = getTagFromAbbreviationTag(Abbrev.first); 486 assert(Tag != 0); 487 Asm->emitULEB128(Abbrev.first); 488 Asm->OutStreamer->AddComment(dwarf::TagString(Tag)); 489 Asm->emitULEB128(Tag); 490 for (const auto &AttrEnc : Abbrev.second) { 491 Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); 492 Asm->emitULEB128(AttrEnc.Form, 493 dwarf::FormEncodingString(AttrEnc.Form).data()); 494 } 495 Asm->emitULEB128(0, "End of abbrev"); 496 Asm->emitULEB128(0, "End of abbrev"); 497 } 498 Asm->emitULEB128(0, "End of abbrev list"); 499 Asm->OutStreamer->emitLabel(AbbrevEnd); 500 } 501 502 template <typename DataT> 503 void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const { 504 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet = 505 getIndexForEntry(Entry); 506 uint32_t AbbrvTag = constructAbbreviationTag(Entry.getDieTag(), EntryRet); 507 auto AbbrevIt = Abbreviations.find(AbbrvTag); 508 assert(AbbrevIt != Abbreviations.end() && 509 "Why wasn't this abbrev generated?"); 510 assert(getTagFromAbbreviationTag(AbbrevIt->first) == Entry.getDieTag() && 511 "Invalid Tag"); 512 Asm->emitULEB128(AbbrevIt->first, "Abbreviation code"); 513 514 for (const auto &AttrEnc : AbbrevIt->second) { 515 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); 516 switch (AttrEnc.Index) { 517 case dwarf::DW_IDX_compile_unit: 518 case dwarf::DW_IDX_type_unit: { 519 DIEInteger ID(EntryRet->Index); 520 ID.emitValue(Asm, AttrEnc.Form); 521 break; 522 } 523 case dwarf::DW_IDX_die_offset: 524 assert(AttrEnc.Form == dwarf::DW_FORM_ref4); 525 Asm->emitInt32(Entry.getDieOffset()); 526 break; 527 default: 528 llvm_unreachable("Unexpected index attribute!"); 529 } 530 } 531 } 532 533 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const { 534 Asm->OutStreamer->emitLabel(EntryPool); 535 for (auto &Bucket : Contents.getBuckets()) { 536 for (auto *Hash : Bucket) { 537 // Remember to emit the label for our offset. 538 Asm->OutStreamer->emitLabel(Hash->Sym); 539 for (const auto *Value : Hash->Values) 540 emitEntry(*static_cast<const DataT *>(Value)); 541 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); 542 Asm->emitInt8(0); 543 } 544 } 545 } 546 547 template <typename DataT> 548 Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter( 549 AsmPrinter *Asm, const AccelTableBase &Contents, 550 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits, 551 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits, 552 llvm::function_ref< 553 std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(const DataT &)> 554 getIndexForEntry) 555 : AccelTableWriter(Asm, Contents, false), 556 Header(CompUnits.size(), TypeUnits.size(), Contents.getBucketCount(), 557 Contents.getUniqueNameCount()), 558 CompUnits(CompUnits), TypeUnits(TypeUnits), 559 getIndexForEntry(std::move(getIndexForEntry)) { 560 populateAbbrevsMap(); 561 } 562 563 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() { 564 Header.emit(*this); 565 emitCUList(); 566 emitTUList(); 567 emitBuckets(); 568 emitHashes(); 569 emitStringOffsets(); 570 emitOffsets(EntryPool); 571 emitAbbrevs(); 572 emitData(); 573 Asm->OutStreamer->emitValueToAlignment(Align(4), 0); 574 Asm->OutStreamer->emitLabel(ContributionEnd); 575 } 576 577 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, 578 StringRef Prefix, const MCSymbol *SecBegin, 579 ArrayRef<AppleAccelTableData::Atom> Atoms) { 580 Contents.finalize(Asm, Prefix); 581 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit(); 582 } 583 584 void llvm::emitDWARF5AccelTable( 585 AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD, 586 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { 587 TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols(); 588 std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits; 589 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits; 590 SmallVector<unsigned, 1> CUIndex(CUs.size()); 591 DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size()); 592 int CUCount = 0; 593 int TUCount = 0; 594 for (const auto &CU : enumerate(CUs)) { 595 switch (CU.value()->getCUNode()->getNameTableKind()) { 596 case DICompileUnit::DebugNameTableKind::Default: 597 case DICompileUnit::DebugNameTableKind::Apple: 598 break; 599 default: 600 continue; 601 } 602 CUIndex[CU.index()] = CUCount++; 603 assert(CU.index() == CU.value()->getUniqueID()); 604 const DwarfCompileUnit *MainCU = 605 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get(); 606 CompUnits.push_back(MainCU->getLabelBegin()); 607 } 608 609 for (const auto &TU : TUSymbols) { 610 TUIndex[TU.UniqueID] = TUCount++; 611 TypeUnits.push_back(TU.Label); 612 } 613 614 if (CompUnits.empty()) 615 return; 616 617 Asm->OutStreamer->switchSection( 618 Asm->getObjFileLowering().getDwarfDebugNamesSection()); 619 620 Contents.finalize(Asm, "names"); 621 dwarf::Form CUIndexForm = 622 DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1); 623 dwarf::Form TUIndexForm = 624 DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1); 625 Dwarf5AccelTableWriter<DWARF5AccelTableData>( 626 Asm, Contents, CompUnits, TypeUnits, 627 [&](const DWARF5AccelTableData &Entry) 628 -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> { 629 if (Entry.isTU()) 630 return {{TUIndex[Entry.getUnitID()], 631 {dwarf::DW_IDX_type_unit, TUIndexForm}}}; 632 if (CUIndex.size() > 1) 633 return {{CUIndex[Entry.getUnitID()], 634 {dwarf::DW_IDX_compile_unit, CUIndexForm}}}; 635 return std::nullopt; 636 }) 637 .emit(); 638 } 639 640 void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) { 641 TUSymbols.push_back({U.getLabelBegin(), U.getUniqueID()}); 642 } 643 644 void llvm::emitDWARF5AccelTable( 645 AsmPrinter *Asm, DWARF5AccelTable &Contents, 646 ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs, 647 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>( 648 const DWARF5AccelTableData &)> 649 getIndexForEntry) { 650 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits; 651 Contents.finalize(Asm, "names"); 652 Dwarf5AccelTableWriter<DWARF5AccelTableData>(Asm, Contents, CUs, TypeUnits, 653 getIndexForEntry) 654 .emit(); 655 } 656 657 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { 658 assert(Die.getDebugSectionOffset() <= UINT32_MAX && 659 "The section offset exceeds the limit."); 660 Asm->emitInt32(Die.getDebugSectionOffset()); 661 } 662 663 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { 664 assert(Die.getDebugSectionOffset() <= UINT32_MAX && 665 "The section offset exceeds the limit."); 666 Asm->emitInt32(Die.getDebugSectionOffset()); 667 Asm->emitInt16(Die.getTag()); 668 Asm->emitInt8(0); 669 } 670 671 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { 672 Asm->emitInt32(Offset); 673 } 674 675 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { 676 Asm->emitInt32(Offset); 677 Asm->emitInt16(Tag); 678 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation 679 : 0); 680 Asm->emitInt32(QualifiedNameHash); 681 } 682 683 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[]; 684 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[]; 685 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[]; 686 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[]; 687 688 #ifndef NDEBUG 689 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const { 690 OS << "Magic: " << format("0x%x", Magic) << "\n" 691 << "Version: " << Version << "\n" 692 << "Hash Function: " << HashFunction << "\n" 693 << "Bucket Count: " << BucketCount << "\n" 694 << "Header Data Length: " << HeaderDataLength << "\n"; 695 } 696 697 void AppleAccelTableData::Atom::print(raw_ostream &OS) const { 698 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" 699 << "Form: " << dwarf::FormEncodingString(Form) << "\n"; 700 } 701 702 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const { 703 OS << "DIE Offset Base: " << DieOffsetBase << "\n"; 704 for (auto Atom : Atoms) 705 Atom.print(OS); 706 } 707 708 void AppleAccelTableWriter::print(raw_ostream &OS) const { 709 Header.print(OS); 710 HeaderData.print(OS); 711 Contents.print(OS); 712 SecBegin->print(OS, nullptr); 713 } 714 715 void AccelTableBase::HashData::print(raw_ostream &OS) const { 716 OS << "Name: " << Name.getString() << "\n"; 717 OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; 718 OS << " Symbol: "; 719 if (Sym) 720 OS << *Sym; 721 else 722 OS << "<none>"; 723 OS << "\n"; 724 for (auto *Value : Values) 725 Value->print(OS); 726 } 727 728 void AccelTableBase::print(raw_ostream &OS) const { 729 // Print Content. 730 OS << "Entries: \n"; 731 for (const auto &[Name, Data] : Entries) { 732 OS << "Name: " << Name << "\n"; 733 for (auto *V : Data.Values) 734 V->print(OS); 735 } 736 737 OS << "Buckets and Hashes: \n"; 738 for (const auto &Bucket : Buckets) 739 for (const auto &Hash : Bucket) 740 Hash->print(OS); 741 742 OS << "Data: \n"; 743 for (const auto &E : Entries) 744 E.second.print(OS); 745 } 746 747 void DWARF5AccelTableData::print(raw_ostream &OS) const { 748 OS << " Offset: " << getDieOffset() << "\n"; 749 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; 750 } 751 752 void AppleAccelTableOffsetData::print(raw_ostream &OS) const { 753 OS << " Offset: " << Die.getOffset() << "\n"; 754 } 755 756 void AppleAccelTableTypeData::print(raw_ostream &OS) const { 757 OS << " Offset: " << Die.getOffset() << "\n"; 758 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; 759 } 760 761 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const { 762 OS << " Static Offset: " << Offset << "\n"; 763 } 764 765 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const { 766 OS << " Static Offset: " << Offset << "\n"; 767 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; 768 OS << " Tag: " << dwarf::TagString(Tag) << "\n"; 769 OS << " ObjCClassIsImplementation: " 770 << (ObjCClassIsImplementation ? "true" : "false"); 771 OS << "\n"; 772 } 773 #endif 774