Index: llvm/test/tools/dsymutil/X86/accelerator.test =================================================================== --- /dev/null +++ llvm/test/tools/dsymutil/X86/accelerator.test @@ -0,0 +1,38 @@ +RUN: dsymutil -accelerator=Dwarf -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 -o %t.dwarf.dSYM +RUN: dsymutil -accelerator=Apple -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 -o %t.apple.dSYM + +RUN: llvm-dwarfdump -verify %t.dwarf.dSYM +RUN: llvm-dwarfdump -verify %t.apple.dSYM + +RUN: llvm-dwarfdump -debug-names %t.dwarf.dSYM | FileCheck %s -check-prefix=NAMES -check-prefix=DWARF +RUN: llvm-dwarfdump -apple-names -apple-namespaces -apple-types %t.apple.dSYM | FileCheck %s -check-prefix=NAMES -check-prefix=APPLE + +RUN: dsymutil -update -accelerator=Dwarf %t.apple.dSYM -o %t.dwarf.updated.dSYM +RUN: dsymutil -update -accelerator=Apple %t.dwarf.dSYM -o %t.apple.updated.dSYM + +RUN: llvm-dwarfdump -verify %t.dwarf.updated.dSYM +RUN: llvm-dwarfdump -verify %t.apple.updated.dSYM + +RUN: llvm-dwarfdump -debug-names %t.dwarf.updated.dSYM | FileCheck %s -check-prefix=NAMES -check-prefix=DWARF +RUN: llvm-dwarfdump -apple-names -apple-namespaces -apple-types %t.apple.updated.dSYM | FileCheck %s -check-prefix=NAMES -check-prefix=APPLE + +DWARF: .debug_names contents: +DWARF: Compilation Unit offsets [ +DWARF: CU[0] +DWARF: CU[1] +DWARF: CU[2] +DWARF: ] + +APPLE-DAG: .apple_names contents: +APPLE-DAG: .apple_types contents: +APPLE-DAG: .apple_namespaces contents: + +NAMES-DAG: "private_int" +NAMES-DAG: "baz" +NAMES-DAG: "int" +NAMES-DAG: "bar" +NAMES-DAG: "foo" +NAMES-DAG: "inc" +NAMES-DAG: "val" +NAMES-DAG: "main" +NAMES-DAG: "char" Index: llvm/test/tools/dsymutil/cmdline.test =================================================================== --- llvm/test/tools/dsymutil/cmdline.test +++ llvm/test/tools/dsymutil/cmdline.test @@ -5,6 +5,7 @@ HELP: Color Options HELP: -color HELP: Specific Options: +HELP: -accelerator HELP: -arch= HELP: -dump-debug-map HELP: -flat Index: llvm/tools/dsymutil/DwarfLinker.h =================================================================== --- llvm/tools/dsymutil/DwarfLinker.h +++ llvm/tools/dsymutil/DwarfLinker.h @@ -73,6 +73,14 @@ MaxDwarfVersion = Version; } + /// If no accelerator table kind has been specified, try deciding based on + /// current input DWARF. + void maybeUpdateAccelKind(DWARFContext &Dwarf); + + /// Returns the current accelerator kind. If no kind has been specified, we + /// commit based on the current max DWARF version. + AccelTableKind getAccelKind(); + /// Emit warnings as Dwarf compile units to leave a trail after linking. bool emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map, OffsetsStringPool &StringPool); @@ -160,7 +168,6 @@ /// Clear compile units and ranges. void Clear() { - CompileUnits.clear(); Ranges.clear(); } }; @@ -411,6 +418,8 @@ /// Emit the accelerator entries for \p Unit. void emitAcceleratorEntriesForUnit(CompileUnit &Unit); + void emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit); + void emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit); /// Patch the frame info for an object file and emit it. void patchFrameInfoForObject(const DebugMapObject &, RangesTy &Ranges, @@ -461,6 +470,7 @@ uint32_t LastCIEOffset = 0; /// Apple accelerator tables. + AccelTable DebugNames; AccelTable AppleNames; AccelTable AppleNamespaces; AccelTable AppleObjc; Index: llvm/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/tools/dsymutil/DwarfLinker.cpp +++ llvm/tools/dsymutil/DwarfLinker.cpp @@ -1746,6 +1746,20 @@ } void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { + switch (getAccelKind()) { + case AccelTableKind::Apple: + emitAppleAcceleratorEntriesForUnit(Unit); + break; + case AccelTableKind::Dwarf: + emitDwarfAcceleratorEntriesForUnit(Unit); + break; + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); + break; + } +} + +void DwarfLinker::emitAppleAcceleratorEntriesForUnit(CompileUnit &Unit) { // Add namespaces. for (const auto &Namespace : Unit.getNamespaces()) AppleNamespaces.addName(Namespace.Name, @@ -1774,6 +1788,18 @@ AppleObjc.addName(ObjC.Name, ObjC.Die->getOffset() + Unit.getStartOffset()); } +void DwarfLinker::emitDwarfAcceleratorEntriesForUnit(CompileUnit &Unit) { + for (const auto &Namespace : Unit.getNamespaces()) + DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(), + Namespace.Die->getTag(), Unit.getUniqueID()); + for (const auto &Pubname : Unit.getPubnames()) + DebugNames.addName(Pubname.Name, Pubname.Die->getOffset(), + Pubname.Die->getTag(), Unit.getUniqueID()); + for (const auto &Pubtype : Unit.getPubtypes()) + DebugNames.addName(Pubtype.Name, Pubtype.Die->getOffset(), + Pubtype.Die->getTag(), Unit.getUniqueID()); +} + /// Read the frame info stored in the object, and emit the /// patched frame descriptions for the linked binary. /// @@ -2172,6 +2198,38 @@ } } +void DwarfLinker::maybeUpdateAccelKind(DWARFContext &Dwarf) { + if (Options.TheAccelTableKind != AccelTableKind::Default) + return; + + auto &DwarfObj = Dwarf.getDWARFObj(); + if (!DwarfObj.getDebugNamesSection().Data.empty()) { + Options.TheAccelTableKind = AccelTableKind::Dwarf; + return; + } + + if (!DwarfObj.getAppleNamesSection().Data.empty() || + !DwarfObj.getAppleTypesSection().Data.empty() || + !DwarfObj.getAppleNamespacesSection().Data.empty() || + !DwarfObj.getAppleObjCSection().Data.empty()) { + Options.TheAccelTableKind = AccelTableKind::Apple; + return; + } +} + +AccelTableKind DwarfLinker::getAccelKind() { + // If the accelerator table kind hasn't been decided by now, we have to + // commit based on the DWARF version. + if (Options.TheAccelTableKind == AccelTableKind::Default) { + if (MaxDwarfVersion >= 5) + Options.TheAccelTableKind = AccelTableKind::Dwarf; + else + Options.TheAccelTableKind = AccelTableKind::Apple; + } + + return Options.TheAccelTableKind; +} + bool DwarfLinker::emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map, OffsetsStringPool &StringPool) { @@ -2325,6 +2383,10 @@ // In a first phase, just read in the debug info and load all clang modules. LinkContext.CompileUnits.reserve( LinkContext.DwarfContext->getNumCompileUnits()); + + // Set accelerator table kind based on input DWARF. + maybeUpdateAccelKind(*LinkContext.DwarfContext); + for (const auto &CU : LinkContext.DwarfContext->compile_units()) { auto CUDie = CU->getUnitDIE(false); if (Options.Verbose) { @@ -2346,8 +2408,8 @@ } } - // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway, - // to be able to emit papertrail warnings. + // If we haven't seen any CUs, pick an arbitrary valid Dwarf version + // anyway, to be able to emit papertrail warnings. if (MaxDwarfVersion == 0) MaxDwarfVersion = 3; @@ -2444,10 +2506,20 @@ if (!Options.NoOutput) { Streamer->emitAbbrevs(Abbreviations, MaxDwarfVersion); Streamer->emitStrings(OffsetsStringPool); - Streamer->emitAppleNames(AppleNames); - Streamer->emitAppleNamespaces(AppleNamespaces); - Streamer->emitAppleTypes(AppleTypes); - Streamer->emitAppleObjc(AppleObjc); + switch (getAccelKind()) { + case AccelTableKind::Apple: + Streamer->emitAppleNames(AppleNames); + Streamer->emitAppleNamespaces(AppleNamespaces); + Streamer->emitAppleTypes(AppleTypes); + Streamer->emitAppleObjc(AppleObjc); + break; + case AccelTableKind::Dwarf: + Streamer->emitDebugNames(DebugNames); + break; + case AccelTableKind::Default: + llvm_unreachable("Default should have already been resolved."); + break; + } } }; Index: llvm/tools/dsymutil/DwarfStreamer.h =================================================================== --- llvm/tools/dsymutil/DwarfStreamer.h +++ llvm/tools/dsymutil/DwarfStreamer.h @@ -27,6 +27,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -121,6 +122,9 @@ void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address, StringRef Bytes); + /// Emit DWARF debug names. + void emitDebugNames(AccelTable &Table); + /// Emit Apple namespaces accelerator table. void emitAppleNamespaces(AccelTable &Table); @@ -162,6 +166,9 @@ uint32_t LineSectionSize; uint32_t FrameSectionSize; + /// Keep track of emitted CUs and their Unique ID. + std::vector EmittedUnits; + /// Emit the pubnames or pubtypes section contribution for \p /// Unit into \p Sec. The data is provided in \p Names. void emitPubSectionForUnit(MCSection *Sec, StringRef Name, Index: llvm/tools/dsymutil/DwarfStreamer.cpp =================================================================== --- llvm/tools/dsymutil/DwarfStreamer.cpp +++ llvm/tools/dsymutil/DwarfStreamer.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "DwarfStreamer.h" +#include "CompileUnit.h" #include "LinkUtils.h" #include "MachOUtils.h" #include "llvm/ADT/Triple.h" @@ -165,6 +166,9 @@ // start of the section. Asm->emitInt32(0); Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize()); + + // Remember this CU. + EmittedUnits.push_back(&Unit); } /// Emit the \p Abbrevs array as the shared abbreviation table @@ -197,6 +201,29 @@ } } +void DwarfStreamer::emitDebugNames( + AccelTable &Table) { + if (EmittedUnits.empty()) + return; + + // Build up data structures needed to emit this section. + std::vector CompUnits; + DenseMap UniqueIdToCuMap; + unsigned Id = 0; + for (auto *CU : EmittedUnits) { + CompUnits.push_back(CU->getLabelBegin()); + // We might be omitting CUs, so we need to remap them. + UniqueIdToCuMap[CU->getUniqueID()] = Id++; + } + + Asm->OutStreamer->SwitchSection(MOFI->getDwarfDebugNamesSection()); + emitDWARF5AccelTable( + Asm.get(), Table, CompUnits, + [&UniqueIdToCuMap](const DWARF5AccelTableStaticData &Entry) { + return UniqueIdToCuMap[Entry.getCUIndex()]; + }); +} + void DwarfStreamer::emitAppleNamespaces( AccelTable &Table) { Asm->OutStreamer->SwitchSection(MOFI->getDwarfAccelNamespaceSection()); Index: llvm/tools/dsymutil/LinkUtils.h =================================================================== --- llvm/tools/dsymutil/LinkUtils.h +++ llvm/tools/dsymutil/LinkUtils.h @@ -22,6 +22,13 @@ Assembly, }; +/// The kind of accelerator tables we should emit. +enum class AccelTableKind { + Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. + Dwarf, ///< DWARF v5 .debug_names. + Default, ///< Dwarf for DWARF5 or later, Apple otherwise. +}; + struct LinkOptions { /// Verbosity bool Verbose = false; @@ -47,6 +54,9 @@ // Output file type. OutputFileType FileType = OutputFileType::Object; + /// The accelerator table kind + AccelTableKind TheAccelTableKind; + /// -oso-prepend-path std::string PrependPath; Index: llvm/tools/dsymutil/dsymutil.cpp =================================================================== --- llvm/tools/dsymutil/dsymutil.cpp +++ llvm/tools/dsymutil/dsymutil.cpp @@ -85,10 +85,10 @@ static opt Minimize( "minimize", - desc("When used when creating a dSYM file, this option will suppress\n" - "the emission of the .debug_inlines, .debug_pubnames, and\n" - ".debug_pubtypes sections since dsymutil currently has better\n" - "equivalents: .apple_names and .apple_types. When used in\n" + desc("When used when creating a dSYM file with Apple accelerator tables,\n" + "this option will suppress the emission of the .debug_inlines, \n" + ".debug_pubnames, and .debug_pubtypes sections since dsymutil \n" + "has better equivalents: .apple_names and .apple_types. When used in\n" "conjunction with --update option, this option will cause redundant\n" "accelerator tables to be removed."), init(false), cat(DsymCategory)); @@ -97,12 +97,18 @@ static opt Update( "update", desc("Updates existing dSYM files to contain the latest accelerator\n" - "tables and other DWARF optimizations. This option will currently\n" - "add the new .apple_names and .apple_types hashed accelerator\n" - "tables."), + "tables and other DWARF optimizations."), init(false), cat(DsymCategory)); static alias UpdateA("u", desc("Alias for --update"), aliasopt(Update)); +static cl::opt AcceleratorTable( + "accelerator", cl::desc("Output accelerator tables."), + cl::values(clEnumValN(AccelTableKind::Default, "Default", + "Default for input."), + clEnumValN(AccelTableKind::Apple, "Apple", "Apple"), + clEnumValN(AccelTableKind::Dwarf, "Dwarf", "DWARF")), + cl::init(AccelTableKind::Default), cat(DsymCategory)); + static opt NumThreads( "num-threads", desc("Specifies the maximum number (n) of simultaneous threads to use\n" @@ -326,6 +332,7 @@ Options.Update = Update; Options.NoTimestamp = NoTimestamp; Options.PrependPath = OsoPrependPath; + Options.TheAccelTableKind = AcceleratorTable; if (Assembly) Options.FileType = OutputFileType::Assembly;