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