JDevlieghere created this revision.
JDevlieghere added reviewers: jingham, aprantl, sgraenitz, labath.
JDevlieghere added a project: LLDB.
Herald added subscribers: teemperor, abidh, mgorny.

This patch changes the way the reproducer is initialized. Rather than making 
changes at run time we now do everything at initialization time. To make this 
happen we had to introduce initializer options and their SB variant. This 
allows us to tell the initializer that we're running in reproducer 
capture/replay mode.

Because of this change we also had to alter our testing strategy. We cannot 
reinitialize LLDB when using the dotest infrastructure. Instead we use lit and 
invoke two instances of the driver.

Another consequence is that we can no longer enable capture or replay through 
commands. This was bound to go away form the beginning, but I had something in 
mind where you could enable/disable specific providers. However this seems like 
it adds very little value right now so I just removed the corresponding 
commands. This also means you now have to control this through the driver, for 
which I replaced `--reproducer` with `--capture` and `--replay`.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D55038

Files:
  include/lldb/API/SBDebugger.h
  include/lldb/API/SBDefines.h
  include/lldb/API/SBFileSpec.h
  include/lldb/API/SBInitializerOptions.h
  include/lldb/Core/Debugger.h
  include/lldb/Host/HostInfoBase.h
  include/lldb/Initialization/SystemInitializer.h
  include/lldb/Initialization/SystemInitializerCommon.h
  include/lldb/Initialization/SystemLifetimeManager.h
  include/lldb/Utility/Reproducer.h
  lit/Reproducer/Inputs/GDBRemoteCapture.in
  lit/Reproducer/Inputs/GDBRemoteReplay.in
  lit/Reproducer/Inputs/simple.c
  lit/Reproducer/TestGDBRemoteRepro.test
  packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile
  
packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py
  packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/main.c
  scripts/interface/SBDebugger.i
  scripts/interface/SBInitializerOptions.i
  scripts/lldb.swig
  source/API/CMakeLists.txt
  source/API/SBDebugger.cpp
  source/API/SBInitializerOptions.cpp
  source/API/SystemInitializerFull.cpp
  source/API/SystemInitializerFull.h
  source/Commands/CommandObjectReproducer.cpp
  source/Core/Debugger.cpp
  source/Host/common/HostInfoBase.cpp
  source/Initialization/SystemInitializerCommon.cpp
  source/Initialization/SystemLifetimeManager.cpp
  source/Utility/Reproducer.cpp
  tools/driver/CMakeLists.txt
  tools/driver/Driver.cpp
  tools/driver/Options.td
  tools/lldb-server/SystemInitializerLLGS.cpp
  tools/lldb-server/SystemInitializerLLGS.h
  tools/lldb-server/lldb-server.cpp
  tools/lldb-test/SystemInitializerTest.cpp
  tools/lldb-test/SystemInitializerTest.h
  tools/lldb-test/lldb-test.cpp
  unittests/Utility/ReproducerTest.cpp

Index: unittests/Utility/ReproducerTest.cpp
===================================================================
--- unittests/Utility/ReproducerTest.cpp
+++ unittests/Utility/ReproducerTest.cpp
@@ -32,34 +32,44 @@
   static char ID;
 };
 
+class DummyReproducer : public Reproducer {
+public:
+  DummyReproducer() : Reproducer(){};
+
+  llvm::Error SetCapture(bool b) { return Reproducer::SetCapture(b); }
+
+  llvm::Error SetReplay(llvm::Optional<FileSpec> root) {
+    return Reproducer::SetReplay(root);
+  }
+};
+
 char DummyProvider::ID = 0;
 
 TEST(ReproducerTest, SetCapture) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   // Initially both generator and loader are unset.
   EXPECT_EQ(nullptr, reproducer.GetGenerator());
   EXPECT_EQ(nullptr, reproducer.GetLoader());
 
   // Enable capture and check that means we have a generator.
-  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
-                    Succeeded());
+  EXPECT_THAT_ERROR(reproducer.SetCapture(true), Succeeded());
   EXPECT_NE(nullptr, reproducer.GetGenerator());
-  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetGenerator()->GetRoot());
-  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetReproducerPath());
+  EXPECT_NE(FileSpec(), reproducer.GetGenerator()->GetRoot());
+  EXPECT_NE(FileSpec(), reproducer.GetReproducerPath());
 
   // Ensure that we cannot enable replay.
   EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec("/bogus/path")), Failed());
   EXPECT_EQ(nullptr, reproducer.GetLoader());
 
   // Ensure we can disable the generator again.
-  EXPECT_THAT_ERROR(reproducer.SetCapture(llvm::None), Succeeded());
+  EXPECT_THAT_ERROR(reproducer.SetCapture(false), Succeeded());
   EXPECT_EQ(nullptr, reproducer.GetGenerator());
   EXPECT_EQ(nullptr, reproducer.GetLoader());
 }
 
 TEST(ReproducerTest, SetReplay) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   // Initially both generator and loader are unset.
   EXPECT_EQ(nullptr, reproducer.GetGenerator());
@@ -75,30 +85,27 @@
   EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetReproducerPath());
 
   // Ensure that we cannot enable replay.
-  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")), Failed());
+  EXPECT_THAT_ERROR(reproducer.SetCapture(true), Failed());
   EXPECT_EQ(nullptr, reproducer.GetGenerator());
 }
 
 TEST(GeneratorTest, Create) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
