Index: include/llvm/LTO/Config.h
===================================================================
--- include/llvm/LTO/Config.h
+++ include/llvm/LTO/Config.h
@@ -73,6 +73,12 @@
   /// Sample PGO profile path.
   std::string SampleProfile;
 
+  /// The directory to store .dwo files when using ThinLTO.
+  std::string DWO_Dir;
+
+  /// The objcopy binary used to extract dwo files.
+  std::string Objcopy;
+
   /// Optimization remarks file path.
   std::string RemarksFilename = "";
 
Index: include/llvm/LTO/LTO.h
===================================================================
--- include/llvm/LTO/LTO.h
+++ include/llvm/LTO/LTO.h
@@ -162,8 +162,11 @@
 /// destructor.
 class NativeObjectStream {
 public:
-  NativeObjectStream(std::unique_ptr<raw_pwrite_stream> OS) : OS(std::move(OS)) {}
+  NativeObjectStream(std::unique_ptr<raw_pwrite_stream> OS,
+                     std::string FileName=std::string())
+      : OS(std::move(OS)), FileName(FileName) {}
   std::unique_ptr<raw_pwrite_stream> OS;
+  std::string FileName;
   virtual ~NativeObjectStream() = default;
 };
 
Index: lib/LTO/LTOBackend.cpp
===================================================================
--- lib/LTO/LTOBackend.cpp
+++ lib/LTO/LTOBackend.cpp
@@ -30,6 +30,8 @@
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/ThreadPool.h"
 #include "llvm/Target/TargetMachine.h"
@@ -279,16 +281,17 @@
   return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
 }
 
-void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
+std::string codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
              unsigned Task, Module &Mod) {
   if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))
-    return;
+    return std::string();
 
   auto Stream = AddStream(Task);
   legacy::PassManager CodeGenPasses;
   if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, Conf.CGFileType))
     report_fatal_error("Failed to setup codegen");
   CodeGenPasses.run(Mod);
+  return Stream->FileName;
 }
 
 void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
@@ -431,6 +434,11 @@
 
   std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod);
 
+  if (!Conf.DWO_Dir.empty()) {
+    SmallString<1024> DwarfFile(Conf.DWO_Dir);
+    llvm::sys::path::append(DwarfFile, Mod.getModuleIdentifier() + ".dwo");
+    TM->Options.MCOptions.SplitDwarfFile = DwarfFile.str().str();
+  }
   if (Conf.CodeGenOnly) {
     codegen(Conf, TM.get(), AddStream, Task, Mod);
     return Error::success();
@@ -476,6 +484,28 @@
            /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex))
     return Error::success();
 
-  codegen(Conf, TM.get(), AddStream, Task, Mod);
+  std::string output_file = codegen(Conf, TM.get(), AddStream, Task, Mod);
+  if (!Conf.DWO_Dir.empty()) {
+    SmallString<1024> DwarfFile(Conf.DWO_Dir);
+    sys::path::append(DwarfFile, Mod.getModuleIdentifier() + ".dwo");
+    sys::path::remove_filename(DwarfFile);
+    std::error_code EC = llvm::sys::fs::create_directories(DwarfFile.str());
+    if (EC) {
+      errs() << "Failed to create directory " << DwarfFile.c_str() << "\n";
+      return errorCodeToError(EC);
+    }
+    SmallVector<const char*, 8> ExtractArgs, StripArgs;
+    ExtractArgs.push_back(Conf.Objcopy.c_str());
+    ExtractArgs.push_back("--extract-dwo");
+    ExtractArgs.push_back(output_file.c_str());
+    ExtractArgs.push_back(TM->Options.MCOptions.SplitDwarfFile.c_str());
+    ExtractArgs.push_back(nullptr);
+    StripArgs.push_back(Conf.Objcopy.c_str());
+    StripArgs.push_back("--strip-dwo");
+    StripArgs.push_back(output_file.c_str());
+    StripArgs.push_back(nullptr);
+    sys::ExecuteAndWait(Conf.Objcopy, ExtractArgs.data());
+    sys::ExecuteAndWait(Conf.Objcopy, StripArgs.data());
+  }
   return Error::success();
 }
Index: tools/gold/gold-plugin.cpp
===================================================================
--- tools/gold/gold-plugin.cpp
+++ tools/gold/gold-plugin.cpp
@@ -185,6 +185,10 @@
   static std::string sample_profile;
   // New pass manager
   static bool new_pass_manager = false;
+  // Objcopy to debug fission.
+  static std::string objcopy;
+  // Directory to store the .dwo files.
+  static std::string dwo_dir;
 
   static void process_plugin_option(const char *opt_)
   {
@@ -243,10 +247,14 @@
     } else if (opt == "disable-verify") {
       DisableVerify = true;
     } else if (opt.startswith("sample-profile=")) {
-      sample_profile= opt.substr(strlen("sample-profile="));
+      sample_profile = opt.substr(strlen("sample-profile="));
     } else if (opt == "new-pass-manager") {
       new_pass_manager = true;
-    } else {
+    } else if (opt.startswith("objcopy=")) {
+      objcopy = opt.substr(strlen("objcopy="));
+    } else if (opt.startswith("dwo_dir=")) {
+      dwo_dir = opt.substr(strlen("dwo_dir="));
+    }else {
       // Save this option to pass to the code generator.
       // ParseCommandLineOptions() expects argv[0] to be program name. Lazily
       // add that.
@@ -803,6 +811,12 @@
   if (!options::sample_profile.empty())
     Conf.SampleProfile = options::sample_profile;
 
+  if (!options::dwo_dir.empty())
+    Conf.DWO_Dir = options::dwo_dir;
+
+  if (!options::objcopy.empty())
+    Conf.Objcopy = options::objcopy;
+
   // Use new pass manager if set in driver
   Conf.UseNewPM = options::new_pass_manager;
 
@@ -927,7 +941,8 @@
     int FD = getOutputFileName(Filename, /* TempOutFile */ !SaveTemps,
                                Files[Task].first, Task);
     return llvm::make_unique<lto::NativeObjectStream>(
-        llvm::make_unique<llvm::raw_fd_ostream>(FD, true));
+        llvm::make_unique<llvm::raw_fd_ostream>(FD, true),
+        Files[Task].first.str().str());
   };
 
   auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {