Index: llvm/include/llvm/BinaryFormat/Dwarf.def
===================================================================
--- llvm/include/llvm/BinaryFormat/Dwarf.def
+++ llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -628,6 +628,7 @@
 HANDLE_DW_AT(0x3fed, APPLE_property, 0, APPLE)
 HANDLE_DW_AT(0x3fee, APPLE_objc_direct, 0, APPLE)
 HANDLE_DW_AT(0x3fef, APPLE_sdk, 0, APPLE)
+HANDLE_DW_AT(0x3ff0, APPLE_origin, 0, APPLE)
 
 // Attribute form encodings.
 HANDLE_DW_FORM(0x01, addr, 2, DWARF)
Index: llvm/include/llvm/BinaryFormat/MachO.h
===================================================================
--- llvm/include/llvm/BinaryFormat/MachO.h
+++ llvm/include/llvm/BinaryFormat/MachO.h
@@ -381,6 +381,7 @@
   N_SSYM = 0x60u,
   N_SO = 0x64u,
   N_OSO = 0x66u,
+  N_LIB = 0x68u,
   N_LSYM = 0x80u,
   N_BINCL = 0x82u,
   N_SOL = 0x84u,
Index: llvm/include/llvm/DWARFLinker/DWARFLinker.h
===================================================================
--- llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -14,6 +14,7 @@
 #include "llvm/CodeGen/AccelTable.h"
 #include "llvm/CodeGen/NonRelocatableStringpool.h"
 #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
+#include "llvm/DWARFLinker/DWARFLinkerRelocs.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
@@ -23,9 +24,11 @@
 
 namespace llvm {
 class DWARFExpression;
+class DWARFLinker;
 class DWARFUnit;
 class DataExtractor;
 class DeclContextTree;
+
 template <typename T> class SmallVectorImpl;
 
 enum class DwarfLinkerClient { Dsymutil, LLD, General };
@@ -62,12 +65,19 @@
   virtual std::optional<int64_t>
   getSubprogramRelocAdjustment(const DWARFDie &DIE) = 0;
 
+  /// Returns the file name associated to the AddessesMap
+  virtual std::optional<StringRef> getFileName() = 0;
+
   /// Apply the valid relocations to the buffer \p Data, taking into
   /// account that Data is at \p BaseOffset in the .debug_info section.
   ///
   /// \returns true whether any reloc has been applied.
   virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
-                                bool IsLittleEndian) = 0;
+                                bool IsLittleEndian, uint64_t CUOffset,
+                                int64_t RelocSlide) = 0;
+
+  /// Add the valid relocations to be serialized to the relocation map
+  virtual void addValidRelocs(RelocMap *RM) = 0;
 
   /// Erases all data.
   virtual void clear() = 0;
@@ -638,6 +648,9 @@
                                    CompileUnit::DIEInfo &MyInfo,
                                    unsigned Flags);
 
+  void visitCompileUnitDIE(AddressesMap &RelocMgr, const DWARFDie &DIE,
+                           CompileUnit::DIEInfo &MyInfo);
+
   /// Resolve the DIE attribute reference that has been extracted in \p
   /// RefValue. The resulting DIE might be in another CompileUnit which is
   /// stored into \p ReferencedCU. \returns null if resolving fails for any
Index: llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
===================================================================
--- llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
+++ llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
@@ -74,6 +74,9 @@
     /// The index of this DIE's parent.
     uint32_t ParentIdx;
 
+    /// Name of the file where the described entity is from.
+    std::optional<StringRef> FileName;
+
     /// Is the DIE part of the linked output?
     bool Keep : 1;
 
@@ -105,7 +108,8 @@
 
   CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
               StringRef ClangModuleName)
-      : OrigUnit(OrigUnit), ID(ID), ClangModuleName(ClangModuleName) {
+      : OrigUnit(OrigUnit), ID(ID), AddedOriginObject(false),
+        ClangModuleName(ClangModuleName) {
     Info.resize(OrigUnit.getNumDIEs());
 
     auto CUDie = OrigUnit.getUnitDIE(false);
@@ -143,6 +147,9 @@
 
   const std::string &getClangModuleName() const { return ClangModuleName; }
 
+  void setOriginObject() { AddedOriginObject = true; }
+  bool addedOriginObject() const { return AddedOriginObject; }
+
   DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
   const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
 
@@ -320,6 +327,9 @@
   /// The DW_AT_language of this unit.
   uint16_t Language = 0;
 
+  /// The DW_AT_APPLE_origin was added
+  bool AddedOriginObject;
+
   /// The DW_AT_LLVM_sysroot of this unit.
   std::string SysRoot;
 
Index: llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
===================================================================
--- llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
+++ llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
@@ -15,6 +15,9 @@
 #include <cstdint>
 
 namespace llvm {
+
+class RelocMap;
+
 namespace dwarflinker_parallel {
 
 /// Mapped value in the address map is the offset to apply to the
@@ -53,12 +56,19 @@
   virtual std::optional<int64_t>
   getSubprogramRelocAdjustment(const DWARFDie &DIE) = 0;
 
+  // Reeturns the file name associated to the AddessesMap
+  virtual std::optional<StringRef> getFileName() = 0;
+
   /// Apply the valid relocations to the buffer \p Data, taking into
   /// account that Data is at \p BaseOffset in the .debug_info section.
   ///
   /// \returns true whether any reloc has been applied.
   virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
-                                bool IsLittleEndian) = 0;
+                                bool IsLittleEndian, uint64_t CUOffset,
+                                int64_t RelocSlide) = 0;
+
+  /// Add the valid relocatios to be serialized to the relocation map
+  virtual void addValidRelocs(RelocMap *RM) = 0;
 
   /// Erases all data.
   virtual void clear() = 0;
Index: llvm/include/llvm/TargetParser/Triple.h
===================================================================
--- llvm/include/llvm/TargetParser/Triple.h
+++ llvm/include/llvm/TargetParser/Triple.h
@@ -439,9 +439,6 @@
   /// Get the architecture (first) component of the triple.
   StringRef getArchName() const;
 
-  /// Get the architecture name based on Kind and SubArch.
-  StringRef getArchName(ArchType Kind, SubArchType SubArch = NoSubArch) const;
-
   /// Get the vendor (second) component of the triple.
   StringRef getVendorName() const;
 
@@ -1177,6 +1174,9 @@
   /// Get the canonical name for the \p Kind architecture.
   static StringRef getArchTypeName(ArchType Kind);
 
+  /// Get the architecture name based on \p Kind and \p SubArch.
+  static StringRef getArchName(ArchType Kind, SubArchType SubArch = NoSubArch);
+
   /// Get the "prefix" canonical name for the \p Kind architecture. This is the
   /// prefix used by the architecture specific builtins, and is suitable for
   /// passing to \see Intrinsic::getIntrinsicForClangBuiltin().
Index: llvm/lib/DWARFLinker/DWARFLinker.cpp
===================================================================
--- llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -538,6 +538,7 @@
 
   MyInfo.AddrAdjust = *LocExprAddrAndRelocAdjustment.second;
   MyInfo.InDebugMap = true;
+  MyInfo.FileName = RelocMgr.getFileName();
 
   if (((Flags & TF_InFunctionScope) &&
        !LLVM_UNLIKELY(Options.KeepFunctionForStatic)))
@@ -573,6 +574,7 @@
 
   MyInfo.AddrAdjust = *RelocAdjustment;
   MyInfo.InDebugMap = true;
+  MyInfo.FileName = RelocMgr.getFileName();
 
   if (Options.Verbose) {
     outs() << "Keeping subprogram DIE:";
@@ -617,6 +619,12 @@
   return Flags;
 }
 
+/// Get information about a compile unit that needs to be updated.
+void DWARFLinker::visitCompileUnitDIE(AddressesMap &RelocMgr,
+                                      const DWARFDie &DIE,
+                                      CompileUnit::DIEInfo &MyInfo) {
+  MyInfo.FileName = RelocMgr.getFileName();
+}
 /// Check if a DIE should be kept.
 /// \returns updated TraversalFlags.
 unsigned DWARFLinker::shouldKeepDIE(AddressesMap &RelocMgr, const DWARFDie &DIE,
@@ -638,6 +646,9 @@
   case dwarf::DW_TAG_imported_unit:
     // We always want to keep these.
     return Flags | TF_Keep;
+  case dwarf::DW_TAG_compile_unit:
+    visitCompileUnitDIE(RelocMgr, DIE, MyInfo);
+    break;
   default:
     break;
   }
@@ -1678,6 +1689,9 @@
     // Since DW_AT_loclists_base is used for only DW_FORM_loclistx the
     // DW_AT_loclists_base is removed.
     return !Update;
+  case dwarf::DW_AT_APPLE_origin:
+    // Always recreate a new DW_AT_APPLE_origin attribute
+    return true;
   case dwarf::DW_AT_location:
   case dwarf::DW_AT_frame_base:
     return !Update && SkipPC;
@@ -1737,7 +1751,13 @@
       DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
 
   // Modify the copy with relocated addresses.
-  ObjFile.Addresses->applyValidRelocs(DIECopy, Offset, Data.isLittleEndian());
+  // Reflect DIEs removed during transformation from .o to .dSYM with a slide.
+  int64_t RelocSlide =
+      !Info.FileName ? (int64_t)OutOffset - (int64_t)Offset : 0;
+  // Reflect displacement due to DW_AT_APPLE_origin attribute in output file.
+  RelocSlide += Unit.addedOriginObject() ? 4 : 0;
+  ObjFile.Addresses->applyValidRelocs(DIECopy, Offset, Data.isLittleEndian(),
+                                      Unit.getStartOffset(), RelocSlide);
 
   // Reset the Offset to 0 as we will be working on the local copy of
   // the data.
@@ -1767,8 +1787,10 @@
       Flags |= TF_SkipPC;
   }
 
+  bool hadOriginAttribute = false;
   for (const auto &AttrSpec : Abbrev->attributes()) {
     if (shouldSkipAttribute(Update, AttrSpec, Flags & TF_SkipPC)) {
+      hadOriginAttribute = AttrSpec.Attr == dwarf::DW_AT_APPLE_origin;
       DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
                                 U.getFormParams());
       continue;
@@ -1783,8 +1805,21 @@
                                 AttrSize, AttrInfo, IsLittleEndian);
   }
 
