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