[llvm] r248331 - dsymutil: Follow references to clang modules and recursively clone the

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 15:20:50 PDT 2015


Author: adrian
Date: Tue Sep 22 17:20:50 2015
New Revision: 248331

URL: http://llvm.org/viewvc/llvm-project?rev=248331&view=rev
Log:
dsymutil: Follow references to clang modules and recursively clone the
debug info.

This does not yet resolve external type references.

Added:
    llvm/trunk/test/tools/dsymutil/Inputs/modules/
    llvm/trunk/test/tools/dsymutil/Inputs/modules/1.o
    llvm/trunk/test/tools/dsymutil/Inputs/modules/Bar.pcm
    llvm/trunk/test/tools/dsymutil/Inputs/modules/Foo.pcm
    llvm/trunk/test/tools/dsymutil/X86/modules.m
Modified:
    llvm/trunk/test/tools/dsymutil/X86/lit.local.cfg
    llvm/trunk/tools/dsymutil/DwarfLinker.cpp

Added: llvm/trunk/test/tools/dsymutil/Inputs/modules/1.o
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/modules/1.o?rev=248331&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/dsymutil/Inputs/modules/1.o (added) and llvm/trunk/test/tools/dsymutil/Inputs/modules/1.o Tue Sep 22 17:20:50 2015 differ

Added: llvm/trunk/test/tools/dsymutil/Inputs/modules/Bar.pcm
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/modules/Bar.pcm?rev=248331&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/dsymutil/Inputs/modules/Bar.pcm (added) and llvm/trunk/test/tools/dsymutil/Inputs/modules/Bar.pcm Tue Sep 22 17:20:50 2015 differ

Added: llvm/trunk/test/tools/dsymutil/Inputs/modules/Foo.pcm
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/modules/Foo.pcm?rev=248331&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/dsymutil/Inputs/modules/Foo.pcm (added) and llvm/trunk/test/tools/dsymutil/Inputs/modules/Foo.pcm Tue Sep 22 17:20:50 2015 differ

Modified: llvm/trunk/test/tools/dsymutil/X86/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/lit.local.cfg?rev=248331&r1=248330&r2=248331&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/lit.local.cfg (original)
+++ llvm/trunk/test/tools/dsymutil/X86/lit.local.cfg Tue Sep 22 17:20:50 2015
@@ -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']

Added: llvm/trunk/test/tools/dsymutil/X86/modules.m
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/modules.m?rev=248331&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/modules.m (added)
+++ llvm/trunk/test/tools/dsymutil/X86/modules.m Tue Sep 22 17:20:50 2015
@@ -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
+ at import Bar;
+typedef struct Bar Bar;
+struct S {};
+
+// ---------------------------------------------------------------------
+#else
+// ---------------------------------------------------------------------
+
+// CHECK: DW_TAG_compile_unit
+// CHECK:   DW_TAG_subprogram
+// CHECK:     DW_AT_name {{.*}}"main"
+ at import Foo;
+int main(int argc, char **argv) {
+  Bar bar;
+  bar.value = 42;
+  return bar.value;
+}
+#endif
+#endif

Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=248331&r1=248330&r2=248331&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Tue Sep 22 17:20:50 2015
@@ -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 &Bi
   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 &M
   // 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 &M
         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




More information about the llvm-commits mailing list