-  // Look for accelerator entries.
   uint16_t Tag = InputDIE.getTag();
+  // Add origin attribute to Compile Unit die.
+  if (Tag == dwarf::DW_TAG_compile_unit) {
+    if (Info.FileName) {
+      auto StringEntry = DebugStrPool.getEntry(Info.FileName.value());
+      Die->addValue(DIEAlloc, dwarf::Attribute(dwarf::DW_AT_APPLE_origin),
+                    dwarf::DW_FORM_strp, DIEInteger(StringEntry.getOffset()));
+      AttrInfo.Name = StringEntry;
+      OutOffset += 4;
+      if (!hadOriginAttribute)
+        Unit.setOriginObject();
+    }
+  }
+
+  // Look for accelerator entries.
   // FIXME: This is slightly wrong. An inline_subroutine without a
   // low_pc, but with AT_ranges might be interesting to get into the
   // accelerator tables too. For now stick with dsymutil's behavior.
Index: llvm/lib/TargetParser/Triple.cpp
===================================================================
--- llvm/lib/TargetParser/Triple.cpp
+++ llvm/lib/TargetParser/Triple.cpp
@@ -89,6 +89,36 @@
   llvm_unreachable("Invalid ArchType!");
 }
 
+StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) {
+  switch (Kind) {
+  case Triple::mips:
+    if (SubArch == MipsSubArch_r6)
+      return "mipsisa32r6";
+    break;
+  case Triple::mipsel:
+    if (SubArch == MipsSubArch_r6)
+      return "mipsisa32r6el";
+    break;
+  case Triple::mips64:
+    if (SubArch == MipsSubArch_r6)
+      return "mipsisa64r6";
+    break;
+  case Triple::mips64el:
+    if (SubArch == MipsSubArch_r6)
+      return "mipsisa64r6el";
+    break;
+  case Triple::aarch64:
+    if (SubArch == AArch64SubArch_arm64ec)
+      return "arm64ec";
+    if (SubArch == AArch64SubArch_arm64e)
+      return "arm64e";
+    break;
+  default:
+    break;
+  }
+  return getArchTypeName(Kind);
+}
+
 StringRef Triple::getArchTypePrefix(ArchType Kind) {
   switch (Kind) {
   default:
@@ -1170,34 +1200,6 @@
   return StringRef(Data).split('-').first;           // Isolate first component
 }
 
-StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) const {
-  switch (Kind) {
-  case Triple::mips:
-    if (SubArch == MipsSubArch_r6)
-      return "mipsisa32r6";
-    break;
-  case Triple::mipsel:
-    if (SubArch == MipsSubArch_r6)
-      return "mipsisa32r6el";
-    break;
-  case Triple::mips64:
-    if (SubArch == MipsSubArch_r6)
-      return "mipsisa64r6";
-    break;
-  case Triple::mips64el:
-    if (SubArch == MipsSubArch_r6)
-      return "mipsisa64r6el";
-    break;
-  case Triple::aarch64:
-    if (SubArch == AArch64SubArch_arm64ec)
-      return "arm64ec";
-    break;
-  default:
-    break;
-  }
-  return getArchTypeName(Kind);
-}
-
 StringRef Triple::getVendorName() const {
   StringRef Tmp = StringRef(Data).split('-').second; // Strip first component
   return Tmp.split('-').first;                       // Isolate second component
Index: llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Info.plist
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.bar-relink-variant.dylib</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
Index: llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink-variant.dylib.yml
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink-variant.dylib.yml
@@ -0,0 +1,8 @@
+---
+triple:          'arm64-apple-darwin'
+binary-path:     bar-relink-variant.dylib
+relocations:
+  - { offsetInCU: 0x26, offset: 0x26, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FB4, symSize: 0x8 }
+  - { offsetInCU: 0x3F, offset: 0x3F, size: 0x8, addend: 0x0, symName: _baz, symObjAddr: 0x8, symBinAddr: 0x4000, symSize: 0x0 }
+  - { offsetInCU: 0x4F, offset: 0x4F, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FB4, symSize: 0x8 }
+...
Index: llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Info.plist
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.bar-relink.dylib</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
Index: llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink.dylib.yml
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink.dylib.yml
@@ -0,0 +1,8 @@
+---
+triple:          'arm64-apple-darwin'
+binary-path:     bar-relink.dylib
+relocations:
+  - { offsetInCU: 0x26, offset: 0x26, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FB4, symSize: 0x8 }
+  - { offsetInCU: 0x3F, offset: 0x3F, size: 0x8, addend: 0x0, symName: _baz, symObjAddr: 0x8, symBinAddr: 0x4000, symSize: 0x0 }
+  - { offsetInCU: 0x4F, offset: 0x4F, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FB4, symSize: 0x8 }
+...
Index: llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Info.plist
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.foo-relink-variant.dylib</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
Index: llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink-variant.dylib.yml
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink-variant.dylib.yml
@@ -0,0 +1,9 @@
+---
+triple:          'arm64-apple-darwin'
+binary-path:     foo-relink-variant.dylib
+relocations:
+  - { offsetInCU: 0x26, offset: 0x26, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F78, symSize: 0x20 }
+  - { offsetInCU: 0x33, offset: 0x33, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F78, symSize: 0x20 }
+  - { offsetInCU: 0x26, offset: 0x88, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F98, symSize: 0x24 }
+  - { offsetInCU: 0x33, offset: 0x95, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F98, symSize: 0x24 }
+...
Index: llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Info.plist
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.foo-relink.dylib</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
Index: llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink.dylib.yml
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink.dylib.yml
@@ -0,0 +1,10 @@
+---
+triple:          'arm64-apple-darwin'
+binary-path:     foo-relink.dylib
+relocations:
+  - { offsetInCU: 0x26, offset: 0x26, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F60, symSize: 0x20 }
+  - { offsetInCU: 0x33, offset: 0x33, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F60, symSize: 0x20 }
+  - { offsetInCU: 0x5B, offset: 0x5B, size: 0x8, addend: 0x0, symName: _foo_unused, symObjAddr: 0x20, symBinAddr: 0x3F80, symSize: 0x8 }
+  - { offsetInCU: 0x26, offset: 0xA1, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F88, symSize: 0x24 }
+  - { offsetInCU: 0x33, offset: 0xAE, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F88, symSize: 0x24 }
+...
Index: llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Info.plist
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.proxy-relink.dylib</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>
Index: llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/proxy-relink.dylib.yml
===================================================================
--- /dev/null
+++ llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/proxy-relink.dylib.yml
@@ -0,0 +1,14 @@
+---
+triple:          'arm64-apple-darwin'
+binary-path:     proxy-relink.dylib
+relocations:
+  - { offsetInCU: 0x26, offset: 0x26, size: 0x8, addend: 0x0, symName: _display, symObjAddr: 0x0, symBinAddr: 0x3F2C, symSize: 0x1C }
+  - { offsetInCU: 0x41, offset: 0x41, size: 0x8, addend: 0x0, symName: _display, symObjAddr: 0x0, symBinAddr: 0x3F2C, symSize: 0x1C }
+  - { offsetInCU: 0x26, offset: 0x7C, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x3FB4, symBinAddr: 0x3F48, symSize: 0x8 }
+  - { offsetInCU: 0x43, offset: 0x99, size: 0x8, addend: 0x0, symName: _baz, symObjAddr: 0x4000, symBinAddr: 0x8000, symSize: 0x0 }
+  - { offsetInCU: 0x53, offset: 0xA9, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x3FB4, symBinAddr: 0x3F48, symSize: 0x8 }
+  - { offsetInCU: 0x26, offset: 0xE8, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x3F74, symBinAddr: 0x3F50, symSize: 0x24 }
+  - { offsetInCU: 0x37, offset: 0xF9, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x3F74, symBinAddr: 0x3F50, symSize: 0x24 }
+  - { offsetInCU: 0x26, offset: 0x14E, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x3F98, symBinAddr: 0x3F74, symSize: 0x24 }
+  - { offsetInCU: 0x37, offset: 0x15F, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x3F98, symBinAddr: 0x3F74, symSize: 0x24 }
+...
Index: llvm/test/tools/dsymutil/basic-linking.test
===================================================================
--- llvm/test/tools/dsymutil/basic-linking.test
+++ llvm/test/tools/dsymutil/basic-linking.test
@@ -2,6 +2,9 @@
 RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic-lto.macho.x86_64 | FileCheck %s --check-prefix=CHECK-LTO
 RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic-archive.macho.x86_64 | FileCheck %s --check-prefix=CHECK-ARCHIVE
 RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic.macho.x86_64 %p/Inputs/basic-lto.macho.x86_64 %p/Inputs/basic-archive.macho.x86_64 | FileCheck %s --check-prefixes=CHECK,CHECK-LTO,CHECK-ARCHIVE
+RUN: dsymutil -no-output -verbose -oso-prepend-path=%p -D %p/Inputs %p/Inputs/basic-relink.macho.arm64.dylib | FileCheck %s --check-prefix=CHECK-RELINK
+RUN: dsymutil -no-output -verbose -oso-prepend-path=%p -D %p/Inputs %p/Inputs/two-level-relink.macho.arm64.dylib | FileCheck %s --check-prefix=CHECK-RELINK-TWO
+RUN: dsymutil -no-output -verbose -oso-prepend-path=%p -build-variant-suffix=_debug -D WrongPath -D %p/Inputs %p/Inputs/variant-relink.macho.arm64.dylib | FileCheck %s --check-prefix=CHECK-RELINK-VARIANT
 
 This test check the basic Dwarf linking process through the debug dumps.
 
@@ -175,3 +178,116 @@
 CHECK-ARCHIVE-NEXT: Keeping subprogram DIE:
 CHECK-ARCHIVE-NEXT: DW_TAG_subprogram
 CHECK-ARCHIVE-NEXT:   DW_AT_name {{.*}}"inc")
