xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectSession.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1be691f3bSpatrick #include "CommandObjectSession.h"
2be691f3bSpatrick #include "lldb/Host/OptionParser.h"
3be691f3bSpatrick #include "lldb/Interpreter/CommandInterpreter.h"
4*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
5be691f3bSpatrick #include "lldb/Interpreter/CommandReturnObject.h"
6be691f3bSpatrick #include "lldb/Interpreter/OptionArgParser.h"
7be691f3bSpatrick #include "lldb/Interpreter/OptionValue.h"
8be691f3bSpatrick #include "lldb/Interpreter/OptionValueBoolean.h"
9be691f3bSpatrick #include "lldb/Interpreter/OptionValueString.h"
10be691f3bSpatrick #include "lldb/Interpreter/OptionValueUInt64.h"
11be691f3bSpatrick #include "lldb/Interpreter/Options.h"
12be691f3bSpatrick 
13be691f3bSpatrick using namespace lldb;
14be691f3bSpatrick using namespace lldb_private;
15be691f3bSpatrick 
16be691f3bSpatrick class CommandObjectSessionSave : public CommandObjectParsed {
17be691f3bSpatrick public:
CommandObjectSessionSave(CommandInterpreter & interpreter)18be691f3bSpatrick   CommandObjectSessionSave(CommandInterpreter &interpreter)
19be691f3bSpatrick       : CommandObjectParsed(interpreter, "session save",
20be691f3bSpatrick                             "Save the current session transcripts to a file.\n"
21be691f3bSpatrick                             "If no file if specified, transcripts will be "
22be691f3bSpatrick                             "saved to a temporary file.",
23be691f3bSpatrick                             "session save [file]") {
24be691f3bSpatrick     CommandArgumentEntry arg1;
25be691f3bSpatrick     arg1.emplace_back(eArgTypePath, eArgRepeatOptional);
26be691f3bSpatrick     m_arguments.push_back(arg1);
27be691f3bSpatrick   }
28be691f3bSpatrick 
29be691f3bSpatrick   ~CommandObjectSessionSave() override = default;
30be691f3bSpatrick 
31be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)32be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
33be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
34be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
35be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
36be691f3bSpatrick         request, nullptr);
37be691f3bSpatrick   }
38be691f3bSpatrick 
39be691f3bSpatrick protected:
DoExecute(Args & args,CommandReturnObject & result)40be691f3bSpatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
41be691f3bSpatrick     llvm::StringRef file_path;
42be691f3bSpatrick 
43be691f3bSpatrick     if (!args.empty())
44be691f3bSpatrick       file_path = args[0].ref();
45be691f3bSpatrick 
46be691f3bSpatrick     if (m_interpreter.SaveTranscript(result, file_path.str()))
47be691f3bSpatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
48be691f3bSpatrick     else
49be691f3bSpatrick       result.SetStatus(eReturnStatusFailed);
50be691f3bSpatrick     return result.Succeeded();
51be691f3bSpatrick   }
52be691f3bSpatrick };
53be691f3bSpatrick 
54be691f3bSpatrick #define LLDB_OPTIONS_history
55be691f3bSpatrick #include "CommandOptions.inc"
56be691f3bSpatrick 
57be691f3bSpatrick class CommandObjectSessionHistory : public CommandObjectParsed {
58be691f3bSpatrick public:
CommandObjectSessionHistory(CommandInterpreter & interpreter)59be691f3bSpatrick   CommandObjectSessionHistory(CommandInterpreter &interpreter)
60be691f3bSpatrick       : CommandObjectParsed(interpreter, "session history",
61be691f3bSpatrick                             "Dump the history of commands in this session.\n"
62be691f3bSpatrick                             "Commands in the history list can be run again "
63be691f3bSpatrick                             "using \"!<INDEX>\".   \"!-<OFFSET>\" will re-run "
64be691f3bSpatrick                             "the command that is <OFFSET> commands from the end"
65be691f3bSpatrick                             " of the list (counting the current command).",
66*f6aab3d8Srobert                             nullptr) {}
67be691f3bSpatrick 
68be691f3bSpatrick   ~CommandObjectSessionHistory() override = default;
69be691f3bSpatrick 
GetOptions()70be691f3bSpatrick   Options *GetOptions() override { return &m_options; }
71be691f3bSpatrick 
72be691f3bSpatrick protected:
73be691f3bSpatrick   class CommandOptions : public Options {
74be691f3bSpatrick   public:
CommandOptions()75be691f3bSpatrick     CommandOptions()
76*f6aab3d8Srobert         : m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {}
77be691f3bSpatrick 
78be691f3bSpatrick     ~CommandOptions() override = default;
79be691f3bSpatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)80be691f3bSpatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
81be691f3bSpatrick                           ExecutionContext *execution_context) override {
82be691f3bSpatrick       Status error;
83be691f3bSpatrick       const int short_option = m_getopt_table[option_idx].val;
84be691f3bSpatrick 
85be691f3bSpatrick       switch (short_option) {
86be691f3bSpatrick       case 'c':
87be691f3bSpatrick         error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
88be691f3bSpatrick         break;
89be691f3bSpatrick       case 's':
90be691f3bSpatrick         if (option_arg == "end") {
91be691f3bSpatrick           m_start_idx.SetCurrentValue(UINT64_MAX);
92be691f3bSpatrick           m_start_idx.SetOptionWasSet();
93be691f3bSpatrick         } else
94be691f3bSpatrick           error = m_start_idx.SetValueFromString(option_arg,
95be691f3bSpatrick                                                  eVarSetOperationAssign);
96be691f3bSpatrick         break;
97be691f3bSpatrick       case 'e':
98be691f3bSpatrick         error =
99be691f3bSpatrick             m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
100be691f3bSpatrick         break;
101be691f3bSpatrick       case 'C':
102be691f3bSpatrick         m_clear.SetCurrentValue(true);
103be691f3bSpatrick         m_clear.SetOptionWasSet();
104be691f3bSpatrick         break;
105be691f3bSpatrick       default:
106be691f3bSpatrick         llvm_unreachable("Unimplemented option");
107be691f3bSpatrick       }
108be691f3bSpatrick 
109be691f3bSpatrick       return error;
110be691f3bSpatrick     }
111be691f3bSpatrick 
OptionParsingStarting(ExecutionContext * execution_context)112be691f3bSpatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
113be691f3bSpatrick       m_start_idx.Clear();
114be691f3bSpatrick       m_stop_idx.Clear();
115be691f3bSpatrick       m_count.Clear();
116be691f3bSpatrick       m_clear.Clear();
117be691f3bSpatrick     }
118be691f3bSpatrick 
GetDefinitions()119be691f3bSpatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
120*f6aab3d8Srobert       return llvm::ArrayRef(g_history_options);
121be691f3bSpatrick     }
122be691f3bSpatrick 
123be691f3bSpatrick     // Instance variables to hold the values for command options.
124be691f3bSpatrick 
125be691f3bSpatrick     OptionValueUInt64 m_start_idx;
126be691f3bSpatrick     OptionValueUInt64 m_stop_idx;
127be691f3bSpatrick     OptionValueUInt64 m_count;
128be691f3bSpatrick     OptionValueBoolean m_clear;
129be691f3bSpatrick   };
130be691f3bSpatrick 
DoExecute(Args & command,CommandReturnObject & result)131be691f3bSpatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
132be691f3bSpatrick     if (m_options.m_clear.GetCurrentValue() &&
133be691f3bSpatrick         m_options.m_clear.OptionWasSet()) {
134be691f3bSpatrick       m_interpreter.GetCommandHistory().Clear();
135be691f3bSpatrick       result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
136be691f3bSpatrick     } else {
137be691f3bSpatrick       if (m_options.m_start_idx.OptionWasSet() &&
138be691f3bSpatrick           m_options.m_stop_idx.OptionWasSet() &&
139be691f3bSpatrick           m_options.m_count.OptionWasSet()) {
140be691f3bSpatrick         result.AppendError("--count, --start-index and --end-index cannot be "
141be691f3bSpatrick                            "all specified in the same invocation");
142be691f3bSpatrick         result.SetStatus(lldb::eReturnStatusFailed);
143be691f3bSpatrick       } else {
144be691f3bSpatrick         std::pair<bool, uint64_t> start_idx(
145be691f3bSpatrick             m_options.m_start_idx.OptionWasSet(),
146be691f3bSpatrick             m_options.m_start_idx.GetCurrentValue());
147be691f3bSpatrick         std::pair<bool, uint64_t> stop_idx(
148be691f3bSpatrick             m_options.m_stop_idx.OptionWasSet(),
149be691f3bSpatrick             m_options.m_stop_idx.GetCurrentValue());
150be691f3bSpatrick         std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
151be691f3bSpatrick                                         m_options.m_count.GetCurrentValue());
152be691f3bSpatrick 
153be691f3bSpatrick         const CommandHistory &history(m_interpreter.GetCommandHistory());
154be691f3bSpatrick 
155be691f3bSpatrick         if (start_idx.first && start_idx.second == UINT64_MAX) {
156be691f3bSpatrick           if (count.first) {
157be691f3bSpatrick             start_idx.second = history.GetSize() - count.second;
158be691f3bSpatrick             stop_idx.second = history.GetSize() - 1;
159be691f3bSpatrick           } else if (stop_idx.first) {
160be691f3bSpatrick             start_idx.second = stop_idx.second;
161be691f3bSpatrick             stop_idx.second = history.GetSize() - 1;
162be691f3bSpatrick           } else {
163be691f3bSpatrick             start_idx.second = 0;
164be691f3bSpatrick             stop_idx.second = history.GetSize() - 1;
165be691f3bSpatrick           }
166be691f3bSpatrick         } else {
167be691f3bSpatrick           if (!start_idx.first && !stop_idx.first && !count.first) {
168be691f3bSpatrick             start_idx.second = 0;
169be691f3bSpatrick             stop_idx.second = history.GetSize() - 1;
170be691f3bSpatrick           } else if (start_idx.first) {
171be691f3bSpatrick             if (count.first) {
172be691f3bSpatrick               stop_idx.second = start_idx.second + count.second - 1;
173be691f3bSpatrick             } else if (!stop_idx.first) {
174be691f3bSpatrick               stop_idx.second = history.GetSize() - 1;
175be691f3bSpatrick             }
176be691f3bSpatrick           } else if (stop_idx.first) {
177be691f3bSpatrick             if (count.first) {
178be691f3bSpatrick               if (stop_idx.second >= count.second)
179be691f3bSpatrick                 start_idx.second = stop_idx.second - count.second + 1;
180be691f3bSpatrick               else
181be691f3bSpatrick                 start_idx.second = 0;
182be691f3bSpatrick             }
183be691f3bSpatrick           } else /* if (count.first) */
184be691f3bSpatrick           {
185be691f3bSpatrick             start_idx.second = 0;
186be691f3bSpatrick             stop_idx.second = count.second - 1;
187be691f3bSpatrick           }
188be691f3bSpatrick         }
189be691f3bSpatrick         history.Dump(result.GetOutputStream(), start_idx.second,
190be691f3bSpatrick                      stop_idx.second);
191be691f3bSpatrick       }
192be691f3bSpatrick     }
193be691f3bSpatrick     return result.Succeeded();
194be691f3bSpatrick   }
195be691f3bSpatrick 
196be691f3bSpatrick   CommandOptions m_options;
197be691f3bSpatrick };
198be691f3bSpatrick 
CommandObjectSession(CommandInterpreter & interpreter)199be691f3bSpatrick CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter)
200be691f3bSpatrick     : CommandObjectMultiword(interpreter, "session",
201be691f3bSpatrick                              "Commands controlling LLDB session.",
202be691f3bSpatrick                              "session <subcommand> [<command-options>]") {
203be691f3bSpatrick   LoadSubCommand("save",
204be691f3bSpatrick                  CommandObjectSP(new CommandObjectSessionSave(interpreter)));
205be691f3bSpatrick   LoadSubCommand("history",
206be691f3bSpatrick                  CommandObjectSP(new CommandObjectSessionHistory(interpreter)));
207be691f3bSpatrick }
208