-  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
-                    Succeeded());
+  EXPECT_THAT_ERROR(reproducer.SetCapture(true), Succeeded());
   auto &generator = *reproducer.GetGenerator();
 
   auto *provider = generator.Create<DummyProvider>();
   EXPECT_NE(nullptr, provider);
-  EXPECT_EQ(FileSpec("/bogus/path"), provider->GetRoot());
   EXPECT_EQ(std::string("dummy"), provider->GetInfo().name);
   EXPECT_EQ((size_t)1, provider->GetInfo().files.size());
   EXPECT_EQ(std::string("dummy.yaml"), provider->GetInfo().files.front());
 }
 
 TEST(GeneratorTest, Get) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
-  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
-                    Succeeded());
+  EXPECT_THAT_ERROR(reproducer.SetCapture(true), Succeeded());
   auto &generator = *reproducer.GetGenerator();
 
   auto *provider = generator.Create<DummyProvider>();
@@ -109,14 +116,12 @@
 }
 
 TEST(GeneratorTest, GetOrCreate) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
-  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
-                    Succeeded());
+  EXPECT_THAT_ERROR(reproducer.SetCapture(true), Succeeded());
   auto &generator = *reproducer.GetGenerator();
 
   auto &provider = generator.GetOrCreate<DummyProvider>();
-  EXPECT_EQ(FileSpec("/bogus/path"), provider.GetRoot());
   EXPECT_EQ(std::string("dummy"), provider.GetInfo().name);
   EXPECT_EQ((size_t)1, provider.GetInfo().files.size());
   EXPECT_EQ(std::string("dummy.yaml"), provider.GetInfo().files.front());
Index: tools/lldb-test/lldb-test.cpp
===================================================================
--- tools/lldb-test/lldb-test.cpp
+++ tools/lldb-test/lldb-test.cpp
@@ -934,7 +934,7 @@
   cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
 
   SystemLifetimeManager DebuggerLifetime;
-  DebuggerLifetime.Initialize(llvm::make_unique<SystemInitializerTest>(),
+  DebuggerLifetime.Initialize(llvm::make_unique<SystemInitializerTest>(), {},
                               nullptr);
   CleanUp TerminateDebugger([&] { DebuggerLifetime.Terminate(); });
 
Index: tools/lldb-test/SystemInitializerTest.h
===================================================================
--- tools/lldb-test/SystemInitializerTest.h
+++ tools/lldb-test/SystemInitializerTest.h
@@ -26,7 +26,7 @@
   SystemInitializerTest();
   ~SystemInitializerTest() override;
 
-  void Initialize() override;
+  void Initialize(SystemInitializer::Options options) override;
   void Terminate() override;
 };
 
Index: tools/lldb-test/SystemInitializerTest.cpp
===================================================================
--- tools/lldb-test/SystemInitializerTest.cpp
+++ tools/lldb-test/SystemInitializerTest.cpp
@@ -111,8 +111,8 @@
 
 SystemInitializerTest::~SystemInitializerTest() {}
 
-void SystemInitializerTest::Initialize() {
-  SystemInitializerCommon::Initialize();
+void SystemInitializerTest::Initialize(SystemInitializer::Options options) {
+  SystemInitializerCommon::Initialize(options);
 
   ObjectFileELF::Initialize();
   ObjectFileMachO::Initialize();
Index: tools/lldb-server/lldb-server.cpp
===================================================================
--- tools/lldb-server/lldb-server.cpp
+++ tools/lldb-server/lldb-server.cpp
@@ -39,7 +39,7 @@
 
 static void initialize() {
   g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerLLGS>(),
-                                  nullptr);
+                                  {}, nullptr);
 }
 
 static void terminate() { g_debugger_lifetime->Terminate(); }
Index: tools/lldb-server/SystemInitializerLLGS.h
===================================================================
--- tools/lldb-server/SystemInitializerLLGS.h
+++ tools/lldb-server/SystemInitializerLLGS.h
@@ -14,7 +14,7 @@
 
 class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon {
 public:
-  void Initialize() override;
+  void Initialize(SystemInitializer::Options options) override;
   void Terminate() override;
 };
 
Index: tools/lldb-server/SystemInitializerLLGS.cpp
===================================================================
--- tools/lldb-server/SystemInitializerLLGS.cpp
+++ tools/lldb-server/SystemInitializerLLGS.cpp
@@ -22,8 +22,8 @@
 
 using namespace lldb_private;
 
-void SystemInitializerLLGS::Initialize() {
-  SystemInitializerCommon::Initialize();
+void SystemInitializerLLGS::Initialize(SystemInitializer::Options options) {
+  SystemInitializerCommon::Initialize(options);
   HostObjectFile::Initialize();
 }
 
Index: tools/driver/Options.td
===================================================================
--- tools/driver/Options.td
+++ tools/driver/Options.td
@@ -209,11 +209,11 @@
   Alias<debug>,
   HelpText<"Alias for --debug">;
 
-def reproducer: Separate<["--", "-"], "reproducer">,
+def capture: Separate<["--", "-"], "capture">,
   MetaVarName<"<filename>">,
-  HelpText<"Tells the debugger to use the fullpath to <filename> as a reproducer.">;
-def: Separate<["-"], "z">,
-  Alias<file>,
-  HelpText<"Alias for --reproducer">;
+  HelpText<"Tells the debugger to capture a reproducer to <filename>.">;
+def replay: Separate<["--", "-"], "replay">,
+  MetaVarName<"<filename>">,
+  HelpText<"Tells the debugger to replay a reproducer from <filename>.">;
 
 def REM : R<["--"], "">;
Index: tools/driver/Driver.cpp
===================================================================
--- tools/driver/Driver.cpp
+++ tools/driver/Driver.cpp
@@ -367,21 +367,6 @@
     m_option_data.m_debug_mode = true;
   }
 