+
+
+================================= Simple relink ================================
+CHECK-RELINK: DEBUG MAP OBJECT: {{.*}}basic-relink.macho.arm64.o
+CHECK-RELINK: Input compilation unit:
+CHECK-RELINK-NEXT: TAG_compile_unit
+CHECK-RELINK-NOT: TAG
+CHECK-RELINK: AT_name {{.*}}basic-relink.macho.arm64.c
+
+CHECK-RELINK: DEBUG MAP OBJECT: {{.*}}foo-relink.dylib
+CHECK-RELINK: Input compilation unit:
+CHECK-RELINK-NEXT: TAG_compile_unit
+CHECK-RELINK-NOT: TAG
+CHECK-RELINK: AT_name {{.*}}foo-relink.c
+
+CHECK-RELINK: DEBUG MAP OBJECT: {{.*}}bar-relink.dylib
+CHECK-RELINK: Input compilation unit:
+CHECK-RELINK-NEXT: TAG_compile_unit
+CHECK-RELINK-NOT: TAG
+CHECK-RELINK: AT_name {{.*}}bar-relink.c
+
+CHECK-RELINK-NOT: Found valid debug map entry
+CHECK-RELINK: Found valid debug map entry: _display	0x0000000000000000 => 0x0000000000003f20
+CHECK-RELINK-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-NEXT: DW_TAG_subprogram
+CHECK-RELINK:   DW_AT_name{{.*}}"display"
+
+CHECK-RELINK: Found valid debug map entry: _foo	0x0000000000003f60 => 0x0000000000003f3c
+CHECK-RELINK-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-NEXT: DW_TAG_subprogram
+CHECK-RELINK:   DW_AT_name {{.*}}"foo"
+
+CHECK-RELINK-NOT: Found valid debug map entry
+CHECK-RELINK: Found valid debug map entry: _foo_unused	0x0000000000003f80 => 0x0000000000003f5c
+CHECK-RELINK-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-NEXT: DW_TAG_subprogram
+CHECK-RELINK:   DW_AT_name {{.*}}"foo_unused"
+
+CHECK-RELINK-NOT: Found valid debug map entry
+CHECK-RELINK: Found valid debug map entry: _altfoo	0x0000000000003f88 => 0x0000000000003f64
+CHECK-RELINK-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-NEXT: DW_TAG_subprogram
+CHECK-RELINK:   DW_AT_name {{.*}}"altfoo"
+
+CHECK-RELINK-NOT: Found valid debug map entry
+CHECK-RELINK: Found valid debug map entry: _baz	0x0000000000004000 => 0x0000000000008000
+CHECK-RELINK-NEXT: Keeping variable DIE:
+CHECK-RELINK-NEXT: DW_TAG_variable
+CHECK-RELINK-NEXT:   DW_AT_name {{.*}}"baz"
+
+CHECK-RELINK-NOT: Found valid debug map entry
+CHECK-RELINK: Found valid debug map entry: _bar	0x0000000000003fb4 => 0x0000000000003f88
+CHECK-RELINK-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-NEXT: DW_TAG_subprogram
+CHECK-RELINK:   DW_AT_name {{.*}}"bar"
+
+================================= Two level relink ================================
+CHECK-RELINK-TWO: DEBUG MAP OBJECT: {{.*}}proxy-relink.dylib
+CHECK-RELINK-TWO: Input compilation unit:
+CHECK-RELINK-TWO-NEXT: TAG_compile_unit
+CHECK-RELINK-TWO-NOT: TAG
+CHECK-RELINK-TWO: AT_name {{.*}}two-level-relink.macho.arm64.c
+
+CHECK-RELINK-TWO: Input compilation unit:
+CHECK-RELINK-TWO-NEXT: TAG_compile_unit
+CHECK-RELINK-TWO-NOT: TAG
+CHECK-RELINK-TWO: AT_name {{.*}}bar-relink.c
+CHECK-RELINK-TWO: DW_AT_APPLE_origin {{.*}}/path/to/bar-relink.dylib
+
+CHECK-RELINK-TWO: Input compilation unit:
+CHECK-RELINK-TWO-NEXT: TAG_compile_unit
+CHECK-RELINK-TWO-NOT: TAG
+CHECK-RELINK-TWO: AT_name {{.*}}foo-relink.c
+CHECK-RELINK-TWO: DW_AT_APPLE_origin {{.*}}/path/to/foo-relink.dylib
+
+CHECK-RELINK-TWO: Input compilation unit:
+CHECK-RELINK-TWO-NEXT: TAG_compile_unit
+CHECK-RELINK-TWO-NOT: TAG
+CHECK-RELINK-TWO: AT_name {{.*}}altfoo-relink.c
+
+CHECK-RELINK-TWO-NOT: Found valid debug map entry
+CHECK-RELINK-TWO: Found valid debug map entry: _display	0x0000000000003f2c => 0x0000000000003f2c
+CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram
+CHECK-RELINK-TWO:   DW_AT_name{{.*}}"display"
+
+CHECK-RELINK-TWO-NOT: Found valid debug map entry
+CHECK-RELINK-TWO: Found valid debug map entry: _baz	0x0000000000008000 => 0x0000000000008000
+CHECK-RELINK-TWO-NEXT: Keeping variable DIE:
+CHECK-RELINK-TWO-NEXT: DW_TAG_variable
+CHECK-RELINK-TWO-NEXT:   DW_AT_name {{.*}}"baz"
+
+CHECK-RELINK-TWO-NOT: Found valid debug map entry
+CHECK-RELINK-TWO: Found valid debug map entry: _bar	0x0000000000003f48 => 0x0000000000003f48
+CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram
+CHECK-RELINK-TWO:   DW_AT_name {{.*}}"bar"
+
+CHECK-RELINK-TWO: Found valid debug map entry: _foo	0x0000000000003f50 => 0x0000000000003f50
+CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram
+CHECK-RELINK-TWO:   DW_AT_name {{.*}}"foo"
+
+CHECK-RELINK-TWO-NOT: Found valid debug map entry
+CHECK-RELINK-TWO: Found valid debug map entry: _altfoo	0x0000000000003f74 => 0x0000000000003f74
+CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE:
+CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram
+CHECK-RELINK-TWO:   DW_AT_name {{.*}}"altfoo"
+
+================================= Build variants relink ================================
+CHECK-RELINK-VARIANT: DEBUG MAP OBJECT: {{.*}}basic-relink.macho.arm64.o
+CHECK-RELINK-VARIANT: DEBUG MAP OBJECT: {{.*}}foo-relink-variant_debug.dylib
+CHECK-RELINK-VARIANT: DEBUG MAP OBJECT: {{.*}}bar-relink-variant.dylib
Index: llvm/tools/dsymutil/CMakeLists.txt
===================================================================
--- llvm/tools/dsymutil/CMakeLists.txt
+++ llvm/tools/dsymutil/CMakeLists.txt
@@ -30,6 +30,7 @@
   MachODebugMapParser.cpp
   MachOUtils.cpp
   Reproducer.cpp
+  RelocationMap.cpp
   SymbolMap.cpp
 
   DEPENDS
