xref: /src/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- CommandObjectLog.cpp ----------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f3fbd1c0SDimitry Andric #include "CommandObjectLog.h"
10f034231aSEd Maste #include "lldb/Core/Debugger.h"
1174a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
124b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
13f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
14f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
15145449b1SDimitry Andric #include "lldb/Interpreter/OptionValueEnumeration.h"
16145449b1SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
1714f1b3e8SDimitry Andric #include "lldb/Interpreter/Options.h"
18f73363f1SDimitry Andric #include "lldb/Utility/Args.h"
1974a628f7SDimitry Andric #include "lldb/Utility/FileSpec.h"
2074a628f7SDimitry Andric #include "lldb/Utility/Log.h"
2174a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
221b306c26SDimitry Andric #include "lldb/Utility/Timer.h"
23f034231aSEd Maste 
24f034231aSEd Maste using namespace lldb;
25f034231aSEd Maste using namespace lldb_private;
26f034231aSEd Maste 
27145449b1SDimitry Andric #define LLDB_OPTIONS_log_enable
28145449b1SDimitry Andric #include "CommandOptions.inc"
29145449b1SDimitry Andric 
30145449b1SDimitry Andric #define LLDB_OPTIONS_log_dump
31ead24645SDimitry Andric #include "CommandOptions.inc"
32ead24645SDimitry Andric 
33ead24645SDimitry Andric /// Common completion logic for log enable/disable.
CompleteEnableDisable(CompletionRequest & request)34ead24645SDimitry Andric static void CompleteEnableDisable(CompletionRequest &request) {
35ead24645SDimitry Andric   size_t arg_index = request.GetCursorIndex();
36ead24645SDimitry Andric   if (arg_index == 0) { // We got: log enable/disable x[tab]
37ead24645SDimitry Andric     for (llvm::StringRef channel : Log::ListChannels())
38ead24645SDimitry Andric       request.TryCompleteCurrentArg(channel);
39ead24645SDimitry Andric   } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
40ead24645SDimitry Andric     llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
41ead24645SDimitry Andric     Log::ForEachChannelCategory(
42ead24645SDimitry Andric         channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
43ead24645SDimitry Andric           request.TryCompleteCurrentArg(name, desc);
44ead24645SDimitry Andric         });
45ead24645SDimitry Andric   }
46ead24645SDimitry Andric }
4714f1b3e8SDimitry Andric 
4814f1b3e8SDimitry Andric class CommandObjectLogEnable : public CommandObjectParsed {
49f034231aSEd Maste public:
50f034231aSEd Maste   // Constructors and Destructors
CommandObjectLogEnable(CommandInterpreter & interpreter)5114f1b3e8SDimitry Andric   CommandObjectLogEnable(CommandInterpreter &interpreter)
5214f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "log enable",
53f034231aSEd Maste                             "Enable logging for a single log channel.",
546f8fc217SDimitry Andric                             nullptr) {
55f034231aSEd Maste     CommandArgumentEntry arg1;
56f034231aSEd Maste     CommandArgumentEntry arg2;
57f034231aSEd Maste     CommandArgumentData channel_arg;
58f034231aSEd Maste     CommandArgumentData category_arg;
59f034231aSEd Maste 
60f034231aSEd Maste     // Define the first (and only) variant of this arg.
61f034231aSEd Maste     channel_arg.arg_type = eArgTypeLogChannel;
62f034231aSEd Maste     channel_arg.arg_repetition = eArgRepeatPlain;
63f034231aSEd Maste 
6414f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
6514f1b3e8SDimitry Andric     // argument entry.
66f034231aSEd Maste     arg1.push_back(channel_arg);
67f034231aSEd Maste 
68f034231aSEd Maste     category_arg.arg_type = eArgTypeLogCategory;
69f034231aSEd Maste     category_arg.arg_repetition = eArgRepeatPlus;
70f034231aSEd Maste 
71f034231aSEd Maste     arg2.push_back(category_arg);
72f034231aSEd Maste 
73f034231aSEd Maste     // Push the data for the first argument into the m_arguments vector.
74f034231aSEd Maste     m_arguments.push_back(arg1);
75f034231aSEd Maste     m_arguments.push_back(arg2);
76f034231aSEd Maste   }
77f034231aSEd Maste 
78f3fbd1c0SDimitry Andric   ~CommandObjectLogEnable() override = default;
79f034231aSEd Maste 
GetOptions()8014f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_options; }
81f034231aSEd Maste 
8214f1b3e8SDimitry Andric   class CommandOptions : public Options {
83f034231aSEd Maste   public:
84145449b1SDimitry Andric     CommandOptions() = default;
85f034231aSEd Maste 
86f3fbd1c0SDimitry Andric     ~CommandOptions() override = default;
87f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)88b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
8914f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
90b76161e4SDimitry Andric       Status error;
91f034231aSEd Maste       const int short_option = m_getopt_table[option_idx].val;
92f034231aSEd Maste 
9314f1b3e8SDimitry Andric       switch (short_option) {
9414f1b3e8SDimitry Andric       case 'f':
9594994d37SDimitry Andric         log_file.SetFile(option_arg, FileSpec::Style::native);
9694994d37SDimitry Andric         FileSystem::Instance().Resolve(log_file);
9714f1b3e8SDimitry Andric         break;
98145449b1SDimitry Andric       case 'h':
99145449b1SDimitry Andric         handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(
100145449b1SDimitry Andric             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
101145449b1SDimitry Andric         if (!error.Success())
102145449b1SDimitry Andric           error.SetErrorStringWithFormat(
103145449b1SDimitry Andric               "unrecognized value for log handler '%s'",
104145449b1SDimitry Andric               option_arg.str().c_str());
105145449b1SDimitry Andric         break;
106145449b1SDimitry Andric       case 'b':
107145449b1SDimitry Andric         error =
108145449b1SDimitry Andric             buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign);
10914f1b3e8SDimitry Andric         break;
11014f1b3e8SDimitry Andric       case 'v':
11114f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_VERBOSE;
11214f1b3e8SDimitry Andric         break;
11314f1b3e8SDimitry Andric       case 's':
11414f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
11514f1b3e8SDimitry Andric         break;
11614f1b3e8SDimitry Andric       case 'T':
11714f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
11814f1b3e8SDimitry Andric         break;
11914f1b3e8SDimitry Andric       case 'p':
12014f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
12114f1b3e8SDimitry Andric         break;
12214f1b3e8SDimitry Andric       case 'n':
12314f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
12414f1b3e8SDimitry Andric         break;
12514f1b3e8SDimitry Andric       case 'S':
12614f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_BACKTRACE;
12714f1b3e8SDimitry Andric         break;
12814f1b3e8SDimitry Andric       case 'a':
12914f1b3e8SDimitry Andric         log_options |= LLDB_LOG_OPTION_APPEND;
13014f1b3e8SDimitry Andric         break;
13174a628f7SDimitry Andric       case 'F':
13274a628f7SDimitry Andric         log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
13374a628f7SDimitry Andric         break;
134f034231aSEd Maste       default:
135ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
136f034231aSEd Maste       }
137f034231aSEd Maste 
138f034231aSEd Maste       return error;
139f034231aSEd Maste     }
140f034231aSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)14114f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
142f034231aSEd Maste       log_file.Clear();
143145449b1SDimitry Andric       buffer_size.Clear();
144145449b1SDimitry Andric       handler = eLogHandlerStream;
145f034231aSEd Maste       log_options = 0;
146f034231aSEd Maste     }
147f034231aSEd Maste 
GetDefinitions()14814f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
149e3b55780SDimitry Andric       return llvm::ArrayRef(g_log_enable_options);
150f034231aSEd Maste     }
151f034231aSEd Maste 
152f034231aSEd Maste     FileSpec log_file;
153145449b1SDimitry Andric     OptionValueUInt64 buffer_size;
154145449b1SDimitry Andric     LogHandlerKind handler = eLogHandlerStream;
155344a3780SDimitry Andric     uint32_t log_options = 0;
156f034231aSEd Maste   };
157f034231aSEd Maste 
158ead24645SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)159ead24645SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
160ead24645SDimitry Andric                            OptionElementVector &opt_element_vector) override {
161ead24645SDimitry Andric     CompleteEnableDisable(request);
162ead24645SDimitry Andric   }
163ead24645SDimitry Andric 
164f034231aSEd Maste protected:
DoExecute(Args & args,CommandReturnObject & result)165b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
16614f1b3e8SDimitry Andric     if (args.GetArgumentCount() < 2) {
16714f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
16814f1b3e8SDimitry Andric           "%s takes a log channel and one or more log types.\n",
16914f1b3e8SDimitry Andric           m_cmd_name.c_str());
170b1c73532SDimitry Andric       return;
171f034231aSEd Maste     }
17214f1b3e8SDimitry Andric 
173145449b1SDimitry Andric     if (m_options.handler == eLogHandlerCircular &&
174145449b1SDimitry Andric         m_options.buffer_size.GetCurrentValue() == 0) {
175145449b1SDimitry Andric       result.AppendError(
176145449b1SDimitry Andric           "the circular buffer handler requires a non-zero buffer size.\n");
177b1c73532SDimitry Andric       return;
178145449b1SDimitry Andric     }
179145449b1SDimitry Andric 
1807fa27ce4SDimitry Andric     if ((m_options.handler != eLogHandlerCircular &&
1817fa27ce4SDimitry Andric          m_options.handler != eLogHandlerStream) &&
1827fa27ce4SDimitry Andric         m_options.buffer_size.GetCurrentValue() != 0) {
1837fa27ce4SDimitry Andric       result.AppendError("a buffer size can only be specified for the circular "
1847fa27ce4SDimitry Andric                          "and stream buffer handler.\n");
185b1c73532SDimitry Andric       return;
1867fa27ce4SDimitry Andric     }
1877fa27ce4SDimitry Andric 
1887fa27ce4SDimitry Andric     if (m_options.handler != eLogHandlerStream && m_options.log_file) {
1897fa27ce4SDimitry Andric       result.AppendError(
1907fa27ce4SDimitry Andric           "a file name can only be specified for the stream handler.\n");
191b1c73532SDimitry Andric       return;
1927fa27ce4SDimitry Andric     }
1937fa27ce4SDimitry Andric 
19414f1b3e8SDimitry Andric     // Store into a std::string since we're about to shift the channel off.
195cfca06d7SDimitry Andric     const std::string channel = std::string(args[0].ref());
196f034231aSEd Maste     args.Shift(); // Shift off the channel
197f034231aSEd Maste     char log_file[PATH_MAX];
198f034231aSEd Maste     if (m_options.log_file)
199f034231aSEd Maste       m_options.log_file.GetPath(log_file, sizeof(log_file));
200f034231aSEd Maste     else
201f034231aSEd Maste       log_file[0] = '\0';
20274a628f7SDimitry Andric 
20374a628f7SDimitry Andric     std::string error;
20474a628f7SDimitry Andric     llvm::raw_string_ostream error_stream(error);
205145449b1SDimitry Andric     bool success = GetDebugger().EnableLog(
206145449b1SDimitry Andric         channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
207145449b1SDimitry Andric         m_options.buffer_size.GetCurrentValue(), m_options.handler,
208145449b1SDimitry Andric         error_stream);
20974a628f7SDimitry Andric     result.GetErrorStream() << error_stream.str();
21074a628f7SDimitry Andric 
211f034231aSEd Maste     if (success)
212f034231aSEd Maste       result.SetStatus(eReturnStatusSuccessFinishNoResult);
213f034231aSEd Maste     else
214f034231aSEd Maste       result.SetStatus(eReturnStatusFailed);
215f034231aSEd Maste   }
216f034231aSEd Maste 
217f034231aSEd Maste   CommandOptions m_options;
218f034231aSEd Maste };
219f034231aSEd Maste 
22014f1b3e8SDimitry Andric class CommandObjectLogDisable : public CommandObjectParsed {
221f034231aSEd Maste public:
222f034231aSEd Maste   // Constructors and Destructors
CommandObjectLogDisable(CommandInterpreter & interpreter)22314f1b3e8SDimitry Andric   CommandObjectLogDisable(CommandInterpreter &interpreter)
22414f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "log disable",
225f034231aSEd Maste                             "Disable one or more log channel categories.",
22614f1b3e8SDimitry Andric                             nullptr) {
227f034231aSEd Maste     CommandArgumentEntry arg1;
228f034231aSEd Maste     CommandArgumentEntry arg2;
229f034231aSEd Maste     CommandArgumentData channel_arg;
230f034231aSEd Maste     CommandArgumentData category_arg;
231f034231aSEd Maste 
232f034231aSEd Maste     // Define the first (and only) variant of this arg.
233f034231aSEd Maste     channel_arg.arg_type = eArgTypeLogChannel;
234f034231aSEd Maste     channel_arg.arg_repetition = eArgRepeatPlain;
235f034231aSEd Maste 
23614f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
23714f1b3e8SDimitry Andric     // argument entry.
238f034231aSEd Maste     arg1.push_back(channel_arg);
239f034231aSEd Maste 
240f034231aSEd Maste     category_arg.arg_type = eArgTypeLogCategory;
241f034231aSEd Maste     category_arg.arg_repetition = eArgRepeatPlus;
242f034231aSEd Maste 
243f034231aSEd Maste     arg2.push_back(category_arg);
244f034231aSEd Maste 
245f034231aSEd Maste     // Push the data for the first argument into the m_arguments vector.
246f034231aSEd Maste     m_arguments.push_back(arg1);
247f034231aSEd Maste     m_arguments.push_back(arg2);
248f034231aSEd Maste   }
249f034231aSEd Maste 
250f3fbd1c0SDimitry Andric   ~CommandObjectLogDisable() override = default;
251f034231aSEd Maste 
252ead24645SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)253ead24645SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
254ead24645SDimitry Andric                            OptionElementVector &opt_element_vector) override {
255ead24645SDimitry Andric     CompleteEnableDisable(request);
256ead24645SDimitry Andric   }
257ead24645SDimitry Andric 
258f034231aSEd Maste protected:
DoExecute(Args & args,CommandReturnObject & result)259b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
26014f1b3e8SDimitry Andric     if (args.empty()) {
26114f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
26214f1b3e8SDimitry Andric           "%s takes a log channel and one or more log types.\n",
26314f1b3e8SDimitry Andric           m_cmd_name.c_str());
264b1c73532SDimitry Andric       return;
265f034231aSEd Maste     }
26614f1b3e8SDimitry Andric 
267cfca06d7SDimitry Andric     const std::string channel = std::string(args[0].ref());
268f034231aSEd Maste     args.Shift(); // Shift off the channel
26974a628f7SDimitry Andric     if (channel == "all") {
27074a628f7SDimitry Andric       Log::DisableAllLogChannels();
271f034231aSEd Maste       result.SetStatus(eReturnStatusSuccessFinishNoResult);
27214f1b3e8SDimitry Andric     } else {
27374a628f7SDimitry Andric       std::string error;
27474a628f7SDimitry Andric       llvm::raw_string_ostream error_stream(error);
27574a628f7SDimitry Andric       if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
27674a628f7SDimitry Andric                                  error_stream))
277f034231aSEd Maste         result.SetStatus(eReturnStatusSuccessFinishNoResult);
27874a628f7SDimitry Andric       result.GetErrorStream() << error_stream.str();
279f034231aSEd Maste     }
280f034231aSEd Maste   }
281f034231aSEd Maste };
282f034231aSEd Maste 
28314f1b3e8SDimitry Andric class CommandObjectLogList : public CommandObjectParsed {
284f034231aSEd Maste public:
285f034231aSEd Maste   // Constructors and Destructors
CommandObjectLogList(CommandInterpreter & interpreter)28614f1b3e8SDimitry Andric   CommandObjectLogList(CommandInterpreter &interpreter)
28714f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "log list",
28814f1b3e8SDimitry Andric                             "List the log categories for one or more log "
28914f1b3e8SDimitry Andric                             "channels.  If none specified, lists them all.",
29014f1b3e8SDimitry Andric                             nullptr) {
291ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeLogChannel, eArgRepeatStar);
292f034231aSEd Maste   }
293f034231aSEd Maste 
294f3fbd1c0SDimitry Andric   ~CommandObjectLogList() override = default;
295f034231aSEd Maste 
296ead24645SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)297ead24645SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
298ead24645SDimitry Andric                            OptionElementVector &opt_element_vector) override {
299ead24645SDimitry Andric     for (llvm::StringRef channel : Log::ListChannels())
300ead24645SDimitry Andric       request.TryCompleteCurrentArg(channel);
301ead24645SDimitry Andric   }
302ead24645SDimitry Andric 
303f034231aSEd Maste protected:
DoExecute(Args & args,CommandReturnObject & result)304b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
30574a628f7SDimitry Andric     std::string output;
30674a628f7SDimitry Andric     llvm::raw_string_ostream output_stream(output);
30714f1b3e8SDimitry Andric     if (args.empty()) {
30874a628f7SDimitry Andric       Log::ListAllLogChannels(output_stream);
309f034231aSEd Maste       result.SetStatus(eReturnStatusSuccessFinishResult);
31014f1b3e8SDimitry Andric     } else {
31174a628f7SDimitry Andric       bool success = true;
31274a628f7SDimitry Andric       for (const auto &entry : args.entries())
31374a628f7SDimitry Andric         success =
314ead24645SDimitry Andric             success && Log::ListChannelCategories(entry.ref(), output_stream);
31574a628f7SDimitry Andric       if (success)
316f034231aSEd Maste         result.SetStatus(eReturnStatusSuccessFinishResult);
317f034231aSEd Maste     }
31874a628f7SDimitry Andric     result.GetOutputStream() << output_stream.str();
319f034231aSEd Maste   }
320f034231aSEd Maste };
321145449b1SDimitry Andric class CommandObjectLogDump : public CommandObjectParsed {
322145449b1SDimitry Andric public:
CommandObjectLogDump(CommandInterpreter & interpreter)323145449b1SDimitry Andric   CommandObjectLogDump(CommandInterpreter &interpreter)
324145449b1SDimitry Andric       : CommandObjectParsed(interpreter, "log dump",
325145449b1SDimitry Andric                             "dump circular buffer logs", nullptr) {
326ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeLogChannel);
327145449b1SDimitry Andric   }
328145449b1SDimitry Andric 
329145449b1SDimitry Andric   ~CommandObjectLogDump() override = default;
330145449b1SDimitry Andric 
GetOptions()331145449b1SDimitry Andric   Options *GetOptions() override { return &m_options; }
332145449b1SDimitry Andric 
333145449b1SDimitry Andric   class CommandOptions : public Options {
334145449b1SDimitry Andric   public:
335145449b1SDimitry Andric     CommandOptions() = default;
336145449b1SDimitry Andric 
337145449b1SDimitry Andric     ~CommandOptions() override = default;
338145449b1SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)339145449b1SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
340145449b1SDimitry Andric                           ExecutionContext *execution_context) override {
341145449b1SDimitry Andric       Status error;
342145449b1SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
343145449b1SDimitry Andric 
344145449b1SDimitry Andric       switch (short_option) {
345145449b1SDimitry Andric       case 'f':
346145449b1SDimitry Andric         log_file.SetFile(option_arg, FileSpec::Style::native);
347145449b1SDimitry Andric         FileSystem::Instance().Resolve(log_file);
348145449b1SDimitry Andric         break;
349145449b1SDimitry Andric       default:
350145449b1SDimitry Andric         llvm_unreachable("Unimplemented option");
351145449b1SDimitry Andric       }
352145449b1SDimitry Andric 
353145449b1SDimitry Andric       return error;
354145449b1SDimitry Andric     }
355145449b1SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)356145449b1SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
357145449b1SDimitry Andric       log_file.Clear();
358145449b1SDimitry Andric     }
359145449b1SDimitry Andric 
GetDefinitions()360145449b1SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
361e3b55780SDimitry Andric       return llvm::ArrayRef(g_log_dump_options);
362145449b1SDimitry Andric     }
363145449b1SDimitry Andric 
364145449b1SDimitry Andric     FileSpec log_file;
365145449b1SDimitry Andric   };
366145449b1SDimitry Andric 
367145449b1SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)368145449b1SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
369145449b1SDimitry Andric                            OptionElementVector &opt_element_vector) override {
370145449b1SDimitry Andric     CompleteEnableDisable(request);
371145449b1SDimitry Andric   }
372145449b1SDimitry Andric 
373145449b1SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)374b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
375145449b1SDimitry Andric     if (args.empty()) {
376145449b1SDimitry Andric       result.AppendErrorWithFormat(
377145449b1SDimitry Andric           "%s takes a log channel and one or more log types.\n",
378145449b1SDimitry Andric           m_cmd_name.c_str());
379b1c73532SDimitry Andric       return;
380145449b1SDimitry Andric     }
381145449b1SDimitry Andric 
382145449b1SDimitry Andric     std::unique_ptr<llvm::raw_ostream> stream_up;
383145449b1SDimitry Andric     if (m_options.log_file) {
384145449b1SDimitry Andric       const File::OpenOptions flags = File::eOpenOptionWriteOnly |
385145449b1SDimitry Andric                                       File::eOpenOptionCanCreate |
386145449b1SDimitry Andric                                       File::eOpenOptionTruncate;
387145449b1SDimitry Andric       llvm::Expected<FileUP> file = FileSystem::Instance().Open(
388145449b1SDimitry Andric           m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
389145449b1SDimitry Andric       if (!file) {
390145449b1SDimitry Andric         result.AppendErrorWithFormat("Unable to open log file '%s': %s",
391e3b55780SDimitry Andric                                      m_options.log_file.GetPath().c_str(),
392145449b1SDimitry Andric                                      llvm::toString(file.takeError()).c_str());
393b1c73532SDimitry Andric         return;
394145449b1SDimitry Andric       }
395145449b1SDimitry Andric       stream_up = std::make_unique<llvm::raw_fd_ostream>(
396145449b1SDimitry Andric           (*file)->GetDescriptor(), /*shouldClose=*/true);
397145449b1SDimitry Andric     } else {
398145449b1SDimitry Andric       stream_up = std::make_unique<llvm::raw_fd_ostream>(
399145449b1SDimitry Andric           GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
400145449b1SDimitry Andric     }
401145449b1SDimitry Andric 
402145449b1SDimitry Andric     const std::string channel = std::string(args[0].ref());
403145449b1SDimitry Andric     std::string error;
404145449b1SDimitry Andric     llvm::raw_string_ostream error_stream(error);
405145449b1SDimitry Andric     if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
406145449b1SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
407145449b1SDimitry Andric     } else {
408145449b1SDimitry Andric       result.SetStatus(eReturnStatusFailed);
409145449b1SDimitry Andric       result.GetErrorStream() << error_stream.str();
410145449b1SDimitry Andric     }
411145449b1SDimitry Andric   }
412145449b1SDimitry Andric 
413145449b1SDimitry Andric   CommandOptions m_options;
414145449b1SDimitry Andric };
415f034231aSEd Maste 
416cfca06d7SDimitry Andric class CommandObjectLogTimerEnable : public CommandObjectParsed {
417f034231aSEd Maste public:
418f034231aSEd Maste   // Constructors and Destructors
CommandObjectLogTimerEnable(CommandInterpreter & interpreter)419cfca06d7SDimitry Andric   CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
420cfca06d7SDimitry Andric       : CommandObjectParsed(interpreter, "log timers enable",
421cfca06d7SDimitry Andric                             "enable LLDB internal performance timers",
422cfca06d7SDimitry Andric                             "log timers enable <depth>") {
423ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeCount, eArgRepeatOptional);
424cfca06d7SDimitry Andric   }
425cfca06d7SDimitry Andric 
426cfca06d7SDimitry Andric   ~CommandObjectLogTimerEnable() override = default;
427f034231aSEd Maste 
428f034231aSEd Maste protected:
DoExecute(Args & args,CommandReturnObject & result)429b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
430f034231aSEd Maste     result.SetStatus(eReturnStatusFailed);
431f034231aSEd Maste 
432cfca06d7SDimitry Andric     if (args.GetArgumentCount() == 0) {
433f034231aSEd Maste       Timer::SetDisplayDepth(UINT32_MAX);
434f034231aSEd Maste       result.SetStatus(eReturnStatusSuccessFinishNoResult);
435cfca06d7SDimitry Andric     } else if (args.GetArgumentCount() == 1) {
43614f1b3e8SDimitry Andric       uint32_t depth;
437cfca06d7SDimitry Andric       if (args[0].ref().consumeInteger(0, depth)) {
43814f1b3e8SDimitry Andric         result.AppendError(
43914f1b3e8SDimitry Andric             "Could not convert enable depth to an unsigned integer.");
44014f1b3e8SDimitry Andric       } else {
441f034231aSEd Maste         Timer::SetDisplayDepth(depth);
442f034231aSEd Maste         result.SetStatus(eReturnStatusSuccessFinishNoResult);
443f034231aSEd Maste       }
444f034231aSEd Maste     }
445f034231aSEd Maste 
44614f1b3e8SDimitry Andric     if (!result.Succeeded()) {
447f034231aSEd Maste       result.AppendError("Missing subcommand");
448f034231aSEd Maste       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
449f034231aSEd Maste     }
450f034231aSEd Maste   }
451f034231aSEd Maste };
452f034231aSEd Maste 
453cfca06d7SDimitry Andric class CommandObjectLogTimerDisable : public CommandObjectParsed {
454cfca06d7SDimitry Andric public:
455cfca06d7SDimitry Andric   // Constructors and Destructors
CommandObjectLogTimerDisable(CommandInterpreter & interpreter)456cfca06d7SDimitry Andric   CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
457cfca06d7SDimitry Andric       : CommandObjectParsed(interpreter, "log timers disable",
458cfca06d7SDimitry Andric                             "disable LLDB internal performance timers",
459cfca06d7SDimitry Andric                             nullptr) {}
460cfca06d7SDimitry Andric 
461cfca06d7SDimitry Andric   ~CommandObjectLogTimerDisable() override = default;
462cfca06d7SDimitry Andric 
463cfca06d7SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)464b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
4657fa27ce4SDimitry Andric     Timer::DumpCategoryTimes(result.GetOutputStream());
466cfca06d7SDimitry Andric     Timer::SetDisplayDepth(0);
467cfca06d7SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
468cfca06d7SDimitry Andric 
469cfca06d7SDimitry Andric     if (!result.Succeeded()) {
470cfca06d7SDimitry Andric       result.AppendError("Missing subcommand");
471cfca06d7SDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
472cfca06d7SDimitry Andric     }
473cfca06d7SDimitry Andric   }
474cfca06d7SDimitry Andric };
475cfca06d7SDimitry Andric 
476cfca06d7SDimitry Andric class CommandObjectLogTimerDump : public CommandObjectParsed {
477cfca06d7SDimitry Andric public:
478cfca06d7SDimitry Andric   // Constructors and Destructors
CommandObjectLogTimerDump(CommandInterpreter & interpreter)479cfca06d7SDimitry Andric   CommandObjectLogTimerDump(CommandInterpreter &interpreter)
480cfca06d7SDimitry Andric       : CommandObjectParsed(interpreter, "log timers dump",
481cfca06d7SDimitry Andric                             "dump LLDB internal performance timers", nullptr) {}
482cfca06d7SDimitry Andric 
483cfca06d7SDimitry Andric   ~CommandObjectLogTimerDump() override = default;
484cfca06d7SDimitry Andric 
485cfca06d7SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)486b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
4877fa27ce4SDimitry Andric     Timer::DumpCategoryTimes(result.GetOutputStream());
488cfca06d7SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
489cfca06d7SDimitry Andric 
490cfca06d7SDimitry Andric     if (!result.Succeeded()) {
491cfca06d7SDimitry Andric       result.AppendError("Missing subcommand");
492cfca06d7SDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
493cfca06d7SDimitry Andric     }
494cfca06d7SDimitry Andric   }
495cfca06d7SDimitry Andric };
496cfca06d7SDimitry Andric 
497cfca06d7SDimitry Andric class CommandObjectLogTimerReset : public CommandObjectParsed {
498cfca06d7SDimitry Andric public:
499cfca06d7SDimitry Andric   // Constructors and Destructors
CommandObjectLogTimerReset(CommandInterpreter & interpreter)500cfca06d7SDimitry Andric   CommandObjectLogTimerReset(CommandInterpreter &interpreter)
501cfca06d7SDimitry Andric       : CommandObjectParsed(interpreter, "log timers reset",
502cfca06d7SDimitry Andric                             "reset LLDB internal performance timers", nullptr) {
503cfca06d7SDimitry Andric   }
504cfca06d7SDimitry Andric 
505cfca06d7SDimitry Andric   ~CommandObjectLogTimerReset() override = default;
506cfca06d7SDimitry Andric 
507cfca06d7SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)508b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
509cfca06d7SDimitry Andric     Timer::ResetCategoryTimes();
510cfca06d7SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
511cfca06d7SDimitry Andric 
512cfca06d7SDimitry Andric     if (!result.Succeeded()) {
513cfca06d7SDimitry Andric       result.AppendError("Missing subcommand");
514cfca06d7SDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
515cfca06d7SDimitry Andric     }
516cfca06d7SDimitry Andric   }
517cfca06d7SDimitry Andric };
518cfca06d7SDimitry Andric 
519cfca06d7SDimitry Andric class CommandObjectLogTimerIncrement : public CommandObjectParsed {
520cfca06d7SDimitry Andric public:
521cfca06d7SDimitry Andric   // Constructors and Destructors
CommandObjectLogTimerIncrement(CommandInterpreter & interpreter)522cfca06d7SDimitry Andric   CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
523cfca06d7SDimitry Andric       : CommandObjectParsed(interpreter, "log timers increment",
524cfca06d7SDimitry Andric                             "increment LLDB internal performance timers",
525cfca06d7SDimitry Andric                             "log timers increment <bool>") {
526ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeBoolean);
527cfca06d7SDimitry Andric   }
528cfca06d7SDimitry Andric 
529cfca06d7SDimitry Andric   ~CommandObjectLogTimerIncrement() override = default;
530cfca06d7SDimitry Andric 
531cfca06d7SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)532cfca06d7SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
533cfca06d7SDimitry Andric                            OptionElementVector &opt_element_vector) override {
534cfca06d7SDimitry Andric     request.TryCompleteCurrentArg("true");
535cfca06d7SDimitry Andric     request.TryCompleteCurrentArg("false");
536cfca06d7SDimitry Andric   }
537cfca06d7SDimitry Andric 
538cfca06d7SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)539b1c73532SDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
540cfca06d7SDimitry Andric     result.SetStatus(eReturnStatusFailed);
541cfca06d7SDimitry Andric 
542cfca06d7SDimitry Andric     if (args.GetArgumentCount() == 1) {
543cfca06d7SDimitry Andric       bool success;
544cfca06d7SDimitry Andric       bool increment =
545cfca06d7SDimitry Andric           OptionArgParser::ToBoolean(args[0].ref(), false, &success);
546cfca06d7SDimitry Andric 
547cfca06d7SDimitry Andric       if (success) {
548cfca06d7SDimitry Andric         Timer::SetQuiet(!increment);
549cfca06d7SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
550cfca06d7SDimitry Andric       } else
551cfca06d7SDimitry Andric         result.AppendError("Could not convert increment value to boolean.");
552cfca06d7SDimitry Andric     }
553cfca06d7SDimitry Andric 
554cfca06d7SDimitry Andric     if (!result.Succeeded()) {
555cfca06d7SDimitry Andric       result.AppendError("Missing subcommand");
556cfca06d7SDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
557cfca06d7SDimitry Andric     }
558cfca06d7SDimitry Andric   }
559cfca06d7SDimitry Andric };
560cfca06d7SDimitry Andric 
561cfca06d7SDimitry Andric class CommandObjectLogTimer : public CommandObjectMultiword {
562cfca06d7SDimitry Andric public:
CommandObjectLogTimer(CommandInterpreter & interpreter)563cfca06d7SDimitry Andric   CommandObjectLogTimer(CommandInterpreter &interpreter)
564cfca06d7SDimitry Andric       : CommandObjectMultiword(interpreter, "log timers",
565cfca06d7SDimitry Andric                                "Enable, disable, dump, and reset LLDB internal "
566cfca06d7SDimitry Andric                                "performance timers.",
567cfca06d7SDimitry Andric                                "log timers < enable <depth> | disable | dump | "
568cfca06d7SDimitry Andric                                "increment <bool> | reset >") {
569cfca06d7SDimitry Andric     LoadSubCommand("enable", CommandObjectSP(
570cfca06d7SDimitry Andric                                  new CommandObjectLogTimerEnable(interpreter)));
571cfca06d7SDimitry Andric     LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
572cfca06d7SDimitry Andric                                   interpreter)));
573cfca06d7SDimitry Andric     LoadSubCommand("dump",
574cfca06d7SDimitry Andric                    CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
575cfca06d7SDimitry Andric     LoadSubCommand(
576cfca06d7SDimitry Andric         "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
577cfca06d7SDimitry Andric     LoadSubCommand(
578cfca06d7SDimitry Andric         "increment",
579cfca06d7SDimitry Andric         CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
580cfca06d7SDimitry Andric   }
581cfca06d7SDimitry Andric 
582cfca06d7SDimitry Andric   ~CommandObjectLogTimer() override = default;
583cfca06d7SDimitry Andric };
584cfca06d7SDimitry Andric 
CommandObjectLog(CommandInterpreter & interpreter)585f3fbd1c0SDimitry Andric CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
58614f1b3e8SDimitry Andric     : CommandObjectMultiword(interpreter, "log",
58714f1b3e8SDimitry Andric                              "Commands controlling LLDB internal logging.",
58814f1b3e8SDimitry Andric                              "log <subcommand> [<command-options>]") {
58914f1b3e8SDimitry Andric   LoadSubCommand("enable",
59014f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectLogEnable(interpreter)));
59114f1b3e8SDimitry Andric   LoadSubCommand("disable",
59214f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectLogDisable(interpreter)));
59314f1b3e8SDimitry Andric   LoadSubCommand("list",
59414f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectLogList(interpreter)));
595145449b1SDimitry Andric   LoadSubCommand("dump",
596145449b1SDimitry Andric                  CommandObjectSP(new CommandObjectLogDump(interpreter)));
59714f1b3e8SDimitry Andric   LoadSubCommand("timers",
59814f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectLogTimer(interpreter)));
599f034231aSEd Maste }
600f034231aSEd Maste 
601f3fbd1c0SDimitry Andric CommandObjectLog::~CommandObjectLog() = default;
602