diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp | 216 |
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))); } |