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