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"
12*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
13061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
14061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
15*f6aab3d8Srobert #include "lldb/Interpreter/OptionValueEnumeration.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/OptionValueUInt64.h"
17061da546Spatrick #include "lldb/Interpreter/Options.h"
18061da546Spatrick #include "lldb/Utility/Args.h"
19061da546Spatrick #include "lldb/Utility/FileSpec.h"
20061da546Spatrick #include "lldb/Utility/Log.h"
21061da546Spatrick #include "lldb/Utility/Stream.h"
22061da546Spatrick #include "lldb/Utility/Timer.h"
23061da546Spatrick 
24061da546Spatrick using namespace lldb;
25061da546Spatrick using namespace lldb_private;
26061da546Spatrick 
27*f6aab3d8Srobert #define LLDB_OPTIONS_log_enable
28*f6aab3d8Srobert #include "CommandOptions.inc"
29*f6aab3d8Srobert 
30*f6aab3d8Srobert #define LLDB_OPTIONS_log_dump
31061da546Spatrick #include "CommandOptions.inc"
32061da546Spatrick 
33061da546Spatrick /// Common completion logic for log enable/disable.
CompleteEnableDisable(CompletionRequest & request)34061da546Spatrick static void CompleteEnableDisable(CompletionRequest &request) {
35061da546Spatrick   size_t arg_index = request.GetCursorIndex();
36061da546Spatrick   if (arg_index == 0) { // We got: log enable/disable x[tab]
37061da546Spatrick     for (llvm::StringRef channel : Log::ListChannels())
38061da546Spatrick       request.TryCompleteCurrentArg(channel);
39061da546Spatrick   } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
40061da546Spatrick     llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
41061da546Spatrick     Log::ForEachChannelCategory(
42061da546Spatrick         channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
43061da546Spatrick           request.TryCompleteCurrentArg(name, desc);
44061da546Spatrick         });
45061da546Spatrick   }
46061da546Spatrick }
47061da546Spatrick 
48061da546Spatrick class CommandObjectLogEnable : public CommandObjectParsed {
49061da546Spatrick public:
50061da546Spatrick   // Constructors and Destructors
CommandObjectLogEnable(CommandInterpreter & interpreter)51061da546Spatrick   CommandObjectLogEnable(CommandInterpreter &interpreter)
52061da546Spatrick       : CommandObjectParsed(interpreter, "log enable",
53061da546Spatrick                             "Enable logging for a single log channel.",
54*f6aab3d8Srobert                             nullptr) {
55061da546Spatrick     CommandArgumentEntry arg1;
56061da546Spatrick     CommandArgumentEntry arg2;
57061da546Spatrick     CommandArgumentData channel_arg;
58061da546Spatrick     CommandArgumentData category_arg;
59061da546Spatrick 
60061da546Spatrick     // Define the first (and only) variant of this arg.
61061da546Spatrick     channel_arg.arg_type = eArgTypeLogChannel;
62061da546Spatrick     channel_arg.arg_repetition = eArgRepeatPlain;
63061da546Spatrick 
64061da546Spatrick     // There is only one variant this argument could be; put it into the
65061da546Spatrick     // argument entry.
66061da546Spatrick     arg1.push_back(channel_arg);
67061da546Spatrick 
68061da546Spatrick     category_arg.arg_type = eArgTypeLogCategory;
69061da546Spatrick     category_arg.arg_repetition = eArgRepeatPlus;
70061da546Spatrick 
71061da546Spatrick     arg2.push_back(category_arg);
72061da546Spatrick 
73061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
74061da546Spatrick     m_arguments.push_back(arg1);
75061da546Spatrick     m_arguments.push_back(arg2);
76061da546Spatrick   }
77061da546Spatrick 
78061da546Spatrick   ~CommandObjectLogEnable() override = default;
79061da546Spatrick 
GetOptions()80061da546Spatrick   Options *GetOptions() override { return &m_options; }
81061da546Spatrick 
82061da546Spatrick   class CommandOptions : public Options {
83061da546Spatrick   public:
84*f6aab3d8Srobert     CommandOptions() = default;
85061da546Spatrick 
86061da546Spatrick     ~CommandOptions() override = default;
87061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)88061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
89061da546Spatrick                           ExecutionContext *execution_context) override {
90061da546Spatrick       Status error;
91061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
92061da546Spatrick 
93061da546Spatrick       switch (short_option) {
94061da546Spatrick       case 'f':
95061da546Spatrick         log_file.SetFile(option_arg, FileSpec::Style::native);
96061da546Spatrick         FileSystem::Instance().Resolve(log_file);
97061da546Spatrick         break;
98*f6aab3d8Srobert       case 'h':
99*f6aab3d8Srobert         handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(
100*f6aab3d8Srobert             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
101*f6aab3d8Srobert         if (!error.Success())
102*f6aab3d8Srobert           error.SetErrorStringWithFormat(
103*f6aab3d8Srobert               "unrecognized value for log handler '%s'",
104*f6aab3d8Srobert               option_arg.str().c_str());
105*f6aab3d8Srobert         break;
106*f6aab3d8Srobert       case 'b':
107*f6aab3d8Srobert         error =
108*f6aab3d8Srobert             buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign);
109061da546Spatrick         break;
110061da546Spatrick       case 'v':
111061da546Spatrick         log_options |= LLDB_LOG_OPTION_VERBOSE;
112061da546Spatrick         break;
113061da546Spatrick       case 's':
114061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
115061da546Spatrick         break;
116061da546Spatrick       case 'T':
117061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
118061da546Spatrick         break;
119061da546Spatrick       case 'p':
120061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
121061da546Spatrick         break;
122061da546Spatrick       case 'n':
123061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
124061da546Spatrick         break;
125061da546Spatrick       case 'S':
126061da546Spatrick         log_options |= LLDB_LOG_OPTION_BACKTRACE;
127061da546Spatrick         break;
128061da546Spatrick       case 'a':
129061da546Spatrick         log_options |= LLDB_LOG_OPTION_APPEND;
130061da546Spatrick         break;
131061da546Spatrick       case 'F':
132061da546Spatrick         log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
133061da546Spatrick         break;
134061da546Spatrick       default:
135061da546Spatrick         llvm_unreachable("Unimplemented option");
136061da546Spatrick       }
137061da546Spatrick 
138061da546Spatrick       return error;
139061da546Spatrick     }
140061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)141061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
142061da546Spatrick       log_file.Clear();
143*f6aab3d8Srobert       buffer_size.Clear();
144*f6aab3d8Srobert       handler = eLogHandlerStream;
145061da546Spatrick       log_options = 0;
146061da546Spatrick     }
147061da546Spatrick 
GetDefinitions()148061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
149*f6aab3d8Srobert       return llvm::ArrayRef(g_log_enable_options);
150061da546Spatrick     }
151061da546Spatrick 
152061da546Spatrick     FileSpec log_file;
153*f6aab3d8Srobert     OptionValueUInt64 buffer_size;
154*f6aab3d8Srobert     LogHandlerKind handler = eLogHandlerStream;
155be691f3bSpatrick     uint32_t log_options = 0;
156061da546Spatrick   };
157061da546Spatrick 
158061da546Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)159061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
160061da546Spatrick                            OptionElementVector &opt_element_vector) override {
161061da546Spatrick     CompleteEnableDisable(request);
162061da546Spatrick   }
163061da546Spatrick 
164061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)165061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
166061da546Spatrick     if (args.GetArgumentCount() < 2) {
167061da546Spatrick       result.AppendErrorWithFormat(
168061da546Spatrick           "%s takes a log channel and one or more log types.\n",
169061da546Spatrick           m_cmd_name.c_str());
170061da546Spatrick       return false;
171061da546Spatrick     }
172061da546Spatrick 
173*f6aab3d8Srobert     if (m_options.handler == eLogHandlerCircular &&
174*f6aab3d8Srobert         m_options.buffer_size.GetCurrentValue() == 0) {
175*f6aab3d8Srobert       result.AppendError(
176*f6aab3d8Srobert           "the circular buffer handler requires a non-zero buffer size.\n");
177*f6aab3d8Srobert       return false;
178*f6aab3d8Srobert     }
179*f6aab3d8Srobert 
180061da546Spatrick     // Store into a std::string since we're about to shift the channel off.
181dda28197Spatrick     const std::string channel = std::string(args[0].ref());
182061da546Spatrick     args.Shift(); // Shift off the channel
183061da546Spatrick     char log_file[PATH_MAX];
184061da546Spatrick     if (m_options.log_file)
185061da546Spatrick       m_options.log_file.GetPath(log_file, sizeof(log_file));
186061da546Spatrick     else
187061da546Spatrick       log_file[0] = '\0';
188061da546Spatrick 
189061da546Spatrick     std::string error;
190061da546Spatrick     llvm::raw_string_ostream error_stream(error);
191*f6aab3d8Srobert     bool success = GetDebugger().EnableLog(
192*f6aab3d8Srobert         channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
193*f6aab3d8Srobert         m_options.buffer_size.GetCurrentValue(), m_options.handler,
194*f6aab3d8Srobert         error_stream);
195061da546Spatrick     result.GetErrorStream() << error_stream.str();
196061da546Spatrick 
197061da546Spatrick     if (success)
198061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
199061da546Spatrick     else
200061da546Spatrick       result.SetStatus(eReturnStatusFailed);
201061da546Spatrick     return result.Succeeded();
202061da546Spatrick   }
203061da546Spatrick 
204061da546Spatrick   CommandOptions m_options;
205061da546Spatrick };
206061da546Spatrick 
207061da546Spatrick class CommandObjectLogDisable : public CommandObjectParsed {
208061da546Spatrick public:
209061da546Spatrick   // Constructors and Destructors
CommandObjectLogDisable(CommandInterpreter & interpreter)210061da546Spatrick   CommandObjectLogDisable(CommandInterpreter &interpreter)
211061da546Spatrick       : CommandObjectParsed(interpreter, "log disable",
212061da546Spatrick                             "Disable one or more log channel categories.",
213061da546Spatrick                             nullptr) {
214061da546Spatrick     CommandArgumentEntry arg1;
215061da546Spatrick     CommandArgumentEntry arg2;
216061da546Spatrick     CommandArgumentData channel_arg;
217061da546Spatrick     CommandArgumentData category_arg;
218061da546Spatrick 
219061da546Spatrick     // Define the first (and only) variant of this arg.
220061da546Spatrick     channel_arg.arg_type = eArgTypeLogChannel;
221061da546Spatrick     channel_arg.arg_repetition = eArgRepeatPlain;
222061da546Spatrick 
223061da546Spatrick     // There is only one variant this argument could be; put it into the
224061da546Spatrick     // argument entry.
225061da546Spatrick     arg1.push_back(channel_arg);
226061da546Spatrick 
227061da546Spatrick     category_arg.arg_type = eArgTypeLogCategory;
228061da546Spatrick     category_arg.arg_repetition = eArgRepeatPlus;
229061da546Spatrick 
230061da546Spatrick     arg2.push_back(category_arg);
231061da546Spatrick 
232061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
233061da546Spatrick     m_arguments.push_back(arg1);
234061da546Spatrick     m_arguments.push_back(arg2);
235061da546Spatrick   }
236061da546Spatrick 
237061da546Spatrick   ~CommandObjectLogDisable() override = default;
238061da546Spatrick 
239061da546Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)240061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
241061da546Spatrick                            OptionElementVector &opt_element_vector) override {
242061da546Spatrick     CompleteEnableDisable(request);
243061da546Spatrick   }
244061da546Spatrick 
245061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)246061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
247061da546Spatrick     if (args.empty()) {
248061da546Spatrick       result.AppendErrorWithFormat(
249061da546Spatrick           "%s takes a log channel and one or more log types.\n",
250061da546Spatrick           m_cmd_name.c_str());
251061da546Spatrick       return false;
252061da546Spatrick     }
253061da546Spatrick 
254dda28197Spatrick     const std::string channel = std::string(args[0].ref());
255061da546Spatrick     args.Shift(); // Shift off the channel
256061da546Spatrick     if (channel == "all") {
257061da546Spatrick       Log::DisableAllLogChannels();
258061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
259061da546Spatrick     } else {
260061da546Spatrick       std::string error;
261061da546Spatrick       llvm::raw_string_ostream error_stream(error);
262061da546Spatrick       if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
263061da546Spatrick                                  error_stream))
264061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
265061da546Spatrick       result.GetErrorStream() << error_stream.str();
266061da546Spatrick     }
267061da546Spatrick     return result.Succeeded();
268061da546Spatrick   }
269061da546Spatrick };
270061da546Spatrick 
271061da546Spatrick class CommandObjectLogList : public CommandObjectParsed {
272061da546Spatrick public:
273061da546Spatrick   // Constructors and Destructors
CommandObjectLogList(CommandInterpreter & interpreter)274061da546Spatrick   CommandObjectLogList(CommandInterpreter &interpreter)
275061da546Spatrick       : CommandObjectParsed(interpreter, "log list",
276061da546Spatrick                             "List the log categories for one or more log "
277061da546Spatrick                             "channels.  If none specified, lists them all.",
278061da546Spatrick                             nullptr) {
279061da546Spatrick     CommandArgumentEntry arg;
280061da546Spatrick     CommandArgumentData channel_arg;
281061da546Spatrick 
282061da546Spatrick     // Define the first (and only) variant of this arg.
283061da546Spatrick     channel_arg.arg_type = eArgTypeLogChannel;
284061da546Spatrick     channel_arg.arg_repetition = eArgRepeatStar;
285061da546Spatrick 
286061da546Spatrick     // There is only one variant this argument could be; put it into the
287061da546Spatrick     // argument entry.
288061da546Spatrick     arg.push_back(channel_arg);
289061da546Spatrick 
290061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
291061da546Spatrick     m_arguments.push_back(arg);
292061da546Spatrick   }
293061da546Spatrick 
294061da546Spatrick   ~CommandObjectLogList() override = default;
295061da546Spatrick 
296061da546Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)297061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
298061da546Spatrick                            OptionElementVector &opt_element_vector) override {
299061da546Spatrick     for (llvm::StringRef channel : Log::ListChannels())
300061da546Spatrick       request.TryCompleteCurrentArg(channel);
301061da546Spatrick   }
302061da546Spatrick 
303061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)304061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
305061da546Spatrick     std::string output;
306061da546Spatrick     llvm::raw_string_ostream output_stream(output);
307061da546Spatrick     if (args.empty()) {
308061da546Spatrick       Log::ListAllLogChannels(output_stream);
309061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
310061da546Spatrick     } else {
311061da546Spatrick       bool success = true;
312061da546Spatrick       for (const auto &entry : args.entries())
313061da546Spatrick         success =
314061da546Spatrick             success && Log::ListChannelCategories(entry.ref(), output_stream);
315061da546Spatrick       if (success)
316061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishResult);
317061da546Spatrick     }
318061da546Spatrick     result.GetOutputStream() << output_stream.str();
319061da546Spatrick     return result.Succeeded();
320061da546Spatrick   }
321061da546Spatrick };
322*f6aab3d8Srobert class CommandObjectLogDump : public CommandObjectParsed {
323*f6aab3d8Srobert public:
CommandObjectLogDump(CommandInterpreter & interpreter)324*f6aab3d8Srobert   CommandObjectLogDump(CommandInterpreter &interpreter)
325*f6aab3d8Srobert       : CommandObjectParsed(interpreter, "log dump",
326*f6aab3d8Srobert                             "dump circular buffer logs", nullptr) {
327*f6aab3d8Srobert     CommandArgumentEntry arg1;
328*f6aab3d8Srobert     CommandArgumentData channel_arg;
329*f6aab3d8Srobert 
330*f6aab3d8Srobert     // Define the first (and only) variant of this arg.
331*f6aab3d8Srobert     channel_arg.arg_type = eArgTypeLogChannel;
332*f6aab3d8Srobert     channel_arg.arg_repetition = eArgRepeatPlain;
333*f6aab3d8Srobert 
334*f6aab3d8Srobert     // There is only one variant this argument could be; put it into the
335*f6aab3d8Srobert     // argument entry.
336*f6aab3d8Srobert     arg1.push_back(channel_arg);
337*f6aab3d8Srobert 
338*f6aab3d8Srobert     // Push the data for the first argument into the m_arguments vector.
339*f6aab3d8Srobert     m_arguments.push_back(arg1);
340*f6aab3d8Srobert   }
341*f6aab3d8Srobert 
342*f6aab3d8Srobert   ~CommandObjectLogDump() override = default;
343*f6aab3d8Srobert 
GetOptions()344*f6aab3d8Srobert   Options *GetOptions() override { return &m_options; }
345*f6aab3d8Srobert 
346*f6aab3d8Srobert   class CommandOptions : public Options {
347*f6aab3d8Srobert   public:
348*f6aab3d8Srobert     CommandOptions() = default;
349*f6aab3d8Srobert 
350*f6aab3d8Srobert     ~CommandOptions() override = default;
351*f6aab3d8Srobert 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)352*f6aab3d8Srobert     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
353*f6aab3d8Srobert                           ExecutionContext *execution_context) override {
354*f6aab3d8Srobert       Status error;
355*f6aab3d8Srobert       const int short_option = m_getopt_table[option_idx].val;
356*f6aab3d8Srobert 
357*f6aab3d8Srobert       switch (short_option) {
358*f6aab3d8Srobert       case 'f':
359*f6aab3d8Srobert         log_file.SetFile(option_arg, FileSpec::Style::native);
360*f6aab3d8Srobert         FileSystem::Instance().Resolve(log_file);
361*f6aab3d8Srobert         break;
362*f6aab3d8Srobert       default:
363*f6aab3d8Srobert         llvm_unreachable("Unimplemented option");
364*f6aab3d8Srobert       }
365*f6aab3d8Srobert 
366*f6aab3d8Srobert       return error;
367*f6aab3d8Srobert     }
368*f6aab3d8Srobert 
OptionParsingStarting(ExecutionContext * execution_context)369*f6aab3d8Srobert     void OptionParsingStarting(ExecutionContext *execution_context) override {
370*f6aab3d8Srobert       log_file.Clear();
371*f6aab3d8Srobert     }
372*f6aab3d8Srobert 
GetDefinitions()373*f6aab3d8Srobert     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
374*f6aab3d8Srobert       return llvm::ArrayRef(g_log_dump_options);
375*f6aab3d8Srobert     }
376*f6aab3d8Srobert 
377*f6aab3d8Srobert     FileSpec log_file;
378*f6aab3d8Srobert   };
379*f6aab3d8Srobert 
380*f6aab3d8Srobert   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)381*f6aab3d8Srobert   HandleArgumentCompletion(CompletionRequest &request,
382*f6aab3d8Srobert                            OptionElementVector &opt_element_vector) override {
383*f6aab3d8Srobert     CompleteEnableDisable(request);
384*f6aab3d8Srobert   }
385*f6aab3d8Srobert 
386*f6aab3d8Srobert protected:
DoExecute(Args & args,CommandReturnObject & result)387*f6aab3d8Srobert   bool DoExecute(Args &args, CommandReturnObject &result) override {
388*f6aab3d8Srobert     if (args.empty()) {
389*f6aab3d8Srobert       result.AppendErrorWithFormat(
390*f6aab3d8Srobert           "%s takes a log channel and one or more log types.\n",
391*f6aab3d8Srobert           m_cmd_name.c_str());
392*f6aab3d8Srobert       return false;
393*f6aab3d8Srobert     }
394*f6aab3d8Srobert 
395*f6aab3d8Srobert     std::unique_ptr<llvm::raw_ostream> stream_up;
396*f6aab3d8Srobert     if (m_options.log_file) {
397*f6aab3d8Srobert       const File::OpenOptions flags = File::eOpenOptionWriteOnly |
398*f6aab3d8Srobert                                       File::eOpenOptionCanCreate |
399*f6aab3d8Srobert                                       File::eOpenOptionTruncate;
400*f6aab3d8Srobert       llvm::Expected<FileUP> file = FileSystem::Instance().Open(
401*f6aab3d8Srobert           m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
402*f6aab3d8Srobert       if (!file) {
403*f6aab3d8Srobert         result.AppendErrorWithFormat("Unable to open log file '%s': %s",
404*f6aab3d8Srobert                                      m_options.log_file.GetPath().c_str(),
405*f6aab3d8Srobert                                      llvm::toString(file.takeError()).c_str());
406*f6aab3d8Srobert         return false;
407*f6aab3d8Srobert       }
408*f6aab3d8Srobert       stream_up = std::make_unique<llvm::raw_fd_ostream>(
409*f6aab3d8Srobert           (*file)->GetDescriptor(), /*shouldClose=*/true);
410*f6aab3d8Srobert     } else {
411*f6aab3d8Srobert       stream_up = std::make_unique<llvm::raw_fd_ostream>(
412*f6aab3d8Srobert           GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
413*f6aab3d8Srobert     }
414*f6aab3d8Srobert 
415*f6aab3d8Srobert     const std::string channel = std::string(args[0].ref());
416*f6aab3d8Srobert     std::string error;
417*f6aab3d8Srobert     llvm::raw_string_ostream error_stream(error);
418*f6aab3d8Srobert     if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
419*f6aab3d8Srobert       result.SetStatus(eReturnStatusSuccessFinishNoResult);
420*f6aab3d8Srobert     } else {
421*f6aab3d8Srobert       result.SetStatus(eReturnStatusFailed);
422*f6aab3d8Srobert       result.GetErrorStream() << error_stream.str();
423*f6aab3d8Srobert     }
424*f6aab3d8Srobert 
425*f6aab3d8Srobert     return result.Succeeded();
426*f6aab3d8Srobert   }
427*f6aab3d8Srobert 
428*f6aab3d8Srobert   CommandOptions m_options;
429*f6aab3d8Srobert };
430061da546Spatrick 
431dda28197Spatrick class CommandObjectLogTimerEnable : public CommandObjectParsed {
432061da546Spatrick public:
433061da546Spatrick   // Constructors and Destructors
CommandObjectLogTimerEnable(CommandInterpreter & interpreter)434dda28197Spatrick   CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
435dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers enable",
436dda28197Spatrick                             "enable LLDB internal performance timers",
437dda28197Spatrick                             "log timers enable <depth>") {
438dda28197Spatrick     CommandArgumentEntry arg;
439dda28197Spatrick     CommandArgumentData depth_arg;
440061da546Spatrick 
441dda28197Spatrick     // Define the first (and only) variant of this arg.
442dda28197Spatrick     depth_arg.arg_type = eArgTypeCount;
443dda28197Spatrick     depth_arg.arg_repetition = eArgRepeatOptional;
444dda28197Spatrick 
445dda28197Spatrick     // There is only one variant this argument could be; put it into the
446dda28197Spatrick     // argument entry.
447dda28197Spatrick     arg.push_back(depth_arg);
448dda28197Spatrick 
449dda28197Spatrick     // Push the data for the first argument into the m_arguments vector.
450dda28197Spatrick     m_arguments.push_back(arg);
451dda28197Spatrick   }
452dda28197Spatrick 
453dda28197Spatrick   ~CommandObjectLogTimerEnable() override = default;
454061da546Spatrick 
455061da546Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)456061da546Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
457061da546Spatrick     result.SetStatus(eReturnStatusFailed);
458061da546Spatrick 
459dda28197Spatrick     if (args.GetArgumentCount() == 0) {
460061da546Spatrick       Timer::SetDisplayDepth(UINT32_MAX);
461061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
462dda28197Spatrick     } else if (args.GetArgumentCount() == 1) {
463061da546Spatrick       uint32_t depth;
464dda28197Spatrick       if (args[0].ref().consumeInteger(0, depth)) {
465061da546Spatrick         result.AppendError(
466061da546Spatrick             "Could not convert enable depth to an unsigned integer.");
467061da546Spatrick       } else {
468061da546Spatrick         Timer::SetDisplayDepth(depth);
469061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
470061da546Spatrick       }
471061da546Spatrick     }
472061da546Spatrick 
473061da546Spatrick     if (!result.Succeeded()) {
474061da546Spatrick       result.AppendError("Missing subcommand");
475061da546Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
476061da546Spatrick     }
477061da546Spatrick     return result.Succeeded();
478061da546Spatrick   }
479061da546Spatrick };
480061da546Spatrick 
481dda28197Spatrick class CommandObjectLogTimerDisable : public CommandObjectParsed {
482dda28197Spatrick public:
483dda28197Spatrick   // Constructors and Destructors
CommandObjectLogTimerDisable(CommandInterpreter & interpreter)484dda28197Spatrick   CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
485dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers disable",
486dda28197Spatrick                             "disable LLDB internal performance timers",
487dda28197Spatrick                             nullptr) {}
488dda28197Spatrick 
489dda28197Spatrick   ~CommandObjectLogTimerDisable() override = default;
490dda28197Spatrick 
491dda28197Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)492dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
493dda28197Spatrick     Timer::DumpCategoryTimes(&result.GetOutputStream());
494dda28197Spatrick     Timer::SetDisplayDepth(0);
495dda28197Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
496dda28197Spatrick 
497dda28197Spatrick     if (!result.Succeeded()) {
498dda28197Spatrick       result.AppendError("Missing subcommand");
499dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
500dda28197Spatrick     }
501dda28197Spatrick     return result.Succeeded();
502dda28197Spatrick   }
503dda28197Spatrick };
504dda28197Spatrick 
505dda28197Spatrick class CommandObjectLogTimerDump : public CommandObjectParsed {
506dda28197Spatrick public:
507dda28197Spatrick   // Constructors and Destructors
CommandObjectLogTimerDump(CommandInterpreter & interpreter)508dda28197Spatrick   CommandObjectLogTimerDump(CommandInterpreter &interpreter)
509dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers dump",
510dda28197Spatrick                             "dump LLDB internal performance timers", nullptr) {}
511dda28197Spatrick 
512dda28197Spatrick   ~CommandObjectLogTimerDump() override = default;
513dda28197Spatrick 
514dda28197Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)515dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
516dda28197Spatrick     Timer::DumpCategoryTimes(&result.GetOutputStream());
517dda28197Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
518dda28197Spatrick 
519dda28197Spatrick     if (!result.Succeeded()) {
520dda28197Spatrick       result.AppendError("Missing subcommand");
521dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
522dda28197Spatrick     }
523dda28197Spatrick     return result.Succeeded();
524dda28197Spatrick   }
525dda28197Spatrick };
526dda28197Spatrick 
527dda28197Spatrick class CommandObjectLogTimerReset : public CommandObjectParsed {
528dda28197Spatrick public:
529dda28197Spatrick   // Constructors and Destructors
CommandObjectLogTimerReset(CommandInterpreter & interpreter)530dda28197Spatrick   CommandObjectLogTimerReset(CommandInterpreter &interpreter)
531dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers reset",
532dda28197Spatrick                             "reset LLDB internal performance timers", nullptr) {
533dda28197Spatrick   }
534dda28197Spatrick 
535dda28197Spatrick   ~CommandObjectLogTimerReset() override = default;
536dda28197Spatrick 
537dda28197Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)538dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
539dda28197Spatrick     Timer::ResetCategoryTimes();
540dda28197Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
541dda28197Spatrick 
542dda28197Spatrick     if (!result.Succeeded()) {
543dda28197Spatrick       result.AppendError("Missing subcommand");
544dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
545dda28197Spatrick     }
546dda28197Spatrick     return result.Succeeded();
547dda28197Spatrick   }
548dda28197Spatrick };
549dda28197Spatrick 
550dda28197Spatrick class CommandObjectLogTimerIncrement : public CommandObjectParsed {
551dda28197Spatrick public:
552dda28197Spatrick   // Constructors and Destructors
CommandObjectLogTimerIncrement(CommandInterpreter & interpreter)553dda28197Spatrick   CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
554dda28197Spatrick       : CommandObjectParsed(interpreter, "log timers increment",
555dda28197Spatrick                             "increment LLDB internal performance timers",
556dda28197Spatrick                             "log timers increment <bool>") {
557dda28197Spatrick     CommandArgumentEntry arg;
558dda28197Spatrick     CommandArgumentData bool_arg;
559dda28197Spatrick 
560dda28197Spatrick     // Define the first (and only) variant of this arg.
561dda28197Spatrick     bool_arg.arg_type = eArgTypeBoolean;
562dda28197Spatrick     bool_arg.arg_repetition = eArgRepeatPlain;
563dda28197Spatrick 
564dda28197Spatrick     // There is only one variant this argument could be; put it into the
565dda28197Spatrick     // argument entry.
566dda28197Spatrick     arg.push_back(bool_arg);
567dda28197Spatrick 
568dda28197Spatrick     // Push the data for the first argument into the m_arguments vector.
569dda28197Spatrick     m_arguments.push_back(arg);
570dda28197Spatrick   }
571dda28197Spatrick 
572dda28197Spatrick   ~CommandObjectLogTimerIncrement() override = default;
573dda28197Spatrick 
574dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)575dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
576dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
577dda28197Spatrick     request.TryCompleteCurrentArg("true");
578dda28197Spatrick     request.TryCompleteCurrentArg("false");
579dda28197Spatrick   }
580dda28197Spatrick 
581dda28197Spatrick protected:
DoExecute(Args & args,CommandReturnObject & result)582dda28197Spatrick   bool DoExecute(Args &args, CommandReturnObject &result) override {
583dda28197Spatrick     result.SetStatus(eReturnStatusFailed);
584dda28197Spatrick 
585dda28197Spatrick     if (args.GetArgumentCount() == 1) {
586dda28197Spatrick       bool success;
587dda28197Spatrick       bool increment =
588dda28197Spatrick           OptionArgParser::ToBoolean(args[0].ref(), false, &success);
589dda28197Spatrick 
590dda28197Spatrick       if (success) {
591dda28197Spatrick         Timer::SetQuiet(!increment);
592dda28197Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
593dda28197Spatrick       } else
594dda28197Spatrick         result.AppendError("Could not convert increment value to boolean.");
595dda28197Spatrick     }
596dda28197Spatrick 
597dda28197Spatrick     if (!result.Succeeded()) {
598dda28197Spatrick       result.AppendError("Missing subcommand");
599dda28197Spatrick       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
600dda28197Spatrick     }
601dda28197Spatrick     return result.Succeeded();
602dda28197Spatrick   }
603dda28197Spatrick };
604dda28197Spatrick 
605dda28197Spatrick class CommandObjectLogTimer : public CommandObjectMultiword {
606dda28197Spatrick public:
CommandObjectLogTimer(CommandInterpreter & interpreter)607dda28197Spatrick   CommandObjectLogTimer(CommandInterpreter &interpreter)
608dda28197Spatrick       : CommandObjectMultiword(interpreter, "log timers",
609dda28197Spatrick                                "Enable, disable, dump, and reset LLDB internal "
610dda28197Spatrick                                "performance timers.",
611dda28197Spatrick                                "log timers < enable <depth> | disable | dump | "
612dda28197Spatrick                                "increment <bool> | reset >") {
613dda28197Spatrick     LoadSubCommand("enable", CommandObjectSP(
614dda28197Spatrick                                  new CommandObjectLogTimerEnable(interpreter)));
615dda28197Spatrick     LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
616dda28197Spatrick                                   interpreter)));
617dda28197Spatrick     LoadSubCommand("dump",
618dda28197Spatrick                    CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
619dda28197Spatrick     LoadSubCommand(
620dda28197Spatrick         "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
621dda28197Spatrick     LoadSubCommand(
622dda28197Spatrick         "increment",
623dda28197Spatrick         CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
624dda28197Spatrick   }
625dda28197Spatrick 
626dda28197Spatrick   ~CommandObjectLogTimer() override = default;
627dda28197Spatrick };
628dda28197Spatrick 
CommandObjectLog(CommandInterpreter & interpreter)629061da546Spatrick CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
630061da546Spatrick     : CommandObjectMultiword(interpreter, "log",
631061da546Spatrick                              "Commands controlling LLDB internal logging.",
632061da546Spatrick                              "log <subcommand> [<command-options>]") {
633061da546Spatrick   LoadSubCommand("enable",
634061da546Spatrick                  CommandObjectSP(new CommandObjectLogEnable(interpreter)));
635061da546Spatrick   LoadSubCommand("disable",
636061da546Spatrick                  CommandObjectSP(new CommandObjectLogDisable(interpreter)));
637061da546Spatrick   LoadSubCommand("list",
638061da546Spatrick                  CommandObjectSP(new CommandObjectLogList(interpreter)));
639*f6aab3d8Srobert   LoadSubCommand("dump",
640*f6aab3d8Srobert                  CommandObjectSP(new CommandObjectLogDump(interpreter)));
641061da546Spatrick   LoadSubCommand("timers",
642061da546Spatrick                  CommandObjectSP(new CommandObjectLogTimer(interpreter)));
643061da546Spatrick }
644061da546Spatrick 
645061da546Spatrick CommandObjectLog::~CommandObjectLog() = default;
646