Index: llvm/tools/dsymutil/DebugMap.h
===================================================================
--- llvm/tools/dsymutil/DebugMap.h
+++ llvm/tools/dsymutil/DebugMap.h
@@ -21,6 +21,7 @@
 #ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
 #define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
 
+#include "RelocationMap.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
@@ -134,22 +135,6 @@
 /// linked binary for all the linked atoms in this object file.
 class DebugMapObject {
 public:
-  struct SymbolMapping {
-    std::optional<yaml::Hex64> ObjectAddress;
-    yaml::Hex64 BinaryAddress;
-    yaml::Hex32 Size;
-
-    SymbolMapping(std::optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
-                  uint32_t Size)
-        : BinaryAddress(BinaryAddress), Size(Size) {
-      if (ObjectAddr)
-        ObjectAddress = *ObjectAddr;
-    }
-
-    /// For YAML IO support
-    SymbolMapping() = default;
-  };
-
   using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>;
   using DebugMapEntry = StringMapEntry<SymbolMapping>;
 
@@ -182,6 +167,16 @@
   }
   const std::vector<std::string> &getWarnings() const { return Warnings; }
 
+  const std::optional<RelocationMap> &getRelocationMap() const {
+    return RelocationMap;
+  }
+  void setRelocationMap(dsymutil::RelocationMap &RM);
+
+  const std::optional<std::string> &getInstallName() const {
+    return InstallName;
+  }
+  void setInstallName(StringRef IN);
+
   void print(raw_ostream &OS) const;
 #ifndef NDEBUG
   void dump() const;
@@ -200,6 +195,9 @@
   DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
   uint8_t Type;
 
+  std::optional<RelocationMap> RelocationMap;
+  std::optional<std::string> InstallName;
+
   std::vector<std::string> Warnings;
 
   /// For YAMLIO support.
@@ -225,10 +223,8 @@
 
 using namespace llvm::dsymutil;
 
-template <>
-struct MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>> {
-  static void mapping(IO &io,
-                      std::pair<std::string, DebugMapObject::SymbolMapping> &s);
+template <> struct MappingTraits<std::pair<std::string, SymbolMapping>> {
+  static void mapping(IO &io, std::pair<std::string, SymbolMapping> &s);
   static const bool flow = true;
 };
 
@@ -237,12 +233,6 @@
   static void mapping(IO &io, dsymutil::DebugMapObject &DMO);
 };
 
-template <> struct ScalarTraits<Triple> {
-  static void output(const Triple &val, void *, raw_ostream &out);
-  static StringRef input(StringRef scalar, void *, Triple &value);
-  static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
-};
-
 template <>
 struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> {
   static size_t
Index: llvm/tools/dsymutil/DebugMap.cpp
===================================================================
--- llvm/tools/dsymutil/DebugMap.cpp
+++ llvm/tools/dsymutil/DebugMap.cpp
@@ -46,6 +46,11 @@
 bool DebugMapObject::addSymbol(StringRef Name,
                                std::optional<uint64_t> ObjectAddress,
                                uint64_t LinkedAddress, uint32_t Size) {
+  if (Symbols.count(Name)) {
+    // Symbol was previously added.
+    return true;
+  }
+
   auto InsertResult = Symbols.insert(
       std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
 
@@ -54,6 +59,12 @@
   return InsertResult.second;
 }
 
+void DebugMapObject::setRelocationMap(dsymutil::RelocationMap &RM) {
+  RelocationMap.emplace(RM);
+}
+
+void DebugMapObject::setInstallName(StringRef IN) { InstallName.emplace(IN); }
+
 void DebugMapObject::print(raw_ostream &OS) const {
   OS << getObjectFilename() << ":\n";
   // Sort the symbols in alphabetical order, like llvm-nm (and to get
@@ -159,8 +170,8 @@
   std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
 };
 
-void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
-    mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
+void MappingTraits<std::pair<std::string, SymbolMapping>>::mapping(
+    IO &io, std::pair<std::string, SymbolMapping> &s) {
   io.mapRequired("sym", s.first);
   io.mapOptional("objAddr", s.second.ObjectAddress);
   io.mapRequired("binAddr", s.second.BinaryAddress);
@@ -276,7 +287,13 @@
     }
   }
 
-  dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
+  uint8_t Type = MachO::N_OSO;
+  if (Path.endswith(".dylib")) {
+    // FIXME: find a more resilient way
+    Type = MachO::N_LIB;
+  }
+  dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), Type);
+
   for (auto &Entry : Entries) {
     auto &Mapping = Entry.second;
     std::optional<uint64_t> ObjAddress;
Index: llvm/tools/dsymutil/DwarfLinkerForBinary.h
===================================================================
--- llvm/tools/dsymutil/DwarfLinkerForBinary.h
+++ llvm/tools/dsymutil/DwarfLinkerForBinary.h
@@ -13,6 +13,7 @@
 #include "DebugMap.h"
 #include "LinkUtils.h"
 #include "MachOUtils.h"
+#include "RelocationMap.h"
 #include "llvm/DWARFLinker/DWARFLinker.h"
 #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
@@ -21,6 +22,7 @@
 #include "llvm/Remarks/RemarkFormat.h"
 #include "llvm/Remarks/RemarkLinker.h"
 #include <mutex>
+#include <optional>
 
 namespace llvm {
 namespace dsymutil {
@@ -67,33 +69,29 @@
   /// Keeps track of relocations.
   template <typename AddressesMapBase>
   class AddressManager : public AddressesMapBase {
-    struct ValidReloc {
-      uint64_t Offset;
-      uint32_t Size;
-      uint64_t Addend;
-      const DebugMapObject::DebugMapEntry *Mapping;
-
-      ValidReloc(uint64_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;
-      }
-      bool operator<(uint64_t RHS) const { return Offset < RHS; }
-    };
 
     const DwarfLinkerForBinary &Linker;
 
     /// The valid relocations for the current DebugMapObject.
-    /// This vector is sorted by relocation offset.
+    /// These vectors are sorted by relocation offset.
+    /// When auxiliary data is cleaned up in order to work on the next
+    /// objects, their content is stored in different permanent vectors.
+    /// Those additional vectors contain the relocations for
+    /// all the objects, and will be serialied into the RelocationMap.
     /// {
     std::vector<ValidReloc> ValidDebugInfoRelocs;
     std::vector<ValidReloc> ValidDebugAddrRelocs;
+
+    std::vector<ValidReloc> StoredValidDebugInfoRelocs;
+    std::vector<ValidReloc> StoredValidDebugAddrRelocs;
     /// }
 
     StringRef SrcFileName;
 
+    uint8_t DebugMapObjectType;
+
+    std::optional<std::string> LibInstallName;
+
     /// Returns list of valid relocations from \p Relocs,
     /// between \p StartOffset and \p NextOffset.
     ///
@@ -116,8 +114,29 @@
   public:
     AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
                    const DebugMapObject &DMO)
-        : Linker(Linker), SrcFileName(DMO.getObjectFilename()) {
-      findValidRelocsInDebugSections(Obj, DMO);
+        : Linker(Linker), SrcFileName(DMO.getObjectFilename()),
+          DebugMapObjectType(MachO::N_OSO) {
+      if (DMO.getRelocationMap().has_value()) {
+        DebugMapObjectType = MachO::N_LIB;
+        LibInstallName.emplace(DMO.getInstallName().value());
+        const RelocationMap &RM = DMO.getRelocationMap().value();
+        for (const auto &Reloc : RM.relocations()) {
+          const auto *DebugMapEntry = DMO.lookupSymbol(Reloc.SymbolName);
+          if (!DebugMapEntry)
+            continue;
+          std::optional<uint64_t> ObjAddress;
+          ObjAddress.emplace(
+              (uint64_t)DebugMapEntry->getValue().ObjectAddress.value());
+          ValidDebugInfoRelocs.emplace_back(
+              Reloc.OffsetInCU, Reloc.Offset, Reloc.Size, Reloc.Addend,
+              Reloc.SymbolName,
+              SymbolMapping(ObjAddress, DebugMapEntry->getValue().BinaryAddress,
+                            DebugMapEntry->getValue().Size));
+          // FIXME: Support relocations debug_addr.
+        }
+      } else {
+        findValidRelocsInDebugSections(Obj, DMO);
+      }
     }
     ~AddressManager() override { clear(); }
 
@@ -158,8 +177,13 @@
     std::optional<int64_t>
     getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
 
+    std::optional<StringRef> getFileName() override;
+
     bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
-                          bool IsLittleEndian) override;
+                          bool IsLittleEndian, uint64_t CUOffset,
+                          int64_t RelocSlide) override;
+
+    void addValidRelocs(RelocMap *RM) override;
 
     void clear() override {
       ValidDebugInfoRelocs.clear();
@@ -180,7 +204,6 @@
   /// Attempt to load a debug object from disk.
   ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
                                                  const Triple &triple);
-
   template <typename OutDWARFFile, typename AddressesMap>
   ErrorOr<std::unique_ptr<OutDWARFFile>> loadObject(const DebugMapObject &Obj,
                                                     const DebugMap &DebugMap,
@@ -207,6 +230,11 @@
   bool linkImpl(const DebugMap &Map,
                 typename Linker::OutputFileType ObjectType);
 
+  template <typename OutDwarfFile, typename AddressMap>
+  Error emitRelocations(
+      const DebugMap &DM,
+      std::vector<std::unique_ptr<OutDwarfFile>> &ObjectsForLinking);
+
   raw_fd_ostream &OutFile;
   BinaryHolder &BinHolder;
   LinkOptions Options;
Index: llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
===================================================================
--- llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -184,6 +184,44 @@
 
   return createFileError(FE->getFileName(), std::move(NewE));
 }
+template <typename OutDwarfFile, typename AddressMap>
+Error DwarfLinkerForBinary::emitRelocations(
+    const DebugMap &DM,
+    std::vector<std::unique_ptr<OutDwarfFile>> &ObjectsForLinking) {
+  // Return early if the "Resources" directory is not being written to.
+  if (!Options.ResourceDir)
+    return Error::success();
+
+  RelocationMap RM(DM.getTriple(), DM.getBinaryPath());
+  for (const auto &Obj : ObjectsForLinking) {
+    if (!Obj->Addresses)
+      continue;
+    Obj->Addresses->addValidRelocs(static_cast<RelocMap *>(&RM));
+  }
+
+  SmallString<128> InputPath;
+  SmallString<128> Path;
+  // Create the "Relocations" directory in the "Resources" directory, and
+  // create an architecture-specific directory in the "Relocations" directory.
+  StringRef ArchName = Triple::getArchName(RM.getTriple().getArch(),
+                                           RM.getTriple().getSubArch());
+  sys::path::append(Path, *Options.ResourceDir, "Relocations", ArchName);
+  if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
+                                                       sys::fs::perms::all_all))
+    return errorCodeToError(EC);
+
+  // Append the file name.
+  sys::path::append(Path, sys::path::filename(DM.getBinaryPath()));
+  Path.append(".yml");
+
+  std::error_code EC;
+  raw_fd_ostream OS(Path.str(), EC, sys::fs::OF_Text);
+  if (EC)
+    return errorCodeToError(EC);
+
+  RM.print(OS);
+  return Error::success();
+}
 
 static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
                          StringRef ArchName, const remarks::RemarkLinker &RL) {
@@ -795,6 +833,10 @@
   if (Options.NoOutput)
     return true;
 
+  if (Error E =
+          emitRelocations<OutDwarfFile, AddressMap>(Map, ObjectsForLinking))
+    return error(toString(std::move(E)));
+
   if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
     StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
     if (auto E = copySwiftInterfaces(ArchName))
@@ -883,12 +925,14 @@
         continue;
       }
       if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
