[Reproducers] Change how reproducers are initialized.
authorJonas Devlieghere <jonas@devlieghere.com>
Mon, 3 Dec 2018 17:28:29 +0000 (17:28 +0000)
committerJonas Devlieghere <jonas@devlieghere.com>
Mon, 3 Dec 2018 17:28:29 +0000 (17:28 +0000)
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 the
corresponding commands were removed.

Finally this change also means you now have to control this through the
driver, for which I replaced --reproducer with --capture and --replay to
differentiate between the two modes.

Differential revision: https://reviews.llvm.org/D55038

llvm-svn: 348152

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

index ccb1f6d..3f31bf1 100644 (file)
@@ -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 @@ public:
   lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs);
 
   static void Initialize();
+  static lldb::SBError Initialize(SBInitializerOptions &options);
 
   static void Terminate();
 
@@ -228,8 +230,6 @@ public:
 
   const char *GetReproducerPath() const;
 
-  lldb::SBError ReplayReproducer(const char *path);
-
   lldb::ScriptLanguage GetScriptLanguage() const;
 
   void SetScriptLanguage(lldb::ScriptLanguage script_lang);
index 166cc2a..c5c9851 100644 (file)
@@ -51,6 +51,7 @@ class LLDB_API SBFileSpecList;
 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 33e48f5..9ad1a5d 100644 (file)
@@ -59,6 +59,7 @@ private:
   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 @@ private:
   friend class SBProcess;
   friend class SBProcessInfo;
   friend class SBSourceManager;
-  friend class SBThread;
   friend class SBTarget;
+  friend class SBThread;
 
   SBFileSpec(const lldb_private::FileSpec &fspec);
 
