dsymutil: Factor out the relocation handling into a RelocationManager (NFC)
authorAdrian Prantl <aprantl@apple.com>
Fri, 11 Sep 2015 23:45:30 +0000 (23:45 +0000)
committerAdrian Prantl <aprantl@apple.com>
Fri, 11 Sep 2015 23:45:30 +0000 (23:45 +0000)
llvm-svn: 247490

llvm/tools/dsymutil/DwarfLinker.cpp

index 619bbf9..f48fcb8 100644 (file)
@@ -1103,52 +1103,74 @@ private:
   /// \brief Called at the end of a debug object link.
   void endDebugObject();
 
-  /// \defgroup FindValidRelocations Translate debug map into a list
-  /// of relevant relocations
-  ///
-  /// @{
-  struct ValidReloc {
-    uint32_t Offset;
-    uint32_t Size;
-    uint64_t Addend;
-    const DebugMapObject::DebugMapEntry *Mapping;
-
-    ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
-               const DebugMapObject::DebugMapEntry *Mapping)
-        : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
-
-    bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
+  /// Keeps track of relocations.
+  class RelocationManager {
+    struct ValidReloc {
+      uint32_t Offset;
+      uint32_t Size;
+      uint64_t Addend;
+      const DebugMapObject::DebugMapEntry *Mapping;
+
+      ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
+                 const DebugMapObject::DebugMapEntry *Mapping)
+          : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
+
+      bool operator<(const ValidReloc &RHS) const {
+        return Offset < RHS.Offset;
+      }
+    };
+
+    DwarfLinker &Linker;
+
+    /// \brief The valid relocations for the current DebugMapObject.
+    /// This vector is sorted by relocation offset.
+    std::vector<ValidReloc> ValidRelocs;
+
+    /// \brief Index into ValidRelocs of the next relocation to
+    /// consider. As we walk the DIEs in acsending file offset and as
+    /// ValidRelocs is sorted by file offset, keeping this index
+    /// uptodate is all we have to do to have a cheap lookup during the
+    /// root DIE selection and during DIE cloning.
+    unsigned NextValidReloc;
+
+  public:
+    RelocationManager(DwarfLinker &Linker)
+        : Linker(Linker), NextValidReloc(0) {}
+
+    bool hasValidRelocs() const { return !ValidRelocs.empty(); }
+    /// \brief Reset the NextValidReloc counter.
+    void resetValidRelocs() { NextValidReloc = 0; }
+
+    /// \defgroup FindValidRelocations Translate debug map into a list
+    /// of relevant relocations
+    ///
+    /// @{
+    bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+                                    const DebugMapObject &DMO);
+
+    bool findValidRelocs(const object::SectionRef &Section,
+                         const object::ObjectFile &Obj,
+                         const DebugMapObject &DMO);
+
+    void findValidRelocsMachO(const object::SectionRef &Section,
+                              const object::MachOObjectFile &Obj,
+                              const DebugMapObject &DMO);
+    /// @}
+
+    bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
+                            CompileUnit::DIEInfo &Info);
+
+    bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
+                          bool isLittleEndian);
   };
 
-  /// \brief The valid relocations for the current DebugMapObject.
-  /// This vector is sorted by relocation offset.
-  std::vector<ValidReloc> ValidRelocs;
-
-  /// \brief Index into ValidRelocs of the next relocation to
-  /// consider. As we walk the DIEs in acsending file offset and as
-  /// ValidRelocs is sorted by file offset, keeping this index
-  /// uptodate is all we have to do to have a cheap lookup during the
-  /// root DIE selection and during DIE cloning.
-  unsigned NextValidReloc;
-
-  bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
-                                  const DebugMapObject &DMO);
-
-  bool findValidRelocs(const object::SectionRef &Section,
-                       const object::ObjectFile &Obj,
-                       const DebugMapObject &DMO);
-
-  void findValidRelocsMachO(const object::SectionRef &Section,
-                            const object::MachOObjectFile &Obj,
-                            const DebugMapObject &DMO);
-  /// @}
-
   /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
   ///
   /// @{
   /// \brief Recursively walk the \p DIE tree and look for DIEs to
   /// keep. Store that information in \p CU's DIEInfo.
