
The FileSpect APIs allow users to modify instance variables directly by getting a non const reference to the directory and filename instance variables. This makes it impossibly to control all of the times the FileSpec object is modified so we can clear the cache. This patch modifies the APIs of FileSpec so no one can modify the directory or filename directly by adding set accessors and by removing the get accessors that are non const. Many clients were using FileSpec::GetCString(...) which returned a unique C string from a ConstString'ified version of the result of GetPath() which returned a std::string. This caused many locations to use this convenient function incorrectly and could cause many strings to be added to the constant string pool that didn't need to. Most clients were converted to using FileSpec::GetPath().c_str() when possible. Other clients were modified to use the newly renamed version of this function which returns an actualy ConstString: ConstString FileSpec::GetPathAsConstString(bool denormalize = true) const; This avoids the issue where people were getting an already uniqued "const char *" that came from a ConstString only to put the "const char *" back into a "ConstString" object. By returning the ConstString instead of a "const char *" clients can be more efficient with the result. The patch: - Removes the non const GetDirectory() and GetFilename() get accessors - Adds set accessors to replace the above functions: SetDirectory() and SetFilename(). - Adds ClearDirectory() and ClearFilename() to replace usage of the FileSpec::GetDirectory().Clear()/FileSpec::GetFilename().Clear() call sites - Fixed all incorrect usage of FileSpec::GetCString() to use FileSpec::GetPath().c_str() where appropriate, and updated other call sites that wanted a ConstString to use the newly returned ConstString appropriately and efficiently. Differential Revision: https://reviews.llvm.org/D130309
646 lines
21 KiB
C++
646 lines
21 KiB
C++
//===-- CommandObjectLog.cpp ----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CommandObjectLog.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Host/OptionParser.h"
|
|
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
|
#include "lldb/Interpreter/OptionArgParser.h"
|
|
#include "lldb/Interpreter/OptionValueEnumeration.h"
|
|
#include "lldb/Interpreter/OptionValueUInt64.h"
|
|
#include "lldb/Interpreter/Options.h"
|
|
#include "lldb/Utility/Args.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/Utility/Log.h"
|
|
#include "lldb/Utility/Stream.h"
|
|
#include "lldb/Utility/Timer.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
#define LLDB_OPTIONS_log_enable
|
|
#include "CommandOptions.inc"
|
|
|
|
#define LLDB_OPTIONS_log_dump
|
|
#include "CommandOptions.inc"
|
|
|
|
/// Common completion logic for log enable/disable.
|
|
static void CompleteEnableDisable(CompletionRequest &request) {
|
|
size_t arg_index = request.GetCursorIndex();
|
|
if (arg_index == 0) { // We got: log enable/disable x[tab]
|
|
for (llvm::StringRef channel : Log::ListChannels())
|
|
request.TryCompleteCurrentArg(channel);
|
|
} else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
|
|
llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
|
|
Log::ForEachChannelCategory(
|
|
channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
|
|
request.TryCompleteCurrentArg(name, desc);
|
|
});
|
|
}
|
|
}
|
|
|
|
class CommandObjectLogEnable : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogEnable(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log enable",
|
|
"Enable logging for a single log channel.",
|
|
nullptr) {
|
|
CommandArgumentEntry arg1;
|
|
CommandArgumentEntry arg2;
|
|
CommandArgumentData channel_arg;
|
|
CommandArgumentData category_arg;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
channel_arg.arg_type = eArgTypeLogChannel;
|
|
channel_arg.arg_repetition = eArgRepeatPlain;
|
|
|
|
// There is only one variant this argument could be; put it into the
|
|
// argument entry.
|
|
arg1.push_back(channel_arg);
|
|
|
|
category_arg.arg_type = eArgTypeLogCategory;
|
|
category_arg.arg_repetition = eArgRepeatPlus;
|
|
|
|
arg2.push_back(category_arg);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back(arg1);
|
|
m_arguments.push_back(arg2);
|
|
}
|
|
|
|
~CommandObjectLogEnable() override = default;
|
|
|
|
Options *GetOptions() override { return &m_options; }
|
|
|
|
class CommandOptions : public Options {
|
|
public:
|
|
CommandOptions() = default;
|
|
|
|
~CommandOptions() override = default;
|
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
ExecutionContext *execution_context) override {
|
|
Status error;
|
|
const int short_option = m_getopt_table[option_idx].val;
|
|
|
|
switch (short_option) {
|
|
case 'f':
|
|
log_file.SetFile(option_arg, FileSpec::Style::native);
|
|
FileSystem::Instance().Resolve(log_file);
|
|
break;
|
|
case 'h':
|
|
handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(
|
|
option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
|
|
if (!error.Success())
|
|
error.SetErrorStringWithFormat(
|
|
"unrecognized value for log handler '%s'",
|
|
option_arg.str().c_str());
|
|
break;
|
|
case 'b':
|
|
error =
|
|
buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign);
|
|
break;
|
|
case 'v':
|
|
log_options |= LLDB_LOG_OPTION_VERBOSE;
|
|
break;
|
|
case 's':
|
|
log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
|
|
break;
|
|
case 'T':
|
|
log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
|
|
break;
|
|
case 'p':
|
|
log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
|
|
break;
|
|
case 'n':
|
|
log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
|
|
break;
|
|
case 'S':
|
|
log_options |= LLDB_LOG_OPTION_BACKTRACE;
|
|
break;
|
|
case 'a':
|
|
log_options |= LLDB_LOG_OPTION_APPEND;
|
|
break;
|
|
case 'F':
|
|
log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Unimplemented option");
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
|
log_file.Clear();
|
|
buffer_size.Clear();
|
|
handler = eLogHandlerStream;
|
|
log_options = 0;
|
|
}
|
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
|
return llvm::makeArrayRef(g_log_enable_options);
|
|
}
|
|
|
|
FileSpec log_file;
|
|
OptionValueUInt64 buffer_size;
|
|
LogHandlerKind handler = eLogHandlerStream;
|
|
uint32_t log_options = 0;
|
|
};
|
|
|
|
void
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
OptionElementVector &opt_element_vector) override {
|
|
CompleteEnableDisable(request);
|
|
}
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
if (args.GetArgumentCount() < 2) {
|
|
result.AppendErrorWithFormat(
|
|
"%s takes a log channel and one or more log types.\n",
|
|
m_cmd_name.c_str());
|
|
return false;
|
|
}
|
|
|
|
if (m_options.handler == eLogHandlerCircular &&
|
|
m_options.buffer_size.GetCurrentValue() == 0) {
|
|
result.AppendError(
|
|
"the circular buffer handler requires a non-zero buffer size.\n");
|
|
return false;
|
|
}
|
|
|
|
// Store into a std::string since we're about to shift the channel off.
|
|
const std::string channel = std::string(args[0].ref());
|
|
args.Shift(); // Shift off the channel
|
|
char log_file[PATH_MAX];
|
|
if (m_options.log_file)
|
|
m_options.log_file.GetPath(log_file, sizeof(log_file));
|
|
else
|
|
log_file[0] = '\0';
|
|
|
|
std::string error;
|
|
llvm::raw_string_ostream error_stream(error);
|
|
bool success = GetDebugger().EnableLog(
|
|
channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
|
|
m_options.buffer_size.GetCurrentValue(), m_options.handler,
|
|
error_stream);
|
|
result.GetErrorStream() << error_stream.str();
|
|
|
|
if (success)
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
else
|
|
result.SetStatus(eReturnStatusFailed);
|
|
return result.Succeeded();
|
|
}
|
|
|
|
CommandOptions m_options;
|
|
};
|
|
|
|
class CommandObjectLogDisable : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogDisable(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log disable",
|
|
"Disable one or more log channel categories.",
|
|
nullptr) {
|
|
CommandArgumentEntry arg1;
|
|
CommandArgumentEntry arg2;
|
|
CommandArgumentData channel_arg;
|
|
CommandArgumentData category_arg;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
channel_arg.arg_type = eArgTypeLogChannel;
|
|
channel_arg.arg_repetition = eArgRepeatPlain;
|
|
|
|
// There is only one variant this argument could be; put it into the
|
|
// argument entry.
|
|
arg1.push_back(channel_arg);
|
|
|
|
category_arg.arg_type = eArgTypeLogCategory;
|
|
category_arg.arg_repetition = eArgRepeatPlus;
|
|
|
|
arg2.push_back(category_arg);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back(arg1);
|
|
m_arguments.push_back(arg2);
|
|
}
|
|
|
|
~CommandObjectLogDisable() override = default;
|
|
|
|
void
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
OptionElementVector &opt_element_vector) override {
|
|
CompleteEnableDisable(request);
|
|
}
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
if (args.empty()) {
|
|
result.AppendErrorWithFormat(
|
|
"%s takes a log channel and one or more log types.\n",
|
|
m_cmd_name.c_str());
|
|
return false;
|
|
}
|
|
|
|
const std::string channel = std::string(args[0].ref());
|
|
args.Shift(); // Shift off the channel
|
|
if (channel == "all") {
|
|
Log::DisableAllLogChannels();
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
} else {
|
|
std::string error;
|
|
llvm::raw_string_ostream error_stream(error);
|
|
if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
|
|
error_stream))
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
result.GetErrorStream() << error_stream.str();
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectLogList : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogList(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log list",
|
|
"List the log categories for one or more log "
|
|
"channels. If none specified, lists them all.",
|
|
nullptr) {
|
|
CommandArgumentEntry arg;
|
|
CommandArgumentData channel_arg;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
channel_arg.arg_type = eArgTypeLogChannel;
|
|
channel_arg.arg_repetition = eArgRepeatStar;
|
|
|
|
// There is only one variant this argument could be; put it into the
|
|
// argument entry.
|
|
arg.push_back(channel_arg);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back(arg);
|
|
}
|
|
|
|
~CommandObjectLogList() override = default;
|
|
|
|
void
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
OptionElementVector &opt_element_vector) override {
|
|
for (llvm::StringRef channel : Log::ListChannels())
|
|
request.TryCompleteCurrentArg(channel);
|
|
}
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
std::string output;
|
|
llvm::raw_string_ostream output_stream(output);
|
|
if (args.empty()) {
|
|
Log::ListAllLogChannels(output_stream);
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
} else {
|
|
bool success = true;
|
|
for (const auto &entry : args.entries())
|
|
success =
|
|
success && Log::ListChannelCategories(entry.ref(), output_stream);
|
|
if (success)
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
}
|
|
result.GetOutputStream() << output_stream.str();
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
class CommandObjectLogDump : public CommandObjectParsed {
|
|
public:
|
|
CommandObjectLogDump(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log dump",
|
|
"dump circular buffer logs", nullptr) {
|
|
CommandArgumentEntry arg1;
|
|
CommandArgumentData channel_arg;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
channel_arg.arg_type = eArgTypeLogChannel;
|
|
channel_arg.arg_repetition = eArgRepeatPlain;
|
|
|
|
// There is only one variant this argument could be; put it into the
|
|
// argument entry.
|
|
arg1.push_back(channel_arg);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back(arg1);
|
|
}
|
|
|
|
~CommandObjectLogDump() override = default;
|
|
|
|
Options *GetOptions() override { return &m_options; }
|
|
|
|
class CommandOptions : public Options {
|
|
public:
|
|
CommandOptions() = default;
|
|
|
|
~CommandOptions() override = default;
|
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
ExecutionContext *execution_context) override {
|
|
Status error;
|
|
const int short_option = m_getopt_table[option_idx].val;
|
|
|
|
switch (short_option) {
|
|
case 'f':
|
|
log_file.SetFile(option_arg, FileSpec::Style::native);
|
|
FileSystem::Instance().Resolve(log_file);
|
|
break;
|
|
default:
|
|
llvm_unreachable("Unimplemented option");
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
|
log_file.Clear();
|
|
}
|
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
|
return llvm::makeArrayRef(g_log_dump_options);
|
|
}
|
|
|
|
FileSpec log_file;
|
|
};
|
|
|
|
void
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
OptionElementVector &opt_element_vector) override {
|
|
CompleteEnableDisable(request);
|
|
}
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
if (args.empty()) {
|
|
result.AppendErrorWithFormat(
|
|
"%s takes a log channel and one or more log types.\n",
|
|
m_cmd_name.c_str());
|
|
return false;
|
|
}
|
|
|
|
std::unique_ptr<llvm::raw_ostream> stream_up;
|
|
if (m_options.log_file) {
|
|
const File::OpenOptions flags = File::eOpenOptionWriteOnly |
|
|
File::eOpenOptionCanCreate |
|
|
File::eOpenOptionTruncate;
|
|
llvm::Expected<FileUP> file = FileSystem::Instance().Open(
|
|
m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
|
|
if (!file) {
|
|
result.AppendErrorWithFormat("Unable to open log file '%s': %s",
|
|
m_options.log_file.GetPath().c_str(),
|
|
llvm::toString(file.takeError()).c_str());
|
|
return false;
|
|
}
|
|
stream_up = std::make_unique<llvm::raw_fd_ostream>(
|
|
(*file)->GetDescriptor(), /*shouldClose=*/true);
|
|
} else {
|
|
stream_up = std::make_unique<llvm::raw_fd_ostream>(
|
|
GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
|
|
}
|
|
|
|
const std::string channel = std::string(args[0].ref());
|
|
std::string error;
|
|
llvm::raw_string_ostream error_stream(error);
|
|
if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
} else {
|
|
result.SetStatus(eReturnStatusFailed);
|
|
result.GetErrorStream() << error_stream.str();
|
|
}
|
|
|
|
return result.Succeeded();
|
|
}
|
|
|
|
CommandOptions m_options;
|
|
};
|
|
|
|
class CommandObjectLogTimerEnable : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log timers enable",
|
|
"enable LLDB internal performance timers",
|
|
"log timers enable <depth>") {
|
|
CommandArgumentEntry arg;
|
|
CommandArgumentData depth_arg;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
depth_arg.arg_type = eArgTypeCount;
|
|
depth_arg.arg_repetition = eArgRepeatOptional;
|
|
|
|
// There is only one variant this argument could be; put it into the
|
|
// argument entry.
|
|
arg.push_back(depth_arg);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back(arg);
|
|
}
|
|
|
|
~CommandObjectLogTimerEnable() override = default;
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
if (args.GetArgumentCount() == 0) {
|
|
Timer::SetDisplayDepth(UINT32_MAX);
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
} else if (args.GetArgumentCount() == 1) {
|
|
uint32_t depth;
|
|
if (args[0].ref().consumeInteger(0, depth)) {
|
|
result.AppendError(
|
|
"Could not convert enable depth to an unsigned integer.");
|
|
} else {
|
|
Timer::SetDisplayDepth(depth);
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
}
|
|
}
|
|
|
|
if (!result.Succeeded()) {
|
|
result.AppendError("Missing subcommand");
|
|
result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectLogTimerDisable : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log timers disable",
|
|
"disable LLDB internal performance timers",
|
|
nullptr) {}
|
|
|
|
~CommandObjectLogTimerDisable() override = default;
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
Timer::DumpCategoryTimes(&result.GetOutputStream());
|
|
Timer::SetDisplayDepth(0);
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
if (!result.Succeeded()) {
|
|
result.AppendError("Missing subcommand");
|
|
result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectLogTimerDump : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogTimerDump(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log timers dump",
|
|
"dump LLDB internal performance timers", nullptr) {}
|
|
|
|
~CommandObjectLogTimerDump() override = default;
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
Timer::DumpCategoryTimes(&result.GetOutputStream());
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
if (!result.Succeeded()) {
|
|
result.AppendError("Missing subcommand");
|
|
result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectLogTimerReset : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogTimerReset(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log timers reset",
|
|
"reset LLDB internal performance timers", nullptr) {
|
|
}
|
|
|
|
~CommandObjectLogTimerReset() override = default;
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
Timer::ResetCategoryTimes();
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
if (!result.Succeeded()) {
|
|
result.AppendError("Missing subcommand");
|
|
result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectLogTimerIncrement : public CommandObjectParsed {
|
|
public:
|
|
// Constructors and Destructors
|
|
CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "log timers increment",
|
|
"increment LLDB internal performance timers",
|
|
"log timers increment <bool>") {
|
|
CommandArgumentEntry arg;
|
|
CommandArgumentData bool_arg;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
bool_arg.arg_type = eArgTypeBoolean;
|
|
bool_arg.arg_repetition = eArgRepeatPlain;
|
|
|
|
// There is only one variant this argument could be; put it into the
|
|
// argument entry.
|
|
arg.push_back(bool_arg);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back(arg);
|
|
}
|
|
|
|
~CommandObjectLogTimerIncrement() override = default;
|
|
|
|
void
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
OptionElementVector &opt_element_vector) override {
|
|
request.TryCompleteCurrentArg("true");
|
|
request.TryCompleteCurrentArg("false");
|
|
}
|
|
|
|
protected:
|
|
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
if (args.GetArgumentCount() == 1) {
|
|
bool success;
|
|
bool increment =
|
|
OptionArgParser::ToBoolean(args[0].ref(), false, &success);
|
|
|
|
if (success) {
|
|
Timer::SetQuiet(!increment);
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
} else
|
|
result.AppendError("Could not convert increment value to boolean.");
|
|
}
|
|
|
|
if (!result.Succeeded()) {
|
|
result.AppendError("Missing subcommand");
|
|
result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectLogTimer : public CommandObjectMultiword {
|
|
public:
|
|
CommandObjectLogTimer(CommandInterpreter &interpreter)
|
|
: CommandObjectMultiword(interpreter, "log timers",
|
|
"Enable, disable, dump, and reset LLDB internal "
|
|
"performance timers.",
|
|
"log timers < enable <depth> | disable | dump | "
|
|
"increment <bool> | reset >") {
|
|
LoadSubCommand("enable", CommandObjectSP(
|
|
new CommandObjectLogTimerEnable(interpreter)));
|
|
LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
|
|
interpreter)));
|
|
LoadSubCommand("dump",
|
|
CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
|
|
LoadSubCommand(
|
|
"reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
|
|
LoadSubCommand(
|
|
"increment",
|
|
CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
|
|
}
|
|
|
|
~CommandObjectLogTimer() override = default;
|
|
};
|
|
|
|
CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
|
|
: CommandObjectMultiword(interpreter, "log",
|
|
"Commands controlling LLDB internal logging.",
|
|
"log <subcommand> [<command-options>]") {
|
|
LoadSubCommand("enable",
|
|
CommandObjectSP(new CommandObjectLogEnable(interpreter)));
|
|
LoadSubCommand("disable",
|
|
CommandObjectSP(new CommandObjectLogDisable(interpreter)));
|
|
LoadSubCommand("list",
|
|
CommandObjectSP(new CommandObjectLogList(interpreter)));
|
|
LoadSubCommand("dump",
|
|
CommandObjectSP(new CommandObjectLogDump(interpreter)));
|
|
LoadSubCommand("timers",
|
|
CommandObjectSP(new CommandObjectLogTimer(interpreter)));
|
|
}
|
|
|
|
CommandObjectLog::~CommandObjectLog() = default;
|