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     result.GetOutputStream()
53         << "Please have a look at the directory to assess if you're willing to "
54            "share the contained information.\n";
55 
56     result.SetStatus(eReturnStatusSuccessFinishResult);
57     return result.Succeeded();
58   }
59 };
60 
61 class CommandObjectReproducerStatus : public CommandObjectParsed {
62 public:
63   CommandObjectReproducerStatus(CommandInterpreter &interpreter)
64       : CommandObjectParsed(interpreter, "reproducer status",
65                             "Show the current reproducer status.", nullptr) {}
66 
67   ~CommandObjectReproducerStatus() override = default;
68 
69 protected:
70   bool DoExecute(Args &command, CommandReturnObject &result) override {
71     if (!command.empty()) {
72       result.AppendErrorWithFormat("'%s' takes no arguments",
73                                    m_cmd_name.c_str());
74       return false;
75     }
76 
77     auto &r = repro::Reproducer::Instance();
78     if (r.GetGenerator()) {
79       result.GetOutputStream() << "Reproducer is in capture mode.\n";
80     } else if (r.GetLoader()) {
81       result.GetOutputStream() << "Reproducer is in replay mode.\n";
82     } else {
83       result.GetOutputStream() << "Reproducer is off.\n";
84     }
85 
86     result.SetStatus(eReturnStatusSuccessFinishResult);
87     return result.Succeeded();
88   }
89 };
90 
91 CommandObjectReproducer::CommandObjectReproducer(
92     CommandInterpreter &interpreter)
93     : CommandObjectMultiword(interpreter, "reproducer",
94                              "Commands controlling LLDB reproducers.",
95                              "log <subcommand> [<command-options>]") {
96   LoadSubCommand(
97       "generate",
98       CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
99   LoadSubCommand("status", CommandObjectSP(
100                                new CommandObjectReproducerStatus(interpreter)));
101 }
102 
103 CommandObjectReproducer::~CommandObjectReproducer() = default;
104