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