[mips] Add initial release notes for MIPS32.
[oota-llvm.git] / tools / dsymutil / DwarfLinker.cpp
index c45ff6a113d88c61bce9013d8616f3b725e86ae9..8c5f7946a4257aca5230995fa4463364e42130f8 100644 (file)
@@ -13,7 +13,7 @@
 #include "MachOUtils.h"
 #include "NonRelocatableStringpool.h"
 #include "llvm/ADT/IntervalMap.h"
-#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/DIE.h"
@@ -31,6 +31,7 @@
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
 #include "llvm/Object/MachO.h"
 #include "llvm/Support/Dwarf.h"
 #include "llvm/Support/LEB128.h"
@@ -166,13 +167,14 @@ public:
   /// required strings will be interned in \a StringPool.
   /// \returns The child DeclContext along with one bit that is set if
   /// this context is invalid.
-  /// FIXME: the invalid bit along the return value is to emulate some
-  /// dsymutil-classic functionality. See the fucntion definition for
-  /// a more thorough discussion of its use.
+  /// An invalid context means it shouldn't be considered for uniquing, but its
+  /// not returning null, because some children of that context might be
+  /// uniquing candidates.  FIXME: The invalid bit along the return value is to
+  /// emulate some dsymutil-classic functionality.
   PointerIntPair<DeclContext *, 1>
   getChildDeclContext(DeclContext &Context,
                       const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &Unit,
-                      NonRelocatableStringpool &StringPool);
+                      NonRelocatableStringpool &StringPool, bool InClangModule);
 
   DeclContext &getRoot() { return Root; }
 };
@@ -188,13 +190,15 @@ public:
     DeclContext *Ctxt;  ///< ODR Declaration context.
     DIE *Clone;         ///< Cloned version of that DIE.
     uint32_t ParentIdx; ///< The index of this DIE's parent.
-    bool Keep;          ///< Is the DIE part of the linked output?
-    bool InDebugMap;    ///< Was this DIE's entity found in the map?
+    bool Keep : 1;      ///< Is the DIE part of the linked output?
+    bool InDebugMap : 1;///< Was this DIE's entity found in the map?
+    bool Prune : 1;     ///< Is this a pure forward declaration we can strip?
   };
 
-  CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR)
+  CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
+              StringRef ClangModuleName)
       : OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(),
-        Ranges(RangeAlloc) {
+        Ranges(RangeAlloc), ClangModuleName(ClangModuleName) {
     Info.resize(OrigUnit.getNumDIEs());
 
     const auto *CUDie = OrigUnit.getUnitDIE(false);
@@ -224,6 +228,8 @@ public:
   void setOutputUnitDIE(DIE *Die) { CUDie = Die; }
 
   bool hasODR() const { return HasODR; }
+  bool isClangModule() const { return !ClangModuleName.empty(); }
+  const std::string &getClangModuleName() const { return ClangModuleName; }
 
   DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
   const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
@@ -378,11 +384,14 @@ private:
   bool HasODR;
   /// Did a DIE actually contain a valid reloc?
   bool HasInterestingContent;
+  /// If this is a Clang module, this holds the module's name.
+  std::string ClangModuleName;
 };
 
 void CompileUnit::markEverythingAsKept() {
   for (auto &I : Info)
-    I.Keep = true;
+    // Mark everything that wasn't explicity marked for pruning.
+    I.Keep = !I.Prune;
 }
 
 uint64_t CompileUnit::computeNextUnitOffset() {
@@ -511,7 +520,7 @@ public:
 
   /// \brief Emit the abbreviation table \p Abbrevs to the
   /// debug_abbrev section.
-  void emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs);
+  void emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs);
 
   /// \brief Emit the string table described by \p Pool.
   void emitStrings(const NonRelocatableStringpool &Pool);
@@ -610,9 +619,11 @@ bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
   if (EC)
     return error(Twine(OutputFilename) + ": " + EC.message(), Context);
 
