#include <stdio.h>
#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBInitializerOptions.h"
#include "lldb/API/SBPlatform.h"
namespace lldb {
lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs);
static void Initialize();
+ static lldb::SBError Initialize(SBInitializerOptions &options);
static void Terminate();
const char *GetReproducerPath() const;
- lldb::SBError ReplayReproducer(const char *path);
-
lldb::ScriptLanguage GetScriptLanguage() const;
void SetScriptLanguage(lldb::ScriptLanguage script_lang);
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;
friend class SBDeclaration;
friend class SBFileSpecList;
friend class SBHostOS;
+ friend class SBInitializerOptions;
friend class SBLaunchInfo;
friend class SBLineEntry;
friend class SBModule;
friend class SBProcess;
friend class SBProcessInfo;
friend class SBSourceManager;
- friend class SBThread;
friend class SBTarget;
+ friend class SBThread;
SBFileSpec(const lldb_private::FileSpec &fspec);
--- /dev/null
+//===-- 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_
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);
/// 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
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);
#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;
};
}
SystemInitializerCommon();
~SystemInitializerCommon() override;
- void Initialize() override;
+ llvm::Error Initialize(const InitializerOptions &options) override;
void Terminate() override;
};
#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:
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 {
/// 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();
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;
--- /dev/null
+breakpoint set -f simple.c -l 13
+run
+bt
+cont
+reproducer status
+reproducer generate
--- /dev/null
+reproducer status
+breakpoint set -f simple.c -l 13
+run
+bt
+cont
--- /dev/null
+//===-- 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;
+}
--- /dev/null
+# 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
--- /dev/null
+# 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
+++ /dev/null
-LEVEL = ../../../make
-
-C_SOURCES := main.c
-
-include $(LEVEL)/Makefile.rules
+++ /dev/null
-"""
-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")
Initialize();
static void
+ Initialize(lldb::SBInitializerOptions& options);
+
+ static void
Terminate();
static lldb::SBDebugger
const char *
GetReproducerPath() const;
- lldb::SBError
- ReplayReproducer (const char *path);
-
lldb::ScriptLanguage
GetScriptLanguage() const;
--- /dev/null
+//===-- 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
%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"
SBFrame.cpp
SBFunction.cpp
SBHostOS.cpp
+ SBInitializerOptions.cpp
SBInstruction.cpp
SBInstructionList.cpp
SBLanguageRuntime.cpp
}
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(); }
: 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);
}
--- /dev/null
+//===-- 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());
+}
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();
// AFTER PluginManager::Initialize is called.
Debugger::SettingsInitialize();
+
+ return llvm::Error::success();
}
void SystemInitializerFull::InitializeSWIG() {
SystemInitializerFull();
~SystemInitializerFull() override;
- void Initialize() override;
+ llvm::Error Initialize(const InitializerOptions &options) override;
void Terminate() override;
private:
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)
}
};
-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;
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);
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();
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.
#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 &&
}
#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();
#if defined(_MSC_VER)
ProcessWindowsLog::Initialize();
#endif
+
+ return llvm::Error::success();
}
void SystemInitializerCommon::Terminate() {
HostInfo::Terminate();
Log::DisableAllLogChannels();
FileSystem::Terminate();
+ Reproducer::Terminate();
}
"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 "
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() {
//===----------------------------------------------------------------------===//
#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/LLDBAssert.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Threading.h"
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;
}
"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();
}
"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();
}
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;
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);
}
<< '\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);
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<["--"], "">;
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() {
#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;
};
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(); }
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();
// AFTER PluginManager::Initialize is called.
Debugger::SettingsInitialize();
+
+ return llvm::Error::success();
}
void SystemInitializerTest::Terminate() {
SystemInitializerTest();
~SystemInitializerTest() override;
- void Initialize() override;
+ llvm::Error Initialize(const InitializerOptions &options) override;
void Terminate() override;
};
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();
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());
}
TEST(ReproducerTest, SetReplay) {
- Reproducer reproducer;
+ DummyReproducer reproducer;
// Initially both generator and loader are unset.
EXPECT_EQ(nullptr, reproducer.GetGenerator());
}
TEST(GeneratorTest, Create) {
- Reproducer reproducer;
+ DummyReproducer reproducer;
EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
Succeeded());
}
TEST(GeneratorTest, Get) {
- Reproducer reproducer;
+ DummyReproducer reproducer;
EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
Succeeded());
}
TEST(GeneratorTest, GetOrCreate) {
- Reproducer reproducer;
+ DummyReproducer reproducer;
EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
Succeeded());