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