-        ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
+        ValidRelocs.emplace_back(Offset64, Offset64, RelocSize, Addend,
+                                 Mapping->getKey(), Mapping->getValue());
     } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
       // Do not store the addend. The addend was the address of the symbol in
       // the object file, the address in the binary that is stored in the debug
       // map doesn't need to be offset.
-      ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
+      ValidRelocs.emplace_back(Offset64, Offset64, RelocSize, SymOffset,
+                               Mapping->getKey(), Mapping->getValue());
     }
   }
 }
@@ -946,20 +990,17 @@
 }
 
 template <typename AddressesMapBase>
-std::vector<
-    typename DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
+std::vector<ValidReloc>
 DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocations(
     const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
-  std::vector<
-      DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
-      Res;
+  std::vector<ValidReloc> Res;
 
   auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
-    return Reloc.Offset < StartPos;
+    return (uint64_t)Reloc.Offset < StartPos;
   });
 
   while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos &&
-         CurReloc->Offset < EndPos) {
+         (uint64_t)CurReloc->Offset < EndPos) {
     Res.push_back(*CurReloc);
     CurReloc++;
   }
@@ -970,12 +1011,12 @@
 template <typename AddressesMapBase>
 void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::printReloc(
     const ValidReloc &Reloc) {
-  const auto &Mapping = Reloc.Mapping->getValue();
+  const auto &Mapping = Reloc.SymbolMapping;
   const uint64_t ObjectAddress = Mapping.ObjectAddress
                                      ? uint64_t(*Mapping.ObjectAddress)
                                      : std::numeric_limits<uint64_t>::max();
 
-  outs() << "Found valid debug map entry: " << Reloc.Mapping->getKey() << "\t"
+  outs() << "Found valid debug map entry: " << Reloc.SymbolName << "\t"
          << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,
                    uint64_t(Mapping.BinaryAddress));
 }
@@ -984,8 +1025,8 @@
 int64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocValue(
     const ValidReloc &Reloc) {
   int64_t AddrAdjust = relocate(Reloc);
-  if (Reloc.Mapping->getValue().ObjectAddress)
-    AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
+  if (Reloc.SymbolMapping.ObjectAddress)
+    AddrAdjust -= uint64_t(*Reloc.SymbolMapping.ObjectAddress);
   return AddrAdjust;
 }
 
@@ -1094,10 +1135,24 @@
   }
 }
 
+template <typename AddressesMapBase>
+std::optional<StringRef>
+DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getFileName() {
+  return LibInstallName;
+}
+
 template <typename AddressesMapBase>
 uint64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::relocate(
     const ValidReloc &Reloc) const {
-  return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
+  return Reloc.SymbolMapping.BinaryAddress + Reloc.Addend;
+}
+template <typename AddressesMapBase>
+void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::addValidRelocs(
+    RelocMap *RM) {
+  for (const auto &InfoReloc : StoredValidDebugInfoRelocs) {
+    RM->addRelocationMapEntry(dyn_cast<const ValidRelocation>(&InfoReloc));
+  }
+  // FIXME: Support relocations debug_addr (DWARF5).
 }
 
 /// Apply the valid relocations found by findValidRelocs() to
@@ -1110,7 +1165,8 @@
 /// \returns whether any reloc has been applied.
 template <typename AddressesMapBase>
 bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::applyValidRelocs(
-    MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
+    MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian,
+    uint64_t CUOffset, int64_t RelocSlide) {
   std::vector<ValidReloc> Relocs = getRelocations(
       ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
 
@@ -1125,8 +1181,13 @@
     }
     assert(CurReloc.Size <= sizeof(Buf));
     memcpy(&Data[CurReloc.Offset - BaseOffset], Buf, CurReloc.Size);
-  }
 
+    // store relocation values to be serialized
+    uint64_t SlidOffset = (int64_t)CurReloc.OffsetInCU + RelocSlide;
+    StoredValidDebugInfoRelocs.emplace_back(
+        SlidOffset, CUOffset + SlidOffset, CurReloc.Size, CurReloc.Addend,
+        CurReloc.SymbolName, CurReloc.SymbolMapping);
+  }
   return Relocs.size() > 0;
 }
 
Index: llvm/tools/dsymutil/LinkUtils.h
===================================================================
--- llvm/tools/dsymutil/LinkUtils.h
+++ llvm/tools/dsymutil/LinkUtils.h
@@ -93,6 +93,12 @@
   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       vfs::getRealFileSystem();
 
+  /// -build-variant-suffix.
+  std::string BuildVariantSuffix;
+
+  /// Paths where to search for the .dSYM files of merged libraries.
+  std::vector<std::string> DSYMSearchPaths;
+
   /// Fields used for linking and placing remarks into the .dSYM bundle.
   /// @{
 
Index: llvm/tools/dsymutil/MachODebugMapParser.cpp
===================================================================
--- llvm/tools/dsymutil/MachODebugMapParser.cpp
+++ llvm/tools/dsymutil/MachODebugMapParser.cpp
@@ -9,6 +9,7 @@
 #include "BinaryHolder.h"
 #include "DebugMap.h"
 #include "MachOUtils.h"
+#include "RelocationMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/Object/MachO.h"
@@ -28,10 +29,13 @@
 public:
   MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
                       StringRef BinaryPath, ArrayRef<std::string> Archs,
-                      StringRef PathPrefix = "",
+                      ArrayRef<std::string> DSYMSearchPaths,
+                      StringRef PathPrefix = "", StringRef VariantSuffix = "",
                       bool PaperTrailWarnings = false, bool Verbose = false)
       : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()),
+        DSYMSearchPaths(DSYMSearchPaths.begin(), DSYMSearchPaths.end()),
         PathPrefix(std::string(PathPrefix)),
+        VariantSuffix(std::string(VariantSuffix)),
         PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose),
         CurrentDebugMapObject(nullptr), SkipDebugMapObject(false) {}
 
@@ -49,7 +53,9 @@
 private:
   std::string BinaryPath;
   SmallVector<StringRef, 1> Archs;
+  SmallVector<StringRef, 1> DSYMSearchPaths;
   std::string PathPrefix;
+  std::string VariantSuffix;
   bool PaperTrailWarnings;
 
   /// Owns the MemoryBuffer for the main binary.
@@ -90,6 +96,9 @@
   void
   switchToNewDebugMapObject(StringRef Filename,
                             sys::TimePoint<std::chrono::seconds> Timestamp);
+  void
+  switchToNewLibDebugMapObject(StringRef Filename,
+                               sys::TimePoint<std::chrono::seconds> Timestamp);
   void resetParserState();
   uint64_t getMainBinarySymbolAddress(StringRef Name);
   std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value);
