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 "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/StringMap.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/MCExpr.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 std::vector<uint32_t> Uniques; 37 Uniques.reserve(Entries.size()); 38 for (const auto &E : Entries) 39 Uniques.push_back(E.second.HashValue); 40 array_pod_sort(Uniques.begin(), Uniques.end()); 41 std::vector<uint32_t>::iterator P = 42 std::unique(Uniques.begin(), Uniques.end()); 43 44 UniqueHashCount = std::distance(Uniques.begin(), P); 45 46 if (UniqueHashCount > 1024) 47 BucketCount = UniqueHashCount / 4; 48 else if (UniqueHashCount > 16) 49 BucketCount = UniqueHashCount / 2; 50 else 51 BucketCount = std::max<uint32_t>(UniqueHashCount, 1); 52 } 53 54 void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) { 55 // Create the individual hash data outputs. 56 for (auto &E : Entries) { 57 // Unique the entries. 58 llvm::stable_sort(E.second.Values, 59 [](const AccelTableData *A, const AccelTableData *B) { 60 return *A < *B; 61 }); 62 E.second.Values.erase( 63 std::unique(E.second.Values.begin(), E.second.Values.end()), 64 E.second.Values.end()); 65 } 66 67 // Figure out how many buckets we need, then compute the bucket contents and 68 // the final ordering. The hashes and offsets can be emitted by walking these 69 // data structures. We add temporary symbols to the data so they can be 70 // referenced when emitting the offsets. 71 computeBucketCount(); 72 73 // Compute bucket contents and final ordering. 74 Buckets.resize(BucketCount); 75 for (auto &E : Entries) { 76 uint32_t Bucket = E.second.HashValue % BucketCount; 77 Buckets[Bucket].push_back(&E.second); 78 E.second.Sym = Asm->createTempSymbol(Prefix); 79 } 80 81 // Sort the contents of the buckets by hash value so that hash collisions end 82 // up together. Stable sort makes testing easier and doesn't cost much more. 83 for (auto &Bucket : Buckets) 84 llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) { 85 return LHS->HashValue < RHS->HashValue; 86 }); 87 } 88 89 namespace { 90 /// Base class for writing out Accelerator tables. It holds the common 91 /// functionality for the two Accelerator table types. 92 class AccelTableWriter { 93 protected: 94 AsmPrinter *const Asm; ///< Destination. 95 const AccelTableBase &Contents; ///< Data to emit. 96 97 /// Controls whether to emit duplicate hash and offset table entries for names 98 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5 99 /// tables do. 100 const bool SkipIdenticalHashes; 101 102 void emitHashes() const; 103 104 /// Emit offsets to lists of entries with identical names. The offsets are 105 /// relative to the Base argument. 106 void emitOffsets(const MCSymbol *Base) const; 107 108 public: 109 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 110 bool SkipIdenticalHashes) 111 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) { 112 } 113 }; 114 115 class AppleAccelTableWriter : public AccelTableWriter { 116 using Atom = AppleAccelTableData::Atom; 117 118 /// The fixed header of an Apple Accelerator Table. 119 struct Header { 120 uint32_t Magic = MagicHash; 121 uint16_t Version = 1; 122 uint16_t HashFunction = dwarf::DW_hash_function_djb; 123 uint32_t BucketCount; 124 uint32_t HashCount; 125 uint32_t HeaderDataLength; 126 127 /// 'HASH' magic value to detect endianness. 128 static const uint32_t MagicHash = 0x48415348; 129 130 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength) 131 : BucketCount(BucketCount), HashCount(UniqueHashCount), 132 HeaderDataLength(DataLength) {} 133 134 void emit(AsmPrinter *Asm) const; 135 #ifndef NDEBUG 136 void print(raw_ostream &OS) const; 137 void dump() const { print(dbgs()); } 138 #endif 139 }; 140 141 /// The HeaderData describes the structure of an Apple accelerator table 142 /// through a list of Atoms. 143 struct HeaderData { 144 /// In the case of data that is referenced via DW_FORM_ref_* the offset 145 /// base is used to describe the offset for all forms in the list of atoms. 146 uint32_t DieOffsetBase; 147 148 const SmallVector<Atom, 4> Atoms; 149 150 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0) 151 : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {} 152 153 void emit(AsmPrinter *Asm) const; 154 #ifndef NDEBUG 155 void print(raw_ostream &OS) const; 156 void dump() const { print(dbgs()); } 157 #endif 158 }; 159 160 Header Header; 161 HeaderData HeaderData; 162 const MCSymbol *SecBegin; 163 164 void emitBuckets() const; 165 void emitData() const; 166 167 public: 168 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 169 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin) 170 : AccelTableWriter(Asm, Contents, true), 171 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(), 172 8 + (Atoms.size() * 4)), 173 HeaderData(Atoms), SecBegin(SecBegin) {} 174 175 void emit() const; 176 177 #ifndef NDEBUG 178 void print(raw_ostream &OS) const; 179 void dump() const { print(dbgs()); } 180 #endif 181 }; 182 183 /// Class responsible for emitting a DWARF v5 Accelerator Table. The only 184 /// public function is emit(), which performs the actual emission. 185 /// 186 /// The class is templated in its data type. This allows us to emit both dyamic 187 /// and static data entries. A callback abstract the logic to provide a CU 188 /// index for a given entry, which is different per data type, but identical 189 /// for every entry in the same table. 190 template <typename DataT> 191 class Dwarf5AccelTableWriter : public AccelTableWriter { 192 struct Header { 193 uint16_t Version = 5; 194 uint16_t Padding = 0; 195 uint32_t CompUnitCount; 196 uint32_t LocalTypeUnitCount = 0; 197 uint32_t ForeignTypeUnitCount = 0; 198 uint32_t BucketCount; 199 uint32_t NameCount; 200 uint32_t AbbrevTableSize = 0; 201 uint32_t AugmentationStringSize = sizeof(AugmentationString); 202 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; 203 204 Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount) 205 : CompUnitCount(CompUnitCount), BucketCount(BucketCount), 206 NameCount(NameCount) {} 207 208 void emit(const Dwarf5AccelTableWriter &Ctx) const; 209 }; 210 struct AttributeEncoding { 211 dwarf::Index Index; 212 dwarf::Form Form; 213 }; 214 215 Header Header; 216 DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations; 217 ArrayRef<MCSymbol *> CompUnits; 218 llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry; 219 MCSymbol *ContributionStart = Asm->createTempSymbol("names_start"); 220 MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end"); 221 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); 222 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); 223 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); 224 225 DenseSet<uint32_t> getUniqueTags() const; 226 227 // Right now, we emit uniform attributes for all tags. 228 SmallVector<AttributeEncoding, 2> getUniformAttributes() const; 229 230 void emitCUList() const; 231 void emitBuckets() const; 232 void emitStringOffsets() const; 233 void emitAbbrevs() const; 234 void emitEntry(const DataT &Entry) const; 235 void emitData() const; 236 237 public: 238 Dwarf5AccelTableWriter( 239 AsmPrinter *Asm, const AccelTableBase &Contents, 240 ArrayRef<MCSymbol *> CompUnits, 241 llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry); 242 243 void emit() const; 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 (auto &Bucket : Contents.getBuckets()) { 251 for (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 (size_t i = 0, e = Buckets.size(); i < e; ++i) { 331 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 332 for (auto &Hash : Buckets[i]) { 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 (!Buckets[i].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 template <typename DataT> 364 void Dwarf5AccelTableWriter<DataT>::Header::emit( 365 const Dwarf5AccelTableWriter &Ctx) const { 366 assert(CompUnitCount > 0 && "Index must have at least one CU."); 367 368 AsmPrinter *Asm = Ctx.Asm; 369 Asm->emitDwarfUnitLength(Ctx.ContributionEnd, Ctx.ContributionStart, 370 "Header: unit length"); 371 Asm->OutStreamer->emitLabel(Ctx.ContributionStart); 372 Asm->OutStreamer->AddComment("Header: version"); 373 Asm->emitInt16(Version); 374 Asm->OutStreamer->AddComment("Header: padding"); 375 Asm->emitInt16(Padding); 376 Asm->OutStreamer->AddComment("Header: compilation unit count"); 377 Asm->emitInt32(CompUnitCount); 378 Asm->OutStreamer->AddComment("Header: local type unit count"); 379 Asm->emitInt32(LocalTypeUnitCount); 380 Asm->OutStreamer->AddComment("Header: foreign type unit count"); 381 Asm->emitInt32(ForeignTypeUnitCount); 382 Asm->OutStreamer->AddComment("Header: bucket count"); 383 Asm->emitInt32(BucketCount); 384 Asm->OutStreamer->AddComment("Header: name count"); 385 Asm->emitInt32(NameCount); 386 Asm->OutStreamer->AddComment("Header: abbreviation table size"); 387 Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t)); 388 Asm->OutStreamer->AddComment("Header: augmentation string size"); 389 assert(AugmentationStringSize % 4 == 0); 390 Asm->emitInt32(AugmentationStringSize); 391 Asm->OutStreamer->AddComment("Header: augmentation string"); 392 Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize}); 393 } 394 395 template <typename DataT> 396 DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const { 397 DenseSet<uint32_t> UniqueTags; 398 for (auto &Bucket : Contents.getBuckets()) { 399 for (auto *Hash : Bucket) { 400 for (auto *Value : Hash->Values) { 401 unsigned Tag = static_cast<const DataT *>(Value)->getDieTag(); 402 UniqueTags.insert(Tag); 403 } 404 } 405 } 406 return UniqueTags; 407 } 408 409 template <typename DataT> 410 SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2> 411 Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const { 412 SmallVector<AttributeEncoding, 2> UA; 413 if (CompUnits.size() > 1) { 414 size_t LargestCUIndex = CompUnits.size() - 1; 415 dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex); 416 UA.push_back({dwarf::DW_IDX_compile_unit, Form}); 417 } 418 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); 419 return UA; 420 } 421 422 template <typename DataT> 423 void Dwarf5AccelTableWriter<DataT>::emitCUList() const { 424 for (const auto &CU : enumerate(CompUnits)) { 425 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index())); 426 Asm->emitDwarfSymbolReference(CU.value()); 427 } 428 } 429 430 template <typename DataT> 431 void Dwarf5AccelTableWriter<DataT>::emitBuckets() const { 432 uint32_t Index = 1; 433 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 434 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); 435 Asm->emitInt32(Bucket.value().empty() ? 0 : Index); 436 Index += Bucket.value().size(); 437 } 438 } 439 440 template <typename DataT> 441 void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const { 442 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 443 for (auto *Hash : Bucket.value()) { 444 DwarfStringPoolEntryRef String = Hash->Name; 445 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + 446 ": " + String.getString()); 447 Asm->emitDwarfStringOffset(String); 448 } 449 } 450 } 451 452 template <typename DataT> 453 void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const { 454 Asm->OutStreamer->emitLabel(AbbrevStart); 455 for (const auto &Abbrev : Abbreviations) { 456 Asm->OutStreamer->AddComment("Abbrev code"); 457 assert(Abbrev.first != 0); 458 Asm->emitULEB128(Abbrev.first); 459 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first)); 460 Asm->emitULEB128(Abbrev.first); 461 for (const auto &AttrEnc : Abbrev.second) { 462 Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); 463 Asm->emitULEB128(AttrEnc.Form, 464 dwarf::FormEncodingString(AttrEnc.Form).data()); 465 } 466 Asm->emitULEB128(0, "End of abbrev"); 467 Asm->emitULEB128(0, "End of abbrev"); 468 } 469 Asm->emitULEB128(0, "End of abbrev list"); 470 Asm->OutStreamer->emitLabel(AbbrevEnd); 471 } 472 473 template <typename DataT> 474 void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const { 475 auto AbbrevIt = Abbreviations.find(Entry.getDieTag()); 476 assert(AbbrevIt != Abbreviations.end() && 477 "Why wasn't this abbrev generated?"); 478 479 Asm->emitULEB128(AbbrevIt->first, "Abbreviation code"); 480 for (const auto &AttrEnc : AbbrevIt->second) { 481 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); 482 switch (AttrEnc.Index) { 483 case dwarf::DW_IDX_compile_unit: { 484 DIEInteger ID(getCUIndexForEntry(Entry)); 485 ID.emitValue(Asm, AttrEnc.Form); 486 break; 487 } 488 case dwarf::DW_IDX_die_offset: 489 assert(AttrEnc.Form == dwarf::DW_FORM_ref4); 490 Asm->emitInt32(Entry.getDieOffset()); 491 break; 492 default: 493 llvm_unreachable("Unexpected index attribute!"); 494 } 495 } 496 } 497 498 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const { 499 Asm->OutStreamer->emitLabel(EntryPool); 500 for (auto &Bucket : Contents.getBuckets()) { 501 for (auto *Hash : Bucket) { 502 // Remember to emit the label for our offset. 503 Asm->OutStreamer->emitLabel(Hash->Sym); 504 for (const auto *Value : Hash->Values) 505 emitEntry(*static_cast<const DataT *>(Value)); 506 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); 507 Asm->emitInt8(0); 508 } 509 } 510 } 511 512 template <typename DataT> 513 Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter( 514 AsmPrinter *Asm, const AccelTableBase &Contents, 515 ArrayRef<MCSymbol *> CompUnits, 516 llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry) 517 : AccelTableWriter(Asm, Contents, false), 518 Header(CompUnits.size(), Contents.getBucketCount(), 519 Contents.getUniqueNameCount()), 520 CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) { 521 DenseSet<uint32_t> UniqueTags = getUniqueTags(); 522 SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes(); 523 524 Abbreviations.reserve(UniqueTags.size()); 525 for (uint32_t Tag : UniqueTags) 526 Abbreviations.try_emplace(Tag, UniformAttributes); 527 } 528 529 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() const { 530 Header.emit(*this); 531 emitCUList(); 532 emitBuckets(); 533 emitHashes(); 534 emitStringOffsets(); 535 emitOffsets(EntryPool); 536 emitAbbrevs(); 537 emitData(); 538 Asm->OutStreamer->emitValueToAlignment(4, 0); 539 Asm->OutStreamer->emitLabel(ContributionEnd); 540 } 541 542 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, 543 StringRef Prefix, const MCSymbol *SecBegin, 544 ArrayRef<AppleAccelTableData::Atom> Atoms) { 545 Contents.finalize(Asm, Prefix); 546 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit(); 547 } 548 549 void llvm::emitDWARF5AccelTable( 550 AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents, 551 const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { 552 std::vector<MCSymbol *> CompUnits; 553 SmallVector<unsigned, 1> CUIndex(CUs.size()); 554 int Count = 0; 555 for (const auto &CU : enumerate(CUs)) { 556 if (CU.value()->getCUNode()->getNameTableKind() != 557 DICompileUnit::DebugNameTableKind::Default) 558 continue; 559 CUIndex[CU.index()] = Count++; 560 assert(CU.index() == CU.value()->getUniqueID()); 561 const DwarfCompileUnit *MainCU = 562 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get(); 563 CompUnits.push_back(MainCU->getLabelBegin()); 564 } 565 566 if (CompUnits.empty()) 567 return; 568 569 Asm->OutStreamer->SwitchSection( 570 Asm->getObjFileLowering().getDwarfDebugNamesSection()); 571 572 Contents.finalize(Asm, "names"); 573 Dwarf5AccelTableWriter<DWARF5AccelTableData>( 574 Asm, Contents, CompUnits, 575 [&](const DWARF5AccelTableData &Entry) { 576 const DIE *CUDie = Entry.getDie().getUnitDie(); 577 return CUIndex[DD.lookupCU(CUDie)->getUniqueID()]; 578 }) 579 .emit(); 580 } 581 582 void llvm::emitDWARF5AccelTable( 583 AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents, 584 ArrayRef<MCSymbol *> CUs, 585 llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)> 586 getCUIndexForEntry) { 587 Contents.finalize(Asm, "names"); 588 Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs, 589 getCUIndexForEntry) 590 .emit(); 591 } 592 593 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { 594 assert(Die.getDebugSectionOffset() <= UINT32_MAX && 595 "The section offset exceeds the limit."); 596 Asm->emitInt32(Die.getDebugSectionOffset()); 597 } 598 599 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { 600 assert(Die.getDebugSectionOffset() <= UINT32_MAX && 601 "The section offset exceeds the limit."); 602 Asm->emitInt32(Die.getDebugSectionOffset()); 603 Asm->emitInt16(Die.getTag()); 604 Asm->emitInt8(0); 605 } 606 607 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { 608 Asm->emitInt32(Offset); 609 } 610 611 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { 612 Asm->emitInt32(Offset); 613 Asm->emitInt16(Tag); 614 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation 615 : 0); 616 Asm->emitInt32(QualifiedNameHash); 617 } 618 619 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[]; 620 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[]; 621 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[]; 622 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[]; 623 624 #ifndef NDEBUG 625 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const { 626 OS << "Magic: " << format("0x%x", Magic) << "\n" 627 << "Version: " << Version << "\n" 628 << "Hash Function: " << HashFunction << "\n" 629 << "Bucket Count: " << BucketCount << "\n" 630 << "Header Data Length: " << HeaderDataLength << "\n"; 631 } 632 633 void AppleAccelTableData::Atom::print(raw_ostream &OS) const { 634 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" 635 << "Form: " << dwarf::FormEncodingString(Form) << "\n"; 636 } 637 638 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const { 639 OS << "DIE Offset Base: " << DieOffsetBase << "\n"; 640 for (auto Atom : Atoms) 641 Atom.print(OS); 642 } 643 644 void AppleAccelTableWriter::print(raw_ostream &OS) const { 645 Header.print(OS); 646 HeaderData.print(OS); 647 Contents.print(OS); 648 SecBegin->print(OS, nullptr); 649 } 650 651 void AccelTableBase::HashData::print(raw_ostream &OS) const { 652 OS << "Name: " << Name.getString() << "\n"; 653 OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; 654 OS << " Symbol: "; 655 if (Sym) 656 OS << *Sym; 657 else 658 OS << "<none>"; 659 OS << "\n"; 660 for (auto *Value : Values) 661 Value->print(OS); 662 } 663 664 void AccelTableBase::print(raw_ostream &OS) const { 665 // Print Content. 666 OS << "Entries: \n"; 667 for (const auto &Entry : Entries) { 668 OS << "Name: " << Entry.first() << "\n"; 669 for (auto *V : Entry.second.Values) 670 V->print(OS); 671 } 672 673 OS << "Buckets and Hashes: \n"; 674 for (auto &Bucket : Buckets) 675 for (auto &Hash : Bucket) 676 Hash->print(OS); 677 678 OS << "Data: \n"; 679 for (auto &E : Entries) 680 E.second.print(OS); 681 } 682 683 void DWARF5AccelTableData::print(raw_ostream &OS) const { 684 OS << " Offset: " << getDieOffset() << "\n"; 685 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; 686 } 687 688 void DWARF5AccelTableStaticData::print(raw_ostream &OS) const { 689 OS << " Offset: " << getDieOffset() << "\n"; 690 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; 691 } 692 693 void AppleAccelTableOffsetData::print(raw_ostream &OS) const { 694 OS << " Offset: " << Die.getOffset() << "\n"; 695 } 696 697 void AppleAccelTableTypeData::print(raw_ostream &OS) const { 698 OS << " Offset: " << Die.getOffset() << "\n"; 699 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; 700 } 701 702 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const { 703 OS << " Static Offset: " << Offset << "\n"; 704 } 705 706 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const { 707 OS << " Static Offset: " << Offset << "\n"; 708 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; 709 OS << " Tag: " << dwarf::TagString(Tag) << "\n"; 710 OS << " ObjCClassIsImplementation: " 711 << (ObjCClassIsImplementation ? "true" : "false"); 712 OS << "\n"; 713 } 714 #endif 715