1dda28197Spatrick //===-- CommandObjectLog.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "CommandObjectLog.h"
10061da546Spatrick #include "lldb/Core/Debugger.h"
11061da546Spatrick #include "lldb/Host/OptionParser.h"
12061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
13061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
14061da546Spatrick #include "lldb/Interpreter/Options.h"
15061da546Spatrick #include "lldb/Utility/Args.h"
16061da546Spatrick #include "lldb/Utility/FileSpec.h"
17061da546Spatrick #include "lldb/Utility/Log.h"
18061da546Spatrick #include "lldb/Utility/Stream.h"
19061da546Spatrick #include "lldb/Utility/Timer.h"
20061da546Spatrick 
21061da546Spatrick using namespace lldb;
22061da546Spatrick using namespace lldb_private;
23061da546Spatrick 
24061da546Spatrick #define LLDB_OPTIONS_log
25061da546Spatrick #include "CommandOptions.inc"
26061da546Spatrick 
27061da546Spatrick /// Common completion logic for log enable/disable.
28061da546Spatrick static void CompleteEnableDisable(CompletionRequest &request) {
29061da546Spatrick   size_t arg_index = request.GetCursorIndex();
30061da546Spatrick   if (arg_index == 0) { // We got: log enable/disable x[tab]
31061da546Spatrick     for (llvm::StringRef channel : Log::ListChannels())
32061da546Spatrick       request.TryCompleteCurrentArg(channel);
33061da546Spatrick   } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
34061da546Spatrick     llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
35061da546Spatrick     Log::ForEachChannelCategory(
36061da546Spatrick         channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
37061da546Spatrick           request.TryCompleteCurrentArg(name, desc);
38061da546Spatrick         });
39061da546Spatrick   }
40061da546Spatrick }
41061da546Spatrick 
42061da546Spatrick class CommandObjectLogEnable : public CommandObjectParsed {
43061da546Spatrick public:
44061da546Spatrick   // Constructors and Destructors
45061da546Spatrick   CommandObjectLogEnable(CommandInterpreter &interpreter)
46061da546Spatrick       : CommandObjectParsed(interpreter, "log enable",
47061da546Spatrick                             "Enable logging for a single log channel.",
48061da546Spatrick                             nullptr),
49061da546Spatrick         m_options() {
50061da546Spatrick     CommandArgumentEntry arg1;
51061da546Spatrick     CommandArgumentEntry arg2;
52061da546Spatrick     CommandArgumentData channel_arg;
53061da546Spatrick     CommandArgumentData category_arg;
54061da546Spatrick 
55061da546Spatrick     // Define the first (and only) variant of this arg.
56061da546Spatrick     channel_arg.arg_type = eArgTypeLogChannel;
57061da546Spatrick     channel_arg.arg_repetition = eArgRepeatPlain;
58061da546Spatrick 
59061da546Spatrick     // There is only one variant this argument could be; put it into the
60061da546Spatrick     // argument entry.
61061da546Spatrick     arg1.push_back(channel_arg);
62061da546Spatrick 
63061da546Spatrick     category_arg.arg_type = eArgTypeLogCategory;
64061da546Spatrick     category_arg.arg_repetition = eArgRepeatPlus;
65061da546Spatrick 
66061da546Spatrick     arg2.push_back(category_arg);
67061da546Spatrick 
68061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
69061da546Spatrick     m_arguments.push_back(arg1);
70061da546Spatrick     m_arguments.push_back(arg2);
71061da546Spatrick   }
72061da546Spatrick 
73061da546Spatrick   ~CommandObjectLogEnable() override = default;
74061da546Spatrick 
75061da546Spatrick   Options *GetOptions() override { return &m_options; }
76061da546Spatrick 
77061da546Spatrick   class CommandOptions : public Options {
78061da546Spatrick   public:
79*be691f3bSpatrick     CommandOptions() : Options(), log_file() {}
80061da546Spatrick 
81061da546Spatrick     ~CommandOptions() override = default;
82061da546Spatrick 
83061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
84061da546Spatrick                           ExecutionContext *execution_context) override {
85061da546Spatrick       Status error;
86061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
87061da546Spatrick 
88061da546Spatrick       switch (short_option) {
89061da546Spatrick       case 'f':
90061da546Spatrick         log_file.SetFile(option_arg, FileSpec::Style::native);
91061da546Spatrick         FileSystem::Instance().Resolve(log_file);
92061da546Spatrick         break;
93061da546Spatrick       case 't':
94061da546Spatrick         log_options |= LLDB_LOG_OPTION_THREADSAFE;
95061da546Spatrick         break;
96061da546Spatrick       case 'v':
97061da546Spatrick         log_options |= LLDB_LOG_OPTION_VERBOSE;
98061da546Spatrick         break;
99061da546Spatrick       case 's':
100061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
101061da546Spatrick         break;
102061da546Spatrick       case 'T':
103061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
104061da546Spatrick         break;
105061da546Spatrick       case 'p':
106061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
107061da546Spatrick         break;
108061da546Spatrick       case 'n':
109061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
110061da546Spatrick         break;
111061da546Spatrick       case 'S':
112061da546Spatrick         log_options |= LLDB_LOG_OPTION_BACKTRACE;
113061da546Spatrick         break;
114061da546Spatrick       case 'a':
115061da546Spatrick         log_options |= LLDB_LOG_OPTION_APPEND;
116061da546Spatrick         break;
117061da546Spatrick       case 'F':
118061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
119061da546Spatrick         break;
120061da546Spatrick       default:
121061da546Spatrick         llvm_unreachable("Unimplemented option");
122061da546Spatrick       }
123061da546Spatrick 
124061da546Spatrick       return error;
125061da546Spatrick     }
126061da546Spatrick 
127061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
128061da546Spatrick       log_file.Clear();
129061da546Spatrick       log_options = 0;
130061da546Spatrick     }
131061da546Spatrick 
132061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
133061da546Spatrick       return llvm::makeArrayRef(g_log_options);
134061da546Spatrick     }
135061da546Spatrick 
136061da546Spatrick     // Instance variables to hold the values for command options.
137061da546Spatrick 
138061da546Spatrick     FileSpec log_file;
139*be691f3bSpatrick     uint32_t log_options = 0;
140061da546Spatrick   };
141061da546Spatrick 
142061da546Spatrick   void
143061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
144061da546Spatrick                            OptionElementVector &opt_element_vector) override {
145061da546Spatrick     CompleteEnableDisable(request);
146061da546Spatrick   }
147061da546Spatrick 
148061da546Spatrick protected:
149061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
150061da546Spatrick     if (args.GetArgumentCount() < 2) {
151061da546Spatrick       result.AppendErrorWithFormat(
152061da546Spatrick           "%s takes a log channel and one or more log types.\n",
153061da546Spatrick           m_cmd_name.c_str());
154061da546Spatrick       return false;
155061da546Spatrick     }
156061da546Spatrick 
157061da546Spatrick     // Store into a std::string since we're about to shift the channel off.
158dda28197Spatrick     const std::string channel = std::string(args[0].ref());
159061da546Spatrick     args.Shift(); // Shift off the channel
160061da546Spatrick     char log_file[PATH_MAX];
161061da546Spatrick     if (m_options.log_file)
162061da546Spatrick       m_options.log_file.GetPath(log_file, sizeof(log_file));
163061da546Spatrick     else
164061da546Spatrick       log_file[0] = '\0';
165061da546Spatrick 
166061da546Spatrick     std::string error;
167061da546Spatrick     llvm::raw_string_ostream error_stream(error);
168061da546Spatrick     bool success =
169061da546Spatrick         GetDebugger().EnableLog(channel, args.GetArgumentArrayRef(), log_file,
170061da546Spatrick                                 m_options.log_options, error_stream);
171061da546Spatrick     result.GetErrorStream() << error_stream.str();
172061da546Spatrick 
173061da546Spatrick     if (success)
174061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
175061da546Spatrick     else
176061da546Spatrick       result.SetStatus(eReturnStatusFailed);
177061da546Spatrick     return result.Succeeded();
178061da546Spatrick   }
179061da546Spatrick 
180061da546Spatrick   CommandOptions m_options;
181061da546Spatrick };
182061da546Spatrick 
183061da546Spatrick class CommandObjectLogDisable : public CommandObjectParsed {
184061da546Spatrick public:
185061da546Spatrick   // Constructors and Destructors
186061da546Spatrick   CommandObjectLogDisable(CommandInterpreter &interpreter)
187061da546Spatrick       : CommandObjectParsed(interpreter, "log disable",
188061da546Spatrick                             "Disable one or more log channel categories.",
189061da546Spatrick                             nullptr) {
190061da546Spatrick     CommandArgumentEntry arg1;
191061da546Spatrick     CommandArgumentEntry arg2;
192061da546Spatrick     CommandArgumentData channel_arg;
193061da546Spatrick     CommandArgumentData category_arg;
194061da546Spatrick 
195061da546Spatrick     // Define the first (and only) variant of this arg.
196061da546Spatrick     channel_arg.arg_type = eArgTypeLogChannel;
197061da546Spatrick     channel_arg.arg_repetition = eArgRepeatPlain;
198061da546Spatrick 
199061da546Spatrick     // There is only one variant this argument could be; put it into the
200061da546Spatrick     // argument entry.
201061da546Spatrick     arg1.push_back(channel_arg);
202061da546Spatrick 
203061da546Spatrick     category_arg.arg_type = eArgTypeLogCategory;
204061da546Spatrick     category_arg.arg_repetition = eArgRepeatPlus;
205061da546Spatrick 
206061da546Spatrick     arg2.push_back(category_arg);
207061da546Spatrick 
208061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
209061da546Spatrick     m_arguments.push_back(arg1);
210061da546Spatrick     m_arguments.push_back(arg2);
211061da546Spatrick   }
212061da546Spatrick 
213061da546Spatrick   ~CommandObjectLogDisable() override = default;
214061da546Spatrick 
215061da546Spatrick   void
216061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
217061da546Spatrick                            OptionElementVector &opt_element_vector) override {
218061da546Spatrick     CompleteEnableDisable(request);
219061da546Spatrick   }
220061da546Spatrick 
221061da546Spatrick protected:
222061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
223061da546Spatrick     if (args.empty()) {
224061da546Spatrick       result.AppendErrorWithFormat(
225061da546Spatrick           "%s takes a log channel and one or more log types.\n",
226061da546Spatrick           m_cmd_name.c_str());
227061da546Spatrick       return false;
228061da546Spatrick     }
229061da546Spatrick 
230dda28197Spatrick     const std::string channel = std::string(args[0].ref());
231061da546Spatrick     args.Shift(); // Shift off the channel
232061da546Spatrick     if (channel == "all") {
233061da546Spatrick       Log::DisableAllLogChannels();
234061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
235061da546Spatrick     } else {
236061da546Spatrick       std::string error;
237061da546Spatrick       llvm::raw_string_ostream error_stream(error);
238061da546Spatrick       if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
239061da546Spatrick                                  error_stream))
240061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
241061da546Spatrick       result.GetErrorStream() << error_stream.str();
242061da546Spatrick     }
243061da546Spatrick     return result.Succeeded();
244061da546Spatrick   }
245061da546Spatrick };
246061da546Spatrick 
247061da546Spatrick class CommandObjectLogList : public CommandObjectParsed {
248061da546Spatrick public:
249061da546Spatrick   // Constructors and Destructors
250061da546Spatrick   CommandObjectLogList(CommandInterpreter &interpreter)
251061da546Spatrick       : CommandObjectParsed(interpreter, "log list",
252061da546Spatrick                             "List the log categories for one or more log "
253061da546Spatrick                             "channels.  If none specified, lists them all.",
254061da546Spatrick                             nullptr) {
255061da546Spatrick     CommandArgumentEntry arg;
256061da546Spatrick     CommandArgumentData channel_arg;
257061da546Spatrick 
258061da546Spatrick     // Define the first (and only) variant of this arg.
259061da546Spatrick     channel_arg.arg_type = eArgTypeLogChannel;
260061da546Spatrick     channel_arg.arg_repetition = eArgRepeatStar;
261061da546Spatrick 
262061da546Spatrick     // There is only one variant this argument could be; put it into the
263061da546Spatrick     // argument entry.
264061da546Spatrick     arg.push_back(channel_arg);
265061da546Spatrick 
266061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
267061da546Spatrick     m_arguments.push_back(arg);
268061da546Spatrick   }
269061da546Spatrick 
270061da546Spatrick   ~CommandObjectLogList() override = default;
271061da546Spatrick 
272061da546Spatrick   void
273061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
274061da546Spatrick                            OptionElementVector &opt_element_vector) override {
275061da546Spatrick     for (llvm::StringRef channel : Log::ListChannels())
276061da546Spatrick       request.TryCompleteCurrentArg(channel);
277061da546Spatrick   }
278061da546Spatrick 
279061da546Spatrick protected:
280061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
281061da546Spatrick     std::string output;
282061da546Spatrick     llvm::raw_string_ostream output_stream(output);
283061da546Spatrick     if (args.empty()) {
284061da546Spatrick       Log::ListAllLogChannels(output_stream);
285061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
286061da546Spatrick     } else {
287061da546Spatrick       bool success = true;
288061da546Spatrick       for (const auto &entry : args.entries())
289061da546Spatrick         success =
290061da546Spatrick             success && Log::ListChannelCategories(entry.ref(), output_stream);
291061da546Spatrick       if (success)
292061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishResult);
293061da546Spatrick     }
294061da546Spatrick     result.GetOutputStream() << output_stream.str();
295061da546Spatrick     return result.Succeeded();
296061da546Spatrick   }
297061da546Spatrick };
298061da546Spatrick 
299dda28197Spatrick class CommandObjectLogTimerEnable : public CommandObjectParsed {
300061da546Spatrick public:
301061da546Spatrick   // Constructors and Destructors
302dda28197Spatrick   CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
303dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers enable",
304dda28197Spatrick                             "enable LLDB internal performance timers",
305dda28197Spatrick                             "log timers enable <depth>") {
306dda28197Spatrick     CommandArgumentEntry arg;
307dda28197Spatrick     CommandArgumentData depth_arg;
308061da546Spatrick 
309dda28197Spatrick     // Define the first (and only) variant of this arg.
310dda28197Spatrick     depth_arg.arg_type = eArgTypeCount;
311dda28197Spatrick     depth_arg.arg_repetition = eArgRepeatOptional;
312dda28197Spatrick 
313dda28197Spatrick     // There is only one variant this argument could be; put it into the
314dda28197Spatrick     // argument entry.
315dda28197Spatrick     arg.push_back(depth_arg);
316dda28197Spatrick 
317dda28197Spatrick     // Push the data for the first argument into the m_arguments vector.
318dda28197Spatrick     m_arguments.push_back(arg);
319dda28197Spatrick   }
320dda28197Spatrick 
321dda28197Spatrick   ~CommandObjectLogTimerEnable() override = default;
322061da546Spatrick 
323061da546Spatrick protected:
324061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
325061da546Spatrick     result.SetStatus(eReturnStatusFailed);
326061da546Spatrick 
327dda28197Spatrick     if (args.GetArgumentCount() == 0) {
328061da546Spatrick       Timer::SetDisplayDepth(UINT32_MAX);
329061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
330dda28197Spatrick     } else if (args.GetArgumentCount() == 1) {
331061da546Spatrick       uint32_t depth;
332dda28197Spatrick       if (args[0].ref().consumeInteger(0, depth)) {
333061da546Spatrick         result.AppendError(
334061da546Spatrick             "Could not convert enable depth to an unsigned integer.");
335061da546Spatrick       } else {
336061da546Spatrick         Timer::SetDisplayDepth(depth);
337061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
338061da546Spatrick       }
339061da546Spatrick     }
340061da546Spatrick 
341061da546Spatrick     if (!result.Succeeded()) {
342061da546Spatrick       result.AppendError("Missing subcommand");
343061da546Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
344061da546Spatrick     }
345061da546Spatrick     return result.Succeeded();
346061da546Spatrick   }
347061da546Spatrick };
348061da546Spatrick 
349dda28197Spatrick class CommandObjectLogTimerDisable : public CommandObjectParsed {
350dda28197Spatrick public:
351dda28197Spatrick   // Constructors and Destructors
352dda28197Spatrick   CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
353dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers disable",
354dda28197Spatrick                             "disable LLDB internal performance timers",
355dda28197Spatrick                             nullptr) {}
356dda28197Spatrick 
357dda28197Spatrick   ~CommandObjectLogTimerDisable() override = default;
358dda28197Spatrick 
359dda28197Spatrick protected:
360dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
361dda28197Spatrick     Timer::DumpCategoryTimes(&result.GetOutputStream());
362dda28197Spatrick     Timer::SetDisplayDepth(0);
363dda28197Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
364dda28197Spatrick 
365dda28197Spatrick     if (!result.Succeeded()) {
366dda28197Spatrick       result.AppendError("Missing subcommand");
367dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
368dda28197Spatrick     }
369dda28197Spatrick     return result.Succeeded();
370dda28197Spatrick   }
371dda28197Spatrick };
372dda28197Spatrick 
373dda28197Spatrick class CommandObjectLogTimerDump : public CommandObjectParsed {
374dda28197Spatrick public:
375dda28197Spatrick   // Constructors and Destructors
376dda28197Spatrick   CommandObjectLogTimerDump(CommandInterpreter &interpreter)
377dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers dump",
378dda28197Spatrick                             "dump LLDB internal performance timers", nullptr) {}
379dda28197Spatrick 
380dda28197Spatrick   ~CommandObjectLogTimerDump() override = default;
381dda28197Spatrick 
382dda28197Spatrick protected:
383dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
384dda28197Spatrick     Timer::DumpCategoryTimes(&result.GetOutputStream());
385dda28197Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
386dda28197Spatrick 
387dda28197Spatrick     if (!result.Succeeded()) {
388dda28197Spatrick       result.AppendError("Missing subcommand");
389dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
390dda28197Spatrick     }
391dda28197Spatrick     return result.Succeeded();
392dda28197Spatrick   }
393dda28197Spatrick };
394dda28197Spatrick 
395dda28197Spatrick class CommandObjectLogTimerReset : public CommandObjectParsed {
396dda28197Spatrick public:
397dda28197Spatrick   // Constructors and Destructors
398dda28197Spatrick   CommandObjectLogTimerReset(CommandInterpreter &interpreter)
399dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers reset",
400dda28197Spatrick                             "reset LLDB internal performance timers", nullptr) {
401dda28197Spatrick   }
402dda28197Spatrick 
403dda28197Spatrick   ~CommandObjectLogTimerReset() override = default;
404dda28197Spatrick 
405dda28197Spatrick protected:
406dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
407dda28197Spatrick     Timer::ResetCategoryTimes();
408dda28197Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
409dda28197Spatrick 
410dda28197Spatrick     if (!result.Succeeded()) {
411dda28197Spatrick       result.AppendError("Missing subcommand");
412dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
413dda28197Spatrick     }
414dda28197Spatrick     return result.Succeeded();
415dda28197Spatrick   }
416dda28197Spatrick };
417dda28197Spatrick 
418dda28197Spatrick class CommandObjectLogTimerIncrement : public CommandObjectParsed {
419dda28197Spatrick public:
420dda28197Spatrick   // Constructors and Destructors
421dda28197Spatrick   CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
422dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers increment",
423dda28197Spatrick                             "increment LLDB internal performance timers",
424dda28197Spatrick                             "log timers increment <bool>") {
425dda28197Spatrick     CommandArgumentEntry arg;
426dda28197Spatrick     CommandArgumentData bool_arg;
427dda28197Spatrick 
428dda28197Spatrick     // Define the first (and only) variant of this arg.
429dda28197Spatrick     bool_arg.arg_type = eArgTypeBoolean;
430dda28197Spatrick     bool_arg.arg_repetition = eArgRepeatPlain;
431dda28197Spatrick 
432dda28197Spatrick     // There is only one variant this argument could be; put it into the
433dda28197Spatrick     // argument entry.
434dda28197Spatrick     arg.push_back(bool_arg);
435dda28197Spatrick 
436dda28197Spatrick     // Push the data for the first argument into the m_arguments vector.
437dda28197Spatrick     m_arguments.push_back(arg);
438dda28197Spatrick   }
439dda28197Spatrick 
440dda28197Spatrick   ~CommandObjectLogTimerIncrement() override = default;
441dda28197Spatrick 
442dda28197Spatrick   void
443dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
444dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
445dda28197Spatrick     request.TryCompleteCurrentArg("true");
446dda28197Spatrick     request.TryCompleteCurrentArg("false");
447dda28197Spatrick   }
448dda28197Spatrick 
449dda28197Spatrick protected:
450dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
451dda28197Spatrick     result.SetStatus(eReturnStatusFailed);
452dda28197Spatrick 
453dda28197Spatrick     if (args.GetArgumentCount() == 1) {
454dda28197Spatrick       bool success;
455dda28197Spatrick       bool increment =
456dda28197Spatrick           OptionArgParser::ToBoolean(args[0].ref(), false, &success);
457dda28197Spatrick 
458dda28197Spatrick       if (success) {
459dda28197Spatrick         Timer::SetQuiet(!increment);
460dda28197Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
461dda28197Spatrick       } else
462dda28197Spatrick         result.AppendError("Could not convert increment value to boolean.");
463dda28197Spatrick     }
464dda28197Spatrick 
465dda28197Spatrick     if (!result.Succeeded()) {
466dda28197Spatrick       result.AppendError("Missing subcommand");
467dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
468dda28197Spatrick     }
469dda28197Spatrick     return result.Succeeded();
470dda28197Spatrick   }
471dda28197Spatrick };
472dda28197Spatrick 
473dda28197Spatrick class CommandObjectLogTimer : public CommandObjectMultiword {
474dda28197Spatrick public:
475dda28197Spatrick   CommandObjectLogTimer(CommandInterpreter &interpreter)
476dda28197Spatrick       : CommandObjectMultiword(interpreter, "log timers",
477dda28197Spatrick                                "Enable, disable, dump, and reset LLDB internal "
478dda28197Spatrick                                "performance timers.",
479dda28197Spatrick                                "log timers < enable <depth> | disable | dump | "
480dda28197Spatrick                                "increment <bool> | reset >") {
481dda28197Spatrick     LoadSubCommand("enable", CommandObjectSP(
482dda28197Spatrick                                  new CommandObjectLogTimerEnable(interpreter)));
483dda28197Spatrick     LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
484dda28197Spatrick                                   interpreter)));
485dda28197Spatrick     LoadSubCommand("dump",
486dda28197Spatrick                    CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
487dda28197Spatrick     LoadSubCommand(
488dda28197Spatrick         "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
489dda28197Spatrick     LoadSubCommand(
490dda28197Spatrick         "increment",
491dda28197Spatrick         CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
492dda28197Spatrick   }
493dda28197Spatrick 
494dda28197Spatrick   ~CommandObjectLogTimer() override = default;
495dda28197Spatrick };
496dda28197Spatrick 
497061da546Spatrick CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
498061da546Spatrick     : CommandObjectMultiword(interpreter, "log",
499061da546Spatrick                              "Commands controlling LLDB internal logging.",
500061da546Spatrick                              "log <subcommand> [<command-options>]") {
501061da546Spatrick   LoadSubCommand("enable",
502061da546Spatrick                  CommandObjectSP(new CommandObjectLogEnable(interpreter)));
503061da546Spatrick   LoadSubCommand("disable",
504061da546Spatrick                  CommandObjectSP(new CommandObjectLogDisable(interpreter)));
505061da546Spatrick   LoadSubCommand("list",
506061da546Spatrick                  CommandObjectSP(new CommandObjectLogList(interpreter)));
507061da546Spatrick   LoadSubCommand("timers",
508061da546Spatrick                  CommandObjectSP(new CommandObjectLogTimer(interpreter)));
509061da546Spatrick }
510061da546Spatrick 
511061da546Spatrick CommandObjectLog::~CommandObjectLog() = default;
512