@@ -186,8 +195,6 @@
 /// everything up to add symbols to the new one.
 void MachODebugMapParser::switchToNewDebugMapObject(
     StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
-  addCommonSymbols();
-  resetParserState();
 
   SmallString<80> Path(PathPrefix);
   sys::path::append(Path, Filename);
@@ -208,11 +215,138 @@
     return;
   }
 
+  addCommonSymbols();
+  resetParserState();
+
   CurrentDebugMapObject =
       &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO);
+
   loadCurrentObjectFileSymbols(*Object);
 }
 
+/// Create a new DebugMapObject of type MachO::N_LIB.
+/// This function resets the state of the
+/// parser that was referring to the last object file and sets
+/// everything up to add symbols to the new one.
+void MachODebugMapParser::switchToNewLibDebugMapObject(
+    StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
+
+  if (DSYMSearchPaths.empty()) {
+    Warning("no dSYM search path was specified");
+    return;
+  }
+
+  StringRef LeafName = sys::path::filename(Filename);
+  SmallString<128> VariantLeafName;
+  SmallString<128> ProductName(LeafName);
+
+  // For Framework.framework/Framework and -build-variant-suffix=_debug,
+  // look in the following order:
+  // 1) Framework.framework.dSYM/Contents/Resources/DWARF/Framework_debug
+  // 2) Framework.framework.dSYM/Contents/Resources/DWARF/Framework
+  //
+  // For libName.dylib and -build-variant-suffix=_debug,
+  // look in the following order:
+  // 1) libName.dylib.dSYM/Contents/Resources/DWARF/libName_debug.dylib
+  // 2) libName.dylib.dSYM/Contents/Resources/DWARF/libName.dylib
+
+  size_t libExt = LeafName.rfind(".dylib");
+  if (libExt != StringRef::npos) {
+    if (!VariantSuffix.empty()) {
+      VariantLeafName.append(LeafName.substr(0, libExt));
+      VariantLeafName.append(VariantSuffix);
+      VariantLeafName.append(".dylib");
+    }
+  } else {
+    // Expected to be a framework
+    ProductName.append(".framework");
+    if (!VariantSuffix.empty()) {
+      VariantLeafName.append(LeafName);
+      VariantLeafName.append(VariantSuffix);
+    }
+  }
+
+  for (auto DSYMSearchPath : DSYMSearchPaths) {
+    SmallString<256> Path(DSYMSearchPath);
+    SmallString<256> FallbackPath(Path);
+
+    SmallString<256> DSYMPath(ProductName);
+    DSYMPath.append(".dSYM");
+    sys::path::append(DSYMPath, "Contents", "Resources", "DWARF");
+
+    if (!VariantSuffix.empty()) {
+      sys::path::append(Path, DSYMPath, VariantLeafName);
+      sys::path::append(FallbackPath, DSYMPath, LeafName);
+    } else {
+      sys::path::append(Path, DSYMPath, LeafName);
+    }
+
+    auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp);
+    if (!ObjectEntry) {
+      auto Err = ObjectEntry.takeError();
+      Warning("unable to open object file: " + toString(std::move(Err)),
+              Path.str());
+      if (!VariantSuffix.empty()) {
+        ObjectEntry = BinHolder.getObjectEntry(FallbackPath, Timestamp);
+        if (!ObjectEntry) {
+          auto Err = ObjectEntry.takeError();
+          Warning("unable to open object file: " + toString(std::move(Err)),
+                  FallbackPath.str());
+          continue;
+        }
+        Path.assign(FallbackPath);
+      } else {
+        continue;
+      }
+    }
+
+    auto Object =
+        ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple());
+    if (!Object) {
+      auto Err = Object.takeError();
+      Warning("unable to open object file: " + toString(std::move(Err)),
+              Path.str());
+      continue;
+    }
+
+    if (CurrentDebugMapObject &&
+        CurrentDebugMapObject->getType() == MachO::N_LIB &&
+        CurrentDebugMapObject->getObjectFilename().compare(Path.str()) == 0) {
+      return;
+    }
+
+    addCommonSymbols();
+    resetParserState();
+
+    CurrentDebugMapObject =
+        &Result->addDebugMapObject(Path, Timestamp, MachO::N_LIB);
+
+    CurrentDebugMapObject->setInstallName(Filename);
+
+    SmallString<256> RMPath(DSYMSearchPath);
+    sys::path::append(RMPath, ProductName);
+    RMPath.append(".dSYM");
+    StringRef ArchName = Triple::getArchName(Result->getTriple().getArch(),
+                                             Result->getTriple().getSubArch());
+    sys::path::append(RMPath, "Contents", "Resources", "Relocations", ArchName);
+    sys::path::append(RMPath, LeafName);
+    RMPath.append(".yml");
+    const auto &RelocMapPtrOrErr =
+        RelocationMap::parseYAMLRelocationMap(RMPath, PathPrefix);
+    if (auto EC = RelocMapPtrOrErr.getError()) {
+      Warning("cannot parse relocation map file: " + EC.message(),
+              RMPath.str());
+      return;
+    }
+    CurrentDebugMapObject->setRelocationMap(*RelocMapPtrOrErr->get());
+
+    loadCurrentObjectFileSymbols(*Object);
+
+    // Found and loaded new dSYM file
+    return;
+  }
+}
+
 static std::string getArchName(const object::MachOObjectFile &Obj) {
   Triple T = Obj.getArchTriple();
   return std::string(T.getArchName());
@@ -285,23 +419,39 @@
   const char *Name;
 };
 
-const struct DarwinStabName DarwinStabNames[] = {
-    {MachO::N_GSYM, "N_GSYM"},    {MachO::N_FNAME, "N_FNAME"},
-    {MachO::N_FUN, "N_FUN"},      {MachO::N_STSYM, "N_STSYM"},
-    {MachO::N_LCSYM, "N_LCSYM"},  {MachO::N_BNSYM, "N_BNSYM"},
-    {MachO::N_PC, "N_PC"},        {MachO::N_AST, "N_AST"},
-    {MachO::N_OPT, "N_OPT"},      {MachO::N_RSYM, "N_RSYM"},
-    {MachO::N_SLINE, "N_SLINE"},  {MachO::N_ENSYM, "N_ENSYM"},
-    {MachO::N_SSYM, "N_SSYM"},    {MachO::N_SO, "N_SO"},
-    {MachO::N_OSO, "N_OSO"},      {MachO::N_LSYM, "N_LSYM"},
-    {MachO::N_BINCL, "N_BINCL"},  {MachO::N_SOL, "N_SOL"},
-    {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"},
-    {MachO::N_OLEVEL, "N_OLEV"},  {MachO::N_PSYM, "N_PSYM"},
-    {MachO::N_EINCL, "N_EINCL"},  {MachO::N_ENTRY, "N_ENTRY"},
-    {MachO::N_LBRAC, "N_LBRAC"},  {MachO::N_EXCL, "N_EXCL"},
-    {MachO::N_RBRAC, "N_RBRAC"},  {MachO::N_BCOMM, "N_BCOMM"},
-    {MachO::N_ECOMM, "N_ECOMM"},  {MachO::N_ECOML, "N_ECOML"},
-    {MachO::N_LENG, "N_LENG"},    {0, nullptr}};
+const struct DarwinStabName DarwinStabNames[] = {{MachO::N_GSYM, "N_GSYM"},
+                                                 {MachO::N_FNAME, "N_FNAME"},
+                                                 {MachO::N_FUN, "N_FUN"},
+                                                 {MachO::N_STSYM, "N_STSYM"},
+                                                 {MachO::N_LCSYM, "N_LCSYM"},
+                                                 {MachO::N_BNSYM, "N_BNSYM"},
+                                                 {MachO::N_PC, "N_PC"},
+                                                 {MachO::N_AST, "N_AST"},
+                                                 {MachO::N_OPT, "N_OPT"},
+                                                 {MachO::N_RSYM, "N_RSYM"},
+                                                 {MachO::N_SLINE, "N_SLINE"},
+                                                 {MachO::N_ENSYM, "N_ENSYM"},
+                                                 {MachO::N_SSYM, "N_SSYM"},
+                                                 {MachO::N_SO, "N_SO"},
+                                                 {MachO::N_OSO, "N_OSO"},
+                                                 {MachO::N_LIB, "N_LIB"},
+                                                 {MachO::N_LSYM, "N_LSYM"},
+                                                 {MachO::N_BINCL, "N_BINCL"},
+                                                 {MachO::N_SOL, "N_SOL"},
+                                                 {MachO::N_PARAMS, "N_PARAM"},
+                                                 {MachO::N_VERSION, "N_VERS"},
+                                                 {MachO::N_OLEVEL, "N_OLEV"},
+                                                 {MachO::N_PSYM, "N_PSYM"},
+                                                 {MachO::N_EINCL, "N_EINCL"},
+                                                 {MachO::N_ENTRY, "N_ENTRY"},
+                                                 {MachO::N_LBRAC, "N_LBRAC"},
+                                                 {MachO::N_EXCL, "N_EXCL"},
+                                                 {MachO::N_RBRAC, "N_RBRAC"},
+                                                 {MachO::N_BCOMM, "N_BCOMM"},
+                                                 {MachO::N_ECOMM, "N_ECOMM"},
+                                                 {MachO::N_ECOML, "N_ECOML"},
+                                                 {MachO::N_LENG, "N_LENG"},
+                                                 {0, nullptr}};
 
 static const char *getDarwinStabString(uint8_t NType) {
   for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
@@ -487,13 +637,25 @@
 
   const char *Name = &MainBinaryStrings.data()[StringIndex];
 
+  // An N_LIB entry represents the start of a new library file description.
+  if (Type == MachO::N_LIB) {
+    switchToNewLibDebugMapObject(Name, sys::toTimePoint(Value));
+    return;
+  }
+
   // An N_OSO entry represents the start of a new object file description.
+  // If an N_LIB entry was present, this is parsed only if the library
+  // dSYM file could not be found.
   if (Type == MachO::N_OSO) {
-    if (Duplicates.count(OSO(Name, Value))) {
-      SkipDebugMapObject = true;
-      return;
+    if (!CurrentDebugMapObject ||
+        CurrentDebugMapObject->getType() != MachO::N_LIB) {
+      if (Duplicates.count(OSO(Name, Value))) {
+        SkipDebugMapObject = true;
+        return;
+      }
+      switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
     }
-    return switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
+    return;
   }
 
   if (SkipDebugMapObject)
@@ -705,20 +867,24 @@
 llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
 parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
               StringRef InputFile, ArrayRef<std::string> Archs,
-              StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+              ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
+              StringRef VariantSuffix, bool PaperTrailWarnings, bool Verbose,
               bool InputIsYAML) {
   if (InputIsYAML)
     return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
 
-  MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath,
-                             PaperTrailWarnings, Verbose);
+  MachODebugMapParser Parser(VFS, InputFile, Archs, DSYMSearchPaths,
+                             PrependPath, VariantSuffix, PaperTrailWarnings,
+                             Verbose);
   return Parser.parse();
 }
 
 bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
               StringRef InputFile, ArrayRef<std::string> Archs,
-              StringRef PrependPath) {
-  MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false);
+              ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
+              StringRef VariantSuffix) {
+  MachODebugMapParser Parser(VFS, InputFile, Archs, DSYMSearchPaths,
+                             PrependPath, VariantSuffix, false);
   return Parser.dumpStab();
 }
 } // namespace dsymutil