-  if (auto *arg = args.getLastArg(OPT_reproducer)) {
-    auto arg_value = arg->getValue();
-    SBFileSpec file(arg_value);
-    if (file.Exists()) {
-      SBError repro_error = m_debugger.ReplayReproducer(arg_value);
-      if (repro_error.Fail())
-        return repro_error;
-    } else {
-      error.SetErrorStringWithFormat("file specified in --reproducer "
-                                     "(-z) option doesn't exist: '%s'",
-                                     arg_value);
-      return error;
-    }
-  }
-
   if (args.hasArg(OPT_no_use_colors)) {
     m_debugger.SetUseColor(false);
   }
@@ -942,7 +927,21 @@
                          << '\n';
   }
 
-  SBDebugger::Initialize();
+  SBInitializerOptions options;
+
+  if (auto *arg = input_args.getLastArg(OPT_capture)) {
+    auto arg_value = arg->getValue();
+    options.SetReproducerPath(arg_value);
+    options.SetCaptureReproducer(true);
+  }
+
+  if (auto *arg = input_args.getLastArg(OPT_replay)) {
+    auto arg_value = arg->getValue();
+    options.SetReplayReproducer(true);
+    options.SetReproducerPath(arg_value);
+  }
+
+  SBDebugger::Initialize(options);
   SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
 
   signal(SIGINT, sigint_handler);
Index: tools/driver/CMakeLists.txt
===================================================================
--- tools/driver/CMakeLists.txt
+++ tools/driver/CMakeLists.txt
@@ -18,6 +18,7 @@
 
   LINK_LIBS
     liblldb
+    lldbUtility
     ${host_lib}
 
   LINK_COMPONENTS
Index: source/Utility/Reproducer.cpp
===================================================================
--- source/Utility/Reproducer.cpp
+++ source/Utility/Reproducer.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/LLDBAssert.h"
 
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Threading.h"
@@ -18,11 +19,50 @@
 using namespace llvm;
 using namespace llvm::yaml;
 
-Reproducer &Reproducer::Instance() {
-  static Reproducer g_reproducer;
+Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
+
+void Reproducer::Initialize(ReproducerMode mode,
+                            llvm::Optional<FileSpec> root) {
+  lldbassert(!InstanceImpl() && "Already initialized.");
+  InstanceImpl().emplace(mode, root);
+}
+
+void Reproducer::Terminate() {
+  lldbassert(InstanceImpl() && "Already terminated.");
+  InstanceImpl().reset();
+}
+
+Optional<Reproducer> &Reproducer::InstanceImpl() {
+  static Optional<Reproducer> g_reproducer;
   return g_reproducer;
 }
 
+Reproducer::Reproducer(ReproducerMode mode, llvm::Optional<FileSpec> root) {
+  // It's unfortunate that we have to do so much I/O here that can fail. The
+  // best we can do is not initialize the reproducer.
+  switch (mode) {
+  case ReproducerMode::Capture: {
+    if (!root) {
+      llvm::SmallString<128> repro_dir;
+      auto ec = llvm::sys::fs::createUniqueDirectory("reproducer", repro_dir);
+      if (ec)
+        return;
+      root.emplace(repro_dir);
+    } else {
+      auto ec = llvm::sys::fs::create_directories(root->GetPath());
+      if (ec)
+        return;
+    }
+    llvm::cantFail(SetCapture(root));
+  } break;
+  case ReproducerMode::Replay:
+    llvm::cantFail(SetReplay(root));
+    break;
+  case ReproducerMode::Off:
+    break;
+  };
+}
+
 const Generator *Reproducer::GetGenerator() const {
   std::lock_guard<std::mutex> guard(m_mutex);
   if (m_generator)
@@ -59,11 +99,12 @@
         "cannot generate a reproducer when replay one",
         inconvertibleErrorCode());
 
-  if (root)
-    m_generator.emplace(*root);
-  else
+  if (!root) {
     m_generator.reset();
+    return Error::success();
+  }
 
+  m_generator.emplace(*root);
   return Error::success();
 }
 
@@ -75,14 +116,15 @@
         "cannot replay a reproducer when generating one",
         inconvertibleErrorCode());
 
-  if (root) {
-    m_loader.emplace(*root);
-    if (auto e = m_loader->LoadIndex())
-      return e;
-  } else {
+  if (!root) {
     m_loader.reset();
+    return Error::success();
   }
 
+  m_loader.emplace(*root);
+  if (auto e = m_loader->LoadIndex())
+    return e;
+
   return Error::success();
 }
 
Index: source/Initialization/SystemLifetimeManager.cpp
===================================================================
--- source/Initialization/SystemLifetimeManager.cpp
+++ source/Initialization/SystemLifetimeManager.cpp
@@ -26,6 +26,7 @@
 
 void SystemLifetimeManager::Initialize(
     std::unique_ptr<SystemInitializer> initializer,
+    SystemInitializer::Options options,
     LoadPluginCallbackType plugin_callback) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   if (!m_initialized) {
@@ -35,7 +36,7 @@
     m_initialized = true;
     m_initializer = std::move(initializer);
 
-    m_initializer->Initialize();
+    m_initializer->Initialize(options);
     Debugger::Initialize(plugin_callback);
   }
 }
