diff options
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/modules/1.o | bin | 0 -> 2392 bytes | |||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/modules/Bar.pcm | bin | 0 -> 25520 bytes | |||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/modules/Foo.pcm | bin | 0 -> 25448 bytes | |||
-rw-r--r-- | llvm/test/tools/dsymutil/X86/lit.local.cfg | 2 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/X86/modules.m | 62 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfLinker.cpp | 142 |
6 files changed, 198 insertions, 8 deletions
diff --git a/llvm/test/tools/dsymutil/Inputs/modules/1.o b/llvm/test/tools/dsymutil/Inputs/modules/1.o Binary files differnew file mode 100644 index 00000000000..6e0775f5755 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/modules/1.o diff --git a/llvm/test/tools/dsymutil/Inputs/modules/Bar.pcm b/llvm/test/tools/dsymutil/Inputs/modules/Bar.pcm Binary files differnew file mode 100644 index 00000000000..8b628e3cf01 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/modules/Bar.pcm diff --git a/llvm/test/tools/dsymutil/Inputs/modules/Foo.pcm b/llvm/test/tools/dsymutil/Inputs/modules/Foo.pcm Binary files differnew file mode 100644 index 00000000000..2416a405443 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/modules/Foo.pcm diff --git a/llvm/test/tools/dsymutil/X86/lit.local.cfg b/llvm/test/tools/dsymutil/X86/lit.local.cfg index ed9eba0b0d9..05f8b38b334 100644 --- a/llvm/test/tools/dsymutil/X86/lit.local.cfg +++ b/llvm/test/tools/dsymutil/X86/lit.local.cfg @@ -1,4 +1,4 @@ if not 'X86' in config.root.targets: config.unsupported = True -config.suffixes = ['.test', '.cpp', '.s'] +config.suffixes = ['.test', '.cpp', '.m', '.s'] diff --git a/llvm/test/tools/dsymutil/X86/modules.m b/llvm/test/tools/dsymutil/X86/modules.m new file mode 100644 index 00000000000..6a93f28587a --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/modules.m @@ -0,0 +1,62 @@ +/* Compile with: + cat >modules.modulemap <<EOF + module Foo { + header "Foo.h" + export * + } + module Bar { + header "Bar.h" + export * + } + EOF + clang -D BAR_H -E -o Bar.h + clang -D FOO_H -E -o Foo.h + clang -cc1 -emit-obj -fmodules -fmodule-map-file=modules.modulemap \ + -fmodule-format=obj -g -dwarf-ext-refs -fmodules-cache-path=. \ + -fdisable-module-hash modules.m -o 1.o +*/ + +// RUN: llvm-dsymutil -f -oso-prepend-path=%p/../Inputs/modules \ +// RUN: -y %p/dummy-debug-map.map -o - \ +// RUN: | llvm-dwarfdump --debug-dump=info - | FileCheck %s + +// --------------------------------------------------------------------- +#ifdef BAR_H +// --------------------------------------------------------------------- +// CHECK: DW_TAG_compile_unit +// CHECK: DW_TAG_module +// CHECK-NEXT: DW_AT_name {{.*}}"Bar" +// CHECK: DW_TAG_member +// CHECK: DW_AT_name {{.*}}"value" + +struct Bar { + int value; +}; + +#else +// --------------------------------------------------------------------- +#ifdef FOO_H +// --------------------------------------------------------------------- +// CHECK: 55{{.*}}DW_TAG_compile_unit +// CHECK: DW_TAG_module +// CHECK-NEXT: DW_AT_name {{.*}}"Foo" +// CHECK: DW_TAG_typedef +@import Bar; +typedef struct Bar Bar; +struct S {}; + +// --------------------------------------------------------------------- +#else +// --------------------------------------------------------------------- + +// CHECK: DW_TAG_compile_unit +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name {{.*}}"main" +@import Foo; +int main(int argc, char **argv) { + Bar bar; + bar.value = 42; + return bar.value; +} +#endif +#endif diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 039e7a3e43c..c45ff6a113d 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -13,7 +13,7 @@ #include "MachOUtils.h" #include "NonRelocatableStringpool.h" #include "llvm/ADT/IntervalMap.h" -#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" @@ -248,6 +248,14 @@ public: return LocationAttributes; } + void setHasInterestingContent() { HasInterestingContent = true; } + bool hasInterestingContent() { return HasInterestingContent; } + + /// Mark every DIE in this unit as kept. This function also + /// marks variables as InDebugMap so that they appear in the + /// reconstructed accelerator tables. + void markEverythingAsKept(); + /// \brief Compute the end offset for this unit. Must be /// called after the CU's DIEs have been cloned. /// \returns the next unit offset (which is also the current @@ -368,8 +376,15 @@ private: /// Is this unit subject to the ODR rule? bool HasODR; + /// Did a DIE actually contain a valid reloc? + bool HasInterestingContent; }; +void CompileUnit::markEverythingAsKept() { + for (auto &I : Info) + I.Keep = true; +} + uint64_t CompileUnit::computeNextUnitOffset() { NextUnitOffset = StartOffset + 11 /* Header size */; // The root DIE might be null, meaning that the Unit had nothing to @@ -1177,6 +1192,22 @@ private: const DebugMapObject &DMO, CompileUnit &CU, unsigned Flags); + /// If this compile unit is really a skeleton CU that points to a + /// clang module, register it in ClangModules and return true. + /// + /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name + /// pointing to the module, and a DW_AT_gnu_dwo_id with the module + /// hash. + bool registerModuleReference(const DWARFDebugInfoEntryMinimal &CUDie, + const DWARFUnit &Unit, DebugMap &ModuleMap, + unsigned Indent = 0); + + /// Recursively add the debug info in this clang module .pcm + /// file (and all the modules imported by it in a bottom-up fashion) + /// to Units. + void loadClangModule(StringRef Filename, StringRef ModulePath, + DebugMap &ModuleMap, unsigned Indent = 0); + /// \brief Flags passed to DwarfLinker::lookForDIEsToKeep enum TravesalFlags { TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. @@ -1383,12 +1414,12 @@ private: const DebugMap &Map); /// @} -private: std::string OutputFilename; LinkOptions Options; BinaryHolder BinHolder; std::unique_ptr<DwarfStreamer> Streamer; uint64_t OutputDebugInfoSize; + unsigned UnitID; ///< A unique ID that identifies each compile unit. /// The units of the current debug map object. std::vector<CompileUnit> Units; @@ -1416,6 +1447,9 @@ private: /// Offset of the last CIE that has been emitted in the output /// debug_frame section. uint32_t LastCIEOffset; + + /// FIXME: We may need to use something more resilient than the PCM filename. + StringSet<> ClangModules; }; /// Similar to DWARFUnitSection::getUnitForOffset(), but returning our @@ -2588,7 +2622,13 @@ DIE *DwarfLinker::DIECloner::cloneDIE( // Extract and clone every attribute. DataExtractor Data = U.getDebugInfoExtractor(); - uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset(); + // Point to the next DIE (generally there is always at least a NULL + // entry after the current one). If this is a lone + // DW_TAG_compile_unit without any children, point to the next unit. + uint32_t NextOffset = + (Idx + 1 < U.getNumDIEs()) + ? U.getDIEAtIndex(Idx + 1)->getOffset() + : U.getNextUnitOffset(); AttributesInfo AttrInfo; // We could copy the data only if we need to aply a relocation to @@ -3051,6 +3091,38 @@ void DwarfLinker::DIECloner::copyAbbrev( Linker.AssignAbbrev(Copy); } +bool DwarfLinker::registerModuleReference( + const DWARFDebugInfoEntryMinimal &CUDie, const DWARFUnit &Unit, + DebugMap &ModuleMap, unsigned Indent) { + std::string PCMfile = + CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_GNU_dwo_name, ""); + if (PCMfile.empty()) + return false; + + // Clang module DWARF skeleton CUs abuse this for the path to the module. + std::string PCMpath = + CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_comp_dir, ""); + + if (Options.Verbose) { + outs().indent(Indent); + outs() << "Found clang module reference " << PCMfile; + } + + if (ClangModules.count(PCMfile)) { + if (Options.Verbose) + outs() << " [cached].\n"; + return true; + } + if (Options.Verbose) + outs() << " ...\n"; + + // Cyclic dependencies are disallowed by Clang, but we still + // shouldn't run into an infinite loop, so mark it as processed now. + ClangModules.insert(PCMfile); + loadClangModule(PCMfile, PCMpath, ModuleMap, Indent + 2); + return true; +} + ErrorOr<const object::ObjectFile &> DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj, const DebugMap &Map) { @@ -3066,6 +3138,58 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj, return ErrOrObj; } +void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath, + DebugMap &ModuleMap, unsigned Indent) { + SmallString<80> Path(Options.PrependPath); + if (sys::path::is_relative(Filename)) + sys::path::append(Path, ModulePath, Filename); + else + sys::path::append(Path, Filename); + BinaryHolder ObjHolder(Options.Verbose); + auto &Obj = + ModuleMap.addDebugMapObject(Path, sys::TimeValue::PosixZeroTime()); + auto ErrOrObj = loadObject(ObjHolder, Obj, ModuleMap); + if (!ErrOrObj) { + ClangModules.erase(ClangModules.find(Filename)); + return; + } + + // FIXME: At this point dsymutil should verify the DW_AT_gnu_dwo_id + // against the module hash of the clang module. + + CompileUnit *Unit = nullptr; + + // Setup access to the debug info. + DWARFContextInMemory DwarfContext(*ErrOrObj); + RelocationManager RelocMgr(*this); + for (const auto &CU : DwarfContext.compile_units()) { + auto *CUDie = CU->getUnitDIE(false); + // Recursively get all modules imported by this one. + if (!registerModuleReference(*CUDie, *CU, ModuleMap, Indent)) { + // Add this module. + if (Unit) { + errs() << Filename << ": Clang modules are expected to have exactly" + << " 1 compile unit.\n"; + exitDsymutil(1); + } + Unit = new CompileUnit(*CU, UnitID++, !Options.NoODR); + Unit->setHasInterestingContent(); + gatherDIEParents(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool, + ODRContexts); + // Keep everything. + Unit->markEverythingAsKept(); + } + } + if (Options.Verbose) { + outs().indent(Indent); + outs() << "cloning .debug_info from " << Filename << "\n"; + } + + DIECloner(*this, RelocMgr, DIEAlloc, MutableArrayRef<CompileUnit>(*Unit), + Options) + .cloneAllCompileUnits(DwarfContext); +} + void DwarfLinker::DIECloner::cloneAllCompileUnits( DWARFContextInMemory &DwarfContext) { if (!Linker.Streamer) @@ -3113,7 +3237,9 @@ bool DwarfLinker::link(const DebugMap &Map) { // Size of the DIEs (and headers) generated for the linked output. OutputDebugInfoSize = 0; // A unique ID that identifies each compile unit. - unsigned UnitID = 0; + UnitID = 0; + DebugMap ModuleMap(Map.getTriple(), Map.getBinaryPath()); + for (const auto &Obj : Map.objects()) { CurrentDebugObject = Obj.get(); @@ -3143,9 +3269,11 @@ bool DwarfLinker::link(const DebugMap &Map) { outs() << "Input compilation unit:"; CUDie->dump(outs(), CU.get(), 0); } - Units.emplace_back(*CU, UnitID++, !Options.NoODR); - gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(), - StringPool, ODRContexts); + if (!registerModuleReference(*CUDie, *CU, ModuleMap)) { + Units.emplace_back(*CU, UnitID++, !Options.NoODR); + gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(), + StringPool, ODRContexts); + } } // Then mark all the DIEs that need to be present in the linked |