llvm-project/lldb/source/Commands/CommandObjectLog.cpp
David Spickett eaf60a4411 [lldb] Remove redundant calls to set eReturnStatusFailed
This is part 2, covering the commands source.

Some uses remain where it's tricky to see what the
logic is or they are not used with AppendError.

Reviewed By: teemperor

Differential Revision: https://reviews.llvm.org/D104448
2021-06-17 14:39:35 +01:00

512 lines
17 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/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.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
#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),
m_options() {
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() : Options(), log_file() {}
~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 't':
log_options |= LLDB_LOG_OPTION_THREADSAFE;
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();
log_options = 0;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
return llvm::makeArrayRef(g_log_options);
}
// Instance variables to hold the values for command options.
FileSpec log_file;
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;
}
// 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, 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 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("timers",
CommandObjectSP(new CommandObjectLogTimer(interpreter)));
}
CommandObjectLog::~CommandObjectLog() = default;