LLDB mainline
CommandObjectLog.cpp
Go to the documentation of this file.
1//===-- CommandObjectLog.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "CommandObjectLog.h"
10#include "lldb/Core/Debugger.h"
18#include "lldb/Utility/Args.h"
20#include "lldb/Utility/Log.h"
21#include "lldb/Utility/Stream.h"
22#include "lldb/Utility/Timer.h"
23
24#include "llvm/Support/FormatAdapters.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29#define LLDB_OPTIONS_log_enable
30#include "CommandOptions.inc"
31
32#define LLDB_OPTIONS_log_dump
33#include "CommandOptions.inc"
34
35/// Common completion logic for log enable/disable.
37 size_t arg_index = request.GetCursorIndex();
38 if (arg_index == 0) { // We got: log enable/disable x[tab]
39 for (llvm::StringRef channel : Log::ListChannels())
40 request.TryCompleteCurrentArg(channel);
41 } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
42 llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
44 channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
45 request.TryCompleteCurrentArg(name, desc);
46 });
47 }
48}
49
51public:
52 // Constructors and Destructors
54 : CommandObjectParsed(interpreter, "log enable",
55 "Enable logging for a single log channel.",
56 nullptr) {
59 CommandArgumentData channel_arg;
60 CommandArgumentData category_arg;
61
62 // Define the first (and only) variant of this arg.
63 channel_arg.arg_type = eArgTypeLogChannel;
64 channel_arg.arg_repetition = eArgRepeatPlain;
65
66 // There is only one variant this argument could be; put it into the
67 // argument entry.
68 arg1.push_back(channel_arg);
69
70 category_arg.arg_type = eArgTypeLogCategory;
71 category_arg.arg_repetition = eArgRepeatPlus;
72
73 arg2.push_back(category_arg);
74
75 // Push the data for the first argument into the m_arguments vector.
76 m_arguments.push_back(arg1);
77 m_arguments.push_back(arg2);
78 }
79
80 ~CommandObjectLogEnable() override = default;
81
82 Options *GetOptions() override { return &m_options; }
83
84 class CommandOptions : public Options {
85 public:
86 CommandOptions() = default;
87
88 ~CommandOptions() override = default;
89
90 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
91 ExecutionContext *execution_context) override {
93 const int short_option = m_getopt_table[option_idx].val;
94
95 switch (short_option) {
96 case 'f':
97 log_file.SetFile(option_arg, FileSpec::Style::native);
99 break;
100 case 'h':
102 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
103 if (!error.Success())
105 "unrecognized value for log handler '{0}'", option_arg);
106 break;
107 case 'b':
108 return buffer_size.SetValueFromString(option_arg,
110 case 'v':
112 break;
113 case 's':
115 break;
116 case 'T':
118 break;
119 case 'p':
121 break;
122 case 'n':
124 break;
125 case 'S':
127 break;
128 case 'a':
130 break;
131 case 'F':
133 break;
134 case 'j':
136 break;
137 default:
138 llvm_unreachable("Unimplemented option");
139 }
140
141 return error;
142 }
143
144 void OptionParsingStarting(ExecutionContext *execution_context) override {
145 log_file.Clear();
146 buffer_size.Clear();
148 log_options = 0;
149 }
150
151 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
152 return llvm::ArrayRef(g_log_enable_options);
153 }
154
158 uint32_t log_options = 0;
159 };
160
161 void
163 OptionElementVector &opt_element_vector) override {
164 CompleteEnableDisable(request);
165 }
166
167protected:
168 void DoExecute(Args &args, CommandReturnObject &result) override {
169 if (args.GetArgumentCount() < 2) {
171 "%s takes a log channel and one or more log types",
172 m_cmd_name.c_str());
173 return;
174 }
175
176 if (m_options.handler == eLogHandlerCircular &&
177 m_options.buffer_size.GetCurrentValue() == 0) {
178 result.AppendError(
179 "the circular buffer handler requires a non-zero buffer size.\n");
180 return;
181 }
182
183 if ((m_options.handler != eLogHandlerCircular &&
184 m_options.handler != eLogHandlerStream) &&
185 m_options.buffer_size.GetCurrentValue() != 0) {
186 result.AppendError("a buffer size can only be specified for the circular "
187 "and stream buffer handler.\n");
188 return;
189 }
190
191 if (m_options.handler != eLogHandlerStream && m_options.log_file) {
192 result.AppendError(
193 "a file name can only be specified for the stream handler.\n");
194 return;
195 }
196
197 // Store into a std::string since we're about to shift the channel off.
198 const std::string channel = std::string(args[0].ref());
199 args.Shift(); // Shift off the channel
200 char log_file[PATH_MAX];
201 if (m_options.log_file)
202 m_options.log_file.GetPath(log_file, sizeof(log_file));
203 else
204 log_file[0] = '\0';
205
206 llvm::Error error = GetDebugger().EnableLog(
207 channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
208 m_options.buffer_size.GetCurrentValue(), m_options.handler);
209
210 if (error) {
211 result.GetErrorStream()
212 << llvm::formatv("{}", llvm::fmt_consume(std::move(error)));
214 } else
216 }
217
219};
220
222public:
223 // Constructors and Destructors
225 : CommandObjectParsed(interpreter, "log disable",
226 "Disable one or more log channel categories.",
227 nullptr) {
230 CommandArgumentData channel_arg;
231 CommandArgumentData category_arg;
232
233 // Define the first (and only) variant of this arg.
234 channel_arg.arg_type = eArgTypeLogChannel;
235 channel_arg.arg_repetition = eArgRepeatPlain;
236
237 // There is only one variant this argument could be; put it into the
238 // argument entry.
239 arg1.push_back(channel_arg);
240
241 category_arg.arg_type = eArgTypeLogCategory;
242 category_arg.arg_repetition = eArgRepeatPlus;
243
244 arg2.push_back(category_arg);
245
246 // Push the data for the first argument into the m_arguments vector.
247 m_arguments.push_back(arg1);
248 m_arguments.push_back(arg2);
249 }
250
251 ~CommandObjectLogDisable() override = default;
252
253 void
255 OptionElementVector &opt_element_vector) override {
256 CompleteEnableDisable(request);
257 }
258
259protected:
260 void DoExecute(Args &args, CommandReturnObject &result) override {
261 if (args.empty()) {
263 "%s takes a log channel and one or more log types",
264 m_cmd_name.c_str());
265 return;
266 }
267
268 const std::string channel = std::string(args[0].ref());
269 args.Shift(); // Shift off the channel
270 if (channel == "all") {
273 } else {
274 if (llvm::Error err =
276 result.AppendError(toString(std::move(err)));
277 else
279 }
280 }
281};
282
284public:
285 // Constructors and Destructors
287 : CommandObjectParsed(interpreter, "log list",
288 "List the log categories for one or more log "
289 "channels. If none specified, lists them all.",
290 nullptr) {
292 }
293
294 ~CommandObjectLogList() override = default;
295
296 void
298 OptionElementVector &opt_element_vector) override {
299 for (llvm::StringRef channel : Log::ListChannels())
300 request.TryCompleteCurrentArg(channel);
301 }
302
303protected:
304 void DoExecute(Args &args, CommandReturnObject &result) override {
305 std::string output;
306 llvm::raw_string_ostream output_stream(output);
307 if (args.empty()) {
308 Log::ListAllLogChannels(output_stream);
310 } else {
311 bool success = true;
312 for (const auto &entry : args.entries()) {
313 auto err_or_list = Log::ListChannelCategories(entry.ref());
314 if (!err_or_list) {
315 success = false;
316 output_stream << toString(err_or_list.takeError());
317 } else
318 output_stream << *err_or_list;
319 }
320 if (success)
322 }
323 result.GetOutputStream() << output;
324 }
325};
327public:
329 : CommandObjectParsed(interpreter, "log dump",
330 "dump circular buffer logs", nullptr) {
332 }
333
334 ~CommandObjectLogDump() override = default;
335
336 Options *GetOptions() override { return &m_options; }
337
338 class CommandOptions : public Options {
339 public:
340 CommandOptions() = default;
341
342 ~CommandOptions() override = default;
343
344 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
345 ExecutionContext *execution_context) override {
347 const int short_option = m_getopt_table[option_idx].val;
348
349 switch (short_option) {
350 case 'f':
351 log_file.SetFile(option_arg, FileSpec::Style::native);
353 break;
354 default:
355 llvm_unreachable("Unimplemented option");
356 }
357
358 return error;
359 }
360
361 void OptionParsingStarting(ExecutionContext *execution_context) override {
362 log_file.Clear();
363 }
364
365 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
366 return llvm::ArrayRef(g_log_dump_options);
367 }
368
370 };
371
372 void
374 OptionElementVector &opt_element_vector) override {
375 CompleteEnableDisable(request);
376 }
377
378protected:
379 void DoExecute(Args &args, CommandReturnObject &result) override {
380 if (args.empty()) {
382 "%s takes a log channel and one or more log types",
383 m_cmd_name.c_str());
384 return;
385 }
386
387 std::unique_ptr<llvm::raw_ostream> stream_up;
388 if (m_options.log_file) {
392 llvm::Expected<FileUP> file = FileSystem::Instance().Open(
393 m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
394 if (!file) {
395 result.AppendErrorWithFormat("Unable to open log file '%s': %s",
396 m_options.log_file.GetPath().c_str(),
397 llvm::toString(file.takeError()).c_str());
398 return;
399 }
400 stream_up = std::make_unique<llvm::raw_fd_ostream>(
401 (*file)->GetDescriptor(), /*shouldClose=*/true);
402 } else {
403 stream_up = std::make_unique<llvm::raw_fd_ostream>(
404 GetDebugger().GetOutputFileSP()->GetDescriptor(),
405 /*shouldClose=*/false);
406 }
407
408 const std::string channel = std::string(args[0].ref());
409 std::string error;
410 llvm::raw_string_ostream error_stream(error);
411 if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
413 } else {
415 result.GetErrorStream() << error;
416 }
417 }
418
420};
421
423public:
424 // Constructors and Destructors
426 : CommandObjectParsed(interpreter, "log timers enable",
427 "enable LLDB internal performance timers",
428 "log timers enable <depth>") {
430 }
431
432 ~CommandObjectLogTimerEnable() override = default;
433
434protected:
435 void DoExecute(Args &args, CommandReturnObject &result) override {
437
438 if (args.GetArgumentCount() == 0) {
441 } else if (args.GetArgumentCount() == 1) {
442 uint32_t depth;
443 if (args[0].ref().consumeInteger(0, depth)) {
444 result.AppendError(
445 "Could not convert enable depth to an unsigned integer.");
446 } else {
449 }
450 }
451
452 if (!result.Succeeded()) {
453 result.AppendError("Missing subcommand");
454 result.AppendErrorWithFormat("Usage: %s", m_cmd_syntax.c_str());
455 }
456 }
457};
458
460public:
461 // Constructors and Destructors
463 : CommandObjectParsed(interpreter, "log timers disable",
464 "disable LLDB internal performance timers",
465 nullptr) {}
466
467 ~CommandObjectLogTimerDisable() override = default;
468
469protected:
470 void DoExecute(Args &args, CommandReturnObject &result) override {
474
475 if (!result.Succeeded()) {
476 result.AppendError("Missing subcommand");
477 result.AppendErrorWithFormat("Usage: %s", m_cmd_syntax.c_str());
478 }
479 }
480};
481
483public:
484 // Constructors and Destructors
486 : CommandObjectParsed(interpreter, "log timers dump",
487 "dump LLDB internal performance timers", nullptr) {}
488
489 ~CommandObjectLogTimerDump() override = default;
490
491protected:
492 void DoExecute(Args &args, CommandReturnObject &result) override {
495
496 if (!result.Succeeded()) {
497 result.AppendError("Missing subcommand");
498 result.AppendErrorWithFormat("Usage: %s", m_cmd_syntax.c_str());
499 }
500 }
501};
502
504public:
505 // Constructors and Destructors
507 : CommandObjectParsed(interpreter, "log timers reset",
508 "reset LLDB internal performance timers", nullptr) {
509 }
510
511 ~CommandObjectLogTimerReset() override = default;
512
513protected:
514 void DoExecute(Args &args, CommandReturnObject &result) override {
517
518 if (!result.Succeeded()) {
519 result.AppendError("Missing subcommand");
520 result.AppendErrorWithFormat("Usage: %s", m_cmd_syntax.c_str());
521 }
522 }
523};
524
526public:
527 // Constructors and Destructors
529 : CommandObjectParsed(interpreter, "log timers increment",
530 "increment LLDB internal performance timers",
531 "log timers increment <bool>") {
533 }
534
536
537 void
539 OptionElementVector &opt_element_vector) override {
540 request.TryCompleteCurrentArg("true");
541 request.TryCompleteCurrentArg("false");
542 }
543
544protected:
545 void DoExecute(Args &args, CommandReturnObject &result) override {
547
548 if (args.GetArgumentCount() == 1) {
549 bool success;
550 bool increment =
551 OptionArgParser::ToBoolean(args[0].ref(), false, &success);
552
553 if (success) {
554 Timer::SetQuiet(!increment);
556 } else
557 result.AppendError("could not convert increment value to boolean");
558 }
559
560 if (!result.Succeeded()) {
561 result.AppendError("Missing subcommand");
562 result.AppendErrorWithFormat("Usage: %s", m_cmd_syntax.c_str());
563 }
564 }
565};
566
568public:
570 : CommandObjectMultiword(interpreter, "log timers",
571 "Enable, disable, dump, and reset LLDB internal "
572 "performance timers.",
573 "log timers < enable <depth> | disable | dump | "
574 "increment <bool> | reset >") {
576 new CommandObjectLogTimerEnable(interpreter)));
578 interpreter)));
579 LoadSubCommand("dump",
582 "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
584 "increment",
586 }
587
588 ~CommandObjectLogTimer() override = default;
589};
590
592 : CommandObjectMultiword(interpreter, "log",
593 "Commands controlling LLDB internal logging.",
594 "log <subcommand> [<command-options>]") {
595 LoadSubCommand("enable",
596 CommandObjectSP(new CommandObjectLogEnable(interpreter)));
597 LoadSubCommand("disable",
598 CommandObjectSP(new CommandObjectLogDisable(interpreter)));
599 LoadSubCommand("list",
600 CommandObjectSP(new CommandObjectLogList(interpreter)));
601 LoadSubCommand("dump",
602 CommandObjectSP(new CommandObjectLogDump(interpreter)));
603 LoadSubCommand("timers",
604 CommandObjectSP(new CommandObjectLogTimer(interpreter)));
605}
606
static void CompleteEnableDisable(CompletionRequest &request)
Common completion logic for log enable/disable.
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION
Definition Log.h:46
#define LLDB_LOG_OPTION_JSON
Definition Log.h:47
#define LLDB_LOG_OPTION_APPEND
Definition Log.h:45
#define LLDB_LOG_OPTION_BACKTRACE
Definition Log.h:44
#define LLDB_LOG_OPTION_PREPEND_TIMESTAMP
Definition Log.h:41
#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD
Definition Log.h:42
#define LLDB_LOG_OPTION_PREPEND_SEQUENCE
Definition Log.h:40
#define LLDB_LOG_OPTION_VERBOSE
Definition Log.h:39
#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME
Definition Log.h:43
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
void DoExecute(Args &args, CommandReturnObject &result) override
CommandObjectLogDisable(CommandInterpreter &interpreter)
~CommandObjectLogDisable() override=default
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void OptionParsingStarting(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
CommandObjectLogDump(CommandInterpreter &interpreter)
Options * GetOptions() override
~CommandObjectLogDump() override=default
void DoExecute(Args &args, CommandReturnObject &result) override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
void OptionParsingStarting(ExecutionContext *execution_context) override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
Options * GetOptions() override
CommandObjectLogEnable(CommandInterpreter &interpreter)
~CommandObjectLogEnable() override=default
void DoExecute(Args &args, CommandReturnObject &result) override
CommandObjectLogList(CommandInterpreter &interpreter)
void DoExecute(Args &args, CommandReturnObject &result) override
~CommandObjectLogList() override=default
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
void DoExecute(Args &args, CommandReturnObject &result) override
~CommandObjectLogTimerDisable() override=default
~CommandObjectLogTimerDump() override=default
CommandObjectLogTimerDump(CommandInterpreter &interpreter)
void DoExecute(Args &args, CommandReturnObject &result) override
~CommandObjectLogTimerEnable() override=default
CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
void DoExecute(Args &args, CommandReturnObject &result) override
CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
void DoExecute(Args &args, CommandReturnObject &result) override
~CommandObjectLogTimerIncrement() override=default
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
CommandObjectLogTimerReset(CommandInterpreter &interpreter)
~CommandObjectLogTimerReset() override=default
void DoExecute(Args &args, CommandReturnObject &result) override
CommandObjectLogTimer(CommandInterpreter &interpreter)
~CommandObjectLogTimer() override=default
A command line argument class.
Definition Args.h:33
llvm::ArrayRef< const char * > GetArgumentArrayRef() const
Gets the argument as an ArrayRef.
Definition Args.h:173
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition Args.cpp:295
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition Args.h:120
llvm::ArrayRef< ArgEntry > entries() const
Definition Args.h:132
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition Args.cpp:273
bool empty() const
Definition Args.h:122
CommandObjectLog(CommandInterpreter &interpreter)
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
CommandObjectMultiword(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
CommandObjectParsed(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
std::vector< CommandArgumentData > CommandArgumentEntry
void AddSimpleArgumentList(lldb::CommandArgumentType arg_type, ArgumentRepetitionType repetition_type=eArgRepeatPlain)
std::vector< CommandArgumentEntry > m_arguments
void AppendError(llvm::StringRef in_string)
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
"lldb/Utility/ArgCompletionRequest.h"
void TryCompleteCurrentArg(llvm::StringRef completion, llvm::StringRef description="")
Adds a possible completion string if the completion would complete the current argument.
llvm::Error EnableLog(llvm::StringRef channel, llvm::ArrayRef< const char * > categories, llvm::StringRef log_file, uint32_t log_options, size_t buffer_size, LogHandlerKind log_handler_kind)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
A file utility class.
Definition FileSpec.h:57
int Open(const char *path, int flags, int mode=0600)
Wraps open in a platform-independent way.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
static llvm::Error DisableLogChannel(llvm::StringRef channel, llvm::ArrayRef< const char * > categories)
Definition Log.cpp:250
static void ListAllLogChannels(llvm::raw_ostream &stream)
Definition Log.cpp:319
static bool DumpLogChannel(llvm::StringRef channel, llvm::raw_ostream &output_stream, llvm::raw_ostream &error_stream)
Definition Log.cpp:269
static void DisableAllLogChannels()
Definition Log.cpp:297
static void ForEachChannelCategory(llvm::StringRef channel, llvm::function_ref< void(llvm::StringRef, llvm::StringRef)> lambda)
Calls the given lambda for every category in the given channel.
Definition Log.cpp:302
static llvm::Expected< std::string > ListChannelCategories(llvm::StringRef channel)
Definition Log.cpp:286
static std::vector< llvm::StringRef > ListChannels()
Returns the list of log channels.
Definition Log.cpp:312
A command line option parsing protocol class.
Definition Options.h:58
std::vector< Option > m_getopt_table
Definition Options.h:198
An error handling class.
Definition Status.h:118
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static void ResetCategoryTimes()
Definition Timer.cpp:130
static void SetQuiet(bool value)
Definition Timer.cpp:58
static void SetDisplayDepth(uint32_t depth)
Definition Timer.cpp:111
static void DumpCategoryTimes(Stream &s)
Definition Timer.cpp:138
#define UINT32_MAX
A class that represents a running process on the host machine.
std::vector< OptionArgElement > OptionElementVector
Definition Options.h:43
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
@ eReturnStatusFailed
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeLogCategory
Used to build individual command argument lists.
static int64_t ToOptionEnum(llvm::StringRef s, const OptionEnumValues &enum_values, int32_t fail_value, Status &error)
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr)
#define PATH_MAX