diff --git a/lldb/include/lldb/API/SBInitializerOptions.h b/lldb/include/lldb/API/SBInitializerOptions.h
new file mode 100644 (file)
index 0000000..184c82d
--- /dev/null
@@ -0,0 +1,43 @@
+//===-- 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"
+
+namespace lldb_private {
+struct InitializerOptions;
+}
+
+namespace lldb {
+
+class LLDB_API SBInitializerOptions {
+public:
+  SBInitializerOptions();
+  SBInitializerOptions(const lldb::SBInitializerOptions &rhs);
+  ~SBInitializerOptions();
+  const SBInitializerOptions &operator=(const lldb::SBInitializerOptions &rhs);
+
+  void SetCaptureReproducer(bool b);
+  void SetReplayReproducer(bool b);
+  void SetReproducerPath(const char *path);
+
+  lldb_private::InitializerOptions &ref() const;
+
+private:
+  friend class SBDebugger;
+
+  std::unique_ptr<lldb_private::InitializerOptions> m_opaque_up;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBInitializerOptuions_h_
index 8056b8b..f7de9ff 100644 (file)
@@ -263,11 +263,6 @@ public:
 
   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 efc6607..f3e49c8 100644 (file)
@@ -93,12 +93,6 @@ public:
   /// 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 @@ protected:
   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 58bbb44..b665b99 100644 (file)
 #ifndef LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H
 #define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H
 
+#include "llvm/Support/Error.h"
+
+#include <string>
+
 namespace lldb_private {
+
+struct InitializerOptions {
+  bool reproducer_capture = false;
+  bool reproducer_replay = false;
+  std::string reproducer_path;
+};
+
 class SystemInitializer {
 public:
   SystemInitializer();
   virtual ~SystemInitializer();
 
-  virtual void Initialize() = 0;
+  virtual llvm::Error Initialize(const InitializerOptions &options) = 0;
   virtual void Terminate() = 0;
 };
 }
index 2a9851c..f33acaf 100644 (file)
@@ -28,7 +28,7 @@ public:
   SystemInitializerCommon();
   ~SystemInitializerCommon() override;
 
-  void Initialize() override;
+  llvm::Error Initialize(const InitializerOptions &options) override;
   void Terminate() override;
 };
 
index 0ebd4a5..0839856 100644 (file)
 #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 "llvm/Support/Error.h"
 
 #include <memory>
 #include <mutex>
 
 namespace lldb_private {
-class SystemInitializer;
 
 class SystemLifetimeManager {
 public:
   SystemLifetimeManager();
   ~SystemLifetimeManager();
 
-  void Initialize(std::unique_ptr<SystemInitializer> initializer,
-                  LoadPluginCallbackType plugin_callback);
+  llvm::Error Initialize(std::unique_ptr<SystemInitializer> initializer,
+                         const InitializerOptions &options,
+                         LoadPluginCallbackType plugin_callback);
   void Terminate();
 
 private:
index 6ad1acf..ea315ad 100644 (file)
@@ -25,6 +25,12 @@ namespace repro {
 
 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,14 @@ private:
 
 /// The reproducer enables clients to obtain access to the Generator and
 /// Loader.
-class Reproducer final {
-
+class Reproducer {
 public:
   static Reproducer &Instance();
+  static llvm::Error Initialize(ReproducerMode mode,
+                                llvm::Optional<FileSpec> root);
+  static void Terminate();
+
+  Reproducer() = default;
 
   Generator *GetGenerator();
   Loader *GetLoader();
@@ -170,12 +180,15 @@ public:
   const Generator *GetGenerator() const;
   const Loader *GetLoader() const;
 
+  FileSpec GetReproducerPath() const;
+
+protected:
   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;
 
diff --git a/lldb/lit/Reproducer/Inputs/GDBRemoteCapture.in b/lldb/lit/Reproducer/Inputs/GDBRemoteCapture.in
new file mode 100644 (file)
index 0000000..8df7ca4
--- /dev/null
@@ -0,0 +1,6 @@
+breakpoint set -f simple.c -l 13
+run
+bt
+cont
+reproducer status
+reproducer generate
diff --git a/lldb/lit/Reproducer/Inputs/GDBRemoteReplay.in b/lldb/lit/Reproducer/Inputs/GDBRemoteReplay.in
new file mode 100644 (file)
index 0000000..1364c7e
--- /dev/null
@@ -0,0 +1,5 @@
+reproducer status
+breakpoint set -f simple.c -l 13
+run
+bt
+cont
diff --git a/lldb/lit/Reproducer/Inputs/simple.c b/lldb/lit/Reproducer/Inputs/simple.c
new file mode 100644 (file)
index 0000000..a4585b3
--- /dev/null
@@ -0,0 +1,19 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+void foo() {
+    printf("testing\n");
+}
+
+int main (int argc, char const *argv[]) {
+    foo();
+    return 0;
+}
diff --git a/lldb/lit/Reproducer/TestDriverOptions.test b/lldb/lit/Reproducer/TestDriverOptions.test
new file mode 100644 (file)
index 0000000..d7a0768
--- /dev/null
@@ -0,0 +1,7 @@
+# Check that errors are propagated to the driver.
+
+# RUN: not %lldb --capture /bogus 2>&1 | FileCheck %s --check-prefix CAPTURE
+# RUN: not %lldb --replay /bogus  2>&1 | FileCheck %s --check-prefix REPLAY
+
+# CAPTURE: unable to create reproducer directory
+# REPLAY: unable to load reproducer index
diff --git a/lldb/lit/Reproducer/TestGDBRemoteRepro.test b/lldb/lit/Reproducer/TestGDBRemoteRepro.test
new file mode 100644 (file)
index 0000000..6a6bdd7
--- /dev/null
@@ -0,0 +1,26 @@
+# UNSUPPORTED: system-windows, system-freebsd
+
+# 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
+# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture %T/reproducer -- %t.out | FileCheck %s --check-prefix CHECK --check-prefix CAPTURE
+# 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
+
+# CAPTURE: testing
+# REPLAY-NOT: testing
+
+# CHECK: Process {{.*}} resuming
+# CHECK: Process {{.*}} exited
+
+# CAPTURE: Reproducer is in capture mode.
+# CAPTURE: Reproducer written
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile
deleted file mode 100644 (file)
index b09a579..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-LEVEL = ../../../make
-
-C_SOURCES := main.c
-
-include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py b/lldb/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py
deleted file mode 100644 (file)
index adbbd1b..0000000
+++ /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 18796e8..fde3d7b 100644 (file)
@@ -124,6 +124,9 @@ public:
     Initialize();
 
     static void
+    Initialize(lldb::SBInitializerOptions& options);
+
+    static void
     Terminate();
 
     static lldb::SBDebugger
@@ -376,9 +379,6 @@ public:
     const char *
     GetReproducerPath() const;
 
-    lldb::SBError
-    ReplayReproducer (const char *path);
-
     lldb::ScriptLanguage
     GetScriptLanguage() const;
 
diff --git a/lldb/scripts/interface/SBInitializerOptions.i b/lldb/scripts/interface/SBInitializerOptions.i
new file mode 100644 (file)
index 0000000..9478642
--- /dev/null
@@ -0,0 +1,24 @@
+//===-- 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 ();
+  SBInitializerOptions (const lldb::SBInitializerOptions &rhs);
+  ~SBInitializerOptions();
+
+  void SetCaptureReproducer(bool b);
+  void SetReplayReproducer(bool b);
+  void SetReproducerPath(const char* path);
+};
+
+} // namespace lldb
index e920718..e8553d0 100644 (file)
@@ -187,6 +187,7 @@ import six
 %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 3c5f4dd..d2ab24c 100644 (file)
@@ -29,6 +29,7 @@ add_lldb_library(liblldb SHARED
   SBFrame.cpp
   SBFunction.cpp
   SBHostOS.cpp
+  SBInitializerOptions.cpp
   SBInstruction.cpp
   SBInstructionList.cpp
   SBLanguageRuntime.cpp
index a721796..af34323 100644 (file)
@@ -125,13 +125,23 @@ SBDebugger &SBDebugger::operator=(const SBDebugger &rhs) {
 }
 
 void SBDebugger::Initialize() {
+  SBInitializerOptions options;
+  SBDebugger::Initialize(options);
+}
+
+lldb::SBError 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);
+  SBError error;
+  if (auto e = g_debugger_lifetime->Initialize(
+          llvm::make_unique<SystemInitializerFull>(), *options.m_opaque_up,
+          LoadPlugin)) {
+    error.SetError(Status(std::move(e)));
+  }
+  return error;
 }
 
 void SBDebugger::Terminate() { g_debugger_lifetime->Terminate(); }
@@ -1057,17 +1067,6 @@ const char *SBDebugger::GetReproducerPath() const {
               : 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);
 }
diff --git a/lldb/source/API/SBInitializerOptions.cpp b/lldb/source/API/SBInitializerOptions.cpp
new file mode 100644 (file)
index 0000000..8d8ec28
--- /dev/null
@@ -0,0 +1,49 @@
+//===-- 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"
+#include "lldb/Initialization/SystemInitializer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBInitializerOptions::SBInitializerOptions(const SBInitializerOptions &rhs) {
+  m_opaque_up.reset(new InitializerOptions());
+  *(m_opaque_up.get()) = rhs.ref();
+}
+
+const SBInitializerOptions &SBInitializerOptions::
+operator=(const SBInitializerOptions &rhs) {
+  if (this != &rhs) {
+    this->ref() = rhs.ref();
+  }
+  return *this;
+}
+
+SBInitializerOptions::~SBInitializerOptions() {}
+
+SBInitializerOptions::SBInitializerOptions() {
+  m_opaque_up.reset(new InitializerOptions());
+}
+
+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;
+}
+
+InitializerOptions &SBInitializerOptions::ref() const {
+  return *(m_opaque_up.get());
+}
index 671077c..9376044 100644 (file)
@@ -263,8 +263,10 @@ SystemInitializerFull::SystemInitializerFull() {}
 
 SystemInitializerFull::~SystemInitializerFull() {}
 
