1 //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains support for writing accelerator tables. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/CodeGen/AccelTable.h" 15 #include "DwarfCompileUnit.h" 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/ADT/Twine.h" 19 #include "llvm/BinaryFormat/Dwarf.h" 20 #include "llvm/CodeGen/AsmPrinter.h" 21 #include "llvm/CodeGen/DIE.h" 22 #include "llvm/MC/MCExpr.h" 23 #include "llvm/MC/MCStreamer.h" 24 #include "llvm/MC/MCSymbol.h" 25 #include "llvm/Support/raw_ostream.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 std::stable_sort(E.second.Values.begin(), E.second.Values.end(), 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 std::stable_sort(Bucket.begin(), Bucket.end(), 85 [](HashData *LHS, HashData *RHS) { 86 return LHS->HashValue < RHS->HashValue; 87 }); 88 } 89 90 namespace { 91 /// Base class for writing out Accelerator tables. It holds the common 92 /// functionality for the two Accelerator table types. 93 class AccelTableWriter { 94 protected: 95 AsmPrinter *const Asm; ///< Destination. 96 const AccelTableBase &Contents; ///< Data to emit. 97 98 /// Controls whether to emit duplicate hash and offset table entries for names 99 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5 100 /// tables do. 101 const bool SkipIdenticalHashes; 102 103 void emitHashes() const; 104 105 /// Emit offsets to lists of entries with identical names. The offsets are 106 /// relative to the Base argument. 107 void emitOffsets(const MCSymbol *Base) const; 108 109 public: 110 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 111 bool SkipIdenticalHashes) 112 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) { 113 } 114 }; 115 116 class AppleAccelTableWriter : public AccelTableWriter { 117 using Atom = AppleAccelTableData::Atom; 118 119 /// The fixed header of an Apple Accelerator Table. 120 struct Header { 121 uint32_t Magic = MagicHash; 122 uint16_t Version = 1; 123 uint16_t HashFunction = dwarf::DW_hash_function_djb; 124 uint32_t BucketCount; 125 uint32_t HashCount; 126 uint32_t HeaderDataLength; 127 128 /// 'HASH' magic value to detect endianness. 129 static const uint32_t MagicHash = 0x48415348; 130 131 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength) 132 : BucketCount(BucketCount), HashCount(UniqueHashCount), 133 HeaderDataLength(DataLength) {} 134 135 void emit(AsmPrinter *Asm) const; 136 #ifndef NDEBUG 137 void print(raw_ostream &OS) const; 138 void dump() const { print(dbgs()); } 139 #endif 140 }; 141 142 /// The HeaderData describes the structure of an Apple accelerator table 143 /// through a list of Atoms. 144 struct HeaderData { 145 /// In the case of data that is referenced via DW_FORM_ref_* the offset 146 /// base is used to describe the offset for all forms in the list of atoms. 147 uint32_t DieOffsetBase; 148 149 const SmallVector<Atom, 4> Atoms; 150 151 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0) 152 : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {} 153 154 void emit(AsmPrinter *Asm) const; 155 #ifndef NDEBUG 156 void print(raw_ostream &OS) const; 157 void dump() const { print(dbgs()); } 158 #endif 159 }; 160 161 Header Header; 162 HeaderData HeaderData; 163 const MCSymbol *SecBegin; 164 165 void emitBuckets() const; 166 void emitData() const; 167 168 public: 169 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 170 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin) 171 : AccelTableWriter(Asm, Contents, true), 172 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(), 173 8 + (Atoms.size() * 4)), 174 HeaderData(Atoms), SecBegin(SecBegin) {} 175 176 void emit() const; 177 178 #ifndef NDEBUG 179 void print(raw_ostream &OS) const; 180 void dump() const { print(dbgs()); } 181 #endif 182 }; 183 184 /// Class responsible for emitting a DWARF v5 Accelerator Table. The only 185 /// public function is emit(), which performs the actual emission. 186 /// 187 /// The class is templated in its data type. This allows us to emit both dyamic 188 /// and static data entries. A callback abstract the logic to provide a CU 189 /// index for a given entry, which is different per data type, but identical 190 /// for every entry in the same table. 191 template <typename DataT> 192 class Dwarf5AccelTableWriter : public AccelTableWriter { 193 struct Header { 194 uint32_t UnitLength = 0; 195 uint16_t Version = 5; 196 uint16_t Padding = 0; 197 uint32_t CompUnitCount; 198 uint32_t LocalTypeUnitCount = 0; 199 uint32_t ForeignTypeUnitCount = 0; 200 uint32_t BucketCount; 201 uint32_t NameCount; 202 uint32_t AbbrevTableSize = 0; 203 uint32_t AugmentationStringSize = sizeof(AugmentationString); 204 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; 205 206 Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount) 207 : CompUnitCount(CompUnitCount), BucketCount(BucketCount), 208 NameCount(NameCount) {} 209 210 void emit(const Dwarf5AccelTableWriter &Ctx) const; 211 }; 212 struct AttributeEncoding { 213 dwarf::Index Index; 214 dwarf::Form Form; 215 }; 216 217 Header Header; 218 DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations; 219 ArrayRef<MCSymbol *> CompUnits; 220 llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry; 221 MCSymbol *ContributionStart = Asm->createTempSymbol("names_start"); 222 MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end"); 223 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); 224 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); 225 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); 226 227 DenseSet<uint32_t> getUniqueTags() const; 228 229 // Right now, we emit uniform attributes for all tags. 230 SmallVector<AttributeEncoding, 2> getUniformAttributes() const; 231 232 void emitCUList() const; 233 void emitBuckets() const; 234 void emitStringOffsets() const; 235 void emitAbbrevs() const; 236 void emitEntry(const DataT &Entry) const; 237 void emitData() const; 238 239 public: 240 Dwarf5AccelTableWriter( 241 AsmPrinter *Asm, const AccelTableBase &Contents, 242 ArrayRef<MCSymbol *> CompUnits, 243 llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry); 244 245 void emit() const; 246 }; 247 } // namespace 248 249 void AccelTableWriter::emitHashes() const { 250 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 251 unsigned BucketIdx = 0; 252 for (auto &Bucket : Contents.getBuckets()) { 253 for (auto &Hash : Bucket) { 254 uint32_t HashValue = Hash->HashValue; 255 if (SkipIdenticalHashes && PrevHash == HashValue) 256 continue; 257 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx)); 258 Asm->emitInt32(HashValue); 259 PrevHash = HashValue; 260 } 261 BucketIdx++; 262 } 263 } 264 265 void AccelTableWriter::emitOffsets(const MCSymbol *Base) const { 266 const auto &Buckets = Contents.getBuckets(); 267 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 268 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 269 for (auto *Hash : Buckets[i]) { 270 uint32_t HashValue = Hash->HashValue; 271 if (SkipIdenticalHashes && PrevHash == HashValue) 272 continue; 273 PrevHash = HashValue; 274 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); 275 Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t)); 276 } 277 } 278 } 279 280 void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const { 281 Asm->OutStreamer->AddComment("Header Magic"); 282 Asm->emitInt32(Magic); 283 Asm->OutStreamer->AddComment("Header Version"); 284 Asm->emitInt16(Version); 285 Asm->OutStreamer->AddComment("Header Hash Function"); 286 Asm->emitInt16(HashFunction); 287 Asm->OutStreamer->AddComment("Header Bucket Count"); 288 Asm->emitInt32(BucketCount); 289 Asm->OutStreamer->AddComment("Header Hash Count"); 290 Asm->emitInt32(HashCount); 291 Asm->OutStreamer->AddComment("Header Data Length"); 292 Asm->emitInt32(HeaderDataLength); 293 } 294 295 void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const { 296 Asm->OutStreamer->AddComment("HeaderData Die Offset Base"); 297 Asm->emitInt32(DieOffsetBase); 298 Asm->OutStreamer->AddComment("HeaderData Atom Count"); 299 Asm->emitInt32(Atoms.size()); 300 301 for (const Atom &A : Atoms) { 302 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type)); 303 Asm->emitInt16(A.Type); 304 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form)); 305 Asm->emitInt16(A.Form); 306 } 307 } 308 309 void AppleAccelTableWriter::emitBuckets() const { 310 const auto &Buckets = Contents.getBuckets(); 311 unsigned index = 0; 312 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 313 Asm->OutStreamer->AddComment("Bucket " + Twine(i)); 314 if (!Buckets[i].empty()) 315 Asm->emitInt32(index); 316 else 317 Asm->emitInt32(std::numeric_limits<uint32_t>::max()); 318 // Buckets point in the list of hashes, not to the data. Do not increment 319 // the index multiple times in case of hash collisions. 320 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 321 for (auto *HD : Buckets[i]) { 322 uint32_t HashValue = HD->HashValue; 323 if (PrevHash != HashValue) 324 ++index; 325 PrevHash = HashValue; 326 } 327 } 328 } 329 330 void AppleAccelTableWriter::emitData() const { 331 const auto &Buckets = Contents.getBuckets(); 332 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 333 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 334 for (auto &Hash : Buckets[i]) { 335 // Terminate the previous entry if there is no hash collision with the 336 // current one. 337 if (PrevHash != std::numeric_limits<uint64_t>::max() && 338 PrevHash != Hash->HashValue) 339 Asm->emitInt32(0); 340 // Remember to emit the label for our offset. 341 Asm->OutStreamer->EmitLabel(Hash->Sym); 342 Asm->OutStreamer->AddComment(Hash->Name.getString()); 343 Asm->emitDwarfStringOffset(Hash->Name); 344 Asm->OutStreamer->AddComment("Num DIEs"); 345 Asm->emitInt32(Hash->Values.size()); 346 for (const auto *V : Hash->Values) 347 static_cast<const AppleAccelTableData *>(V)->emit(Asm); 348 PrevHash = Hash->HashValue; 349 } 350 // Emit the final end marker for the bucket. 351 if (!Buckets[i].empty()) 352 Asm->emitInt32(0); 353 } 354 } 355 356 void AppleAccelTableWriter::emit() const { 357 Header.emit(Asm); 358 HeaderData.emit(Asm); 359 emitBuckets(); 360 emitHashes(); 361 emitOffsets(SecBegin); 362 emitData(); 363 } 364 365 template <typename DataT> 366 void Dwarf5AccelTableWriter<DataT>::Header::emit( 367 const Dwarf5AccelTableWriter &Ctx) const { 368 assert(CompUnitCount > 0 && "Index must have at least one CU."); 369 370 AsmPrinter *Asm = Ctx.Asm; 371 Asm->OutStreamer->AddComment("Header: unit length"); 372 Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart, 373 sizeof(uint32_t)); 374 Asm->OutStreamer->EmitLabel(Ctx.ContributionStart); 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 template <typename DataT> 399 DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const { 400 DenseSet<uint32_t> UniqueTags; 401 for (auto &Bucket : Contents.getBuckets()) { 402 for (auto *Hash : Bucket) { 403 for (auto *Value : Hash->Values) { 404 unsigned Tag = static_cast<const DataT *>(Value)->getDieTag(); 405 UniqueTags.insert(Tag); 406 } 407 } 408 } 409 return UniqueTags; 410 } 411 412 template <typename DataT> 413 SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2> 414 Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const { 415 SmallVector<AttributeEncoding, 2> UA; 416 if (CompUnits.size() > 1) { 417 size_t LargestCUIndex = CompUnits.size() - 1; 418 dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex); 419 UA.push_back({dwarf::DW_IDX_compile_unit, Form}); 420 } 421 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); 422 return UA; 423 } 424 425 template <typename DataT> 426 void Dwarf5AccelTableWriter<DataT>::emitCUList() const { 427 for (const auto &CU : enumerate(CompUnits)) { 428 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index())); 429 Asm->emitDwarfSymbolReference(CU.value()); 430 } 431 } 432 433 template <typename DataT> 434 void Dwarf5AccelTableWriter<DataT>::emitBuckets() const { 435 uint32_t Index = 1; 436 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 437 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); 438 Asm->emitInt32(Bucket.value().empty() ? 0 : Index); 439 Index += Bucket.value().size(); 440 } 441 } 442 443 template <typename DataT> 444 void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const { 445 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 446 for (auto *Hash : Bucket.value()) { 447 DwarfStringPoolEntryRef String = Hash->Name; 448 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + 449 ": " + String.getString()); 450 Asm->emitDwarfStringOffset(String); 451 } 452 } 453 } 454 455 template <typename DataT> 456 void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const { 457 Asm->OutStreamer->EmitLabel(AbbrevStart); 458 for (const auto &Abbrev : Abbreviations) { 459 Asm->OutStreamer->AddComment("Abbrev code"); 460 assert(Abbrev.first != 0); 461 Asm->EmitULEB128(Abbrev.first); 462 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first)); 463 Asm->EmitULEB128(Abbrev.first); 464 for (const auto &AttrEnc : Abbrev.second) { 465 Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); 466 Asm->EmitULEB128(AttrEnc.Form, 467 dwarf::FormEncodingString(AttrEnc.Form).data()); 468 } 469 Asm->EmitULEB128(0, "End of abbrev"); 470 Asm->EmitULEB128(0, "End of abbrev"); 471 } 472 Asm->EmitULEB128(0, "End of abbrev list"); 473 Asm->OutStreamer->EmitLabel(AbbrevEnd); 474 } 475 476 template <typename DataT> 477 void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const { 478 auto AbbrevIt = Abbreviations.find(Entry.getDieTag()); 479 assert(AbbrevIt != Abbreviations.end() && 480 "Why wasn't this abbrev generated?"); 481 482 Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code"); 483 for (const auto &AttrEnc : AbbrevIt->second) { 484 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); 485 switch (AttrEnc.Index) { 486 case dwarf::DW_IDX_compile_unit: { 487 DIEInteger ID(getCUIndexForEntry(Entry)); 488 ID.EmitValue(Asm, AttrEnc.Form); 489 break; 490 } 491 case dwarf::DW_IDX_die_offset: 492 assert(AttrEnc.Form == dwarf::DW_FORM_ref4); 493 Asm->emitInt32(Entry.getDieOffset()); 494 break; 495 default: 496 llvm_unreachable("Unexpected index attribute!"); 497 } 498 } 499 } 500 501 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const { 502 Asm->OutStreamer->EmitLabel(EntryPool); 503 for (auto &Bucket : Contents.getBuckets()) { 504 for (auto *Hash : Bucket) { 505 // Remember to emit the label for our offset. 506 Asm->OutStreamer->EmitLabel(Hash->Sym); 507 for (const auto *Value : Hash->Values) 508 emitEntry(*static_cast<const DataT *>(Value)); 509 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); 510 Asm->emitInt32(0); 511 } 512 } 513 } 514 515 template <typename DataT> 516 Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter( 517 AsmPrinter *Asm, const AccelTableBase &Contents, 518 ArrayRef<MCSymbol *> CompUnits, 519 llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry) 520 : AccelTableWriter(Asm, Contents, false), 521 Header(CompUnits.size(), Contents.getBucketCount(), 522 Contents.getUniqueNameCount()), 523 CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) { 524 DenseSet<uint32_t> UniqueTags = getUniqueTags(); 525 SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes(); 526 527 Abbreviations.reserve(UniqueTags.size()); 528 for (uint32_t Tag : UniqueTags) 529 Abbreviations.try_emplace(Tag, UniformAttributes); 530 } 531 532 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() const { 533 Header.emit(*this); 534 emitCUList(); 535 emitBuckets(); 536 emitHashes(); 537 emitStringOffsets(); 538 emitOffsets(EntryPool); 539 emitAbbrevs(); 540 emitData(); 541 Asm->OutStreamer->EmitValueToAlignment(4, 0); 542 Asm->OutStreamer->EmitLabel(ContributionEnd); 543 } 544 545 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, 546 StringRef Prefix, const MCSymbol *SecBegin, 547 ArrayRef<AppleAccelTableData::Atom> Atoms) { 548 Contents.finalize(Asm, Prefix); 549 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit(); 550 } 551 552 void llvm::emitDWARF5AccelTable( 553 AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents, 554 const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { 555 std::vector<MCSymbol *> CompUnits; 556 for (const auto &CU : enumerate(CUs)) { 557 assert(CU.index() == CU.value()->getUniqueID()); 558 const DwarfCompileUnit *MainCU = 559 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get(); 560 CompUnits.push_back(MainCU->getLabelBegin()); 561 } 562 563 Contents.finalize(Asm, "names"); 564 Dwarf5AccelTableWriter<DWARF5AccelTableData>( 565 Asm, Contents, CompUnits, 566 [&DD](const DWARF5AccelTableData &Entry) { 567 const DIE *CUDie = Entry.getDie().getUnitDie(); 568 return DD.lookupCU(CUDie)->getUniqueID(); 569 }) 570 .emit(); 571 } 572 573 void llvm::emitDWARF5AccelTable( 574 AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents, 575 ArrayRef<MCSymbol *> CUs, 576 llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)> 577 getCUIndexForEntry) { 578 Contents.finalize(Asm, "names"); 579 Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs, 580 getCUIndexForEntry) 581 .emit(); 582 } 583 584 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { 585 Asm->emitInt32(Die.getDebugSectionOffset()); 586 } 587 588 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { 589 Asm->emitInt32(Die.getDebugSectionOffset()); 590 Asm->emitInt16(Die.getTag()); 591 Asm->emitInt8(0); 592 } 593 594 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { 595 Asm->emitInt32(Offset); 596 } 597 598 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { 599 Asm->emitInt32(Offset); 600 Asm->emitInt16(Tag); 601 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation 602 : 0); 603 Asm->emitInt32(QualifiedNameHash); 604 } 605 606 #ifndef _MSC_VER 607 // The lines below are rejected by older versions (TBD) of MSVC. 608 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[]; 609 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[]; 610 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[]; 611 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[]; 612 #else 613 // FIXME: Erase this path once the minimum MSCV version has been bumped. 614 const SmallVector<AppleAccelTableData::Atom, 4> 615 AppleAccelTableOffsetData::Atoms = { 616 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; 617 const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms = 618 {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), 619 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), 620 Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; 621 const SmallVector<AppleAccelTableData::Atom, 4> 622 AppleAccelTableStaticOffsetData::Atoms = { 623 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; 624 const SmallVector<AppleAccelTableData::Atom, 4> 625 AppleAccelTableStaticTypeData::Atoms = { 626 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), 627 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), 628 Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)}; 629 #endif 630 631 #ifndef NDEBUG 632 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const { 633 OS << "Magic: " << format("0x%x", Magic) << "\n" 634 << "Version: " << Version << "\n" 635 << "Hash Function: " << HashFunction << "\n" 636 << "Bucket Count: " << BucketCount << "\n" 637 << "Header Data Length: " << HeaderDataLength << "\n"; 638 } 639 640 void AppleAccelTableData::Atom::print(raw_ostream &OS) const { 641 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" 642 << "Form: " << dwarf::FormEncodingString(Form) << "\n"; 643 } 644 645 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const { 646 OS << "DIE Offset Base: " << DieOffsetBase << "\n"; 647 for (auto Atom : Atoms) 648 Atom.print(OS); 649 } 650 651 void AppleAccelTableWriter::print(raw_ostream &OS) const { 652 Header.print(OS); 653 HeaderData.print(OS); 654 Contents.print(OS); 655 SecBegin->print(OS, nullptr); 656 } 657 658 void AccelTableBase::HashData::print(raw_ostream &OS) const { 659 OS << "Name: " << Name.getString() << "\n"; 660 OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; 661 OS << " Symbol: "; 662 if (Sym) 663 OS << *Sym; 664 else 665 OS << "<none>"; 666 OS << "\n"; 667 for (auto *Value : Values) 668 Value->print(OS); 669 } 670 671 void AccelTableBase::print(raw_ostream &OS) const { 672 // Print Content. 673 OS << "Entries: \n"; 674 for (const auto &Entry : Entries) { 675 OS << "Name: " << Entry.first() << "\n"; 676 for (auto *V : Entry.second.Values) 677 V->print(OS); 678 } 679 680 OS << "Buckets and Hashes: \n"; 681 for (auto &Bucket : Buckets) 682 for (auto &Hash : Bucket) 683 Hash->print(OS); 684 685 OS << "Data: \n"; 686 for (auto &E : Entries) 687 E.second.print(OS); 688 } 689 690 void DWARF5AccelTableData::print(raw_ostream &OS) const { 691 OS << " Offset: " << getDieOffset() << "\n"; 692 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; 693 } 694 695 void DWARF5AccelTableStaticData::print(raw_ostream &OS) const { 696 OS << " Offset: " << getDieOffset() << "\n"; 697 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; 698 } 699 700 void AppleAccelTableOffsetData::print(raw_ostream &OS) const { 701 OS << " Offset: " << Die.getOffset() << "\n"; 702 } 703 704 void AppleAccelTableTypeData::print(raw_ostream &OS) const { 705 OS << " Offset: " << Die.getOffset() << "\n"; 706 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; 707 } 708 709 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const { 710 OS << " Static Offset: " << Offset << "\n"; 711 } 712 713 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const { 714 OS << " Static Offset: " << Offset << "\n"; 715 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; 716 OS << " Tag: " << dwarf::TagString(Tag) << "\n"; 717 OS << " ObjCClassIsImplementation: " 718 << (ObjCClassIsImplementation ? "true" : "false"); 719 OS << "\n"; 720 } 721 #endif 722