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