Index: source/Initialization/SystemInitializerCommon.cpp
===================================================================
--- source/Initialization/SystemInitializerCommon.cpp
+++ source/Initialization/SystemInitializerCommon.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/Timer.h"
 
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
@@ -35,12 +36,13 @@
 #include <string>
 
 using namespace lldb_private;
+using namespace lldb_private::repro;
 
 SystemInitializerCommon::SystemInitializerCommon() {}
 
 SystemInitializerCommon::~SystemInitializerCommon() {}
 
-void SystemInitializerCommon::Initialize() {
+void SystemInitializerCommon::Initialize(SystemInitializer::Options options) {
 #if defined(_MSC_VER)
   const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
   if (disable_crash_dialog_var &&
@@ -63,6 +65,13 @@
   }
 #endif
 
+  ReproducerMode mode = ReproducerMode::Off;
+  if (options.reproducer_capture)
+    mode = ReproducerMode::Capture;
+  if (options.reproducer_replay)
+    mode = ReproducerMode::Replay;
+
+  Reproducer::Initialize(mode, FileSpec(options.reproducer_path.c_str()));
   FileSystem::Initialize();
   Log::Initialize();
   HostInfo::Initialize();
@@ -109,4 +118,5 @@
   HostInfo::Terminate();
   Log::DisableAllLogChannels();
   FileSystem::Terminate();
+  Reproducer::Terminate();
 }
Index: source/Host/common/HostInfoBase.cpp
===================================================================
--- source/Host/common/HostInfoBase.cpp
+++ source/Host/common/HostInfoBase.cpp
@@ -194,19 +194,6 @@
   return success ? g_fields->m_lldb_global_tmp_dir : FileSpec();
 }
 
-FileSpec HostInfoBase::GetReproducerTempDir() {
-  static llvm::once_flag g_once_flag;
-  static bool success = false;
-  llvm::call_once(g_once_flag, []() {
-    success = HostInfo::ComputeReproducerTempFileDirectory(
-        g_fields->m_lldb_global_tmp_dir);
-    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
-    LLDB_LOG(log, "reproducer temp dir -> `{0}`",
-             g_fields->m_lldb_global_tmp_dir);
-  });
-  return success ? g_fields->m_lldb_global_tmp_dir : FileSpec();
-}
-
 ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
   if (triple.empty())
     return ArchSpec();
@@ -289,26 +276,6 @@
   return true;
 }
 
-bool HostInfoBase::ComputeReproducerTempFileDirectory(FileSpec &file_spec) {
-  file_spec.Clear();
-
-  FileSpec temp_file_spec;
-  if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
-    return false;
-
-  temp_file_spec.AppendPathComponent("reproducer");
-  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
-    return false;
-
-  std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
-  temp_file_spec.AppendPathComponent(pid_str);
-  if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
-    return false;
-
-  file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
-  return true;
-}
-
 bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
   // TODO(zturner): Figure out how to compute the header directory for all
   // platforms.
Index: source/Core/Debugger.cpp
===================================================================
--- source/Core/Debugger.cpp
+++ source/Core/Debugger.cpp
@@ -418,24 +418,6 @@
   return r.GetReproducerPath().GetCString();
 }
 
-llvm::Error Debugger::SetReproducerReplay(llvm::StringRef p) {
-  llvm::Optional<FileSpec> arg = llvm::None;
-
-  if (!p.empty())
-    arg = FileSpec(p);
-
-  return repro::Reproducer::Instance().SetReplay(arg);
-}
-
-llvm::Error Debugger::SetReproducerCapture(bool b) {
-  llvm::Optional<FileSpec> arg = llvm::None;
-
-  if (b)
-    arg = HostInfo::GetReproducerTempDir();
-
-  return repro::Reproducer::Instance().SetCapture(arg);
-}
-
 const FormatEntity::Entry *Debugger::GetThreadFormat() const {
   const uint32_t idx = ePropertyThreadFormat;
   return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
Index: source/Commands/CommandObjectReproducer.cpp
===================================================================
--- source/Commands/CommandObjectReproducer.cpp
+++ source/Commands/CommandObjectReproducer.cpp
@@ -19,65 +19,6 @@
 using namespace lldb;
 using namespace lldb_private;
 
-static void AppendErrorToResult(llvm::Error e, CommandReturnObject &result) {
-  std::string error_str = llvm::toString(std::move(e));
-  result.AppendErrorWithFormat("%s", error_str.c_str());
-}
-
-class CommandObjectReproducerCaptureEnable : public CommandObjectParsed {
-public:
-  CommandObjectReproducerCaptureEnable(CommandInterpreter &interpreter)
-      : CommandObjectParsed(interpreter, "reproducer capture enable",
-                            "Enable gathering information for reproducer",
-                            nullptr) {}
-
-  ~CommandObjectReproducerCaptureEnable() override = default;
-
-protected:
-  bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
-      return false;
-    }
-
-    if (auto e = m_interpreter.GetDebugger().SetReproducerCapture(true)) {
-      AppendErrorToResult(std::move(e), result);
-      return false;
-    }
-
-    result.SetStatus(eReturnStatusSuccessFinishNoResult);
-    return result.Succeeded();
-  }
-};
-
-class CommandObjectReproducerCaptureDisable : public CommandObjectParsed {
-public:
-  CommandObjectReproducerCaptureDisable(CommandInterpreter &interpreter)
-      : CommandObjectParsed(interpreter, "reproducer capture enable",
-                            "Disable gathering information for reproducer",
-                            nullptr) {}
-
-  ~CommandObjectReproducerCaptureDisable() override = default;
-
-protected:
-  bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (!command.empty()) {
-      result.AppendErrorWithFormat("'%s' takes no arguments",
-                                   m_cmd_name.c_str());
-      return false;
-    }
-
-    if (auto e = m_interpreter.GetDebugger().SetReproducerCapture(false)) {
-      AppendErrorToResult(std::move(e), result);
-      return false;
-    }
-
-    result.SetStatus(eReturnStatusSuccessFinishNoResult);
-    return result.Succeeded();
-  }
-};
-
 class CommandObjectReproducerGenerate : public CommandObjectParsed {
 public:
   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
@@ -110,82 +51,47 @@
   }
 };
 
