19e046f02SJonas Devlieghere //===-- CommandObjectReproducer.cpp -----------------------------*- C++ -*-===// 29e046f02SJonas Devlieghere // 39e046f02SJonas Devlieghere // The LLVM Compiler Infrastructure 49e046f02SJonas Devlieghere // 59e046f02SJonas Devlieghere // This file is distributed under the University of Illinois Open Source 69e046f02SJonas Devlieghere // License. See LICENSE.TXT for details. 79e046f02SJonas Devlieghere // 89e046f02SJonas Devlieghere //===----------------------------------------------------------------------===// 99e046f02SJonas Devlieghere 109e046f02SJonas Devlieghere #include "CommandObjectReproducer.h" 119e046f02SJonas Devlieghere 129e046f02SJonas Devlieghere #include "lldb/Utility/Reproducer.h" 139e046f02SJonas Devlieghere 14*df14b942SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h" 159e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 169e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h" 179e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionGroupBoolean.h" 189e046f02SJonas Devlieghere 199e046f02SJonas Devlieghere using namespace lldb; 209e046f02SJonas Devlieghere using namespace lldb_private; 219e046f02SJonas Devlieghere 229e046f02SJonas Devlieghere static void AppendErrorToResult(llvm::Error e, CommandReturnObject &result) { 239e046f02SJonas Devlieghere std::string error_str = llvm::toString(std::move(e)); 249e046f02SJonas Devlieghere result.AppendErrorWithFormat("%s", error_str.c_str()); 259e046f02SJonas Devlieghere } 269e046f02SJonas Devlieghere 279e046f02SJonas Devlieghere class CommandObjectReproducerCaptureEnable : public CommandObjectParsed { 289e046f02SJonas Devlieghere public: 299e046f02SJonas Devlieghere CommandObjectReproducerCaptureEnable(CommandInterpreter &interpreter) 309e046f02SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer capture enable", 319e046f02SJonas Devlieghere "Enable gathering information for reproducer", 329e046f02SJonas Devlieghere nullptr) {} 339e046f02SJonas Devlieghere 349e046f02SJonas Devlieghere ~CommandObjectReproducerCaptureEnable() override = default; 359e046f02SJonas Devlieghere 369e046f02SJonas Devlieghere protected: 379e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 389e046f02SJonas Devlieghere if (!command.empty()) { 399e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 409e046f02SJonas Devlieghere m_cmd_name.c_str()); 419e046f02SJonas Devlieghere return false; 429e046f02SJonas Devlieghere } 439e046f02SJonas Devlieghere 44*df14b942SJonas Devlieghere if (auto e = m_interpreter.GetDebugger().SetReproducerCapture(true)) { 459e046f02SJonas Devlieghere AppendErrorToResult(std::move(e), result); 469e046f02SJonas Devlieghere return false; 479e046f02SJonas Devlieghere } 489e046f02SJonas Devlieghere 499e046f02SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 509e046f02SJonas Devlieghere return result.Succeeded(); 519e046f02SJonas Devlieghere } 529e046f02SJonas Devlieghere }; 539e046f02SJonas Devlieghere 549e046f02SJonas Devlieghere class CommandObjectReproducerCaptureDisable : public CommandObjectParsed { 559e046f02SJonas Devlieghere public: 569e046f02SJonas Devlieghere CommandObjectReproducerCaptureDisable(CommandInterpreter &interpreter) 579e046f02SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer capture enable", 589e046f02SJonas Devlieghere "Disable gathering information for reproducer", 599e046f02SJonas Devlieghere nullptr) {} 609e046f02SJonas Devlieghere 619e046f02SJonas Devlieghere ~CommandObjectReproducerCaptureDisable() override = default; 629e046f02SJonas Devlieghere 639e046f02SJonas Devlieghere protected: 649e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 659e046f02SJonas Devlieghere if (!command.empty()) { 669e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 679e046f02SJonas Devlieghere m_cmd_name.c_str()); 689e046f02SJonas Devlieghere return false; 699e046f02SJonas Devlieghere } 709e046f02SJonas Devlieghere 71*df14b942SJonas Devlieghere if (auto e = m_interpreter.GetDebugger().SetReproducerCapture(false)) { 729e046f02SJonas Devlieghere AppendErrorToResult(std::move(e), result); 739e046f02SJonas Devlieghere return false; 749e046f02SJonas Devlieghere } 759e046f02SJonas Devlieghere 769e046f02SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 779e046f02SJonas Devlieghere return result.Succeeded(); 789e046f02SJonas Devlieghere } 799e046f02SJonas Devlieghere }; 809e046f02SJonas Devlieghere 819e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed { 829e046f02SJonas Devlieghere public: 839e046f02SJonas Devlieghere CommandObjectReproducerGenerate(CommandInterpreter &interpreter) 849e046f02SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer generate", 859e046f02SJonas Devlieghere "Generate reproducer on disk.", nullptr) {} 869e046f02SJonas Devlieghere 879e046f02SJonas Devlieghere ~CommandObjectReproducerGenerate() override = default; 889e046f02SJonas Devlieghere 899e046f02SJonas Devlieghere protected: 909e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 919e046f02SJonas Devlieghere if (!command.empty()) { 929e046f02SJonas Devlieghere result.AppendErrorWithFormat("'%s' takes no arguments", 939e046f02SJonas Devlieghere m_cmd_name.c_str()); 949e046f02SJonas Devlieghere return false; 959e046f02SJonas Devlieghere } 969e046f02SJonas Devlieghere 979e046f02SJonas Devlieghere auto &r = repro::Reproducer::Instance(); 989e046f02SJonas Devlieghere if (auto generator = r.GetGenerator()) { 999e046f02SJonas Devlieghere generator->Keep(); 1009e046f02SJonas Devlieghere } else { 1019e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to get the reproducer generator"); 1029e046f02SJonas Devlieghere return false; 1039e046f02SJonas Devlieghere } 1049e046f02SJonas Devlieghere 1059e046f02SJonas Devlieghere result.GetOutputStream() 1069e046f02SJonas Devlieghere << "Reproducer written to '" << r.GetReproducerPath() << "'\n"; 1079e046f02SJonas Devlieghere 1089e046f02SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishResult); 1099e046f02SJonas Devlieghere return result.Succeeded(); 1109e046f02SJonas Devlieghere } 1119e046f02SJonas Devlieghere }; 1129e046f02SJonas Devlieghere 1139e046f02SJonas Devlieghere class CommandObjectReproducerReplay : public CommandObjectParsed { 1149e046f02SJonas Devlieghere public: 1159e046f02SJonas Devlieghere CommandObjectReproducerReplay(CommandInterpreter &interpreter) 116*df14b942SJonas Devlieghere : CommandObjectParsed(interpreter, "reproducer replay", 117*df14b942SJonas Devlieghere "Replay a reproducer.", nullptr) { 1189e046f02SJonas Devlieghere CommandArgumentEntry arg1; 1199e046f02SJonas Devlieghere CommandArgumentData path_arg; 1209e046f02SJonas Devlieghere 1219e046f02SJonas Devlieghere // Define the first (and only) variant of this arg. 1229e046f02SJonas Devlieghere path_arg.arg_type = eArgTypePath; 1239e046f02SJonas Devlieghere path_arg.arg_repetition = eArgRepeatPlain; 1249e046f02SJonas Devlieghere 1259e046f02SJonas Devlieghere // There is only one variant this argument could be; put it into the 1269e046f02SJonas Devlieghere // argument entry. 1279e046f02SJonas Devlieghere arg1.push_back(path_arg); 1289e046f02SJonas Devlieghere 1299e046f02SJonas Devlieghere // Push the data for the first argument into the m_arguments vector. 1309e046f02SJonas Devlieghere m_arguments.push_back(arg1); 1319e046f02SJonas Devlieghere } 1329e046f02SJonas Devlieghere 1339e046f02SJonas Devlieghere ~CommandObjectReproducerReplay() override = default; 1349e046f02SJonas Devlieghere 1359e046f02SJonas Devlieghere protected: 1369e046f02SJonas Devlieghere bool DoExecute(Args &command, CommandReturnObject &result) override { 1379e046f02SJonas Devlieghere if (command.empty()) { 1389e046f02SJonas Devlieghere result.AppendErrorWithFormat( 1399e046f02SJonas Devlieghere "'%s' takes a single argument: the reproducer path", 1409e046f02SJonas Devlieghere m_cmd_name.c_str()); 1419e046f02SJonas Devlieghere return false; 1429e046f02SJonas Devlieghere } 1439e046f02SJonas Devlieghere 1449e046f02SJonas Devlieghere auto &r = repro::Reproducer::Instance(); 1459e046f02SJonas Devlieghere 1469e046f02SJonas Devlieghere if (auto e = r.SetReplayReproducer(true)) { 1479e046f02SJonas Devlieghere std::string error_str = llvm::toString(std::move(e)); 1489e046f02SJonas Devlieghere result.AppendErrorWithFormat("%s", error_str.c_str()); 1499e046f02SJonas Devlieghere return false; 1509e046f02SJonas Devlieghere } 1519e046f02SJonas Devlieghere 1529e046f02SJonas Devlieghere if (auto loader = r.GetLoader()) { 1539e046f02SJonas Devlieghere const char *repro_path = command.GetArgumentAtIndex(0); 1549e046f02SJonas Devlieghere if (auto e = loader->LoadIndex(FileSpec(repro_path))) { 1559e046f02SJonas Devlieghere std::string error_str = llvm::toString(std::move(e)); 1569e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to load reproducer: %s", 1579e046f02SJonas Devlieghere error_str.c_str()); 1589e046f02SJonas Devlieghere return false; 1599e046f02SJonas Devlieghere } 1609e046f02SJonas Devlieghere } else { 1619e046f02SJonas Devlieghere result.AppendErrorWithFormat("Unable to get the reproducer loader"); 1629e046f02SJonas Devlieghere return false; 1639e046f02SJonas Devlieghere } 1649e046f02SJonas Devlieghere 1659e046f02SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 1669e046f02SJonas Devlieghere return result.Succeeded(); 1679e046f02SJonas Devlieghere } 1689e046f02SJonas Devlieghere }; 1699e046f02SJonas Devlieghere 1709e046f02SJonas Devlieghere class CommandObjectReproducerCapture : public CommandObjectMultiword { 1719e046f02SJonas Devlieghere private: 1729e046f02SJonas Devlieghere public: 1739e046f02SJonas Devlieghere CommandObjectReproducerCapture(CommandInterpreter &interpreter) 1749e046f02SJonas Devlieghere : CommandObjectMultiword( 1759e046f02SJonas Devlieghere interpreter, "reproducer capture", 1769e046f02SJonas Devlieghere "Manage gathering of information needed to generate a reproducer.", 1779e046f02SJonas Devlieghere NULL) { 1789e046f02SJonas Devlieghere LoadSubCommand( 1799e046f02SJonas Devlieghere "enable", 1809e046f02SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerCaptureEnable(interpreter))); 1819e046f02SJonas Devlieghere LoadSubCommand("disable", 1829e046f02SJonas Devlieghere CommandObjectSP( 1839e046f02SJonas Devlieghere new CommandObjectReproducerCaptureDisable(interpreter))); 1849e046f02SJonas Devlieghere } 1859e046f02SJonas Devlieghere 1869e046f02SJonas Devlieghere ~CommandObjectReproducerCapture() {} 1879e046f02SJonas Devlieghere }; 1889e046f02SJonas Devlieghere 1899e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer( 1909e046f02SJonas Devlieghere CommandInterpreter &interpreter) 1919e046f02SJonas Devlieghere : CommandObjectMultiword(interpreter, "reproducer", 1929e046f02SJonas Devlieghere "Commands controlling LLDB reproducers.", 1939e046f02SJonas Devlieghere "log <subcommand> [<command-options>]") { 1949e046f02SJonas Devlieghere LoadSubCommand("capture", CommandObjectSP(new CommandObjectReproducerCapture( 1959e046f02SJonas Devlieghere interpreter))); 1969e046f02SJonas Devlieghere LoadSubCommand( 1979e046f02SJonas Devlieghere "generate", 1989e046f02SJonas Devlieghere CommandObjectSP(new CommandObjectReproducerGenerate(interpreter))); 1999e046f02SJonas Devlieghere LoadSubCommand("replay", CommandObjectSP( 2009e046f02SJonas Devlieghere new CommandObjectReproducerReplay(interpreter))); 2019e046f02SJonas Devlieghere } 2029e046f02SJonas Devlieghere 2039e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default; 204