Index: lldb/trunk/include/lldb/API/SBDebugger.h =================================================================== --- lldb/trunk/include/lldb/API/SBDebugger.h +++ lldb/trunk/include/lldb/API/SBDebugger.h @@ -13,6 +13,7 @@ #include #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 lldb::SBError 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); Index: lldb/trunk/include/lldb/API/SBDefines.h =================================================================== --- lldb/trunk/include/lldb/API/SBDefines.h +++ lldb/trunk/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: lldb/trunk/include/lldb/API/SBFileSpec.h =================================================================== --- lldb/trunk/include/lldb/API/SBFileSpec.h +++ lldb/trunk/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: lldb/trunk/include/lldb/API/SBInitializerOptions.h =================================================================== --- lldb/trunk/include/lldb/API/SBInitializerOptions.h +++ lldb/trunk/include/lldb/API/SBInitializerOptions.h @@ -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 m_opaque_up; +}; + +} // namespace lldb + +#endif // LLDB_SBInitializerOptuions_h_ Index: lldb/trunk/include/lldb/Core/Debugger.h =================================================================== --- lldb/trunk/include/lldb/Core/Debugger.h +++ lldb/trunk/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: lldb/trunk/include/lldb/Host/HostInfoBase.h =================================================================== --- lldb/trunk/include/lldb/Host/HostInfoBase.h +++ lldb/trunk/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: lldb/trunk/include/lldb/Initialization/SystemInitializer.h =================================================================== --- lldb/trunk/include/lldb/Initialization/SystemInitializer.h +++ lldb/trunk/include/lldb/Initialization/SystemInitializer.h @@ -10,13 +10,24 @@ #ifndef LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H #define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H +#include "llvm/Support/Error.h" + +#include + 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: lldb/trunk/include/lldb/Initialization/SystemInitializerCommon.h =================================================================== --- lldb/trunk/include/lldb/Initialization/SystemInitializerCommon.h +++ lldb/trunk/include/lldb/Initialization/SystemInitializerCommon.h @@ -28,7 +28,7 @@ SystemInitializerCommon(); ~SystemInitializerCommon() override; - void Initialize() override; + llvm::Error Initialize(const InitializerOptions &options) override; void Terminate() override; }; Index: lldb/trunk/include/lldb/Initialization/SystemLifetimeManager.h =================================================================== --- lldb/trunk/include/lldb/Initialization/SystemLifetimeManager.h +++ lldb/trunk/include/lldb/Initialization/SystemLifetimeManager.h @@ -10,21 +10,23 @@ #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 #include namespace lldb_private { -class SystemInitializer; class SystemLifetimeManager { public: SystemLifetimeManager(); ~SystemLifetimeManager(); - void Initialize(std::unique_ptr initializer, - LoadPluginCallbackType plugin_callback); + llvm::Error Initialize(std::unique_ptr initializer, + const InitializerOptions &options, + LoadPluginCallbackType plugin_callback); void Terminate(); private: Index: lldb/trunk/include/lldb/Utility/Reproducer.h =================================================================== --- lldb/trunk/include/lldb/Utility/Reproducer.h +++ lldb/trunk/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,14 @@ /// 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 root); + static void Terminate(); + + Reproducer() = default; Generator *GetGenerator(); Loader *GetLoader(); @@ -170,12 +180,15 @@ const Generator *GetGenerator() const; const Loader *GetLoader() const; + FileSpec GetReproducerPath() const; + +protected: llvm::Error SetCapture(llvm::Optional root); llvm::Error SetReplay(llvm::Optional root); - FileSpec GetReproducerPath() const; - private: + static llvm::Optional &InstanceImpl(); + llvm::Optional m_generator; llvm::Optional m_loader; Index: lldb/trunk/lit/Reproducer/Inputs/GDBRemoteCapture.in =================================================================== --- lldb/trunk/lit/Reproducer/Inputs/GDBRemoteCapture.in +++ lldb/trunk/lit/Reproducer/Inputs/GDBRemoteCapture.in @@ -0,0 +1,6 @@ +breakpoint set -f simple.c -l 13 +run +bt +cont +reproducer status +reproducer generate Index: lldb/trunk/lit/Reproducer/Inputs/GDBRemoteReplay.in =================================================================== --- lldb/trunk/lit/Reproducer/Inputs/GDBRemoteReplay.in +++ lldb/trunk/lit/Reproducer/Inputs/GDBRemoteReplay.in @@ -0,0 +1,5 @@ +reproducer status +breakpoint set -f simple.c -l 13 +run +bt +cont Index: lldb/trunk/lit/Reproducer/Inputs/simple.c =================================================================== --- lldb/trunk/lit/Reproducer/Inputs/simple.c +++ lldb/trunk/lit/Reproducer/Inputs/simple.c @@ -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 + +void foo() { + printf("testing\n"); +} + +int main (int argc, char const *argv[]) { + foo(); + return 0; +} Index: lldb/trunk/lit/Reproducer/TestDriverOptions.test =================================================================== --- lldb/trunk/lit/Reproducer/TestDriverOptions.test +++ lldb/trunk/lit/Reproducer/TestDriverOptions.test @@ -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 Index: lldb/trunk/lit/Reproducer/TestGDBRemoteRepro.test =================================================================== --- lldb/trunk/lit/Reproducer/TestGDBRemoteRepro.test +++ lldb/trunk/lit/Reproducer/TestGDBRemoteRepro.test @@ -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 Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/Makefile @@ -1,5 +0,0 @@ -LEVEL = ../../../make - -C_SOURCES := main.c - -include $(LEVEL)/Makefile.rules Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/reproducer/gdb-remote/TestGdbRemoteReproducer.py @@ -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: lldb/trunk/scripts/interface/SBDebugger.i =================================================================== --- lldb/trunk/scripts/interface/SBDebugger.i +++ lldb/trunk/scripts/interface/SBDebugger.i @@ -124,6 +124,9 @@ Initialize(); static void + Initialize(lldb::SBInitializerOptions& options); + + static void Terminate(); static lldb::SBDebugger @@ -376,9 +379,6 @@ const char * GetReproducerPath() const; - lldb::SBError - ReplayReproducer (const char *path); - lldb::ScriptLanguage GetScriptLanguage() const; Index: lldb/trunk/scripts/interface/SBInitializerOptions.i =================================================================== --- lldb/trunk/scripts/interface/SBInitializerOptions.i +++ lldb/trunk/scripts/interface/SBInitializerOptions.i @@ -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: lldb/trunk/scripts/lldb.swig =================================================================== --- lldb/trunk/scripts/lldb.swig +++ lldb/trunk/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: lldb/trunk/source/API/CMakeLists.txt =================================================================== --- lldb/trunk/source/API/CMakeLists.txt +++ lldb/trunk/source/API/CMakeLists.txt @@ -29,6 +29,7 @@ SBFrame.cpp SBFunction.cpp SBHostOS.cpp + SBInitializerOptions.cpp SBInstruction.cpp SBInstructionList.cpp SBLanguageRuntime.cpp Index: lldb/trunk/source/API/SBDebugger.cpp =================================================================== --- lldb/trunk/source/API/SBDebugger.cpp +++ lldb/trunk/source/API/SBDebugger.cpp @@ -125,13 +125,23 @@ } 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(), - LoadPlugin); + SBError error; + if (auto e = g_debugger_lifetime->Initialize( + llvm::make_unique(), *options.m_opaque_up, + LoadPlugin)) { + error.SetError(Status(std::move(e))); + } + return error; } void SBDebugger::Terminate() { g_debugger_lifetime->Terminate(); } @@ -1057,17 +1067,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: lldb/trunk/source/API/SBInitializerOptions.cpp =================================================================== --- lldb/trunk/source/API/SBInitializerOptions.cpp +++ lldb/trunk/source/API/SBInitializerOptions.cpp @@ -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: lldb/trunk/source/API/SystemInitializerFull.h =================================================================== --- lldb/trunk/source/API/SystemInitializerFull.h +++ lldb/trunk/source/API/SystemInitializerFull.h @@ -26,7 +26,7 @@ SystemInitializerFull(); ~SystemInitializerFull() override; - void Initialize() override; + llvm::Error Initialize(const InitializerOptions &options) override; void Terminate() override; private: Index: lldb/trunk/source/API/SystemInitializerFull.cpp =================================================================== --- lldb/trunk/source/API/SystemInitializerFull.cpp +++ lldb/trunk/source/API/SystemInitializerFull.cpp @@ -263,8 +263,10 @@ 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 @@ // AFTER PluginManager::Initialize is called. Debugger::SettingsInitialize(); + + return llvm::Error::success(); } void SystemInitializerFull::InitializeSWIG() { Index: lldb/trunk/source/Commands/CommandObjectReproducer.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectReproducer.cpp +++ lldb/trunk/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 []") { - 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: lldb/trunk/source/Core/Debugger.cpp =================================================================== --- lldb/trunk/source/Core/Debugger.cpp +++ lldb/trunk/source/Core/Debugger.cpp @@ -418,24 +418,6 @@ return r.GetReproducerPath().GetCString(); } -llvm::Error Debugger::SetReproducerReplay(llvm::StringRef p) { - llvm::Optional arg = llvm::None; - - if (!p.empty()) - arg = FileSpec(p); - - return repro::Reproducer::Instance().SetReplay(arg); -} - -llvm::Error Debugger::SetReproducerCapture(bool b) { - llvm::Optional 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: lldb/trunk/source/Host/common/HostInfoBase.cpp =================================================================== --- lldb/trunk/source/Host/common/HostInfoBase.cpp +++ lldb/trunk/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: lldb/trunk/source/Initialization/SystemInitializerCommon.cpp =================================================================== --- lldb/trunk/source/Initialization/SystemInitializerCommon.cpp +++ lldb/trunk/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,14 @@ #include 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 @@ } #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 @@ #if defined(_MSC_VER) ProcessWindowsLog::Initialize(); #endif + + return llvm::Error::success(); } void SystemInitializerCommon::Terminate() { @@ -109,4 +123,5 @@ HostInfo::Terminate(); Log::DisableAllLogChannels(); FileSystem::Terminate(); + Reproducer::Terminate(); } Index: lldb/trunk/source/Initialization/SystemLifetimeManager.cpp =================================================================== --- lldb/trunk/source/Initialization/SystemLifetimeManager.cpp +++ lldb/trunk/source/Initialization/SystemLifetimeManager.cpp @@ -24,9 +24,9 @@ "SystemLifetimeManager destroyed without calling Terminate!"); } -void SystemLifetimeManager::Initialize( +llvm::Error SystemLifetimeManager::Initialize( std::unique_ptr initializer, - LoadPluginCallbackType plugin_callback) { + const InitializerOptions &options, LoadPluginCallbackType plugin_callback) { std::lock_guard guard(m_mutex); if (!m_initialized) { assert(!m_initializer && "Attempting to call " @@ -35,9 +35,13 @@ 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: lldb/trunk/source/Utility/Reproducer.cpp =================================================================== --- lldb/trunk/source/Utility/Reproducer.cpp +++ lldb/trunk/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,8 +19,46 @@ 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 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( + "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("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::InstanceImpl() { + static Optional g_reproducer; return g_reproducer; } @@ -59,11 +98,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 +115,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(); } @@ -153,14 +194,14 @@ auto error_or_file = MemoryBuffer::getFile(index.GetPath()); if (auto err = error_or_file.getError()) - return errorCodeToError(err); + return make_error("unable to load reproducer index", err); std::vector provider_info; yaml::Input yin((*error_or_file)->getBuffer()); yin >> provider_info; if (auto err = yin.error()) - return errorCodeToError(err); + return make_error("unable to read reproducer index", err); for (auto &info : provider_info) m_provider_info[info.name] = info; Index: lldb/trunk/tools/driver/Driver.cpp =================================================================== --- lldb/trunk/tools/driver/Driver.cpp +++ lldb/trunk/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,27 @@ << '\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(""); signal(SIGINT, sigint_handler); Index: lldb/trunk/tools/driver/Options.td =================================================================== --- lldb/trunk/tools/driver/Options.td +++ lldb/trunk/tools/driver/Options.td @@ -209,11 +209,11 @@ Alias, HelpText<"Alias for --debug">; -def reproducer: Separate<["--", "-"], "reproducer">, +def capture: Separate<["--", "-"], "capture">, MetaVarName<"">, - HelpText<"Tells the debugger to use the fullpath to as a reproducer.">; -def: Separate<["-"], "z">, - Alias, - HelpText<"Alias for --reproducer">; + HelpText<"Tells the debugger to capture a reproducer to .">; +def replay: Separate<["--", "-"], "replay">, + MetaVarName<"">, + HelpText<"Tells the debugger to replay a reproducer from .">; def REM : R<["--"], "">; Index: lldb/trunk/tools/lldb-server/SystemInitializerLLGS.h =================================================================== --- lldb/trunk/tools/lldb-server/SystemInitializerLLGS.h +++ lldb/trunk/tools/lldb-server/SystemInitializerLLGS.h @@ -10,11 +10,13 @@ #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: lldb/trunk/tools/lldb-server/SystemInitializerLLGS.cpp =================================================================== --- lldb/trunk/tools/lldb-server/SystemInitializerLLGS.cpp +++ lldb/trunk/tools/lldb-server/SystemInitializerLLGS.cpp @@ -22,9 +22,14 @@ 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: lldb/trunk/tools/lldb-server/lldb-server.cpp =================================================================== --- lldb/trunk/tools/lldb-server/lldb-server.cpp +++ lldb/trunk/tools/lldb-server/lldb-server.cpp @@ -38,8 +38,9 @@ int main_platform(int argc, char *argv[]); static void initialize() { - g_debugger_lifetime->Initialize(llvm::make_unique(), - nullptr); + if (auto e = g_debugger_lifetime->Initialize( + llvm::make_unique(), {}, nullptr)) + llvm::consumeError(std::move(e)); } static void terminate() { g_debugger_lifetime->Terminate(); } Index: lldb/trunk/tools/lldb-test/SystemInitializerTest.h =================================================================== --- lldb/trunk/tools/lldb-test/SystemInitializerTest.h +++ lldb/trunk/tools/lldb-test/SystemInitializerTest.h @@ -26,7 +26,7 @@ SystemInitializerTest(); ~SystemInitializerTest() override; - void Initialize() override; + llvm::Error Initialize(const InitializerOptions &options) override; void Terminate() override; }; Index: lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp =================================================================== --- lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp +++ lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp @@ -111,8 +111,10 @@ 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 @@ // AFTER PluginManager::Initialize is called. Debugger::SettingsInitialize(); + + return llvm::Error::success(); } void SystemInitializerTest::Terminate() { Index: lldb/trunk/tools/lldb-test/lldb-test.cpp =================================================================== --- lldb/trunk/tools/lldb-test/lldb-test.cpp +++ lldb/trunk/tools/lldb-test/lldb-test.cpp @@ -934,8 +934,13 @@ cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n"); SystemLifetimeManager DebuggerLifetime; - DebuggerLifetime.Initialize(llvm::make_unique(), - nullptr); + if (auto e = DebuggerLifetime.Initialize( + llvm::make_unique(), {}, nullptr)) { + WithColor::error() << "initialization failed: " << toString(std::move(e)) + << '\n'; + return 1; + } + CleanUp TerminateDebugger([&] { DebuggerLifetime.Terminate(); }); auto Dbg = lldb_private::Debugger::CreateInstance(); Index: lldb/trunk/unittests/Utility/ReproducerTest.cpp =================================================================== --- lldb/trunk/unittests/Utility/ReproducerTest.cpp +++ lldb/trunk/unittests/Utility/ReproducerTest.cpp @@ -32,10 +32,18 @@ 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, SetReplay) { - Reproducer reproducer; + DummyReproducer reproducer; // Initially both generator and loader are unset. EXPECT_EQ(nullptr, reproducer.GetGenerator()); @@ -80,7 +88,7 @@ } TEST(GeneratorTest, Create) { - Reproducer reproducer; + DummyReproducer reproducer; EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")), Succeeded()); @@ -95,7 +103,7 @@ } TEST(GeneratorTest, Get) { - Reproducer reproducer; + DummyReproducer reproducer; EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")), Succeeded()); @@ -109,7 +117,7 @@ } TEST(GeneratorTest, GetOrCreate) { - Reproducer reproducer; + DummyReproducer reproducer; EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")), Succeeded());