-class CommandObjectReproducerReplay : public CommandObjectParsed {
+class CommandObjectReproducerStatus : public CommandObjectParsed {
 public:
-  CommandObjectReproducerReplay(CommandInterpreter &interpreter)
-      : CommandObjectParsed(interpreter, "reproducer replay",
-                            "Replay a reproducer.", nullptr) {
-    CommandArgumentEntry arg1;
-    CommandArgumentData path_arg;
-
-    // Define the first (and only) variant of this arg.
-    path_arg.arg_type = eArgTypePath;
-    path_arg.arg_repetition = eArgRepeatPlain;
-
-    // There is only one variant this argument could be; put it into the
-    // argument entry.
-    arg1.push_back(path_arg);
-
-    // Push the data for the first argument into the m_arguments vector.
-    m_arguments.push_back(arg1);
-  }
+  CommandObjectReproducerStatus(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "reproducer status",
+                            "Show the current reproducer status.", nullptr) {}
 
-  ~CommandObjectReproducerReplay() override = default;
+  ~CommandObjectReproducerStatus() override = default;
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
-    if (command.empty()) {
-      result.AppendErrorWithFormat(
-          "'%s' takes a single argument: the reproducer path",
-          m_cmd_name.c_str());
+    if (!command.empty()) {
+      result.AppendErrorWithFormat("'%s' takes no arguments",
+                                   m_cmd_name.c_str());
       return false;
     }
 
     auto &r = repro::Reproducer::Instance();
+    if (auto generator = r.GetGenerator()) {
+      result.GetOutputStream() << "Reproducer is in capture mode.\n";
+    } else if (auto generator = r.GetLoader()) {
+      result.GetOutputStream() << "Reproducer is in replay mode.\n";
+    } else {
 
-    const char *repro_path = command.GetArgumentAtIndex(0);
-    if (auto e = r.SetReplay(FileSpec(repro_path))) {
-      std::string error_str = llvm::toString(std::move(e));
-      result.AppendErrorWithFormat("%s", error_str.c_str());
-      return false;
+      result.GetOutputStream() << "Reproducer is off.\n";
     }
 
-    result.SetStatus(eReturnStatusSuccessFinishNoResult);
+    result.SetStatus(eReturnStatusSuccessFinishResult);
     return result.Succeeded();
   }
 };
 
-class CommandObjectReproducerCapture : public CommandObjectMultiword {
-private:
-public:
-  CommandObjectReproducerCapture(CommandInterpreter &interpreter)
-      : CommandObjectMultiword(
-            interpreter, "reproducer capture",
-            "Manage gathering of information needed to generate a reproducer.",
-            NULL) {
-    LoadSubCommand(
-        "enable",
-        CommandObjectSP(new CommandObjectReproducerCaptureEnable(interpreter)));
-    LoadSubCommand("disable",
-                   CommandObjectSP(
-                       new CommandObjectReproducerCaptureDisable(interpreter)));
-  }
-
-  ~CommandObjectReproducerCapture() {}
-};
-
 CommandObjectReproducer::CommandObjectReproducer(
     CommandInterpreter &interpreter)
     : CommandObjectMultiword(interpreter, "reproducer",
                              "Commands controlling LLDB reproducers.",
                              "log <subcommand> [<command-options>]") {
-  LoadSubCommand("capture", CommandObjectSP(new CommandObjectReproducerCapture(
-                                interpreter)));
   LoadSubCommand(
       "generate",
       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
-  LoadSubCommand("replay", CommandObjectSP(
-                               new CommandObjectReproducerReplay(interpreter)));
+  LoadSubCommand("status", CommandObjectSP(
+                               new CommandObjectReproducerStatus(interpreter)));
 }
 
 CommandObjectReproducer::~CommandObjectReproducer() = default;
Index: source/API/SystemInitializerFull.h
===================================================================
--- source/API/SystemInitializerFull.h
+++ source/API/SystemInitializerFull.h
@@ -26,7 +26,7 @@
   SystemInitializerFull();
   ~SystemInitializerFull() override;
 
-  void Initialize() override;
+  void Initialize(SystemInitializer::Options options) override;
   void Terminate() override;
 
 private:
Index: source/API/SystemInitializerFull.cpp
===================================================================
--- source/API/SystemInitializerFull.cpp
+++ source/API/SystemInitializerFull.cpp
@@ -263,8 +263,8 @@
 
 SystemInitializerFull::~SystemInitializerFull() {}
 
-void SystemInitializerFull::Initialize() {
-  SystemInitializerCommon::Initialize();
+void SystemInitializerFull::Initialize(SystemInitializer::Options options) {
+  SystemInitializerCommon::Initialize(options);
 
   ObjectFileELF::Initialize();
   ObjectFileMachO::Initialize();
Index: source/API/SBInitializerOptions.cpp
===================================================================
--- /dev/null
+++ source/API/SBInitializerOptions.cpp
@@ -0,0 +1,29 @@
+//===-- SBInitializerOptions.cpp --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBInitializerOptions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBInitializerOptions::SBInitializerOptions() {
+  m_opaque_up.reset(new SystemInitializer::Options());
+}
+
+void SBInitializerOptions::SetCaptureReproducer(bool b) {
+  m_opaque_up->reproducer_capture = b;
+}
+
+void SBInitializerOptions::SetReplayReproducer(bool b) {
+  m_opaque_up->reproducer_replay = b;
+}
+
+void SBInitializerOptions::SetReproducerPath(const char *path) {
+  m_opaque_up->reproducer_path = path;
+}
Index: source/API/SBDebugger.cpp
===================================================================
--- source/API/SBDebugger.cpp
+++ source/API/SBDebugger.cpp
@@ -125,13 +125,18 @@
 }
 
 void SBDebugger::Initialize() {
+  SBInitializerOptions options;
+  SBDebugger::Initialize(options);
+}
+
+void SBDebugger::Initialize(SBInitializerOptions &options) {
   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 
   if (log)
     log->Printf("SBDebugger::Initialize ()");
 
   g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerFull>(),
-                                  LoadPlugin);
+                                  *options.m_opaque_up, LoadPlugin);
 }
 
 void SBDebugger::Terminate() { g_debugger_lifetime->Terminate(); }
@@ -1057,17 +1062,6 @@
               : nullptr);
 }
 
