1 //===-- CommandObjectReproducer.cpp -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectReproducer.h"
10 
11 #include "lldb/Utility/Reproducer.h"
12 
13 #include "lldb/Interpreter/CommandInterpreter.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Interpreter/OptionArgParser.h"
16 #include "lldb/Interpreter/OptionGroupBoolean.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
21 class CommandObjectReproducerGenerate : public CommandObjectParsed {
22 public:
23   CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
24       : CommandObjectParsed(interpreter, "reproducer generate",
25                             "Generate reproducer on disk.", nullptr) {}
26 
27   ~CommandObjectReproducerGenerate() override = default;
28 
29 protected:
30   bool DoExecute(Args &command, CommandReturnObject &result) override {
31     if (!command.empty()) {
32       result.AppendErrorWithFormat("'%s' takes no arguments",
33                                    m_cmd_name.c_str());
34       return false;
35     }
36 
37     auto &r = repro::Reproducer::Instance();
38     if (auto generator = r.GetGenerator()) {
39       generator->Keep();
40     } else if (r.GetLoader()) {
41       // Make this operation a NOP in replay mode.
42       result.SetStatus(eReturnStatusSuccessFinishNoResult);
43       return result.Succeeded();
44     } else {
45       result.AppendErrorWithFormat("Unable to get the reproducer generator");
46       result.SetStatus(eReturnStatusFailed);
47       return false;
48     }
49 
50     result.GetOutputStream()
51         << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
52 
53     result.SetStatus(eReturnStatusSuccessFinishResult);
54     return result.Succeeded();
55   }
56 };
57 
58 class CommandObjectReproducerStatus : public CommandObjectParsed {
59 public:
60   CommandObjectReproducerStatus(CommandInterpreter &interpreter)
61       : CommandObjectParsed(interpreter, "reproducer status",
62                             "Show the current reproducer status.", nullptr) {}
63 
64   ~CommandObjectReproducerStatus() override = default;
65 
66 protected:
67   bool DoExecute(Args &command, CommandReturnObject &result) override {
68     if (!command.empty()) {
69       result.AppendErrorWithFormat("'%s' takes no arguments",
70                                    m_cmd_name.c_str());
71       return false;
72     }
73 
74     auto &r = repro::Reproducer::Instance();
75     if (r.GetGenerator()) {
76       result.GetOutputStream() << "Reproducer is in capture mode.\n";
77     } else if (r.GetLoader()) {
78       result.GetOutputStream() << "Reproducer is in replay mode.\n";
79     } else {
80       result.GetOutputStream() << "Reproducer is off.\n";
81     }
82 
83     result.SetStatus(eReturnStatusSuccessFinishResult);
84     return result.Succeeded();
85   }
86 };
87 
88 CommandObjectReproducer::CommandObjectReproducer(
89     CommandInterpreter &interpreter)
90     : CommandObjectMultiword(interpreter, "reproducer",
91                              "Commands controlling LLDB reproducers.",
92                              "log <subcommand> [<command-options>]") {
93   LoadSubCommand(
94       "generate",
95       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
96   LoadSubCommand("status", CommandObjectSP(
97                                new CommandObjectReproducerStatus(interpreter)));
98 }
99 
100 CommandObjectReproducer::~CommandObjectReproducer() = default;
101