-  void lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE,
+  void lookForDIEsToKeep(RelocationManager &RelocMgr,
+                         const DWARFDebugInfoEntryMinimal &DIE,
                          const DebugMapObject &DMO, CompileUnit &CU,
                          unsigned Flags);
 
@@ -1164,20 +1186,24 @@ private:
 
   /// \brief Mark the passed DIE as well as all the ones it depends on
   /// as kept.
-  void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
+  void keepDIEAndDenpendencies(RelocationManager &RelocMgr,
+                               const DWARFDebugInfoEntryMinimal &DIE,
                                CompileUnit::DIEInfo &MyInfo,
                                const DebugMapObject &DMO, CompileUnit &CU,
                                bool UseODR);
 
-  unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
+  unsigned shouldKeepDIE(RelocationManager &RelocMgr,
+                         const DWARFDebugInfoEntryMinimal &DIE,
                          CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
                          unsigned Flags);
 
-  unsigned shouldKeepVariableDIE(const DWARFDebugInfoEntryMinimal &DIE,
+  unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr,
+                                 const DWARFDebugInfoEntryMinimal &DIE,
                                  CompileUnit &Unit,
                                  CompileUnit::DIEInfo &MyInfo, unsigned Flags);
 
-  unsigned shouldKeepSubprogramDIE(const DWARFDebugInfoEntryMinimal &DIE,
+  unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr,
+                                   const DWARFDebugInfoEntryMinimal &DIE,
                                    CompileUnit &Unit,
                                    CompileUnit::DIEInfo &MyInfo,
                                    unsigned Flags);
@@ -1200,9 +1226,19 @@ private:
   /// applied to the entry point of the function to get the linked address.
   ///
   /// \returns the root of the cloned tree.
-  DIE *cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U,
+  DIE *cloneDIE(RelocationManager &RelocMgr,
+                const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U,
                 int64_t PCOffset, uint32_t OutOffset, unsigned Flags);
 
+  /// Construct the output DIE tree by cloning the DIEs we chose to
+  /// keep above. If there are no valid relocs, then there's nothing
+  /// to clone/emit.
+  void cloneCompileUnit(RelocationManager &RelocMgr,
+                        MutableArrayRef<CompileUnit> CompileUnit,
+                        DWARFContextInMemory &DwarfContext);
+
+
+
   typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec;
 
   /// \brief Information gathered and exchanged between the various
@@ -1257,10 +1293,6 @@ private:
                                 const DWARFFormValue &Val, unsigned AttrSize,
                                 AttributesInfo &Info);
 
-  /// \brief Helper for cloneDIE.
-  bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
-                        bool isLittleEndian);
-
   /// \brief Assign an abbreviation number to \p Abbrev
   void AssignAbbrev(DIEAbbrev &Abbrev);
 
@@ -1334,6 +1366,7 @@ private:
   LinkOptions Options;
   BinaryHolder BinHolder;
   std::unique_ptr<DwarfStreamer> Streamer;
+  uint64_t OutputDebugInfoSize;
 
   /// The units of the current debug map object.
   std::vector<CompileUnit> Units;