-SBError SBDebugger::ReplayReproducer(const char *p) {
-  SBError sb_error;
-  if (m_opaque_sp) {
-    auto error =
-        m_opaque_sp->SetReproducerReplay(llvm::StringRef::withNullAsEmpty(p));
-    std::string error_str = llvm::toString(std::move(error));
-    sb_error.ref().SetErrorString(error_str);
-  }
-  return sb_error;
-}
-
 ScriptLanguage SBDebugger::GetScriptLanguage() const {
   return (m_opaque_sp ? m_opaque_sp->GetScriptLanguage() : eScriptLanguageNone);
 }
Index: source/API/CMakeLists.txt
===================================================================
--- source/API/CMakeLists.txt
+++ source/API/CMakeLists.txt
@@ -29,6 +29,7 @@
   SBFrame.cpp
   SBFunction.cpp
   SBHostOS.cpp
+  SBInitializerOptions.cpp
   SBInstruction.cpp
   SBInstructionList.cpp
   SBLanguageRuntime.cpp
Index: scripts/lldb.swig
===================================================================
--- scripts/lldb.swig
+++ scripts/lldb.swig
@@ -187,6 +187,7 @@
 %include "./interface/SBFrame.i"
 %include "./interface/SBFunction.i"
 %include "./interface/SBHostOS.i"
+%include "./interface/SBInitializerOptions.i"
 %include "./interface/SBInstruction.i"
 %include "./interface/SBInstructionList.i"
 %include "./interface/SBLanguageRuntime.i"
Index: scripts/interface/SBInitializerOptions.i
===================================================================
--- /dev/null
+++ scripts/interface/SBInitializerOptions.i
@@ -0,0 +1,22 @@
+//===-- SWIG Interface for SBInitializerOptions -----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+namespace lldb {
+
+class SBInitializerOptions
+{
+public:
+    SBInitializerOptions ();
+
+  void SetCaptureReproducer(bool b);
+  void SetReplayReproducer(bool b);
+  void SetReproducerPath(const char* path);
+};
+
+} // namespace lldb
Index: scripts/interface/SBDebugger.i
===================================================================
--- scripts/interface/SBDebugger.i
+++ scripts/interface/SBDebugger.i
@@ -123,6 +123,9 @@
     static void
     Initialize();
 
+    static void
+    Initialize(lldb::SBInitializerOptions& options);
+
     static void
     Terminate();
 
@@ -376,9 +379,6 @@
     const char *
     GetReproducerPath() const;
 
-    lldb::SBError
-    ReplayReproducer (const char *path);
-
     lldb::ScriptLanguage
     GetScriptLanguage() const;
 