-  MS = TheTarget->createMCObjectStreamer(TheTriple, *MC, *MAB, *OutFile, MCE,
-                                         *MSTI, false,
-                                         /*DWARFMustBeAtTheEnd*/ false);
+  MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
+  MS = TheTarget->createMCObjectStreamer(
+      TheTriple, *MC, *MAB, *OutFile, MCE, *MSTI, MCOptions.MCRelaxAll,
+      MCOptions.MCIncrementalLinkerCompatible,
+      /*DWARFMustBeAtTheEnd*/ false);
   if (!MS)
     return error("no object streamer for target " + TripleName, Context);
 
@@ -675,7 +686,8 @@ void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
 
 /// \brief Emit the \p Abbrevs array as the shared abbreviation table
 /// for the linked Dwarf file.
-void DwarfStreamer::emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs) {
+void DwarfStreamer::emitAbbrevs(
+    const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs) {
   MS->SwitchSection(MOFI->getDwarfAbbrevSection());
   Asm->emitDwarfAbbrevs(Abbrevs);
 }
@@ -1103,11 +1115,6 @@ public:
       : OutputFilename(OutputFilename), Options(Options),
         BinHolder(Options.Verbose), LastCIEOffset(0) {}
 
-  ~DwarfLinker() {
-    for (auto *Abbrev : Abbreviations)
-      delete Abbrev;
-  }
-
   /// \brief Link the contents of the DebugMap.
   bool link(const DebugMap &);
 
@@ -1206,6 +1213,7 @@ private:
   /// file (and all the modules imported by it in a bottom-up fashion)
   /// to Units.
   void loadClangModule(StringRef Filename, StringRef ModulePath,
+                       StringRef ModuleName, uint64_t DwoId,
                        DebugMap &ModuleMap, unsigned Indent = 0);
 
   /// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
@@ -1370,7 +1378,7 @@ private:
   /// \brief Storage for the unique Abbreviations.
   /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot
   /// be changed to a vecot of unique_ptrs.
-  std::vector<DIEAbbrev *> Abbreviations;
+  std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
 
   /// \brief Compute and emit debug_ranges section for \p Unit, and
   /// patch the attributes referencing it.
@@ -1424,7 +1432,7 @@ private:
   /// The units of the current debug map object.
   std::vector<CompileUnit> Units;
 
-  /// The debug map object curently under consideration.
+  /// The debug map object currently under consideration.
   DebugMapObject *CurrentDebugObject;
 
   /// \brief The Dwarf string pool
@@ -1448,8 +1456,8 @@ private:
   /// debug_frame section.
   uint32_t LastCIEOffset;
 
-  /// FIXME: We may need to use something more resilient than the PCM filename.
-  StringSet<> ClangModules;
+  /// Mapping the PCM filename to the DwoId.
+  StringMap<uint64_t> ClangModules;
 };
 
 /// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
@@ -1527,18 +1535,9 @@ bool DeclContext::setLastSeenDIE(CompileUnit &U,
   return true;
 }
 
-/// Get the child context of \a Context corresponding to \a DIE.
-///
-/// \returns the child context or null if we shouldn't track children
-/// contexts. It also returns an additional bit meaning 'invalid'. An
-/// invalid context means it shouldn't be considered for uniquing, but
-/// its not returning null, because some children of that context
-/// might be uniquing candidates.
-/// FIXME: this is for dsymutil-classic compatibility, I don't think
-/// it buys us much.
 PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
     DeclContext &Context, const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &U,
-    NonRelocatableStringpool &StringPool) {
+    NonRelocatableStringpool &StringPool, bool InClangModule) {
   unsigned Tag = DIE->getTag();
 
   // FIXME: dsymutil-classic compat: We should bail out here if we
@@ -1549,8 +1548,9 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
   default:
     // By default stop gathering child contexts.
     return PointerIntPair<DeclContext *, 1>(nullptr);
+  case dwarf::DW_TAG_module:
+    break;
   case dwarf::DW_TAG_compile_unit:
-    // FIXME: Add support for DW_TAG_module.
     return PointerIntPair<DeclContext *, 1>(&Context);
   case dwarf::DW_TAG_subprogram:
     // Do not unique anything inside CU local functions.
@@ -1603,48 +1603,52 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
 
   std::string File;
   unsigned Line = 0;
-  unsigned ByteSize = 0;
-
-  // Gather some discriminating data about the DeclContext we will be
-  // creating: File, line number and byte size. This shouldn't be
-  // necessary, because the ODR is just about names, but given that we
-  // do some approximations with overloaded functions and anonymous
-  // namespaces, use these additional data points to make the process safer.
-  ByteSize = DIE->getAttributeValueAsUnsignedConstant(
-      &U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX);
-  if (Tag != dwarf::DW_TAG_namespace || !Name) {
-    if (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant(
-            &U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) {
-      if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
-              &U.getOrigUnit())) {
-        // FIXME: dsymutil-classic compatibility. I'd rather not
-        // unique anything in anonymous namespaces, but if we do, then
-        // verify that the file and line correspond.
-        if (!Name && Tag == dwarf::DW_TAG_namespace)
-          FileNum = 1;
-
-        // FIXME: Passing U.getOrigUnit().getCompilationDir()
-        // instead of "" would allow more uniquing, but for now, do
-        // it this way to match dsymutil-classic.
-        if (LT->getFileNameByIndex(
-                FileNum, "",
-                DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
-                File)) {
-          Line = DIE->getAttributeValueAsUnsignedConstant(
-              &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0);
+  unsigned ByteSize = UINT32_MAX;
+
+  if (!InClangModule) {
+    // Gather some discriminating data about the DeclContext we will be
+    // creating: File, line number and byte size. This shouldn't be
+    // necessary, because the ODR is just about names, but given that we
+    // do some approximations with overloaded functions and anonymous
+    // namespaces, use these additional data points to make the process
+    // safer.  This is disabled for clang modules, because forward
+    // declarations of module-defined types do not have a file and line.
+    ByteSize = DIE->getAttributeValueAsUnsignedConstant(
+        &U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX);
+    if (Tag != dwarf::DW_TAG_namespace || !Name) {
+      if (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant(
+              &U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) {
+        if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
+                &U.getOrigUnit())) {
+          // FIXME: dsymutil-classic compatibility. I'd rather not
+          // unique anything in anonymous namespaces, but if we do, then
+          // verify that the file and line correspond.
+          if (!Name && Tag == dwarf::DW_TAG_namespace)
+            FileNum = 1;
+
+          // FIXME: Passing U.getOrigUnit().getCompilationDir()
+          // instead of "" would allow more uniquing, but for now, do
+          // it this way to match dsymutil-classic.
+          if (LT->getFileNameByIndex(
+                  FileNum, "",
+                  DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+                  File)) {
+            Line = DIE->getAttributeValueAsUnsignedConstant(
+                &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0);
 #ifdef HAVE_REALPATH
-          // Cache the resolved paths, because calling realpath is expansive.
-          if (const char *ResolvedPath = U.getResolvedPath(FileNum)) {
-            File = ResolvedPath;
-          } else {
-            char RealPath[PATH_MAX + 1];
-            RealPath[PATH_MAX] = 0;
-            if (::realpath(File.c_str(), RealPath))
-              File = RealPath;
-            U.setResolvedPath(FileNum, File);
-          }
+            // Cache the resolved paths, because calling realpath is expansive.
+            if (const char *ResolvedPath = U.getResolvedPath(FileNum)) {
+              File = ResolvedPath;
+            } else {
+              char RealPath[PATH_MAX + 1];
+              RealPath[PATH_MAX] = 0;
+              if (::realpath(File.c_str(), RealPath))
+                File = RealPath;
+              U.setResolvedPath(FileNum, File);
+            }
 #endif
-          FileRef = StringPool.internString(File);
+            FileRef = StringPool.internString(File);
+          }
         }
       }
     }
@@ -1653,11 +1657,16 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
   if (!Line && NameRef.empty())
     return PointerIntPair<DeclContext *, 1>(nullptr);
 
-  // FIXME: dsymutil-classic compat won't unique the same type
-  // presented once as a struct and once as a class. Use the Tag in
-  // the fully qualified name hash to get the same effect.
   // We hash NameRef, which is the mangled name, in order to get most
-  // overloaded functions resolvec correctly.
+  // overloaded functions resolve correctly.
+  //
+  // Strictly speaking, hashing the Tag is only necessary for a
+  // DW_TAG_module, to prevent uniquing of a module and a namespace
+  // with the same name.
+  //
+  // FIXME: dsymutil-classic won't unique the same type presented
+  // once as a struct and once as a class. Using the Tag in the fully
+  // qualified name hash to get the same effect.
   unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef);
 
   // FIXME: dsymutil-classic compatibility: when we don't have a name,
@@ -1737,21 +1746,45 @@ bool DwarfLinker::createStreamer(Triple TheTriple, StringRef OutputFilename) {
   return Streamer->init(TheTriple, OutputFilename);
 }
 
-/// \brief Recursive helper to gather the child->parent relationships in the
-/// original compile unit.
-static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
-                             unsigned ParentIdx, CompileUnit &CU,
-                             DeclContext *CurrentDeclContext,
-                             NonRelocatableStringpool &StringPool,
-                             DeclContextTree &Contexts) {
+/// Recursive helper to build the global DeclContext information and
+/// gather the child->parent relationships in the original compile unit.
+///
+/// \return true when this DIE and all of its children are only
+/// forward declarations to types defined in external clang modules
+/// (i.e., forward declarations that are children of a DW_TAG_module).
+static bool analyzeContextInfo(const DWARFDebugInfoEntryMinimal *DIE,
+                               unsigned ParentIdx, CompileUnit &CU,
+                               DeclContext *CurrentDeclContext,
+                               NonRelocatableStringpool &StringPool,
+                               DeclContextTree &Contexts,
+                               bool InImportedModule = false) {
   unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
   CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx);
 
+  // Clang imposes an ODR on modules(!) regardless of the language:
+  //  "The module-id should consist of only a single identifier,
+  //   which provides the name of the module being defined. Each
+  //   module shall have a single definition."
+  //
+  // This does not extend to the types inside the modules:
+  //  "[I]n C, this implies that if two structs are defined in
+  //   different submodules with the same name, those two types are
+  //   distinct types (but may be compatible types if their
+  //   definitions match)."
+  //
+  // We treat non-C++ modules like namespaces for this reason.
+  if (DIE->getTag() == dwarf::DW_TAG_module && ParentIdx == 0 &&
+      DIE->getAttributeValueAsString(&CU.getOrigUnit(), dwarf::DW_AT_name,
+                                     "") != CU.getClangModuleName()) {
+    InImportedModule = true;
+  }
+
   Info.ParentIdx = ParentIdx;
-  if (CU.hasODR()) {
+  bool InClangModule = CU.isClangModule() || InImportedModule;
+  if (CU.hasODR() || InClangModule) {
     if (CurrentDeclContext) {
-      auto PtrInvalidPair = Contexts.getChildDeclContext(*CurrentDeclContext,
-                                                         DIE, CU, StringPool);
+      auto PtrInvalidPair = Contexts.getChildDeclContext(
+          *CurrentDeclContext, DIE, CU, StringPool, InClangModule);
       CurrentDeclContext = PtrInvalidPair.getPointer();
       Info.Ctxt =
           PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();
@@ -1759,11 +1792,24 @@ static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
       Info.Ctxt = CurrentDeclContext = nullptr;
   }
 
+  Info.Prune = InImportedModule;
   if (DIE->hasChildren())
     for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
          Child = Child->getSibling())
-      gatherDIEParents(Child, MyIdx, CU, CurrentDeclContext, StringPool,
-                       Contexts);
+      Info.Prune &= analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext,
+                                       StringPool, Contexts, InImportedModule);
+
+  // Prune this DIE if it is either a forward declaration inside a
+  // DW_TAG_module or a DW_TAG_module that contains nothing but
+  // forward declarations.
+  Info.Prune &= (DIE->getTag() == dwarf::DW_TAG_module) ||
+                DIE->getAttributeValueAsUnsignedConstant(
+                    &CU.getOrigUnit(), dwarf::DW_AT_declaration, 0);
+
+  // Don't prune it if there is no definition for the DIE.
+  Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset();
+
+  return Info.Prune;
 }
 
 static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
@@ -2148,6 +2194,11 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr,
           Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr))
         continue;
 
