1*9e046f02SJonas Devlieghere //===-- CommandObjectReproducer.cpp -----------------------------*- C++ -*-===//
2*9e046f02SJonas Devlieghere //
3*9e046f02SJonas Devlieghere //                     The LLVM Compiler Infrastructure
4*9e046f02SJonas Devlieghere //
5*9e046f02SJonas Devlieghere // This file is distributed under the University of Illinois Open Source
6*9e046f02SJonas Devlieghere // License. See LICENSE.TXT for details.
7*9e046f02SJonas Devlieghere //
8*9e046f02SJonas Devlieghere //===----------------------------------------------------------------------===//
9*9e046f02SJonas Devlieghere 
10*9e046f02SJonas Devlieghere #include "CommandObjectReproducer.h"
11*9e046f02SJonas Devlieghere 
12*9e046f02SJonas Devlieghere #include "lldb/Utility/Reproducer.h"
13*9e046f02SJonas Devlieghere 
14*9e046f02SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h"
15*9e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionArgParser.h"
16*9e046f02SJonas Devlieghere #include "lldb/Interpreter/OptionGroupBoolean.h"
17*9e046f02SJonas Devlieghere 
18*9e046f02SJonas Devlieghere using namespace lldb;
19*9e046f02SJonas Devlieghere using namespace lldb_private;
20*9e046f02SJonas Devlieghere 
21*9e046f02SJonas Devlieghere static void AppendErrorToResult(llvm::Error e, CommandReturnObject &result) {
22*9e046f02SJonas Devlieghere   std::string error_str = llvm::toString(std::move(e));
23*9e046f02SJonas Devlieghere   result.AppendErrorWithFormat("%s", error_str.c_str());
24*9e046f02SJonas Devlieghere }
25*9e046f02SJonas Devlieghere 
26*9e046f02SJonas Devlieghere class CommandObjectReproducerCaptureEnable : public CommandObjectParsed {
27*9e046f02SJonas Devlieghere public:
28*9e046f02SJonas Devlieghere   CommandObjectReproducerCaptureEnable(CommandInterpreter &interpreter)
29*9e046f02SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer capture enable",
30*9e046f02SJonas Devlieghere                             "Enable gathering information for reproducer",
31*9e046f02SJonas Devlieghere                             nullptr) {}
32*9e046f02SJonas Devlieghere 
33*9e046f02SJonas Devlieghere   ~CommandObjectReproducerCaptureEnable() override = default;
34*9e046f02SJonas Devlieghere 
35*9e046f02SJonas Devlieghere protected:
36*9e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
37*9e046f02SJonas Devlieghere     if (!command.empty()) {
38*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
39*9e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
40*9e046f02SJonas Devlieghere       return false;
41*9e046f02SJonas Devlieghere     }
42*9e046f02SJonas Devlieghere 
43*9e046f02SJonas Devlieghere     auto &r = repro::Reproducer::Instance();
44*9e046f02SJonas Devlieghere     if (auto e = r.SetGenerateReproducer(true)) {
45*9e046f02SJonas Devlieghere       AppendErrorToResult(std::move(e), result);
46*9e046f02SJonas Devlieghere       return false;
47*9e046f02SJonas Devlieghere     }
48*9e046f02SJonas Devlieghere 
49*9e046f02SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
50*9e046f02SJonas Devlieghere     return result.Succeeded();
51*9e046f02SJonas Devlieghere   }
52*9e046f02SJonas Devlieghere };
53*9e046f02SJonas Devlieghere 
54*9e046f02SJonas Devlieghere class CommandObjectReproducerCaptureDisable : public CommandObjectParsed {
55*9e046f02SJonas Devlieghere public:
56*9e046f02SJonas Devlieghere   CommandObjectReproducerCaptureDisable(CommandInterpreter &interpreter)
57*9e046f02SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer capture enable",
58*9e046f02SJonas Devlieghere                             "Disable gathering information for reproducer",
59*9e046f02SJonas Devlieghere                             nullptr) {}
60*9e046f02SJonas Devlieghere 
61*9e046f02SJonas Devlieghere   ~CommandObjectReproducerCaptureDisable() override = default;
62*9e046f02SJonas Devlieghere 
63*9e046f02SJonas Devlieghere protected:
64*9e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
65*9e046f02SJonas Devlieghere     if (!command.empty()) {
66*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
67*9e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
68*9e046f02SJonas Devlieghere       return false;
69*9e046f02SJonas Devlieghere     }
70*9e046f02SJonas Devlieghere 
71*9e046f02SJonas Devlieghere     auto &r = repro::Reproducer::Instance();
72*9e046f02SJonas Devlieghere     if (auto e = r.SetGenerateReproducer(false)) {
73*9e046f02SJonas Devlieghere       AppendErrorToResult(std::move(e), result);
74*9e046f02SJonas Devlieghere       return false;
75*9e046f02SJonas Devlieghere     }
76*9e046f02SJonas Devlieghere 
77*9e046f02SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
78*9e046f02SJonas Devlieghere     return result.Succeeded();
79*9e046f02SJonas Devlieghere   }
80*9e046f02SJonas Devlieghere };
81*9e046f02SJonas Devlieghere 
82*9e046f02SJonas Devlieghere class CommandObjectReproducerGenerate : public CommandObjectParsed {
83*9e046f02SJonas Devlieghere public:
84*9e046f02SJonas Devlieghere   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
85*9e046f02SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer generate",
86*9e046f02SJonas Devlieghere                             "Generate reproducer on disk.", nullptr) {}
87*9e046f02SJonas Devlieghere 
88*9e046f02SJonas Devlieghere   ~CommandObjectReproducerGenerate() override = default;
89*9e046f02SJonas Devlieghere 
90*9e046f02SJonas Devlieghere protected:
91*9e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
92*9e046f02SJonas Devlieghere     if (!command.empty()) {
93*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat("'%s' takes no arguments",
94*9e046f02SJonas Devlieghere                                    m_cmd_name.c_str());
95*9e046f02SJonas Devlieghere       return false;
96*9e046f02SJonas Devlieghere     }
97*9e046f02SJonas Devlieghere 
98*9e046f02SJonas Devlieghere     auto &r = repro::Reproducer::Instance();
99*9e046f02SJonas Devlieghere     if (auto generator = r.GetGenerator()) {
100*9e046f02SJonas Devlieghere       generator->Keep();
101*9e046f02SJonas Devlieghere     } else {
102*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat("Unable to get the reproducer generator");
103*9e046f02SJonas Devlieghere       return false;
104*9e046f02SJonas Devlieghere     }
105*9e046f02SJonas Devlieghere 
106*9e046f02SJonas Devlieghere     result.GetOutputStream()
107*9e046f02SJonas Devlieghere         << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
108*9e046f02SJonas Devlieghere 
109*9e046f02SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishResult);
110*9e046f02SJonas Devlieghere     return result.Succeeded();
111*9e046f02SJonas Devlieghere   }
112*9e046f02SJonas Devlieghere };
113*9e046f02SJonas Devlieghere 
114*9e046f02SJonas Devlieghere class CommandObjectReproducerReplay : public CommandObjectParsed {
115*9e046f02SJonas Devlieghere public:
116*9e046f02SJonas Devlieghere   CommandObjectReproducerReplay(CommandInterpreter &interpreter)
117*9e046f02SJonas Devlieghere       : CommandObjectParsed(interpreter, "reproducer capture",
118*9e046f02SJonas Devlieghere                             "Enable or disable gathering of information needed "
119*9e046f02SJonas Devlieghere                             "to generate a reproducer.",
120*9e046f02SJonas Devlieghere                             nullptr) {
121*9e046f02SJonas Devlieghere     CommandArgumentEntry arg1;
122*9e046f02SJonas Devlieghere     CommandArgumentData path_arg;
123*9e046f02SJonas Devlieghere 
124*9e046f02SJonas Devlieghere     // Define the first (and only) variant of this arg.
125*9e046f02SJonas Devlieghere     path_arg.arg_type = eArgTypePath;
126*9e046f02SJonas Devlieghere     path_arg.arg_repetition = eArgRepeatPlain;
127*9e046f02SJonas Devlieghere 
128*9e046f02SJonas Devlieghere     // There is only one variant this argument could be; put it into the
129*9e046f02SJonas Devlieghere     // argument entry.
130*9e046f02SJonas Devlieghere     arg1.push_back(path_arg);
131*9e046f02SJonas Devlieghere 
132*9e046f02SJonas Devlieghere     // Push the data for the first argument into the m_arguments vector.
133*9e046f02SJonas Devlieghere     m_arguments.push_back(arg1);
134*9e046f02SJonas Devlieghere   }
135*9e046f02SJonas Devlieghere 
136*9e046f02SJonas Devlieghere   ~CommandObjectReproducerReplay() override = default;
137*9e046f02SJonas Devlieghere 
138*9e046f02SJonas Devlieghere protected:
139*9e046f02SJonas Devlieghere   bool DoExecute(Args &command, CommandReturnObject &result) override {
140*9e046f02SJonas Devlieghere     if (command.empty()) {
141*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat(
142*9e046f02SJonas Devlieghere           "'%s' takes a single argument: the reproducer path",
143*9e046f02SJonas Devlieghere           m_cmd_name.c_str());
144*9e046f02SJonas Devlieghere       return false;
145*9e046f02SJonas Devlieghere     }
146*9e046f02SJonas Devlieghere 
147*9e046f02SJonas Devlieghere     auto &r = repro::Reproducer::Instance();
148*9e046f02SJonas Devlieghere 
149*9e046f02SJonas Devlieghere     if (auto e = r.SetReplayReproducer(true)) {
150*9e046f02SJonas Devlieghere       std::string error_str = llvm::toString(std::move(e));
151*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat("%s", error_str.c_str());
152*9e046f02SJonas Devlieghere       return false;
153*9e046f02SJonas Devlieghere     }
154*9e046f02SJonas Devlieghere 
155*9e046f02SJonas Devlieghere     if (auto loader = r.GetLoader()) {
156*9e046f02SJonas Devlieghere       const char *repro_path = command.GetArgumentAtIndex(0);
157*9e046f02SJonas Devlieghere       if (auto e = loader->LoadIndex(FileSpec(repro_path))) {
158*9e046f02SJonas Devlieghere         std::string error_str = llvm::toString(std::move(e));
159*9e046f02SJonas Devlieghere         result.AppendErrorWithFormat("Unable to load reproducer: %s",
160*9e046f02SJonas Devlieghere                                      error_str.c_str());
161*9e046f02SJonas Devlieghere         return false;
162*9e046f02SJonas Devlieghere       }
163*9e046f02SJonas Devlieghere     } else {
164*9e046f02SJonas Devlieghere       result.AppendErrorWithFormat("Unable to get the reproducer loader");
165*9e046f02SJonas Devlieghere       return false;
166*9e046f02SJonas Devlieghere     }
167*9e046f02SJonas Devlieghere 
168*9e046f02SJonas Devlieghere     result.SetStatus(eReturnStatusSuccessFinishNoResult);
169*9e046f02SJonas Devlieghere     return result.Succeeded();
170*9e046f02SJonas Devlieghere   }
171*9e046f02SJonas Devlieghere };
172*9e046f02SJonas Devlieghere 
173*9e046f02SJonas Devlieghere class CommandObjectReproducerCapture : public CommandObjectMultiword {
174*9e046f02SJonas Devlieghere private:
175*9e046f02SJonas Devlieghere public:
176*9e046f02SJonas Devlieghere   CommandObjectReproducerCapture(CommandInterpreter &interpreter)
177*9e046f02SJonas Devlieghere       : CommandObjectMultiword(
178*9e046f02SJonas Devlieghere             interpreter, "reproducer capture",
179*9e046f02SJonas Devlieghere             "Manage gathering of information needed to generate a reproducer.",
180*9e046f02SJonas Devlieghere             NULL) {
181*9e046f02SJonas Devlieghere     LoadSubCommand(
182*9e046f02SJonas Devlieghere         "enable",
183*9e046f02SJonas Devlieghere         CommandObjectSP(new CommandObjectReproducerCaptureEnable(interpreter)));
184*9e046f02SJonas Devlieghere     LoadSubCommand("disable",
185*9e046f02SJonas Devlieghere                    CommandObjectSP(
186*9e046f02SJonas Devlieghere                        new CommandObjectReproducerCaptureDisable(interpreter)));
187*9e046f02SJonas Devlieghere   }
188*9e046f02SJonas Devlieghere 
189*9e046f02SJonas Devlieghere   ~CommandObjectReproducerCapture() {}
190*9e046f02SJonas Devlieghere };
191*9e046f02SJonas Devlieghere 
192*9e046f02SJonas Devlieghere CommandObjectReproducer::CommandObjectReproducer(
193*9e046f02SJonas Devlieghere     CommandInterpreter &interpreter)
194*9e046f02SJonas Devlieghere     : CommandObjectMultiword(interpreter, "reproducer",
195*9e046f02SJonas Devlieghere                              "Commands controlling LLDB reproducers.",
196*9e046f02SJonas Devlieghere                              "log <subcommand> [<command-options>]") {
197*9e046f02SJonas Devlieghere   LoadSubCommand("capture", CommandObjectSP(new CommandObjectReproducerCapture(
198*9e046f02SJonas Devlieghere                                 interpreter)));
199*9e046f02SJonas Devlieghere   LoadSubCommand(
200*9e046f02SJonas Devlieghere       "generate",
201*9e046f02SJonas Devlieghere       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
202*9e046f02SJonas Devlieghere   LoadSubCommand("replay", CommandObjectSP(
203*9e046f02SJonas Devlieghere                                new CommandObjectReproducerReplay(interpreter)));
204*9e046f02SJonas Devlieghere }
205*9e046f02SJonas Devlieghere 
206*9e046f02SJonas Devlieghere CommandObjectReproducer::~CommandObjectReproducer() = default;
207