Index: packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py
+++ /dev/null
@@ -1,49 +0,0 @@
-"""
-Test the GDB remote reproducer.
-"""
-
-from __future__ import print_function
-
-import os
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class TestGdbRemoteReproducer(TestBase):
-
-    mydir = TestBase.compute_mydir(__file__)
-    NO_DEBUG_INFO_TESTCASE = True
-
-    def test(self):
-        """Test record and replay of gdb-remote packets."""
-        self.build()
-
-        # Create temp directory for the reproducer.
-        exe = self.getBuildArtifact("a.out")
-
-        # First capture a regular debugging session.
-        self.runCmd("reproducer capture enable")
-
-        reproducer_path = self.dbg.GetReproducerPath()
-
-        self.runCmd("file {}".format(exe))
-        self.runCmd("breakpoint set -f main.c -l 13")
-        self.runCmd("run")
-        self.runCmd("bt")
-        self.runCmd("cont")
-
-        # Generate the reproducer and stop capturing.
-        self.runCmd("reproducer generate")
-        self.runCmd("reproducer capture disable")
-
-        # Replay the session from the reproducer.
-        self.runCmd("reproducer replay {}".format(reproducer_path))
-
-        # We have to issue the same commands.
-        self.runCmd("file {}".format(exe))
-        self.runCmd("breakpoint set -f main.c -l 13")
-        self.runCmd("run")
-        self.runCmd("bt")
-        self.expect("cont")
Index: packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile
===================================================================
--- packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-LEVEL = ../../../make
-
-C_SOURCES := main.c
-
-include $(LEVEL)/Makefile.rules
Index: lit/Reproducer/TestGDBRemoteRepro.test
===================================================================
--- /dev/null
+++ lit/Reproducer/TestGDBRemoteRepro.test
@@ -0,0 +1,24 @@
+# This tests the replaying of GDB remote packets.
+#
+# We issue the same commands and ensure the output is identical to the original
+# process. To ensure we're not actually running the original binary we check
+# that the string "testing" is not printed.
+
+# RUN: %clang %S/Inputs/simple.c -g -o %t.out --target=x86_64-apple-macosx
+# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture %T/reproducer -- %t.out | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
+# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteReplay.in --replay %T/reproducer -- %t.out | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
+
+# CHECK: Breakpoint 1
+# CHECK: Process {{.*}} stopped
+# CHECK: Process {{.*}} launched
+# CHECK: thread {{.*}} stop reason = breakpoint
+# CHECK: frame {{.*}} simple.c
+# CHECK: Process {{.*}} resuming
+#
+# CAPTURE: testing
+# REPLAY-NOT: testing
+#
+# CHECK: Process {{.*}} exited
+#
+# CAPTURE: Reproducer is in capture mode.
+# CAPTURE: Reproducer written
Index: lit/Reproducer/Inputs/simple.c
===================================================================
--- lit/Reproducer/Inputs/simple.c
+++ lit/Reproducer/Inputs/simple.c
@@ -9,11 +9,9 @@
 
 #include <stdio.h>
 
-void foo() {
-    printf("testing\n");
-}
+void foo() { printf("testing\n"); }
 