+      // Keep a module forward declaration if there is no definition.
+      if (!(isODRAttribute(AttrSpec.Attr) && Info.Ctxt &&
+            Info.Ctxt->getCanonicalDIEOffset()))
+        Info.Prune = false;
+
       unsigned ODRFlag = UseODR ? TF_ODR : 0;
       lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU,
                         TF_Keep | TF_DependencyWalk | ODRFlag);
@@ -2174,6 +2225,8 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
   unsigned Idx = CU.getOrigUnit().getDIEIndex(&Die);
   CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx);
   bool AlreadyKept = MyInfo.Keep;
+  if (MyInfo.Prune)
+    return;
 
   // If the Keep flag is set, we are marking a required DIE's
   // dependencies. If our target is already marked as kept, we're all
@@ -2228,10 +2281,10 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) {
   } else {
     // Add to abbreviation list.
     Abbreviations.push_back(
-        new DIEAbbrev(Abbrev.getTag(), Abbrev.hasChildren()));
+        llvm::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));
     for (const auto &Attr : Abbrev.getData())
       Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm());
-    AbbreviationsSet.InsertNode(Abbreviations.back(), InsertToken);
+    AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);
     // Assign the unique abbreviation number.
     Abbrev.setNumber(Abbreviations.size());
     Abbreviations.back()->setNumber(Abbreviations.size());
