diff options
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp | 244 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 89 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h | 24 |
3 files changed, 332 insertions, 25 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp index c80cc59691f..d6cfbdb37e5 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/AccelTable.h" +#include "DwarfCompileUnit.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" @@ -86,6 +87,8 @@ void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) { } namespace { +/// Base class for writing out Accelerator tables. It holds the common +/// functionality for the two Accelerator table types. class AccelTableEmitter { protected: AsmPrinter *const Asm; ///< Destination. @@ -176,6 +179,63 @@ public: void dump() const { print(dbgs()); } #endif }; + +/// Class responsible for emitting a DWARF v5 Accelerator Table. The only public +/// function is emit(), which performs the actual emission. +class Dwarf5AccelTableEmitter : public AccelTableEmitter { + struct Header { + uint32_t UnitLength = 0; + uint16_t Version = 5; + uint16_t Padding = 0; + uint32_t CompUnitCount; + uint32_t LocalTypeUnitCount = 0; + uint32_t ForeignTypeUnitCount = 0; + uint32_t BucketCount; + uint32_t NameCount; + uint32_t AbbrevTableSize = 0; + uint32_t AugmentationStringSize = sizeof(AugmentationString); + char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; + + Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount) + : CompUnitCount(CompUnitCount), BucketCount(BucketCount), + NameCount(NameCount) {} + + void emit(const Dwarf5AccelTableEmitter &Ctx) const; + }; + struct AttributeEncoding { + dwarf::Index Index; + dwarf::Form Form; + }; + + Header Header; + DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations; + const DwarfDebug ⅅ + ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits; + MCSymbol *ContributionStart = Asm->createTempSymbol("names_start"); + MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end"); + MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); + MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); + MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); + + DenseSet<uint32_t> getUniqueTags() const; + + // Right now, we emit uniform attributes for all tags. + SmallVector<AttributeEncoding, 2> getUniformAttributes() const; + + void emitCUList() const; + void emitBuckets() const; + void emitStringOffsets() const; + void emitAbbrevs() const; + void emitEntry(const DWARF5AccelTableData &Data) const; + void emitData() const; + +public: + Dwarf5AccelTableEmitter( + AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD, + ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits); + + void emit() const; +}; } // namespace void AccelTableEmitter::emitHashes() const { @@ -294,6 +354,178 @@ void AppleAccelTableEmitter::emit() const { emitData(); } +void Dwarf5AccelTableEmitter::Header::emit( + const Dwarf5AccelTableEmitter &Ctx) const { + AsmPrinter *Asm = Ctx.Asm; + Asm->OutStreamer->AddComment("Header: unit length"); + Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart, + sizeof(uint32_t)); + Asm->OutStreamer->EmitLabel(Ctx.ContributionStart); + Asm->OutStreamer->AddComment("Header: version"); + Asm->emitInt16(Version); + Asm->OutStreamer->AddComment("Header: padding"); + Asm->emitInt16(Padding); + Asm->OutStreamer->AddComment("Header: compilation unit count"); + Asm->emitInt32(CompUnitCount); + Asm->OutStreamer->AddComment("Header: local type unit count"); + Asm->emitInt32(LocalTypeUnitCount); + Asm->OutStreamer->AddComment("Header: foreign type unit count"); + Asm->emitInt32(ForeignTypeUnitCount); + Asm->OutStreamer->AddComment("Header: bucket count"); + Asm->emitInt32(BucketCount); + Asm->OutStreamer->AddComment("Header: name count"); + Asm->emitInt32(NameCount); + Asm->OutStreamer->AddComment("Header: abbreviation table size"); + Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t)); + Asm->OutStreamer->AddComment("Header: augmentation string size"); + assert(AugmentationStringSize % 4 == 0); + Asm->emitInt32(AugmentationStringSize); + Asm->OutStreamer->AddComment("Header: augmentation string"); + Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize}); +} + +DenseSet<uint32_t> Dwarf5AccelTableEmitter::getUniqueTags() const { + DenseSet<uint32_t> UniqueTags; + for (auto &Bucket : Contents.getBuckets()) { + for (auto *Hash : Bucket) { + for (auto *Value : Hash->Values) { + const DIE &Die = + static_cast<const DWARF5AccelTableData *>(Value)->getDie(); + UniqueTags.insert(Die.getTag()); + } + } + } + return UniqueTags; +} + +SmallVector<Dwarf5AccelTableEmitter::AttributeEncoding, 2> +Dwarf5AccelTableEmitter::getUniformAttributes() const { + SmallVector<AttributeEncoding, 2> UA; + if (CompUnits.size() > 1) { + size_t LargestCUIndex = CompUnits.size() - 1; + dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex); + UA.push_back({dwarf::DW_IDX_compile_unit, Form}); + } + UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); + return UA; +} + +void Dwarf5AccelTableEmitter::emitCUList() const { + for (const auto &CU : enumerate(CompUnits)) { + assert(CU.index() == CU.value()->getUniqueID()); + Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index())); + Asm->emitDwarfSymbolReference(CU.value()->getLabelBegin()); + } +} + +void Dwarf5AccelTableEmitter::emitBuckets() const { + uint32_t Index = 1; + for (const auto &Bucket : enumerate(Contents.getBuckets())) { + Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); + Asm->emitInt32(Bucket.value().empty() ? 0 : Index); + Index += Bucket.value().size(); + } +} + +void Dwarf5AccelTableEmitter::emitStringOffsets() const { + for (const auto &Bucket : enumerate(Contents.getBuckets())) { + for (auto *Hash : Bucket.value()) { + DwarfStringPoolEntryRef String = Hash->Name; + Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + + ": " + String.getString()); + Asm->emitDwarfStringOffset(String); + } + } +} + +void Dwarf5AccelTableEmitter::emitAbbrevs() const { + Asm->OutStreamer->EmitLabel(AbbrevStart); + for (const auto &Abbrev : Abbreviations) { + Asm->OutStreamer->AddComment("Abbrev code"); + assert(Abbrev.first != 0); + Asm->EmitULEB128(Abbrev.first); + Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first)); + Asm->EmitULEB128(Abbrev.first); + for (const auto &AttrEnc : Abbrev.second) { + Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); + Asm->EmitULEB128(AttrEnc.Form, + dwarf::FormEncodingString(AttrEnc.Form).data()); + } + Asm->EmitULEB128(0, "End of abbrev"); + Asm->EmitULEB128(0, "End of abbrev"); + } + Asm->EmitULEB128(0, "End of abbrev list"); + Asm->OutStreamer->EmitLabel(AbbrevEnd); +} + +void Dwarf5AccelTableEmitter::emitEntry( + const DWARF5AccelTableData &Entry) const { + auto AbbrevIt = Abbreviations.find(Entry.getDie().getTag()); + assert(AbbrevIt != Abbreviations.end() && + "Why wasn't this abbrev generated?"); + + Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code"); + for (const auto &AttrEnc : AbbrevIt->second) { + Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); + switch (AttrEnc.Index) { + case dwarf::DW_IDX_compile_unit: { + const DIE *CUDie = Entry.getDie().getUnitDie(); + DIEInteger ID(DD.lookupCU(CUDie)->getUniqueID()); + ID.EmitValue(Asm, AttrEnc.Form); + break; + } + case dwarf::DW_IDX_die_offset: + assert(AttrEnc.Form == dwarf::DW_FORM_ref4); + Asm->emitInt32(Entry.getDie().getOffset()); + break; + default: + llvm_unreachable("Unexpected index attribute!"); + } + } +} + +void Dwarf5AccelTableEmitter::emitData() const { + Asm->OutStreamer->EmitLabel(EntryPool); + for (auto &Bucket : Contents.getBuckets()) { + for (auto *Hash : Bucket) { + // Remember to emit the label for our offset. + Asm->OutStreamer->EmitLabel(Hash->Sym); + for (const auto *Value : Hash->Values) + emitEntry(*static_cast<const DWARF5AccelTableData *>(Value)); + Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); + Asm->emitInt32(0); + } + } +} + +Dwarf5AccelTableEmitter::Dwarf5AccelTableEmitter( + AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD, + ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits) + : AccelTableEmitter(Asm, Contents, false), + Header(CompUnits.size(), Contents.getBucketCount(), + Contents.getUniqueNameCount()), + DD(DD), CompUnits(CompUnits) { + DenseSet<uint32_t> UniqueTags = getUniqueTags(); + SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes(); + + Abbreviations.reserve(UniqueTags.size()); + for (uint32_t Tag : UniqueTags) + Abbreviations.try_emplace(Tag, UniformAttributes); +} + +void Dwarf5AccelTableEmitter::emit() const { + Header.emit(*this); + emitCUList(); + emitBuckets(); + emitHashes(); + emitStringOffsets(); + emitOffsets(EntryPool); + emitAbbrevs(); + emitData(); + Asm->OutStreamer->EmitValueToAlignment(4, 0); + Asm->OutStreamer->EmitLabel(ContributionEnd); +} + void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, StringRef Prefix, const MCSymbol *SecBegin, ArrayRef<AppleAccelTableData::Atom> Atoms) { @@ -301,6 +533,13 @@ void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, AppleAccelTableEmitter(Asm, Contents, Atoms, SecBegin).emit(); } +void llvm::emitDWARF5AccelTable( + AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents, + const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { + Contents.finalize(Asm, "names"); + Dwarf5AccelTableEmitter(Asm, Contents, DD, CUs).emit(); +} + void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { Asm->emitInt32(Die->getDebugSectionOffset()); } @@ -407,6 +646,11 @@ void AccelTableBase::print(raw_ostream &OS) const { E.second.print(OS); } +void DWARF5AccelTableData::print(raw_ostream &OS) const { + OS << " Offset: " << Die.getOffset() << "\n"; + OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; +} + void AppleAccelTableOffsetData::print(raw_ostream &OS) const { OS << " Offset: " << Die->getOffset() << "\n"; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 7353875ad39..76a360d2ca2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -107,13 +107,14 @@ static cl::opt<DefaultOnOff> UnknownLocations( clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")), cl::init(Default)); -static cl::opt<DefaultOnOff> -DwarfAccelTables("dwarf-accel-tables", cl::Hidden, - cl::desc("Output prototype dwarf accelerator tables."), - cl::values(clEnumVal(Default, "Default for platform"), - clEnumVal(Enable, "Enabled"), - clEnumVal(Disable, "Disabled")), - cl::init(Default)); +static cl::opt<AccelTableKind> AccelTables( + "accel-tables", cl::Hidden, cl::desc("Output dwarf accelerator tables."), + cl::values(clEnumValN(AccelTableKind::Default, "Default", + "Default for platform"), + clEnumValN(AccelTableKind::None, "Disable", "Disabled."), + clEnumValN(AccelTableKind::Apple, "Apple", "Apple"), + clEnumValN(AccelTableKind::Dwarf, "Dwarf", "DWARF")), + cl::init(AccelTableKind::Default)); static cl::opt<DefaultOnOff> DwarfInlinedStrings("dwarf-inlined-strings", cl::Hidden, @@ -303,11 +304,13 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) // Turn on accelerator tables by default, if tuning for LLDB and the target is // supported. - if (DwarfAccelTables == Default) - HasDwarfAccelTables = - tuneForLLDB() && A->TM.getTargetTriple().isOSBinFormatMachO(); - else - HasDwarfAccelTables = DwarfAccelTables == Enable; + if (AccelTables == AccelTableKind::Default) { + if (tuneForLLDB() && A->TM.getTargetTriple().isOSBinFormatMachO()) + AccelTableKind = AccelTableKind::Apple; + else + AccelTableKind = AccelTableKind::None; + } else + AccelTableKind = AccelTables; UseInlineStrings = DwarfInlinedStrings == Enable; HasAppleExtensionAttributes = tuneForLLDB(); @@ -839,11 +842,20 @@ void DwarfDebug::endModule() { } // Emit info into the dwarf accelerator table sections. - if (useDwarfAccelTables()) { + switch (getAccelTableKind()) { + case AccelTableKind::Apple: emitAccelNames(); emitAccelObjC(); emitAccelNamespaces(); emitAccelTypes(); + break; + case AccelTableKind::Dwarf: + emitAccelDebugNames(); + break; + case AccelTableKind::None: + break; + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); } // Emit the pubnames and pubtypes sections if requested. @@ -1455,6 +1467,12 @@ void DwarfDebug::emitAccel(AccelTableT &Accel, MCSection *Section, emitAppleAccelTable(Asm, Accel, TableName, Section->getBeginSymbol()); } +void DwarfDebug::emitAccelDebugNames() { + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfDebugNamesSection()); + emitDWARF5AccelTable(Asm, AccelDebugNames, *this, getUnits()); +} + // Emit visible names into a hashed accelerator table section. void DwarfDebug::emitAccelNames() { emitAccel(AccelNames, Asm->getObjFileLowering().getDwarfAccelNamesSection(), @@ -2250,27 +2268,58 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, // to reference is in the string table. We do this since the names we // add may not only be identical to the names in the DIE. void DwarfDebug::addAccelName(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) + switch (getAccelTableKind()) { + case AccelTableKind::Apple: + AccelNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + break; + case AccelTableKind::Dwarf: + AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), + Die); + break; + case AccelTableKind::None: return; - AccelNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); + } } void DwarfDebug::addAccelObjC(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) + if (getAccelTableKind() != AccelTableKind::Apple) return; AccelObjC.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); } void DwarfDebug::addAccelNamespace(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) + switch (getAccelTableKind()) { + case AccelTableKind::Apple: + AccelNamespace.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), + &Die); + break; + case AccelTableKind::Dwarf: + AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), + Die); + break; + case AccelTableKind::None: return; - AccelNamespace.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); + } } void DwarfDebug::addAccelType(StringRef Name, const DIE &Die, char Flags) { - if (!useDwarfAccelTables()) + switch (getAccelTableKind()) { + case AccelTableKind::Apple: + AccelTypes.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + break; + case AccelTableKind::Dwarf: + AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), + Die); + break; + case AccelTableKind::None: return; - AccelTypes.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); + } } uint16_t DwarfDebug::getDwarfVersion() const { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index 3ee78710e8f..b1703e9a46a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -192,6 +192,14 @@ struct SymbolCU { DwarfCompileUnit *CU; }; +/// The kind of accelerator tables we should emit. +enum class AccelTableKind { + Default, ///< Platform default. + None, ///< None. + Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. + Dwarf, ///< DWARF v5 .debug_names. +}; + /// Collects and handles dwarf debug information. class DwarfDebug : public DebugHandlerBase { /// All DIEValues are allocated through this allocator. @@ -270,7 +278,7 @@ class DwarfDebug : public DebugHandlerBase { /// DWARF5 Experimental Options /// @{ - bool HasDwarfAccelTables; + AccelTableKind AccelTableKind; bool HasAppleExtensionAttributes; bool HasSplitDwarf; @@ -302,7 +310,8 @@ class DwarfDebug : public DebugHandlerBase { AddressPool AddrPool; - /// Apple accelerator tables. + /// Accelerator tables. + AccelTable<DWARF5AccelTableData> AccelDebugNames; AccelTable<AppleAccelTableOffsetData> AccelNames; AccelTable<AppleAccelTableOffsetData> AccelObjC; AccelTable<AppleAccelTableOffsetData> AccelNamespace; @@ -351,6 +360,9 @@ class DwarfDebug : public DebugHandlerBase { template <typename AccelTableT> void emitAccel(AccelTableT &Accel, MCSection *Section, StringRef TableName); + /// Emit DWARF v5 accelerator table. + void emitAccelDebugNames(); + /// Emit visible names into a hashed accelerator table section. void emitAccelNames(); @@ -523,9 +535,8 @@ public: // Experimental DWARF5 features. - /// Returns whether or not to emit tables that dwarf consumers can - /// use to accelerate lookup. - bool useDwarfAccelTables() const { return HasDwarfAccelTables; } + /// Returns what kind (if any) of accelerator tables to emit. + llvm::AccelTableKind getAccelTableKind() const { return AccelTableKind; } bool useAppleExtensionAttributes() const { return HasAppleExtensionAttributes; @@ -590,6 +601,9 @@ public: /// Find the matching DwarfCompileUnit for the given CU DIE. DwarfCompileUnit *lookupCU(const DIE *Die) { return CUDieMap.lookup(Die); } + const DwarfCompileUnit *lookupCU(const DIE *Die) const { + return CUDieMap.lookup(Die); + } /// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger. /// |