-int main (int argc, char const *argv[]) {
-    foo();
-    return 0;
+int main(int argc, char const *argv[]) {
+  foo();
+  return 0;
 }
Index: lit/Reproducer/Inputs/GDBRemoteReplay.in
===================================================================
--- /dev/null
+++ lit/Reproducer/Inputs/GDBRemoteReplay.in
@@ -0,0 +1,5 @@
+reproducer status
+breakpoint set -f simple.c -l 13
+run
+bt
+cont
Index: lit/Reproducer/Inputs/GDBRemoteCapture.in
===================================================================
--- /dev/null
+++ lit/Reproducer/Inputs/GDBRemoteCapture.in
@@ -0,0 +1,6 @@
+breakpoint set -f simple.c -l 13
+run
+bt
+cont
+reproducer status
+reproducer generate
Index: include/lldb/Utility/Reproducer.h
===================================================================
--- include/lldb/Utility/Reproducer.h
+++ include/lldb/Utility/Reproducer.h
@@ -25,6 +25,12 @@
 
 class Reproducer;
 
+enum class ReproducerMode {
+  Capture,
+  Replay,
+  Off,
+};
+
 /// Abstraction for information associated with a provider. This information
 /// is serialized into an index which is used by the loader.
 struct ProviderInfo {
@@ -159,10 +165,13 @@
 
 /// The reproducer enables clients to obtain access to the Generator and
 /// Loader.
-class Reproducer final {
-
+class Reproducer {
 public:
   static Reproducer &Instance();
+  static void Initialize(ReproducerMode mode, llvm::Optional<FileSpec> root);
+  static void Terminate();
+
+  Reproducer(ReproducerMode mode, llvm::Optional<FileSpec> root);
 
   Generator *GetGenerator();
   Loader *GetLoader();
@@ -170,12 +179,16 @@
   const Generator *GetGenerator() const;
   const Loader *GetLoader() const;
 
+  FileSpec GetReproducerPath() const;
+
+protected:
+  Reproducer() = default;
   llvm::Error SetCapture(llvm::Optional<FileSpec> root);
   llvm::Error SetReplay(llvm::Optional<FileSpec> root);
 
-  FileSpec GetReproducerPath() const;
-
 private:
+  static llvm::Optional<Reproducer> &InstanceImpl();
+
   llvm::Optional<Generator> m_generator;
   llvm::Optional<Loader> m_loader;
 
Index: include/lldb/Initialization/SystemLifetimeManager.h
===================================================================
--- include/lldb/Initialization/SystemLifetimeManager.h
+++ include/lldb/Initialization/SystemLifetimeManager.h
@@ -10,13 +10,13 @@
 #ifndef LLDB_INITIALIZATION_SYSTEM_LIFETIME_MANAGER_H
 #define LLDB_INITIALIZATION_SYSTEM_LIFETIME_MANAGER_H
 
+#include "lldb/Initialization/SystemInitializer.h"
 #include "lldb/lldb-private-types.h"
 
 #include <memory>
 #include <mutex>
 
 namespace lldb_private {
-class SystemInitializer;
 
 class SystemLifetimeManager {
 public:
@@ -24,6 +24,7 @@
   ~SystemLifetimeManager();
 
   void Initialize(std::unique_ptr<SystemInitializer> initializer,
+                  SystemInitializer::Options options,
                   LoadPluginCallbackType plugin_callback);
   void Terminate();
 
Index: include/lldb/Initialization/SystemInitializerCommon.h
===================================================================
--- include/lldb/Initialization/SystemInitializerCommon.h
+++ include/lldb/Initialization/SystemInitializerCommon.h
@@ -28,7 +28,7 @@
   SystemInitializerCommon();
   ~SystemInitializerCommon() override;
 
-  void Initialize() override;
+  void Initialize(SystemInitializer::Options options) override;
   void Terminate() override;
 };
 
Index: include/lldb/Initialization/SystemInitializer.h
===================================================================
--- include/lldb/Initialization/SystemInitializer.h
+++ include/lldb/Initialization/SystemInitializer.h
@@ -10,13 +10,22 @@
 #ifndef LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H
 #define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H
 
+#include <string>
+
 namespace lldb_private {
+
 class SystemInitializer {
 public:
   SystemInitializer();
   virtual ~SystemInitializer();
 
-  virtual void Initialize() = 0;
+  struct Options {
+    bool reproducer_capture = false;
+    bool reproducer_replay = false;
+    std::string reproducer_path;
+  };
+
+  virtual void Initialize(Options options) = 0;
   virtual void Terminate() = 0;
 };
 }
Index: include/lldb/Host/HostInfoBase.h
===================================================================
--- include/lldb/Host/HostInfoBase.h
+++ include/lldb/Host/HostInfoBase.h
@@ -93,12 +93,6 @@
   /// FileSpec is filled in.
   static FileSpec GetGlobalTempDir();
 
-  /// Returns the reproducer temporary directory. This directory will **not**
-  /// be automatically cleaned up when this process exits, but might be removed
-  /// by the reproducer generator. Only the directory member of the FileSpec is
-  /// filled in.
-  static FileSpec GetReproducerTempDir();
-
   //---------------------------------------------------------------------------
   /// If the triple does not specify the vendor, os, and environment parts, we
   /// "augment" these using information from the host and return the resulting
@@ -111,7 +105,6 @@
   static bool ComputeSupportExeDirectory(FileSpec &file_spec);
   static bool ComputeProcessTempFileDirectory(FileSpec &file_spec);
   static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec);
-  static bool ComputeReproducerTempFileDirectory(FileSpec &file_spec);
   static bool ComputeTempFileBaseDirectory(FileSpec &file_spec);
   static bool ComputeHeaderDirectory(FileSpec &file_spec);
   static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
Index: include/lldb/Core/Debugger.h
===================================================================
--- include/lldb/Core/Debugger.h
+++ include/lldb/Core/Debugger.h
@@ -263,11 +263,6 @@
 
   llvm::StringRef GetReproducerPath() const;
 
-  llvm::Error SetReproducerReplay(llvm::StringRef p);
-  llvm::Error SetReproducerReplay(const char *) = delete;
-
-  llvm::Error SetReproducerCapture(bool b);
-
   bool GetUseExternalEditor() const;
 
   bool SetUseExternalEditor(bool use_external_editor_p);
Index: include/lldb/API/SBInitializerOptions.h
===================================================================
--- /dev/null
+++ include/lldb/API/SBInitializerOptions.h
@@ -0,0 +1,37 @@
+//===-- SBInitializerOptions.h ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBInitializerOptuions_h_
+#define LLDB_SBInitializerOptuions_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/Initialization/SystemInitializer.h"
+
+#include <vector>
+
+namespace lldb {
+
+class LLDB_API SBInitializerOptions {
+public:
+  SBInitializerOptions();
+
+  void SetCaptureReproducer(bool b);
+  void SetReplayReproducer(bool b);
+  void SetReproducerPath(const char *path);
+
+private:
+  friend class SBDebugger;
+
+  mutable std::unique_ptr<lldb_private::SystemInitializer::Options> m_opaque_up;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBInitializerOptuions_h_
Index: include/lldb/API/SBFileSpec.h
===================================================================
--- include/lldb/API/SBFileSpec.h
+++ include/lldb/API/SBFileSpec.h
@@ -59,6 +59,7 @@
   friend class SBDeclaration;
   friend class SBFileSpecList;
   friend class SBHostOS;
+  friend class SBInitializerOptions;
   friend class SBLaunchInfo;
   friend class SBLineEntry;
   friend class SBModule;
@@ -67,8 +68,8 @@
   friend class SBProcess;
   friend class SBProcessInfo;
   friend class SBSourceManager;
-  friend class SBThread;
   friend class SBTarget;
+  friend class SBThread;
 
   SBFileSpec(const lldb_private::FileSpec &fspec);
 
Index: include/lldb/API/SBDefines.h
===================================================================
--- include/lldb/API/SBDefines.h
+++ include/lldb/API/SBDefines.h
@@ -51,6 +51,7 @@
 class LLDB_API SBFrame;
 class LLDB_API SBFunction;
 class LLDB_API SBHostOS;
+class LLDB_API SBInitializerOptions;
 class LLDB_API SBInstruction;
 class LLDB_API SBInstructionList;
 class LLDB_API SBLanguageRuntime;
Index: include/lldb/API/SBDebugger.h
===================================================================
--- include/lldb/API/SBDebugger.h
+++ include/lldb/API/SBDebugger.h
@@ -13,6 +13,7 @@
 #include <stdio.h>
 
 #include "lldb/API/SBDefines.h"
+#include "lldb/API/SBInitializerOptions.h"
 #include "lldb/API/SBPlatform.h"
 
 namespace lldb {
@@ -45,6 +46,7 @@
   lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs);
 
   static void Initialize();
+  static void Initialize(SBInitializerOptions &options);
 
   static void Terminate();
 
@@ -228,8 +230,6 @@
 
   const char *GetReproducerPath() const;
 
-  lldb::SBError ReplayReproducer(const char *path);
-
   lldb::ScriptLanguage GetScriptLanguage() const;
 
   void SetScriptLanguage(lldb::ScriptLanguage script_lang);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to