@@ -2611,7 +2664,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
     Die = Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));
   assert(Die->getTag() == InputDIE.getTag());
   Die->setOffset(OutOffset);
-  if (Unit.hasODR() && Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt &&
+  if ((Unit.hasODR() || Unit.isClangModule()) &&
+      Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt &&
       Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt &&
       !Info.Ctxt->getCanonicalDIEOffset()) {
     // We are about to emit a DIE that is the root of its own valid
@@ -2716,11 +2770,19 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
     Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset);
   }
 
+  // Determine whether there are any children that we want to keep.
+  bool HasChildren = false;
+  for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL();
+       Child = Child->getSibling()) {
+    unsigned Idx = U.getDIEIndex(Child);
+    if (Unit.getInfo(Idx).Keep) {
+      HasChildren = true;
+      break;
+    }
+  }
+
   DIEAbbrev NewAbbrev = Die->generateAbbrev();
-  // If a scope DIE is kept, we must have kept at least one child. If
-  // it's not the case, we'll just be emitting one wasteful end of
-  // children marker, but things won't break.
-  if (InputDIE.hasChildren())
+  if (HasChildren)
     NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
   // Assign a permanent abbrev number
   Linker.AssignAbbrev(NewAbbrev);
@@ -2729,7 +2791,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
   // Add the size of the abbreviation number to the output offset.
   OutOffset += getULEB128Size(Die->getAbbrevNumber());
 
-  if (!Abbrev->hasChildren()) {
+  if (!HasChildren) {
     // Update our size.
     Die->setSize(OutOffset - Die->getOffset());
     return Die;
@@ -2767,7 +2829,7 @@ void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit,
   uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
       &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
   // Ranges addresses are based on the unit's low_pc. Compute the
-  // offset we need to apply to adapt to the the new unit's low_pc.
+  // offset we need to apply to adapt to the new unit's low_pc.
   int64_t UnitPcOffset = 0;
   if (OrigLowPc != -1ULL)
     UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
@@ -3091,24 +3153,49 @@ void DwarfLinker::DIECloner::copyAbbrev(
   Linker.AssignAbbrev(Copy);
 }
 
+static uint64_t getDwoId(const DWARFDebugInfoEntryMinimal &CUDie,
+                         const DWARFUnit &Unit) {
+  uint64_t DwoId =
+      CUDie.getAttributeValueAsUnsignedConstant(&Unit, dwarf::DW_AT_dwo_id, 0);
+  if (!DwoId)
+    DwoId = CUDie.getAttributeValueAsUnsignedConstant(&Unit,
+                                                      dwarf::DW_AT_GNU_dwo_id, 0);
+  return DwoId;
+}
+
 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, "");
+      CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_dwo_name, "");
+  if (PCMfile.empty())
+    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, "");
+  uint64_t DwoId = getDwoId(CUDie, Unit);
+
+  std::string Name =
+      CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_name, "");
+  if (Name.empty()) {
+    reportWarning("Anonymous module skeleton CU for " + PCMfile);
+    return true;
+  }
 
   if (Options.Verbose) {
     outs().indent(Indent);
     outs() << "Found clang module reference " << PCMfile;
   }
 
-  if (ClangModules.count(PCMfile)) {
+  auto Cached = ClangModules.find(PCMfile);
+  if (Cached != ClangModules.end()) {
+    if (Cached->second != DwoId)
+      reportWarning(Twine("hash mismatch: this object file was built against a "
+                          "different version of the module ") + PCMfile);
     if (Options.Verbose)
       outs() << " [cached].\n";
     return true;
@@ -3118,8 +3205,8 @@ bool DwarfLinker::registerModuleReference(
 
   // 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);
+  ClangModules.insert({PCMfile, DwoId});
+  loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, Indent + 2);
   return true;
 }
 
@@ -3139,6 +3226,7 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
 }
 
 void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
+                                  StringRef ModuleName, uint64_t DwoId,
                                   DebugMap &ModuleMap, unsigned Indent) {
   SmallString<80> Path(Options.PrependPath);
   if (sys::path::is_relative(Filename))
@@ -3154,10 +3242,7 @@ void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
     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;
+  std::unique_ptr<CompileUnit> Unit;
 
   // Setup access to the debug info.
   DWARFContextInMemory DwarfContext(*ErrOrObj);
@@ -3166,16 +3251,22 @@ void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
     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);
+      if (getDwoId(*CUDie, *CU) != DwoId)
+        reportWarning(
+            Twine("hash mismatch: this object file was built against a "
+                  "different version of the module ") + Filename);
+
+      // Add this module.
+      Unit = llvm::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR,
+                                            ModuleName);
       Unit->setHasInterestingContent();
-      gatherDIEParents(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
-                       ODRContexts);
+      analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
+                         ODRContexts);
       // Keep everything.
       Unit->markEverythingAsKept();
     }
@@ -3261,21 +3352,23 @@ bool DwarfLinker::link(const DebugMap &Map) {
     DWARFContextInMemory DwarfContext(*ErrOrObj);
     startDebugObject(DwarfContext, *Obj);
 
-    // In a first phase, just read in the debug info and store the DIE
-    // parent links that we will use during the next phase.
+    // In a first phase, just read in the debug info and load all clang modules.
     for (const auto &CU : DwarfContext.compile_units()) {
       auto *CUDie = CU->getUnitDIE(false);
       if (Options.Verbose) {
         outs() << "Input compilation unit:";
         CUDie->dump(outs(), CU.get(), 0);
       }
-      if (!registerModuleReference(*CUDie, *CU, ModuleMap)) {
-        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, "");
     }
 
+    // Now build the DIE parent links that we will use during the next phase.
+    for (auto &CurrentUnit : Units)
+      analyzeContextInfo(CurrentUnit.getOrigUnit().getUnitDIE(), 0, CurrentUnit,
+                         &ODRContexts.getRoot(), StringPool, ODRContexts);
+
     // Then mark all the DIEs that need to be present in the linked
     // output and collect some information about them. Note that this
     // loop can not be merged with the previous one becaue cross-cu