@@ -1701,7 +1734,6 @@ static unsigned getRefAddrSize(const DWARFUnit &U) {
 
 void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) {
   Units.reserve(Dwarf.getNumCompileUnits());
-  NextValidReloc = 0;
   // Iterate over the debug map entries and put all the ones that are
   // functions (because they have a size) into the Ranges map. This
   // map is very similar to the FunctionRanges that are stored in each
@@ -1727,7 +1759,6 @@ void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) {
 
 void DwarfLinker::endDebugObject() {
   Units.clear();
-  ValidRelocs.clear();
   Ranges.clear();
 
   for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I)
@@ -1743,9 +1774,10 @@ void DwarfLinker::endDebugObject() {
 /// \brief Iterate over the relocations of the given \p Section and
 /// store the ones that correspond to debug map entries into the
 /// ValidRelocs array.
-void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
-                                       const object::MachOObjectFile &Obj,
-                                       const DebugMapObject &DMO) {
+void DwarfLinker::RelocationManager::
+findValidRelocsMachO(const object::SectionRef &Section,
+                     const object::MachOObjectFile &Obj,
+                     const DebugMapObject &DMO) {
   StringRef Contents;
   Section.getContents(Contents);
   DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
@@ -1756,7 +1788,7 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
     unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
     uint64_t Offset64 = Reloc.getOffset();
     if ((RelocSize != 4 && RelocSize != 8)) {
-      reportWarning(" unsupported relocation in debug_info section.");
+      Linker.reportWarning(" unsupported relocation in debug_info section.");
       continue;
     }
     uint32_t Offset = Offset64;
@@ -1767,7 +1799,7 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
     if (Sym != Obj.symbol_end()) {
       ErrorOr<StringRef> SymbolName = Sym->getName();
       if (!SymbolName) {
-        reportWarning("error getting relocation symbol name.");
+        Linker.reportWarning("error getting relocation symbol name.");
         continue;
       }
       if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
@@ -1783,14 +1815,15 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
 
 /// \brief Dispatch the valid relocation finding logic to the
 /// appropriate handler depending on the object file format.
-bool DwarfLinker::findValidRelocs(const object::SectionRef &Section,
-                                  const object::ObjectFile &Obj,
-                                  const DebugMapObject &DMO) {
+bool DwarfLinker::RelocationManager::findValidRelocs(
+    const object::SectionRef &Section, const object::ObjectFile &Obj,
+    const DebugMapObject &DMO) {
   // Dispatch to the right handler depending on the file type.
   if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
     findValidRelocsMachO(Section, *MachOObj, DMO);
   else
-    reportWarning(Twine("unsupported object file type: ") + Obj.getFileName());
+    Linker.reportWarning(Twine("unsupported object file type: ") +
+                         Obj.getFileName());
 
   if (ValidRelocs.empty())
     return false;
@@ -1808,8 +1841,9 @@ bool DwarfLinker::findValidRelocs(const object::SectionRef &Section,
 /// link by indicating which DIEs refer to symbols present in the
 /// linked binary.
 /// \returns wether there are any valid relocations in the debug info.
-bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
-                                             const DebugMapObject &DMO) {
+bool DwarfLinker::RelocationManager::
+findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+                           const DebugMapObject &DMO) {
   // Find the debug_info section.
   for (const object::SectionRef &Section : Obj.sections()) {
     StringRef SectionName;
@@ -1828,8 +1862,9 @@ bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
 /// This function must be called with offsets in strictly ascending
 /// order because it never looks back at relocations it already 'went past'.
 /// \returns true and sets Info.InDebugMap if it is the case.
-bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
-                                     CompileUnit::DIEInfo &Info) {
+bool DwarfLinker::RelocationManager::
+hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
+                   CompileUnit::DIEInfo &Info) {
   assert(NextValidReloc == 0 ||
          StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
   if (NextValidReloc >= ValidRelocs.size())
@@ -1849,7 +1884,7 @@ bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
 
   const auto &ValidReloc = ValidRelocs[NextValidReloc++];
   const auto &Mapping = ValidReloc.Mapping->getValue();
-  if (Options.Verbose)
+  if (Linker.Options.Verbose)
     outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
            << " " << format("\t%016" PRIx64 " => %016" PRIx64,
                             uint64_t(Mapping.ObjectAddress),
@@ -1882,9 +1917,11 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
 
 /// \brief Check if a variable describing DIE should be kept.
 /// \returns updated TraversalFlags.
-unsigned DwarfLinker::shouldKeepVariableDIE(
-    const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit,
-    CompileUnit::DIEInfo &MyInfo, unsigned Flags) {
+unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr,
+                                            const DWARFDebugInfoEntryMinimal &DIE,
+                                            CompileUnit &Unit,
+                                            CompileUnit::DIEInfo &MyInfo,
+                                            unsigned Flags) {
   const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
 
   // Global variables with constant value can always be kept.
@@ -1909,7 +1946,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE(
   // always check in the variable has a valid relocation, so that the
   // DIEInfo is filled. However, we don't want a static variable in a
   // function to force us to keep the enclosing function.
-  if (!hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
+  if (!RelocMgr.hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
       (Flags & TF_InFunctionScope))
     return Flags;
 
@@ -1922,6 +1959,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE(
 /// \brief Check if a function describing DIE should be kept.
 /// \returns updated TraversalFlags.
 unsigned DwarfLinker::shouldKeepSubprogramDIE(
+    RelocationManager &RelocMgr,
     const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit,
     CompileUnit::DIEInfo &MyInfo, unsigned Flags) {
   const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
@@ -1942,7 +1980,7 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
       DIE.getAttributeValueAsAddress(&OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
   assert(LowPc != -1ULL && "low_pc attribute is not an address.");
   if (LowPc == -1ULL ||
-      !hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
+      !RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
     return Flags;
 
   if (Options.Verbose)
@@ -1973,16 +2011,17 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
 
 /// \brief Check if a DIE should be kept.
 /// \returns updated TraversalFlags.
-unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
+unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr,
+                                    const DWARFDebugInfoEntryMinimal &DIE,
                                     CompileUnit &Unit,
                                     CompileUnit::DIEInfo &MyInfo,
                                     unsigned Flags) {
   switch (DIE.getTag()) {
   case dwarf::DW_TAG_constant:
   case dwarf::DW_TAG_variable:
-    return shouldKeepVariableDIE(DIE, Unit, MyInfo, Flags);
+    return shouldKeepVariableDIE(RelocMgr, DIE, Unit, MyInfo, Flags);
   case dwarf::DW_TAG_subprogram:
-    return shouldKeepSubprogramDIE(DIE, Unit, MyInfo, Flags);
+    return shouldKeepSubprogramDIE(RelocMgr, DIE, Unit, MyInfo, Flags);
   case dwarf::DW_TAG_module:
   case dwarf::DW_TAG_imported_module:
   case dwarf::DW_TAG_imported_declaration:
@@ -2002,7 +2041,8 @@ unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
 /// back to lookForDIEsToKeep while adding TF_DependencyWalk to the
 /// TraversalFlags to inform it that it's not doing the primary DIE
 /// tree walk.
-void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
+void DwarfLinker::keepDIEAndDenpendencies(RelocationManager &RelocMgr,
+                                          const DWARFDebugInfoEntryMinimal &Die,
                                           CompileUnit::DIEInfo &MyInfo,
                                           const DebugMapObject &DMO,
                                           CompileUnit &CU, bool UseODR) {
@@ -2013,7 +2053,7 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
   unsigned AncestorIdx = MyInfo.ParentIdx;
   while (!CU.getInfo(AncestorIdx).Keep) {
     unsigned ODRFlag = UseODR ? TF_ODR : 0;
-    lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
+    lookForDIEsToKeep(RelocMgr, *Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
                       TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag);
     AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx;
   }
@@ -2053,7 +2093,7 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
         continue;
 
       unsigned ODRFlag = UseODR ? TF_ODR : 0;
-      lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU,
+      lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU,
                         TF_Keep | TF_DependencyWalk | ODRFlag);
     }
   }
@@ -2071,7 +2111,8 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
 /// also called, but during these dependency walks the file order is
 /// not respected. The TF_DependencyWalk flag tells us which kind of
 /// traversal we are currently doing.
-void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die,
+void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
+                                    const DWARFDebugInfoEntryMinimal &Die,
                                     const DebugMapObject &DMO, CompileUnit &CU,
                                     unsigned Flags) {
   unsigned Idx = CU.getOrigUnit().getDIEIndex(&Die);
@@ -2087,12 +2128,12 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die,
   // We must not call shouldKeepDIE while called from keepDIEAndDenpendencies,
   // because it would screw up the relocation finding logic.
   if (!(Flags & TF_DependencyWalk))
-    Flags = shouldKeepDIE(Die, CU, MyInfo, Flags);
+    Flags = shouldKeepDIE(RelocMgr, Die, CU, MyInfo, Flags);
 
   // If it is a newly kept DIE mark it as well as all its dependencies as kept.
   if (!AlreadyKept && (Flags & TF_Keep)) {
     bool UseOdr = (Flags & TF_DependencyWalk) ? (Flags & TF_ODR) : CU.hasODR();
-    keepDIEAndDenpendencies(Die, MyInfo, DMO, CU, UseOdr);
+    keepDIEAndDenpendencies(RelocMgr, Die, MyInfo, DMO, CU, UseOdr);
   }
   // The TF_ParentWalk flag tells us that we are currently walking up
   // the parent chain of a required DIE, and we don't want to mark all
@@ -2108,7 +2149,7 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die,
 
   for (auto *Child = Die.getFirstChild(); Child && !Child->isNULL();
        Child = Child->getSibling())
-    lookForDIEsToKeep(*Child, DMO, CU, Flags);
+    lookForDIEsToKeep(RelocMgr, *Child, DMO, CU, Flags);
 }
 
 /// \brief Assign an abbreviation numer to \p Abbrev.
@@ -2412,8 +2453,9 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die,
 /// monotonic \p BaseOffset values.
 ///
 /// \returns wether any reloc has been applied.
-bool DwarfLinker::applyValidRelocs(MutableArrayRef<char> Data,
-                                   uint32_t BaseOffset, bool isLittleEndian) {
+bool DwarfLinker::RelocationManager::
+applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
+                 bool isLittleEndian) {
   assert((NextValidReloc == 0 ||
           BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
          "BaseOffset should only be increasing.");
@@ -2512,7 +2554,8 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
 /// lie in the linked compile unit.
 ///
 /// \returns the cloned DIE object or null if nothing was selected.
-DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
+DIE *DwarfLinker::cloneDIE(RelocationManager &RelocMgr,
+                           const DWARFDebugInfoEntryMinimal &InputDIE,
                            CompileUnit &Unit, int64_t PCOffset,
                            uint32_t OutOffset, unsigned Flags) {
   DWARFUnit &U = Unit.getOrigUnit();
@@ -2551,7 +2594,7 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
   SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));
   Data = DataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
   // Modify the copy with relocated addresses.
-  if (applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
+  if (RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
     // If we applied relocations, we store the value of high_pc that was
     // potentially stored in the input DIE. If high_pc is an address
     // (Dwarf version == 2), then it might have been relocated to a
@@ -2652,7 +2695,8 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
   // Recursively clone children.
   for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL();
        Child = Child->getSibling()) {
-    if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset, Flags)) {
+    if (DIE *Clone =
+            cloneDIE(RelocMgr, *Child, Unit, PCOffset, OutOffset, Flags)) {
       Die->addChild(Clone);
       OutOffset = Clone->getOffset() + Clone->getSize();
     }
@@ -3020,13 +3064,53 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
   return ErrOrObj;
 }
 
+void DwarfLinker::cloneCompileUnit(RelocationManager &RelocMgr,
+                                   MutableArrayRef<CompileUnit> CompileUnits,
+                                   DWARFContextInMemory &DwarfContext) {
+  if (!Streamer)
+    return;
+
+  for (auto &CurrentUnit : CompileUnits) {
+    const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
+    CurrentUnit.setStartOffset(OutputDebugInfoSize);
+    DIE *OutputDIE = cloneDIE(RelocMgr, *InputDIE, CurrentUnit,
+                              0 /* PC offset */, 11 /* Unit Header size */, 0);
+    CurrentUnit.setOutputUnitDIE(OutputDIE);
+    OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset();
+    if (Options.NoOutput)
+      continue;
+    // FIXME: for compatibility with the classic dsymutil, we emit
+    // an empty line table for the unit, even if the unit doesn't
+    // actually exist in the DIE tree.
+    patchLineTableForUnit(CurrentUnit, DwarfContext);
+    if (!OutputDIE)
+      continue;
+    patchRangesForUnit(CurrentUnit, DwarfContext);
+    Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
+    emitAcceleratorEntriesForUnit(CurrentUnit);
+  }
+
+  if (Options.NoOutput)
+    return;
+
+  // Emit all the compile unit's debug information.
+  for (auto &CurrentUnit : CompileUnits) {
+    generateUnitRanges(CurrentUnit);
+    CurrentUnit.fixupForwardReferences();
+    Streamer->emitCompileUnitHeader(CurrentUnit);
+    if (!CurrentUnit.getOutputUnitDIE())
+      continue;
+    Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE());
+  }
+}
+
 bool DwarfLinker::link(const DebugMap &Map) {
 
   if (!createStreamer(Map.getTriple(), OutputFilename))
     return false;
 
   // Size of the DIEs (and headers) generated for the linked output.
-  uint64_t OutputDebugInfoSize = 0;
+  OutputDebugInfoSize = 0;
   // A unique ID that identifies each compile unit.
   unsigned UnitID = 0;
   for (const auto &Obj : Map.objects()) {
@@ -3039,7 +3123,8 @@ bool DwarfLinker::link(const DebugMap &Map) {
       continue;
 
     // Look for relocations that correspond to debug map entries.
-    if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
+    RelocationManager RelocMgr(*this);
+    if (!RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
       if (Options.Verbose)
         outs() << "No valid relocations found. Skipping.\n";
       continue;
@@ -3068,50 +3153,16 @@ bool DwarfLinker::link(const DebugMap &Map) {
     // references require the ParentIdx to be setup for every CU in
     // the object file before calling this.
     for (auto &CurrentUnit : Units)
-      lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
+      lookForDIEsToKeep(RelocMgr, *CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
                         CurrentUnit, 0);
 
     // The calls to applyValidRelocs inside cloneDIE will walk the
     // reloc array again (in the same way findValidRelocsInDebugInfo()
     // did). We need to reset the NextValidReloc index to the beginning.
-    NextValidReloc = 0;
-
-    // Construct the output DIE tree by cloning the DIEs we chose to
-    // keep above. If there are no valid relocs, then there's nothing
-    // to clone/emit.
-    if (!ValidRelocs.empty())
-      for (auto &CurrentUnit : Units) {
-        const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
-        CurrentUnit.setStartOffset(OutputDebugInfoSize);
-        DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */,
-                                  11 /* Unit Header size */, /* Flags =*/0);
-        CurrentUnit.setOutputUnitDIE(OutputDIE);
-        OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset();
-        if (Options.NoOutput)
-          continue;
-        // FIXME: for compatibility with the classic dsymutil, we emit
-        // an empty line table for the unit, even if the unit doesn't
-        // actually exist in the DIE tree.
-        patchLineTableForUnit(CurrentUnit, DwarfContext);
-        if (!OutputDIE)
-          continue;
-        patchRangesForUnit(CurrentUnit, DwarfContext);
-        Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
-        emitAcceleratorEntriesForUnit(CurrentUnit);
-      }
-
-    // Emit all the compile unit's debug information.
-    if (!ValidRelocs.empty() && !Options.NoOutput)
-      for (auto &CurrentUnit : Units) {
-        generateUnitRanges(CurrentUnit);
-        CurrentUnit.fixupForwardReferences();
-        Streamer->emitCompileUnitHeader(CurrentUnit);
-        if (!CurrentUnit.getOutputUnitDIE())
-          continue;
-        Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE());
-      }
-
-    if (!ValidRelocs.empty() && !Options.NoOutput && !Units.empty())
+    RelocMgr.resetValidRelocs();
+    if (RelocMgr.hasValidRelocs())
+      cloneCompileUnit(RelocMgr, Units, DwarfContext);
+    if (!Options.NoOutput && !Units.empty())
       patchFrameInfoForObject(*Obj, DwarfContext,
                               Units[0].getOrigUnit().getAddressByteSize());