Index: llvm/tools/dsymutil/Options.td
===================================================================
--- llvm/tools/dsymutil/Options.td
+++ llvm/tools/dsymutil/Options.td
@@ -205,3 +205,14 @@
   HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">,
   Group<grp_general>;
 def: Joined<["--", "-"], "linker=">, Alias<linker>;
+
+def build_variant_suffix: Separate<["--", "-"], "build-variant-suffix">,
+  MetaVarName<"<suffix=buildvariant>">,
+  HelpText<"Specify the build variant suffix used to build the executabe file.">,
+  Group<grp_general>;
+def: Joined<["--", "-"], "build-variant-suffix=">, Alias<build_variant_suffix>;
+
+def dsym_search_path: Separate<["-", "--"], "D">,
+  MetaVarName<"<path>">,
+  HelpText<"Specify a directory that contain dSYM files to search for.">,
+  Group<grp_general>;
Index: llvm/tools/dsymutil/RelocationMap.h
===================================================================
--- /dev/null
+++ llvm/tools/dsymutil/RelocationMap.h
@@ -0,0 +1,168 @@
+//===- tools/dsymutil/RelocationMap.h -------------------------- *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// This file contains the class declaration of the RelocationMap
+/// entity. RelocationMap lists all the relocations of all the
+/// atoms used in the object files linked together to
+/// produce an executable.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H
+#define LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DWARFLinker/DWARFLinkerRelocs.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace dsymutil {
+
+struct SymbolMapping {
+  std::optional<yaml::Hex64> ObjectAddress;
+  yaml::Hex64 BinaryAddress;
+  yaml::Hex32 Size;
+
+  SymbolMapping(std::optional<uint64_t> ObjectAddr, uint64_t BinaryAddress,
+                uint32_t Size)
+      : BinaryAddress(BinaryAddress), Size(Size) {
+    if (ObjectAddr)
+      ObjectAddress = *ObjectAddr;
+  }
+
+  /// For YAML IO support
+  SymbolMapping() = default;
+};
+
+/// ValidReloc represents one relocation entry described by the RelocationMap.
+/// It contains a list of DWARF relocations to apply to a linked binary.
+class ValidReloc : public ValidRelocation {
+public:
+  yaml::Hex64 OffsetInCU;
+  yaml::Hex64 Offset;
+  yaml::Hex32 Size;
+  yaml::Hex64 Addend;
+  std::string SymbolName;
+  SymbolMapping SymbolMapping;
+
+  struct SymbolMapping getSymbolMapping() const { return SymbolMapping; }
+
+  ValidReloc(uint64_t OffsetInCU, uint64_t Offset, uint32_t Size,
+             uint64_t Addend, StringRef SymbolName,
+             struct SymbolMapping SymbolMapping)
+      : ValidRelocation(VRK_ValidReloc), OffsetInCU(OffsetInCU), Offset(Offset),
+        Size(Size), Addend(Addend), SymbolName(SymbolName),
+        SymbolMapping(SymbolMapping) {}
+
+  bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
+
+  /// For YAMLIO support.
+  ValidReloc() : ValidRelocation(VRK_ValidReloc) {}
+
+  static bool classof(const ValidRelocation *VR) {
+    return VR->getKind() == VRK_ValidReloc;
+  }
+};
+
+/// The RelocationMap object stores the list of relocation entries for a binary
+class RelocationMap : public RelocMap {
+  Triple BinaryTriple;
+  std::string BinaryPath;
+  using RelocContainer = std::vector<ValidReloc>;
+
+  RelocContainer Relocations;
+
+  /// For YAML IO support.
+  ///@{
+  friend yaml::MappingTraits<std::unique_ptr<RelocationMap>>;
+  friend yaml::MappingTraits<RelocationMap>;
+
+  RelocationMap() = default;
+  ///@}
+
+public:
+  RelocationMap(const Triple &BinaryTriple, StringRef BinaryPath)
+      : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)) {}
+
+  using const_iterator = RelocContainer::const_iterator;
+
+  iterator_range<const_iterator> relocations() const {
+    return make_range(begin(), end());
+  }
+
+  const_iterator begin() const { return Relocations.begin(); }
+
+  const_iterator end() const { return Relocations.end(); }
+
+  size_t getNumberOfEntries() const { return Relocations.size(); }
+
+  /// This function adds a ValidReloc to the list owned by this
+  /// relocation map.
+  void addRelocationMapEntry(const ValidRelocation *Relocation) override;
+
+  const Triple &getTriple() const { return BinaryTriple; }
+
+  StringRef getBinaryPath() const { return BinaryPath; }
+
+  void print(raw_ostream &OS) const;
+
+#ifndef NDEBUG
+  void dump() const;
+#endif
+
+  /// Read a relocation map from \a InputFile.
+  static ErrorOr<std::unique_ptr<RelocationMap>>
+  parseYAMLRelocationMap(StringRef InputFile, StringRef PrependPath);
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(dsymutil::ValidReloc)
+
+namespace llvm {
+namespace yaml {
+
+using namespace llvm::dsymutil;
+
+template <> struct MappingTraits<dsymutil::ValidReloc> {
+  static void mapping(IO &io, dsymutil::ValidReloc &VR);
+  static const bool flow = true;
+};
+
+template <> struct MappingTraits<dsymutil::RelocationMap> {
+  struct YamlRM;
+  static void mapping(IO &io, dsymutil::RelocationMap &RM);
+};
+
+template <> struct MappingTraits<std::unique_ptr<dsymutil::RelocationMap>> {
+  struct YamlRM;
+  static void mapping(IO &io, std::unique_ptr<dsymutil::RelocationMap> &RM);
+};
+
+template <> struct ScalarTraits<Triple> {
+  static void output(const Triple &val, void *, raw_ostream &out);
+  static StringRef input(StringRef scalar, void *, Triple &value);
+  static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H
Index: llvm/tools/dsymutil/RelocationMap.cpp
===================================================================
--- /dev/null
+++ llvm/tools/dsymutil/RelocationMap.cpp
@@ -0,0 +1,93 @@
+//===- tools/dsymutil/RelocationMap.cpp - Relocation map representation---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RelocationMap.h"
+
+namespace llvm {
+
+namespace dsymutil {
+
+void RelocationMap::print(raw_ostream &OS) const {
+  yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
+  yout << const_cast<RelocationMap &>(*this);
+}
+
+#ifndef NDEBUG
+void RelocationMap::dump() const { print(errs()); }
+#endif
+
+void RelocationMap::addRelocationMapEntry(const ValidRelocation *Relocation) {
+  Relocations.push_back(*dyn_cast<ValidReloc>(Relocation));
+}
+
+namespace {
+
+struct YAMLContext {
+  StringRef PrependPath;
+  Triple BinaryTriple;
+};
+
+} // end anonymous namespace
+
+ErrorOr<std::unique_ptr<RelocationMap>>
+RelocationMap::parseYAMLRelocationMap(StringRef InputFile,
+                                      StringRef PrependPath) {
+  auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
+  if (auto Err = ErrOrFile.getError())
+    return Err;
+
+  YAMLContext Ctxt;
+
+  Ctxt.PrependPath = PrependPath;
+
+  std::unique_ptr<RelocationMap> Result;
+  yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
+  yin >> Result;
+
+  if (auto EC = yin.error())
+    return EC;
+  return std::move(Result);
+}
+
+} // end namespace dsymutil
+
+namespace yaml {
+
+void MappingTraits<dsymutil::ValidReloc>::mapping(IO &io,
+                                                  dsymutil::ValidReloc &VR) {
+  io.mapRequired("offsetInCU", VR.OffsetInCU);
+  io.mapRequired("offset", VR.Offset);
+  io.mapRequired("size", VR.Size);
+  io.mapRequired("addend", VR.Addend);
+  io.mapRequired("symName", VR.SymbolName);
+  io.mapOptional("symObjAddr", VR.SymbolMapping.ObjectAddress);
+  io.mapRequired("symBinAddr", VR.SymbolMapping.BinaryAddress);
+  io.mapRequired("symSize", VR.SymbolMapping.Size);
+}
+
+void MappingTraits<dsymutil::RelocationMap>::mapping(
+    IO &io, dsymutil::RelocationMap &RM) {
+  io.mapRequired("triple", RM.BinaryTriple);
+  io.mapRequired("binary-path", RM.BinaryPath);
+  if (void *Ctxt = io.getContext())
+    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = RM.BinaryTriple;
+  io.mapRequired("relocations", RM.Relocations);
+}
+
+void MappingTraits<std::unique_ptr<dsymutil::RelocationMap>>::mapping(
+    IO &io, std::unique_ptr<dsymutil::RelocationMap> &RM) {
+  if (!RM)
+    RM.reset(new RelocationMap());
+  io.mapRequired("triple", RM->BinaryTriple);
+  io.mapRequired("binary-path", RM->BinaryPath);
+  if (void *Ctxt = io.getContext())
+    reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = RM->BinaryTriple;
+  io.mapRequired("relocations", RM->Relocations);
+}
+} // end namespace yaml
+} // end namespace llvm
Index: llvm/tools/dsymutil/dsymutil.h
===================================================================
--- llvm/tools/dsymutil/dsymutil.h
+++ llvm/tools/dsymutil/dsymutil.h
@@ -36,13 +36,15 @@
 ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
 parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
               StringRef InputFile, ArrayRef<std::string> Archs,
-              StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+              ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
+              StringRef VariantSuffix, bool PaperTrailWarnings, bool Verbose,
               bool InputIsYAML);
 
 /// Dump the symbol table.
 bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
               StringRef InputFile, ArrayRef<std::string> Archs,
-              StringRef PrependPath = "");
+              ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath = "",
+              StringRef VariantSuffix = "");
 
 } // end namespace dsymutil
 } // end namespace llvm
