mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-05-17 11:26:37 +00:00

When I landed the initial reproducer framework I knew there were some things that needed improvement. Rather than bundling it with a patch that adds more functionality I split it off into this patch. I also think the API is stable enough to add unit testing, which is included in this patch as well. Other improvements include: - Refactor how we initialize the loader and generator. - Improve naming consistency: capture and replay seems the least ambiguous. - Index providers by name and make sure there's only one of each. - Add convenience methods for creating and accessing providers. Differential revision: https://reviews.llvm.org/D54616 llvm-svn: 347716
192 lines
6.4 KiB
C++
192 lines
6.4 KiB
C++
//===-- CommandObjectReproducer.cpp -----------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CommandObjectReproducer.h"
|
|
|
|
#include "lldb/Utility/Reproducer.h"
|
|
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
|
#include "lldb/Interpreter/OptionArgParser.h"
|
|
#include "lldb/Interpreter/OptionGroupBoolean.h"
|
|
|
|
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)
|
|
: CommandObjectParsed(interpreter, "reproducer generate",
|
|
"Generate reproducer on disk.", nullptr) {}
|
|
|
|
~CommandObjectReproducerGenerate() 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;
|
|
}
|
|
|
|
auto &r = repro::Reproducer::Instance();
|
|
if (auto generator = r.GetGenerator()) {
|
|
generator->Keep();
|
|
} else {
|
|
result.AppendErrorWithFormat("Unable to get the reproducer generator");
|
|
return false;
|
|
}
|
|
|
|
result.GetOutputStream()
|
|
<< "Reproducer written to '" << r.GetReproducerPath() << "'\n";
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectReproducerReplay : 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);
|
|
}
|
|
|
|
~CommandObjectReproducerReplay() 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());
|
|
return false;
|
|
}
|
|
|
|
auto &r = repro::Reproducer::Instance();
|
|
|
|
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.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
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)));
|
|
}
|
|
|
|
CommandObjectReproducer::~CommandObjectReproducer() = default;
|