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