Index: llvm/tools/dsymutil/dsymutil.cpp
===================================================================
--- llvm/tools/dsymutil/dsymutil.cpp
+++ llvm/tools/dsymutil/dsymutil.cpp
@@ -413,6 +413,12 @@
   Options.LinkOpts.RemarksKeepAll =
       !Args.hasArg(OPT_remarks_drop_without_debug);
 
+  if (opt::Arg *BuildVariantSuffix = Args.getLastArg(OPT_build_variant_suffix))
+    Options.LinkOpts.BuildVariantSuffix = BuildVariantSuffix->getValue();
+
+  for (auto *SearchPath : Args.filtered(OPT_dsym_search_path))
+    Options.LinkOpts.DSYMSearchPaths.push_back(SearchPath->getValue());
+
   if (Error E = verifyOptions(Options))
     return std::move(E);
   return Options;
@@ -670,15 +676,18 @@
     // Dump the symbol table for each input file and requested arch
     if (Options.DumpStab) {
       if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs,
-                    Options.LinkOpts.PrependPath))
+                    Options.LinkOpts.DSYMSearchPaths,
+                    Options.LinkOpts.PrependPath,
+                    Options.LinkOpts.BuildVariantSuffix))
         return EXIT_FAILURE;
       continue;
     }
 
-    auto DebugMapPtrsOrErr =
-        parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs,
-                      Options.LinkOpts.PrependPath, Options.PaperTrailWarnings,
-                      Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
+    auto DebugMapPtrsOrErr = parseDebugMap(
+        Options.LinkOpts.VFS, InputFile, Options.Archs,
+        Options.LinkOpts.DSYMSearchPaths, Options.LinkOpts.PrependPath,
+        Options.LinkOpts.BuildVariantSuffix, Options.PaperTrailWarnings,
+        Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
 
     if (auto EC = DebugMapPtrsOrErr.getError()) {
       WithColor::error() << "cannot parse the debug map for '" << InputFile
Index: llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
===================================================================
--- llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -130,11 +130,16 @@
     return std::nullopt;
   }
 
-  bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
+  std::optional<StringRef> getFileName() override { return std::nullopt; }
+
+  bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool, uint64_t,
+                        int64_t) override {
     // no need to apply relocations to the linked binary.
     return false;
   }
 
+  void addValidRelocs(RelocMap *RM) override {}
+
   void clear() override {}
 
 protected:
Index: llvm/tools/llvm-nm/llvm-nm.cpp
===================================================================
--- llvm/tools/llvm-nm/llvm-nm.cpp
+++ llvm/tools/llvm-nm/llvm-nm.cpp
@@ -561,37 +561,22 @@
   const char *Name;
 };
 const struct DarwinStabName DarwinStabNames[] = {
-    {MachO::N_GSYM, "GSYM"},
-    {MachO::N_FNAME, "FNAME"},
-    {MachO::N_FUN, "FUN"},
-    {MachO::N_STSYM, "STSYM"},
-    {MachO::N_LCSYM, "LCSYM"},
-    {MachO::N_BNSYM, "BNSYM"},
-    {MachO::N_PC, "PC"},
-    {MachO::N_AST, "AST"},
-    {MachO::N_OPT, "OPT"},
-    {MachO::N_RSYM, "RSYM"},
-    {MachO::N_SLINE, "SLINE"},
-    {MachO::N_ENSYM, "ENSYM"},
-    {MachO::N_SSYM, "SSYM"},
-    {MachO::N_SO, "SO"},
-    {MachO::N_OSO, "OSO"},
-    {MachO::N_LSYM, "LSYM"},
-    {MachO::N_BINCL, "BINCL"},
-    {MachO::N_SOL, "SOL"},
-    {MachO::N_PARAMS, "PARAM"},
-    {MachO::N_VERSION, "VERS"},
-    {MachO::N_OLEVEL, "OLEV"},
-    {MachO::N_PSYM, "PSYM"},
-    {MachO::N_EINCL, "EINCL"},
-    {MachO::N_ENTRY, "ENTRY"},
-    {MachO::N_LBRAC, "LBRAC"},
-    {MachO::N_EXCL, "EXCL"},
-    {MachO::N_RBRAC, "RBRAC"},
-    {MachO::N_BCOMM, "BCOMM"},
-    {MachO::N_ECOMM, "ECOMM"},
-    {MachO::N_ECOML, "ECOML"},
-    {MachO::N_LENG, "LENG"},
+    {MachO::N_GSYM, "GSYM"},    {MachO::N_FNAME, "FNAME"},
+    {MachO::N_FUN, "FUN"},      {MachO::N_STSYM, "STSYM"},
+    {MachO::N_LCSYM, "LCSYM"},  {MachO::N_BNSYM, "BNSYM"},
+    {MachO::N_PC, "PC"},        {MachO::N_AST, "AST"},
+    {MachO::N_OPT, "OPT"},      {MachO::N_RSYM, "RSYM"},
+    {MachO::N_SLINE, "SLINE"},  {MachO::N_ENSYM, "ENSYM"},
+    {MachO::N_SSYM, "SSYM"},    {MachO::N_SO, "SO"},
+    {MachO::N_OSO, "OSO"},      {MachO::N_LIB, "LIB"},
+    {MachO::N_LSYM, "LSYM"},    {MachO::N_BINCL, "BINCL"},
+    {MachO::N_SOL, "SOL"},      {MachO::N_PARAMS, "PARAM"},
+    {MachO::N_VERSION, "VERS"}, {MachO::N_OLEVEL, "OLEV"},
+    {MachO::N_PSYM, "PSYM"},    {MachO::N_EINCL, "EINCL"},
+    {MachO::N_ENTRY, "ENTRY"},  {MachO::N_LBRAC, "LBRAC"},
+    {MachO::N_EXCL, "EXCL"},    {MachO::N_RBRAC, "RBRAC"},
+    {MachO::N_BCOMM, "BCOMM"},  {MachO::N_ECOMM, "ECOMM"},
+    {MachO::N_ECOML, "ECOML"},  {MachO::N_LENG, "LENG"},
 };
 
 static const char *getDarwinStabString(uint8_t NType) {