-void SystemInitializerFull::Initialize() {
-  SystemInitializerCommon::Initialize();
+llvm::Error
+SystemInitializerFull::Initialize(const InitializerOptions &options) {
+  if (auto e = SystemInitializerCommon::Initialize(options))
+    return e;
 
   ObjectFileELF::Initialize();
   ObjectFileMachO::Initialize();
@@ -396,6 +398,8 @@ void SystemInitializerFull::Initialize() {
   // AFTER PluginManager::Initialize is called.
 
   Debugger::SettingsInitialize();
+
+  return llvm::Error::success();
 }
 
 void SystemInitializerFull::InitializeSWIG() {
index 9cfc689..b0cf476 100644 (file)
@@ -26,7 +26,7 @@ public:
   SystemInitializerFull();
   ~SystemInitializerFull() override;
 
-  void Initialize() override;
+  llvm::Error Initialize(const InitializerOptions &options) override;
   void Terminate() override;
 
 private:
index 03a3e23..f393f17 100644 (file)
 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 @@ protected:
   }
 };
 
-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 1f12dc4..6e86519 100644 (file)
@@ -418,24 +418,6 @@ llvm::StringRef Debugger::GetReproducerPath() const {
   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 e82fec3..34c362e 100644 (file)
@@ -194,19 +194,6 @@ FileSpec HostInfoBase::GetGlobalTempDir() {
   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 @@ bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
   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 221dc8c..d1d55fc 100644 (file)
@@ -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__)
 #include <string>
 
 using namespace lldb_private;
+using namespace lldb_private::repro;
 
 SystemInitializerCommon::SystemInitializerCommon() {}
 
 SystemInitializerCommon::~SystemInitializerCommon() {}
 
-void SystemInitializerCommon::Initialize() {
+llvm::Error
+SystemInitializerCommon::Initialize(const InitializerOptions &options) {
 #if defined(_MSC_VER)
   const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
   if (disable_crash_dialog_var &&
@@ -63,6 +66,15 @@ void SystemInitializerCommon::Initialize() {
   }
 #endif
 
+  ReproducerMode mode = ReproducerMode::Off;
+  if (options.reproducer_capture)
+    mode = ReproducerMode::Capture;
+  if (options.reproducer_replay)
+    mode = ReproducerMode::Replay;
+
+  if (auto e = Reproducer::Initialize(mode, FileSpec(options.reproducer_path)))
+    return e;
+
   FileSystem::Initialize();
   Log::Initialize();
   HostInfo::Initialize();
@@ -89,6 +101,8 @@ void SystemInitializerCommon::Initialize() {
 #if defined(_MSC_VER)
   ProcessWindowsLog::Initialize();
 #endif
+
+  return llvm::Error::success();
 }
 
 void SystemInitializerCommon::Terminate() {
@@ -109,4 +123,5 @@ void SystemInitializerCommon::Terminate() {
   HostInfo::Terminate();
   Log::DisableAllLogChannels();
   FileSystem::Terminate();
+  Reproducer::Terminate();
 }
index 4d27178..65431bf 100644 (file)
@@ -24,9 +24,9 @@ SystemLifetimeManager::~SystemLifetimeManager() {
          "SystemLifetimeManager destroyed without calling Terminate!");
 }
 
-void SystemLifetimeManager::Initialize(
+llvm::Error SystemLifetimeManager::Initialize(
     std::unique_ptr<SystemInitializer> initializer,
-    LoadPluginCallbackType plugin_callback) {
+    const InitializerOptions &options, LoadPluginCallbackType plugin_callback) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   if (!m_initialized) {
     assert(!m_initializer && "Attempting to call "
@@ -35,9 +35,13 @@ void SystemLifetimeManager::Initialize(
     m_initialized = true;
     m_initializer = std::move(initializer);
 
-    m_initializer->Initialize();
+    if (auto e = m_initializer->Initialize(options))
+      return e;
+
     Debugger::Initialize(plugin_callback);
   }
+
+  return llvm::Error::success();
 }
 
 void SystemLifetimeManager::Terminate() {
index 0048a11..a6b5fa8 100644 (file)
@@ -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,8 +19,46 @@ using namespace lldb_private::repro;
 using namespace llvm;
 using namespace llvm::yaml;
 
-Reproducer &Reproducer::Instance() {
-  static Reproducer g_reproducer;
+Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
+
+llvm::Error Reproducer::Initialize(ReproducerMode mode,
+                                   llvm::Optional<FileSpec> root) {
+  lldbassert(!InstanceImpl() && "Already initialized.");
+  InstanceImpl().emplace();
+
+  switch (mode) {
+  case ReproducerMode::Capture: {
+    if (!root) {
+      SmallString<128> repro_dir;
+      auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir);
+      if (ec)
+        return make_error<StringError>(
+            "unable to create unique reproducer directory", ec);
+      root.emplace(repro_dir);
+    } else {
+      auto ec = sys::fs::create_directories(root->GetPath());
+      if (ec)
+        return make_error<StringError>("unable to create reproducer directory",
+                                       ec);
+    }
+    return Instance().SetCapture(root);
+  } break;
+  case ReproducerMode::Replay:
+    return Instance().SetReplay(root);
+  case ReproducerMode::Off:
+    break;
+  };
+
+  return Error::success();
+}
+
+void Reproducer::Terminate() {
+  lldbassert(InstanceImpl() && "Already terminated.");
+  InstanceImpl().reset();
+}
+
+Optional<Reproducer> &Reproducer::InstanceImpl() {
+  static Optional<Reproducer> g_reproducer;
   return g_reproducer;
 }
 
@@ -59,11 +98,12 @@ llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
         "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 +115,15 @@ llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) {
         "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();
 }
 
@@ -153,14 +194,14 @@ llvm::Error Loader::LoadIndex() {
 
   auto error_or_file = MemoryBuffer::getFile(index.GetPath());
   if (auto err = error_or_file.getError())
-    return errorCodeToError(err);
+    return make_error<StringError>("unable to load reproducer index", err);
 
   std::vector<ProviderInfo> provider_info;
   yaml::Input yin((*error_or_file)->getBuffer());
   yin >> provider_info;
 
   if (auto err = yin.error())
-    return errorCodeToError(err);
+    return make_error<StringError>("unable to read reproducer index", err);
 
   for (auto &info : provider_info)
     m_provider_info[info.name] = info;
index 6371030..cd61cf6 100644 (file)
@@ -367,21 +367,6 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
     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,27 @@ main(int argc, char const *argv[])
                          << '\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);
+  }
+
+  SBError error = SBDebugger::Initialize(options);
+  if (error.Fail()) {
+    WithColor::error() << "initialization failed: " << error.GetCString()
+                       << '\n';
+    return 1;
+  }
+
   SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
 
   signal(SIGINT, sigint_handler);
index 90df963..4a2ddfe 100644 (file)
@@ -209,11 +209,11 @@ def: Flag<["-"], "d">,
   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 aeaf382..93ef4d9 100644 (file)
@@ -22,9 +22,14 @@ using HostObjectFile = ObjectFileELF;
 
 using namespace lldb_private;
 
-void SystemInitializerLLGS::Initialize() {
-  SystemInitializerCommon::Initialize();
+llvm::Error
+SystemInitializerLLGS::Initialize(const InitializerOptions &options) {
+  if (auto e = SystemInitializerCommon::Initialize(options))
+    return e;
+
   HostObjectFile::Initialize();
+
+  return llvm::Error::success();
 }
 
 void SystemInitializerLLGS::Terminate() {
index e6460a2..7feba3f 100644 (file)
 #ifndef LLDB_SYSTEMINITIALIZERLLGS_H
 #define LLDB_SYSTEMINITIALIZERLLGS_H
 
+#include "lldb/Initialization/SystemInitializer.h"
 #include "lldb/Initialization/SystemInitializerCommon.h"
 
 class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon {
 public:
-  void Initialize() override;
+  llvm::Error
+  Initialize(const lldb_private::InitializerOptions &options) override;
   void Terminate() override;
 };
 
index f05c96c..c924fa2 100644 (file)
@@ -38,8 +38,9 @@ int main_gdbserver(int argc, char *argv[]);
 int main_platform(int argc, char *argv[]);
 
 static void initialize() {
-  g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerLLGS>(),
-                                  nullptr);
+  if (auto e = g_debugger_lifetime->Initialize(
+          llvm::make_unique<SystemInitializerLLGS>(), {}, nullptr))
+    llvm::consumeError(std::move(e));
 }
 
 static void terminate() { g_debugger_lifetime->Terminate(); }
index 750f9c3..8f549bc 100644 (file)
@@ -111,8 +111,10 @@ SystemInitializerTest::SystemInitializerTest() {}
 
 SystemInitializerTest::~SystemInitializerTest() {}
 
-void SystemInitializerTest::Initialize() {
-  SystemInitializerCommon::Initialize();
+llvm::Error
+SystemInitializerTest::Initialize(const InitializerOptions &options) {
+  if (auto e = SystemInitializerCommon::Initialize(options))
+    return e;
 
   ObjectFileELF::Initialize();
   ObjectFileMachO::Initialize();
@@ -231,6 +233,8 @@ void SystemInitializerTest::Initialize() {
   // AFTER PluginManager::Initialize is called.
 
   Debugger::SettingsInitialize();
+
+  return llvm::Error::success();
 }
 
 void SystemInitializerTest::Terminate() {
index 887d624..5950ff7 100644 (file)
@@ -26,7 +26,7 @@ public:
   SystemInitializerTest();
   ~SystemInitializerTest() override;
 
-  void Initialize() override;
+  llvm::Error Initialize(const InitializerOptions &options) override;
   void Terminate() override;
 };
 
index 631e6a5..25ee168 100644 (file)
@@ -934,8 +934,13 @@ int main(int argc, const char *argv[]) {
   cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
 
   SystemLifetimeManager DebuggerLifetime;
-  DebuggerLifetime.Initialize(llvm::make_unique<SystemInitializerTest>(),
-                              nullptr);
+  if (auto e = DebuggerLifetime.Initialize(
+          llvm::make_unique<SystemInitializerTest>(), {}, nullptr)) {
+    WithColor::error() << "initialization failed: " << toString(std::move(e))
+                       << '\n';
+    return 1;
+  }
+
   CleanUp TerminateDebugger([&] { DebuggerLifetime.Terminate(); });
 
   auto Dbg = lldb_private::Debugger::CreateInstance();
index 29d65e5..aadb92b 100644 (file)
@@ -32,10 +32,18 @@ public:
   static char ID;
 };
 
+class DummyReproducer : public Reproducer {
+public:
+  DummyReproducer() : Reproducer(){};
+
+  using Reproducer::SetCapture;
+  using Reproducer::SetReplay;
+};
+
 char DummyProvider::ID = 0;
 
 TEST(ReproducerTest, SetCapture) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   // Initially both generator and loader are unset.
   EXPECT_EQ(nullptr, reproducer.GetGenerator());
@@ -59,7 +67,7 @@ TEST(ReproducerTest, SetCapture) {
 }
 
 TEST(ReproducerTest, SetReplay) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   // Initially both generator and loader are unset.
   EXPECT_EQ(nullptr, reproducer.GetGenerator());
@@ -80,7 +88,7 @@ TEST(ReproducerTest, SetReplay) {
 }
 
 TEST(GeneratorTest, Create) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                     Succeeded());
@@ -95,7 +103,7 @@ TEST(GeneratorTest, Create) {
 }
 
 TEST(GeneratorTest, Get) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                     Succeeded());
@@ -109,7 +117,7 @@ TEST(GeneratorTest, Get) {
 }
 
 TEST(GeneratorTest, GetOrCreate) {
-  Reproducer reproducer;
+  DummyReproducer reproducer;
 
   EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                     Succeeded());