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