aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp216
1 files changed, 187 insertions, 29 deletions
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp
index 104130b70b2b..55f34c05d11d 100644
--- a/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp
@@ -27,10 +27,12 @@ using namespace lldb_private::repro;
enum ReproducerProvider {
eReproducerProviderCommands,
eReproducerProviderFiles,
+ eReproducerProviderSymbolFiles,
eReproducerProviderGDB,
eReproducerProviderProcessInfo,
eReproducerProviderVersion,
eReproducerProviderWorkingDirectory,
+ eReproducerProviderHomeDirectory,
eReproducerProviderNone
};
@@ -46,6 +48,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
"Files",
},
{
+ eReproducerProviderSymbolFiles,
+ "symbol-files",
+ "Symbol Files",
+ },
+ {
eReproducerProviderGDB,
"gdb",
"GDB Remote Packets",
@@ -66,6 +73,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
"Working Directory",
},
{
+ eReproducerProviderHomeDirectory,
+ "home",
+ "Home Directory",
+ },
+ {
eReproducerProviderNone,
"none",
"None",
@@ -104,6 +116,9 @@ static constexpr OptionEnumValues ReproducerSignalType() {
#define LLDB_OPTIONS_reproducer_xcrash
#include "CommandOptions.inc"
+#define LLDB_OPTIONS_reproducer_verify
+#include "CommandOptions.inc"
+
template <typename T>
llvm::Expected<T> static ReadFromYAML(StringRef filename) {
auto error_or_file = MemoryBuffer::getFile(filename);
@@ -122,6 +137,38 @@ llvm::Expected<T> static ReadFromYAML(StringRef filename) {
return t;
}
+static void SetError(CommandReturnObject &result, Error err) {
+ result.GetErrorStream().Printf("error: %s\n",
+ toString(std::move(err)).c_str());
+ result.SetStatus(eReturnStatusFailed);
+}
+
+/// Create a loader from the given path if specified. Otherwise use the current
+/// loader used for replay.
+static Loader *
+GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage,
+ CommandReturnObject &result,
+ FileSpec reproducer_path) {
+ if (reproducer_path) {
+ loader_storage.emplace(reproducer_path);
+ Loader *loader = &(*loader_storage);
+ if (Error err = loader->LoadIndex()) {
+ // This is a hard error and will set the result to eReturnStatusFailed.
+ SetError(result, std::move(err));
+ return nullptr;
+ }
+ return loader;
+ }
+
+ if (Loader *loader = Reproducer::Instance().GetLoader())
+ return loader;
+
+ // This is a soft error because this is expected to fail during capture.
+ result.SetError("Not specifying a reproducer is only support during replay.");
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return nullptr;
+}
+
class CommandObjectReproducerGenerate : public CommandObjectParsed {
public:
CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
@@ -145,6 +192,10 @@ protected:
auto &r = Reproducer::Instance();
if (auto generator = r.GetGenerator()) {
generator->Keep();
+ if (llvm::Error e = repro::Finalize(r.GetReproducerPath())) {
+ SetError(result, std::move(e));
+ return result.Succeeded();
+ }
} else if (r.IsReplaying()) {
// Make this operation a NO-OP in replay mode.
result.SetStatus(eReturnStatusSuccessFinishNoResult);
@@ -300,12 +351,6 @@ protected:
}
};
-static void SetError(CommandReturnObject &result, Error err) {
- result.GetErrorStream().Printf("error: %s\n",
- toString(std::move(err)).c_str());
- result.SetStatus(eReturnStatusFailed);
-}
-
class CommandObjectReproducerDump : public CommandObjectParsed {
public:
CommandObjectReproducerDump(CommandInterpreter &interpreter)
@@ -370,29 +415,11 @@ protected:
return false;
}
- // If no reproducer path is specified, use the loader currently used for
- // replay. Otherwise create a new loader just for dumping.
llvm::Optional<Loader> loader_storage;
- Loader *loader = nullptr;
- if (!m_options.file) {
- loader = Reproducer::Instance().GetLoader();
- if (loader == nullptr) {
- result.SetError(
- "Not specifying a reproducer is only support during replay.");
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- return false;
- }
- } else {
- loader_storage.emplace(m_options.file);
- loader = &(*loader_storage);
- if (Error err = loader->LoadIndex()) {
- SetError(result, std::move(err));
- return false;
- }
- }
-
- // If we get here we should have a valid loader.
- assert(loader);
+ Loader *loader =
+ GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
+ if (!loader)
+ return false;
switch (m_options.provider) {
case eReproducerProviderFiles: {
@@ -421,6 +448,29 @@ protected:
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
+ case eReproducerProviderSymbolFiles: {
+ Expected<std::string> symbol_files =
+ loader->LoadBuffer<SymbolFileProvider>();
+ if (!symbol_files) {
+ SetError(result, symbol_files.takeError());
+ return false;
+ }
+
+ std::vector<SymbolFileProvider::Entry> entries;
+ llvm::yaml::Input yin(*symbol_files);
+ yin >> entries;
+
+ for (const auto &entry : entries) {
+ result.AppendMessageWithFormat("- uuid: %s\n",
+ entry.uuid.c_str());
+ result.AppendMessageWithFormat(" module path: %s\n",
+ entry.module_path.c_str());
+ result.AppendMessageWithFormat(" symbol path: %s\n",
+ entry.symbol_path.c_str());
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
case eReproducerProviderVersion: {
Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
if (!version) {
@@ -433,7 +483,7 @@ protected:
}
case eReproducerProviderWorkingDirectory: {
Expected<std::string> cwd =
- loader->LoadBuffer<WorkingDirectoryProvider>();
+ repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
if (!cwd) {
SetError(result, cwd.takeError());
return false;
@@ -442,6 +492,17 @@ protected:
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
+ case eReproducerProviderHomeDirectory: {
+ Expected<std::string> home =
+ repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
+ if (!home) {
+ SetError(result, home.takeError());
+ return false;
+ }
+ result.AppendMessage(*home);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
case eReproducerProviderCommands: {
std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
repro::MultiLoader<repro::CommandProvider>::Create(loader);
@@ -537,6 +598,101 @@ private:
CommandOptions m_options;
};
+class CommandObjectReproducerVerify : public CommandObjectParsed {
+public:
+ CommandObjectReproducerVerify(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "reproducer verify",
+ "Verify the contents of a reproducer. "
+ "If no reproducer is specified during replay, it "
+ "verifies the content of the current reproducer.",
+ nullptr) {}
+
+ ~CommandObjectReproducerVerify() override = default;
+
+ Options *GetOptions() override { return &m_options; }
+
+ class CommandOptions : public Options {
+ public:
+ CommandOptions() : Options(), file() {}
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 'f':
+ file.SetFile(option_arg, FileSpec::Style::native);
+ FileSystem::Instance().Resolve(file);
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ file.Clear();
+ }
+
+ ArrayRef<OptionDefinition> GetDefinitions() override {
+ return makeArrayRef(g_reproducer_verify_options);
+ }
+
+ FileSpec file;
+ };
+
+protected:
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ if (!command.empty()) {
+ result.AppendErrorWithFormat("'%s' takes no arguments",
+ m_cmd_name.c_str());
+ return false;
+ }
+
+ llvm::Optional<Loader> loader_storage;
+ Loader *loader =
+ GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
+ if (!loader)
+ return false;
+
+ bool errors = false;
+ auto error_callback = [&](llvm::StringRef error) {
+ errors = true;
+ result.AppendError(error);
+ };
+
+ bool warnings = false;
+ auto warning_callback = [&](llvm::StringRef warning) {
+ warnings = true;
+ result.AppendWarning(warning);
+ };
+
+ auto note_callback = [&](llvm::StringRef warning) {
+ result.AppendMessage(warning);
+ };
+
+ Verifier verifier(loader);
+ verifier.Verify(error_callback, warning_callback, note_callback);
+
+ if (warnings || errors) {
+ result.AppendMessage("reproducer verification failed");
+ result.SetStatus(eReturnStatusFailed);
+ } else {
+ result.AppendMessage("reproducer verification succeeded");
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
CommandObjectReproducer::CommandObjectReproducer(
CommandInterpreter &interpreter)
: CommandObjectMultiword(
@@ -559,6 +715,8 @@ CommandObjectReproducer::CommandObjectReproducer(
new CommandObjectReproducerStatus(interpreter)));
LoadSubCommand("dump",
CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
+ LoadSubCommand("verify", CommandObjectSP(
+ new CommandObjectReproducerVerify(interpreter)));
LoadSubCommand("xcrash", CommandObjectSP(
new CommandObjectReproducerXCrash(interpreter)));
}