Index: include/llvm/CodeGen/AccelTable.h =================================================================== --- include/llvm/CodeGen/AccelTable.h +++ include/llvm/CodeGen/AccelTable.h @@ -92,6 +92,8 @@ namespace llvm { class AsmPrinter; +class DwarfCompileUnit; +class DwarfDebug; /// Interface which the different types of accelerator table data have to /// conform. It serves as a base class for different values of the template @@ -227,6 +229,24 @@ static uint32_t hash(StringRef Buffer) { return djbHash(Buffer); } }; +class DWARF5AccelTableData : public AccelTableData { +public: + static uint32_t hash(StringRef Name) { return caseFoldingDjbHash(Name); } + + DWARF5AccelTableData(const DIE &Die) : Die(Die) {} + +#ifndef NDEBUG + void print(raw_ostream &OS) const override { llvm_unreachable(""); } +#endif + + const DIE &getDie() const { return Die; } + +protected: + const DIE &Die; + + uint64_t order() const override { return Die.getOffset(); } +}; + namespace detail { void emitAppleAccelTable(AsmPrinter *Asm, AccelTableBase &Contents, StringRef Prefix, const MCSymbol *SecBegin, @@ -243,6 +263,11 @@ detail::emitAppleAccelTable(Asm, Contents, Prefix, SecBegin, DataT::Atoms); } +void emitDWARF5AccelTable(AsmPrinter *Asm, + AccelTable &Contents, + const DwarfDebug &DD, + ArrayRef> CUs); + /// Accelerator table data implementation for simple Apple accelerator tables /// with just a DIE reference. class AppleAccelTableOffsetData : public AppleAccelTableData { Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ include/llvm/MC/MCObjectFileInfo.h @@ -97,6 +97,7 @@ /// DwarfAccelNamespaceSection, DwarfAccelTypesSection - /// If we use the DWARF accelerated hash tables then we want to emit these /// sections. + MCSection *DwarfDebugNamesSection; MCSection *DwarfAccelNamesSection; MCSection *DwarfAccelObjCSection; MCSection *DwarfAccelNamespaceSection; @@ -255,6 +256,9 @@ MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; } // DWARF5 Experimental Debug Info Sections + MCSection *getDwarfDebugNamesSection() const { + return DwarfDebugNamesSection; + } MCSection *getDwarfAccelNamesSection() const { return DwarfAccelNamesSection; } Index: lib/CodeGen/AsmPrinter/AccelTable.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AccelTable.cpp +++ 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" @@ -178,6 +179,63 @@ void dump() const { print(dbgs()); } #endif }; + +class Dwarf5EmissionContext : public EmissionContext { + 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'}; + static_assert(sizeof(AugmentationString) % 4 == 0, ""); + + Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount) + : CompUnitCount(CompUnitCount), BucketCount(BucketCount), + NameCount(NameCount) {} + + void emit(const Dwarf5EmissionContext &Ctx) const; + }; + struct AttributeEncoding { + dwarf::Index Index; + dwarf::Form Form; + }; + + Header Header; + DenseMap> Abbreviations; + const DwarfDebug ⅅ + ArrayRef> 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 getUniqueTags() const; + + // Right now, we emit uniform attributes for all tags. + SmallVector getUniformAttributes() const; + + void emitCUList() const; + void emitBuckets() const; + void emitStringOffsets() const; + void emitAbbrevs() const; + void emitCompileUnitIndex(dwarf::Form Form, const DIE &CUDie) const; + void emitEntry(const DWARF5AccelTableData &Data) const; + void emitData() const; + +public: + Dwarf5EmissionContext(AsmPrinter *Asm, const AccelTableBase &Contents, + const DwarfDebug &DD, + ArrayRef> CompUnits); + + void emit() const; +}; } // namespace void EmissionContext::emitHashes() const { @@ -296,6 +354,205 @@ emitData(); } +void Dwarf5EmissionContext::Header::emit( + const Dwarf5EmissionContext &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"); + Asm->EmitInt32(AugmentationStringSize); + Asm->OutStreamer->AddComment("Header: augmentation string"); + Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize}); +} + +DenseSet Dwarf5EmissionContext::getUniqueTags() const { + DenseSet UniqueTags; + for (auto &Bucket : Contents.getBuckets()) { + for (auto *Hash : Bucket) { + for (auto *Value : Hash->Values) { + const DIE &Die = + static_cast(Value)->getDie(); + UniqueTags.insert(Die.getTag()); + } + } + } + return UniqueTags; +} + +SmallVector +Dwarf5EmissionContext::getUniformAttributes() const { + SmallVector UA; + if (CompUnits.size() > 1) { + dwarf::Form Form; + if (CompUnits.size() < 0x100) + Form = dwarf::DW_FORM_data1; + else if (CompUnits.size() < 0x10000) + Form = dwarf::DW_FORM_data2; + else { + assert(CompUnits.size() < 0x1000000ull && "Too many compilation units"); + Form = dwarf::DW_FORM_data4; + } + UA.push_back({dwarf::DW_IDX_compile_unit, Form}); + } + UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_sec_offset}); + return UA; +} + +void Dwarf5EmissionContext::emitCUList() const { + uint32_t Index = 0; + for (const auto &CU : CompUnits) { + assert(Index == CU->getUniqueID()); + Asm->OutStreamer->AddComment("Compilation unit " + Twine(Index++)); + Asm->emitDwarfSymbolReference(CU->getLabelBegin()); + } +} + +void Dwarf5EmissionContext::emitBuckets() const { + uint32_t Index = 1; + uint32_t BucketIdx = 0; + for (auto &Bucket : Contents.getBuckets()) { + Asm->OutStreamer->AddComment("Bucket " + Twine(BucketIdx)); + Asm->EmitInt32(Bucket.empty() ? 0 : Index); + + ++BucketIdx; + Index += Bucket.size(); + } +} + +void Dwarf5EmissionContext::emitStringOffsets() const { + size_t Index = 0; + for (auto &Bucket : Contents.getBuckets()) { + for (auto *Hash : Bucket) { + DwarfStringPoolEntryRef String = Hash->Name; + Asm->OutStreamer->AddComment("String in Bucket " + Twine(Index) + ": " + + String.getString()); + Asm->emitDwarfStringOffset(String); + } + ++Index; + } +} + +void Dwarf5EmissionContext::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 Dwarf5EmissionContext::emitCompileUnitIndex(dwarf::Form Form, + const DIE &CUDie) const { + unsigned Size; + switch (Form) { + case dwarf::DW_FORM_data1: + Size = 1; + break; + case dwarf::DW_FORM_data2: + Size = 2; + break; + case dwarf::DW_FORM_data4: + Size = 4; + break; + default: + llvm_unreachable("Unexpected form!"); + } + Asm->OutStreamer->EmitIntValue(DD.lookupCU(&CUDie)->getUniqueID(), Size); +} + +void Dwarf5EmissionContext::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: + emitCompileUnitIndex(AttrEnc.Form, *Entry.getDie().getUnitDie()); + break; + case dwarf::DW_IDX_die_offset: + assert(AttrEnc.Form == dwarf::DW_FORM_sec_offset); + Asm->EmitInt32(Entry.getDie().getOffset()); + break; + default: + llvm_unreachable("Unexpected index attribute!"); + } + } +} + +void Dwarf5EmissionContext::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(Value)); + Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); + Asm->EmitInt32(0); + } + } +} + +Dwarf5EmissionContext::Dwarf5EmissionContext( + AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD, + ArrayRef> CompUnits) + : EmissionContext(Asm, Contents, false), + Header(CompUnits.size(), Contents.getBucketCount(), + Contents.getUniqueNameCount()), + DD(DD), CompUnits(CompUnits) { + DenseSet UniqueTags = getUniqueTags(); + SmallVector UniformAttributes = getUniformAttributes(); + + Abbreviations.reserve(UniqueTags.size()); + for (uint32_t Tag : UniqueTags) + Abbreviations.try_emplace(Tag, UniformAttributes); +} + +void Dwarf5EmissionContext::emit() const { + Header.emit(*this); + emitCUList(); + emitBuckets(); + emitHashes(); + emitStringOffsets(); + emitOffsets(EntryPool); + emitAbbrevs(); + emitData(); + Asm->OutStreamer->EmitValueToAlignment(4, 0); + Asm->OutStreamer->EmitLabel(ContributionEnd); +} + void detail::emitAppleAccelTable(AsmPrinter *Asm, AccelTableBase &Contents, StringRef Prefix, const MCSymbol *SecBegin, ArrayRef Atoms) { @@ -303,6 +560,13 @@ AppleEmissionContext(Asm, Contents, Atoms, SecBegin).emit(); } +void llvm::emitDWARF5AccelTable( + AsmPrinter *Asm, AccelTable &Contents, + const DwarfDebug &DD, ArrayRef> CUs) { + Contents.finalize(Asm, "names"); + Dwarf5EmissionContext(Asm, Contents, DD, CUs).emit(); +} + void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { Asm->EmitInt32(Die->getDebugSectionOffset()); } Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -290,6 +290,7 @@ AddressPool AddrPool; /// Apple accelerator tables. + AccelTable AccelDebugNames; AccelTable AccelNames; AccelTable AccelObjC; AccelTable AccelNamespace; @@ -560,6 +561,9 @@ /// 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. /// Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1425,6 +1425,10 @@ void DwarfDebug::emitAccelNames() { emitAccel(AccelNames, Asm->getObjFileLowering().getDwarfAccelNamesSection(), "Names"); + + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfDebugNamesSection()); + emitDWARF5AccelTable(Asm, AccelDebugNames, *this, getUnits()); } // Emit objective C classes and categories into a hashed accelerator table @@ -2195,6 +2199,7 @@ if (!useDwarfAccelTables()) return; AccelNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), Die); } void DwarfDebug::addAccelObjC(StringRef Name, const DIE &Die) { Index: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ lib/MC/MCObjectFileInfo.cpp @@ -201,6 +201,9 @@ } // Debug Information. + DwarfDebugNamesSection = + Ctx->getMachOSection("__DWARF", "__debug_names", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "debug_names_begin"); DwarfAccelNamesSection = Ctx->getMachOSection("__DWARF", "__apple_names", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "names_begin"); @@ -556,6 +559,8 @@ // DWARF5 Experimental Debug Info // Accelerator Tables + DwarfDebugNamesSection = + Ctx->getELFSection(".debug_names", ELF::SHT_PROGBITS, 0); DwarfAccelNamesSection = Ctx->getELFSection(".apple_names", ELF::SHT_PROGBITS, 0); DwarfAccelObjCSection = @@ -793,6 +798,11 @@ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata()); + DwarfDebugNamesSection = Ctx->getCOFFSection( + ".debug_names", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata(), "debug_names_begin"); DwarfAccelNamesSection = Ctx->getCOFFSection( ".apple_names", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |