15ffd83dbSDimitry Andric //===-- CommandObjectLog.cpp ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "CommandObjectLog.h"
100b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
110b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
12fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
130b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
140b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
1581ad6265SDimitry Andric #include "lldb/Interpreter/OptionValueEnumeration.h"
1681ad6265SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
170b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
180b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
190b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
200b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
210b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
220b57cec5SDimitry Andric #include "lldb/Utility/Timer.h"
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric using namespace lldb;
250b57cec5SDimitry Andric using namespace lldb_private;
260b57cec5SDimitry Andric
2781ad6265SDimitry Andric #define LLDB_OPTIONS_log_enable
2881ad6265SDimitry Andric #include "CommandOptions.inc"
2981ad6265SDimitry Andric
3081ad6265SDimitry Andric #define LLDB_OPTIONS_log_dump
319dba64beSDimitry Andric #include "CommandOptions.inc"
329dba64beSDimitry Andric
339dba64beSDimitry Andric /// Common completion logic for log enable/disable.
CompleteEnableDisable(CompletionRequest & request)349dba64beSDimitry Andric static void CompleteEnableDisable(CompletionRequest &request) {
359dba64beSDimitry Andric size_t arg_index = request.GetCursorIndex();
369dba64beSDimitry Andric if (arg_index == 0) { // We got: log enable/disable x[tab]
379dba64beSDimitry Andric for (llvm::StringRef channel : Log::ListChannels())
389dba64beSDimitry Andric request.TryCompleteCurrentArg(channel);
399dba64beSDimitry Andric } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
409dba64beSDimitry Andric llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
419dba64beSDimitry Andric Log::ForEachChannelCategory(
429dba64beSDimitry Andric channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
439dba64beSDimitry Andric request.TryCompleteCurrentArg(name, desc);
449dba64beSDimitry Andric });
459dba64beSDimitry Andric }
469dba64beSDimitry Andric }
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric class CommandObjectLogEnable : public CommandObjectParsed {
490b57cec5SDimitry Andric public:
500b57cec5SDimitry Andric // Constructors and Destructors
CommandObjectLogEnable(CommandInterpreter & interpreter)510b57cec5SDimitry Andric CommandObjectLogEnable(CommandInterpreter &interpreter)
520b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "log enable",
530b57cec5SDimitry Andric "Enable logging for a single log channel.",
5404eeddc0SDimitry Andric nullptr) {
550b57cec5SDimitry Andric CommandArgumentEntry arg1;
560b57cec5SDimitry Andric CommandArgumentEntry arg2;
570b57cec5SDimitry Andric CommandArgumentData channel_arg;
580b57cec5SDimitry Andric CommandArgumentData category_arg;
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
610b57cec5SDimitry Andric channel_arg.arg_type = eArgTypeLogChannel;
620b57cec5SDimitry Andric channel_arg.arg_repetition = eArgRepeatPlain;
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
650b57cec5SDimitry Andric // argument entry.
660b57cec5SDimitry Andric arg1.push_back(channel_arg);
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric category_arg.arg_type = eArgTypeLogCategory;
690b57cec5SDimitry Andric category_arg.arg_repetition = eArgRepeatPlus;
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric arg2.push_back(category_arg);
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
740b57cec5SDimitry Andric m_arguments.push_back(arg1);
750b57cec5SDimitry Andric m_arguments.push_back(arg2);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric ~CommandObjectLogEnable() override = default;
790b57cec5SDimitry Andric
GetOptions()800b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric class CommandOptions : public Options {
830b57cec5SDimitry Andric public:
8481ad6265SDimitry Andric CommandOptions() = default;
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric ~CommandOptions() override = default;
870b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)880b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
890b57cec5SDimitry Andric ExecutionContext *execution_context) override {
900b57cec5SDimitry Andric Status error;
910b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric switch (short_option) {
940b57cec5SDimitry Andric case 'f':
950b57cec5SDimitry Andric log_file.SetFile(option_arg, FileSpec::Style::native);
960b57cec5SDimitry Andric FileSystem::Instance().Resolve(log_file);
970b57cec5SDimitry Andric break;
9881ad6265SDimitry Andric case 'h':
9981ad6265SDimitry Andric handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(
10081ad6265SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
10181ad6265SDimitry Andric if (!error.Success())
10281ad6265SDimitry Andric error.SetErrorStringWithFormat(
10381ad6265SDimitry Andric "unrecognized value for log handler '%s'",
10481ad6265SDimitry Andric option_arg.str().c_str());
10581ad6265SDimitry Andric break;
10681ad6265SDimitry Andric case 'b':
10781ad6265SDimitry Andric error =
10881ad6265SDimitry Andric buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign);
1090b57cec5SDimitry Andric break;
1100b57cec5SDimitry Andric case 'v':
1110b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_VERBOSE;
1120b57cec5SDimitry Andric break;
1130b57cec5SDimitry Andric case 's':
1140b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
1150b57cec5SDimitry Andric break;
1160b57cec5SDimitry Andric case 'T':
1170b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
1180b57cec5SDimitry Andric break;
1190b57cec5SDimitry Andric case 'p':
1200b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
1210b57cec5SDimitry Andric break;
1220b57cec5SDimitry Andric case 'n':
1230b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
1240b57cec5SDimitry Andric break;
1250b57cec5SDimitry Andric case 'S':
1260b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_BACKTRACE;
1270b57cec5SDimitry Andric break;
1280b57cec5SDimitry Andric case 'a':
1290b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_APPEND;
1300b57cec5SDimitry Andric break;
1310b57cec5SDimitry Andric case 'F':
1320b57cec5SDimitry Andric log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
1330b57cec5SDimitry Andric break;
1340b57cec5SDimitry Andric default:
1359dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric return error;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)1410b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1420b57cec5SDimitry Andric log_file.Clear();
14381ad6265SDimitry Andric buffer_size.Clear();
14481ad6265SDimitry Andric handler = eLogHandlerStream;
1450b57cec5SDimitry Andric log_options = 0;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric
GetDefinitions()1480b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
149bdd1243dSDimitry Andric return llvm::ArrayRef(g_log_enable_options);
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric
1520b57cec5SDimitry Andric FileSpec log_file;
15381ad6265SDimitry Andric OptionValueUInt64 buffer_size;
15481ad6265SDimitry Andric LogHandlerKind handler = eLogHandlerStream;
155fe6060f1SDimitry Andric uint32_t log_options = 0;
1560b57cec5SDimitry Andric };
1570b57cec5SDimitry Andric
1589dba64beSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1599dba64beSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1609dba64beSDimitry Andric OptionElementVector &opt_element_vector) override {
1619dba64beSDimitry Andric CompleteEnableDisable(request);
1629dba64beSDimitry Andric }
1639dba64beSDimitry Andric
1640b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)165*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
1660b57cec5SDimitry Andric if (args.GetArgumentCount() < 2) {
1670b57cec5SDimitry Andric result.AppendErrorWithFormat(
1680b57cec5SDimitry Andric "%s takes a log channel and one or more log types.\n",
1690b57cec5SDimitry Andric m_cmd_name.c_str());
170*c9157d92SDimitry Andric return;
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric
17381ad6265SDimitry Andric if (m_options.handler == eLogHandlerCircular &&
17481ad6265SDimitry Andric m_options.buffer_size.GetCurrentValue() == 0) {
17581ad6265SDimitry Andric result.AppendError(
17681ad6265SDimitry Andric "the circular buffer handler requires a non-zero buffer size.\n");
177*c9157d92SDimitry Andric return;
17881ad6265SDimitry Andric }
17981ad6265SDimitry Andric
180fe013be4SDimitry Andric if ((m_options.handler != eLogHandlerCircular &&
181fe013be4SDimitry Andric m_options.handler != eLogHandlerStream) &&
182fe013be4SDimitry Andric m_options.buffer_size.GetCurrentValue() != 0) {
183fe013be4SDimitry Andric result.AppendError("a buffer size can only be specified for the circular "
184fe013be4SDimitry Andric "and stream buffer handler.\n");
185*c9157d92SDimitry Andric return;
186fe013be4SDimitry Andric }
187fe013be4SDimitry Andric
188fe013be4SDimitry Andric if (m_options.handler != eLogHandlerStream && m_options.log_file) {
189fe013be4SDimitry Andric result.AppendError(
190fe013be4SDimitry Andric "a file name can only be specified for the stream handler.\n");
191*c9157d92SDimitry Andric return;
192fe013be4SDimitry Andric }
193fe013be4SDimitry Andric
1940b57cec5SDimitry Andric // Store into a std::string since we're about to shift the channel off.
1955ffd83dbSDimitry Andric const std::string channel = std::string(args[0].ref());
1960b57cec5SDimitry Andric args.Shift(); // Shift off the channel
1970b57cec5SDimitry Andric char log_file[PATH_MAX];
1980b57cec5SDimitry Andric if (m_options.log_file)
1990b57cec5SDimitry Andric m_options.log_file.GetPath(log_file, sizeof(log_file));
2000b57cec5SDimitry Andric else
2010b57cec5SDimitry Andric log_file[0] = '\0';
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric std::string error;
2040b57cec5SDimitry Andric llvm::raw_string_ostream error_stream(error);
20581ad6265SDimitry Andric bool success = GetDebugger().EnableLog(
20681ad6265SDimitry Andric channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
20781ad6265SDimitry Andric m_options.buffer_size.GetCurrentValue(), m_options.handler,
20881ad6265SDimitry Andric error_stream);
2090b57cec5SDimitry Andric result.GetErrorStream() << error_stream.str();
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric if (success)
2120b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2130b57cec5SDimitry Andric else
2140b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed);
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric CommandOptions m_options;
2180b57cec5SDimitry Andric };
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andric class CommandObjectLogDisable : public CommandObjectParsed {
2210b57cec5SDimitry Andric public:
2220b57cec5SDimitry Andric // Constructors and Destructors
CommandObjectLogDisable(CommandInterpreter & interpreter)2230b57cec5SDimitry Andric CommandObjectLogDisable(CommandInterpreter &interpreter)
2240b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "log disable",
2250b57cec5SDimitry Andric "Disable one or more log channel categories.",
2260b57cec5SDimitry Andric nullptr) {
2270b57cec5SDimitry Andric CommandArgumentEntry arg1;
2280b57cec5SDimitry Andric CommandArgumentEntry arg2;
2290b57cec5SDimitry Andric CommandArgumentData channel_arg;
2300b57cec5SDimitry Andric CommandArgumentData category_arg;
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
2330b57cec5SDimitry Andric channel_arg.arg_type = eArgTypeLogChannel;
2340b57cec5SDimitry Andric channel_arg.arg_repetition = eArgRepeatPlain;
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
2370b57cec5SDimitry Andric // argument entry.
2380b57cec5SDimitry Andric arg1.push_back(channel_arg);
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric category_arg.arg_type = eArgTypeLogCategory;
2410b57cec5SDimitry Andric category_arg.arg_repetition = eArgRepeatPlus;
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric arg2.push_back(category_arg);
2440b57cec5SDimitry Andric
2450b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
2460b57cec5SDimitry Andric m_arguments.push_back(arg1);
2470b57cec5SDimitry Andric m_arguments.push_back(arg2);
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric
2500b57cec5SDimitry Andric ~CommandObjectLogDisable() override = default;
2510b57cec5SDimitry Andric
2529dba64beSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2539dba64beSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
2549dba64beSDimitry Andric OptionElementVector &opt_element_vector) override {
2559dba64beSDimitry Andric CompleteEnableDisable(request);
2569dba64beSDimitry Andric }
2579dba64beSDimitry Andric
2580b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)259*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
2600b57cec5SDimitry Andric if (args.empty()) {
2610b57cec5SDimitry Andric result.AppendErrorWithFormat(
2620b57cec5SDimitry Andric "%s takes a log channel and one or more log types.\n",
2630b57cec5SDimitry Andric m_cmd_name.c_str());
264*c9157d92SDimitry Andric return;
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric
2675ffd83dbSDimitry Andric const std::string channel = std::string(args[0].ref());
2680b57cec5SDimitry Andric args.Shift(); // Shift off the channel
2690b57cec5SDimitry Andric if (channel == "all") {
2700b57cec5SDimitry Andric Log::DisableAllLogChannels();
2710b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2720b57cec5SDimitry Andric } else {
2730b57cec5SDimitry Andric std::string error;
2740b57cec5SDimitry Andric llvm::raw_string_ostream error_stream(error);
2750b57cec5SDimitry Andric if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
2760b57cec5SDimitry Andric error_stream))
2770b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2780b57cec5SDimitry Andric result.GetErrorStream() << error_stream.str();
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric };
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric class CommandObjectLogList : public CommandObjectParsed {
2840b57cec5SDimitry Andric public:
2850b57cec5SDimitry Andric // Constructors and Destructors
CommandObjectLogList(CommandInterpreter & interpreter)2860b57cec5SDimitry Andric CommandObjectLogList(CommandInterpreter &interpreter)
2870b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "log list",
2880b57cec5SDimitry Andric "List the log categories for one or more log "
2890b57cec5SDimitry Andric "channels. If none specified, lists them all.",
2900b57cec5SDimitry Andric nullptr) {
2910b57cec5SDimitry Andric CommandArgumentEntry arg;
2920b57cec5SDimitry Andric CommandArgumentData channel_arg;
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
2950b57cec5SDimitry Andric channel_arg.arg_type = eArgTypeLogChannel;
2960b57cec5SDimitry Andric channel_arg.arg_repetition = eArgRepeatStar;
2970b57cec5SDimitry Andric
2980b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
2990b57cec5SDimitry Andric // argument entry.
3000b57cec5SDimitry Andric arg.push_back(channel_arg);
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
3030b57cec5SDimitry Andric m_arguments.push_back(arg);
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric
3060b57cec5SDimitry Andric ~CommandObjectLogList() override = default;
3070b57cec5SDimitry Andric
3089dba64beSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)3099dba64beSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
3109dba64beSDimitry Andric OptionElementVector &opt_element_vector) override {
3119dba64beSDimitry Andric for (llvm::StringRef channel : Log::ListChannels())
3129dba64beSDimitry Andric request.TryCompleteCurrentArg(channel);
3139dba64beSDimitry Andric }
3149dba64beSDimitry Andric
3150b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)316*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
3170b57cec5SDimitry Andric std::string output;
3180b57cec5SDimitry Andric llvm::raw_string_ostream output_stream(output);
3190b57cec5SDimitry Andric if (args.empty()) {
3200b57cec5SDimitry Andric Log::ListAllLogChannels(output_stream);
3210b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
3220b57cec5SDimitry Andric } else {
3230b57cec5SDimitry Andric bool success = true;
3240b57cec5SDimitry Andric for (const auto &entry : args.entries())
3250b57cec5SDimitry Andric success =
3269dba64beSDimitry Andric success && Log::ListChannelCategories(entry.ref(), output_stream);
3270b57cec5SDimitry Andric if (success)
3280b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric result.GetOutputStream() << output_stream.str();
3310b57cec5SDimitry Andric }
3320b57cec5SDimitry Andric };
33381ad6265SDimitry Andric class CommandObjectLogDump : public CommandObjectParsed {
33481ad6265SDimitry Andric public:
CommandObjectLogDump(CommandInterpreter & interpreter)33581ad6265SDimitry Andric CommandObjectLogDump(CommandInterpreter &interpreter)
33681ad6265SDimitry Andric : CommandObjectParsed(interpreter, "log dump",
33781ad6265SDimitry Andric "dump circular buffer logs", nullptr) {
33881ad6265SDimitry Andric CommandArgumentEntry arg1;
33981ad6265SDimitry Andric CommandArgumentData channel_arg;
34081ad6265SDimitry Andric
34181ad6265SDimitry Andric // Define the first (and only) variant of this arg.
34281ad6265SDimitry Andric channel_arg.arg_type = eArgTypeLogChannel;
34381ad6265SDimitry Andric channel_arg.arg_repetition = eArgRepeatPlain;
34481ad6265SDimitry Andric
34581ad6265SDimitry Andric // There is only one variant this argument could be; put it into the
34681ad6265SDimitry Andric // argument entry.
34781ad6265SDimitry Andric arg1.push_back(channel_arg);
34881ad6265SDimitry Andric
34981ad6265SDimitry Andric // Push the data for the first argument into the m_arguments vector.
35081ad6265SDimitry Andric m_arguments.push_back(arg1);
35181ad6265SDimitry Andric }
35281ad6265SDimitry Andric
35381ad6265SDimitry Andric ~CommandObjectLogDump() override = default;
35481ad6265SDimitry Andric
GetOptions()35581ad6265SDimitry Andric Options *GetOptions() override { return &m_options; }
35681ad6265SDimitry Andric
35781ad6265SDimitry Andric class CommandOptions : public Options {
35881ad6265SDimitry Andric public:
35981ad6265SDimitry Andric CommandOptions() = default;
36081ad6265SDimitry Andric
36181ad6265SDimitry Andric ~CommandOptions() override = default;
36281ad6265SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)36381ad6265SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
36481ad6265SDimitry Andric ExecutionContext *execution_context) override {
36581ad6265SDimitry Andric Status error;
36681ad6265SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
36781ad6265SDimitry Andric
36881ad6265SDimitry Andric switch (short_option) {
36981ad6265SDimitry Andric case 'f':
37081ad6265SDimitry Andric log_file.SetFile(option_arg, FileSpec::Style::native);
37181ad6265SDimitry Andric FileSystem::Instance().Resolve(log_file);
37281ad6265SDimitry Andric break;
37381ad6265SDimitry Andric default:
37481ad6265SDimitry Andric llvm_unreachable("Unimplemented option");
37581ad6265SDimitry Andric }
37681ad6265SDimitry Andric
37781ad6265SDimitry Andric return error;
37881ad6265SDimitry Andric }
37981ad6265SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)38081ad6265SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
38181ad6265SDimitry Andric log_file.Clear();
38281ad6265SDimitry Andric }
38381ad6265SDimitry Andric
GetDefinitions()38481ad6265SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
385bdd1243dSDimitry Andric return llvm::ArrayRef(g_log_dump_options);
38681ad6265SDimitry Andric }
38781ad6265SDimitry Andric
38881ad6265SDimitry Andric FileSpec log_file;
38981ad6265SDimitry Andric };
39081ad6265SDimitry Andric
39181ad6265SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)39281ad6265SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
39381ad6265SDimitry Andric OptionElementVector &opt_element_vector) override {
39481ad6265SDimitry Andric CompleteEnableDisable(request);
39581ad6265SDimitry Andric }
39681ad6265SDimitry Andric
39781ad6265SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)398*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
39981ad6265SDimitry Andric if (args.empty()) {
40081ad6265SDimitry Andric result.AppendErrorWithFormat(
40181ad6265SDimitry Andric "%s takes a log channel and one or more log types.\n",
40281ad6265SDimitry Andric m_cmd_name.c_str());
403*c9157d92SDimitry Andric return;
40481ad6265SDimitry Andric }
40581ad6265SDimitry Andric
40681ad6265SDimitry Andric std::unique_ptr<llvm::raw_ostream> stream_up;
40781ad6265SDimitry Andric if (m_options.log_file) {
40881ad6265SDimitry Andric const File::OpenOptions flags = File::eOpenOptionWriteOnly |
40981ad6265SDimitry Andric File::eOpenOptionCanCreate |
41081ad6265SDimitry Andric File::eOpenOptionTruncate;
41181ad6265SDimitry Andric llvm::Expected<FileUP> file = FileSystem::Instance().Open(
41281ad6265SDimitry Andric m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
41381ad6265SDimitry Andric if (!file) {
41481ad6265SDimitry Andric result.AppendErrorWithFormat("Unable to open log file '%s': %s",
415bdd1243dSDimitry Andric m_options.log_file.GetPath().c_str(),
41681ad6265SDimitry Andric llvm::toString(file.takeError()).c_str());
417*c9157d92SDimitry Andric return;
41881ad6265SDimitry Andric }
41981ad6265SDimitry Andric stream_up = std::make_unique<llvm::raw_fd_ostream>(
42081ad6265SDimitry Andric (*file)->GetDescriptor(), /*shouldClose=*/true);
42181ad6265SDimitry Andric } else {
42281ad6265SDimitry Andric stream_up = std::make_unique<llvm::raw_fd_ostream>(
42381ad6265SDimitry Andric GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
42481ad6265SDimitry Andric }
42581ad6265SDimitry Andric
42681ad6265SDimitry Andric const std::string channel = std::string(args[0].ref());
42781ad6265SDimitry Andric std::string error;
42881ad6265SDimitry Andric llvm::raw_string_ostream error_stream(error);
42981ad6265SDimitry Andric if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
43081ad6265SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
43181ad6265SDimitry Andric } else {
43281ad6265SDimitry Andric result.SetStatus(eReturnStatusFailed);
43381ad6265SDimitry Andric result.GetErrorStream() << error_stream.str();
43481ad6265SDimitry Andric }
43581ad6265SDimitry Andric }
43681ad6265SDimitry Andric
43781ad6265SDimitry Andric CommandOptions m_options;
43881ad6265SDimitry Andric };
4390b57cec5SDimitry Andric
4405ffd83dbSDimitry Andric class CommandObjectLogTimerEnable : public CommandObjectParsed {
4410b57cec5SDimitry Andric public:
4420b57cec5SDimitry Andric // Constructors and Destructors
CommandObjectLogTimerEnable(CommandInterpreter & interpreter)4435ffd83dbSDimitry Andric CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
4445ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "log timers enable",
4455ffd83dbSDimitry Andric "enable LLDB internal performance timers",
4465ffd83dbSDimitry Andric "log timers enable <depth>") {
4475ffd83dbSDimitry Andric CommandArgumentEntry arg;
4485ffd83dbSDimitry Andric CommandArgumentData depth_arg;
4490b57cec5SDimitry Andric
4505ffd83dbSDimitry Andric // Define the first (and only) variant of this arg.
4515ffd83dbSDimitry Andric depth_arg.arg_type = eArgTypeCount;
4525ffd83dbSDimitry Andric depth_arg.arg_repetition = eArgRepeatOptional;
4535ffd83dbSDimitry Andric
4545ffd83dbSDimitry Andric // There is only one variant this argument could be; put it into the
4555ffd83dbSDimitry Andric // argument entry.
4565ffd83dbSDimitry Andric arg.push_back(depth_arg);
4575ffd83dbSDimitry Andric
4585ffd83dbSDimitry Andric // Push the data for the first argument into the m_arguments vector.
4595ffd83dbSDimitry Andric m_arguments.push_back(arg);
4605ffd83dbSDimitry Andric }
4615ffd83dbSDimitry Andric
4625ffd83dbSDimitry Andric ~CommandObjectLogTimerEnable() override = default;
4630b57cec5SDimitry Andric
4640b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)465*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
4660b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed);
4670b57cec5SDimitry Andric
4685ffd83dbSDimitry Andric if (args.GetArgumentCount() == 0) {
4690b57cec5SDimitry Andric Timer::SetDisplayDepth(UINT32_MAX);
4700b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
4715ffd83dbSDimitry Andric } else if (args.GetArgumentCount() == 1) {
4720b57cec5SDimitry Andric uint32_t depth;
4735ffd83dbSDimitry Andric if (args[0].ref().consumeInteger(0, depth)) {
4740b57cec5SDimitry Andric result.AppendError(
4750b57cec5SDimitry Andric "Could not convert enable depth to an unsigned integer.");
4760b57cec5SDimitry Andric } else {
4770b57cec5SDimitry Andric Timer::SetDisplayDepth(depth);
4780b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
4790b57cec5SDimitry Andric }
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric
4820b57cec5SDimitry Andric if (!result.Succeeded()) {
4830b57cec5SDimitry Andric result.AppendError("Missing subcommand");
4840b57cec5SDimitry Andric result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric }
4870b57cec5SDimitry Andric };
4880b57cec5SDimitry Andric
4895ffd83dbSDimitry Andric class CommandObjectLogTimerDisable : public CommandObjectParsed {
4905ffd83dbSDimitry Andric public:
4915ffd83dbSDimitry Andric // Constructors and Destructors
CommandObjectLogTimerDisable(CommandInterpreter & interpreter)4925ffd83dbSDimitry Andric CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
4935ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "log timers disable",
4945ffd83dbSDimitry Andric "disable LLDB internal performance timers",
4955ffd83dbSDimitry Andric nullptr) {}
4965ffd83dbSDimitry Andric
4975ffd83dbSDimitry Andric ~CommandObjectLogTimerDisable() override = default;
4985ffd83dbSDimitry Andric
4995ffd83dbSDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)500*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
501fe013be4SDimitry Andric Timer::DumpCategoryTimes(result.GetOutputStream());
5025ffd83dbSDimitry Andric Timer::SetDisplayDepth(0);
5035ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
5045ffd83dbSDimitry Andric
5055ffd83dbSDimitry Andric if (!result.Succeeded()) {
5065ffd83dbSDimitry Andric result.AppendError("Missing subcommand");
5075ffd83dbSDimitry Andric result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5085ffd83dbSDimitry Andric }
5095ffd83dbSDimitry Andric }
5105ffd83dbSDimitry Andric };
5115ffd83dbSDimitry Andric
5125ffd83dbSDimitry Andric class CommandObjectLogTimerDump : public CommandObjectParsed {
5135ffd83dbSDimitry Andric public:
5145ffd83dbSDimitry Andric // Constructors and Destructors
CommandObjectLogTimerDump(CommandInterpreter & interpreter)5155ffd83dbSDimitry Andric CommandObjectLogTimerDump(CommandInterpreter &interpreter)
5165ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "log timers dump",
5175ffd83dbSDimitry Andric "dump LLDB internal performance timers", nullptr) {}
5185ffd83dbSDimitry Andric
5195ffd83dbSDimitry Andric ~CommandObjectLogTimerDump() override = default;
5205ffd83dbSDimitry Andric
5215ffd83dbSDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)522*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
523fe013be4SDimitry Andric Timer::DumpCategoryTimes(result.GetOutputStream());
5245ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
5255ffd83dbSDimitry Andric
5265ffd83dbSDimitry Andric if (!result.Succeeded()) {
5275ffd83dbSDimitry Andric result.AppendError("Missing subcommand");
5285ffd83dbSDimitry Andric result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5295ffd83dbSDimitry Andric }
5305ffd83dbSDimitry Andric }
5315ffd83dbSDimitry Andric };
5325ffd83dbSDimitry Andric
5335ffd83dbSDimitry Andric class CommandObjectLogTimerReset : public CommandObjectParsed {
5345ffd83dbSDimitry Andric public:
5355ffd83dbSDimitry Andric // Constructors and Destructors
CommandObjectLogTimerReset(CommandInterpreter & interpreter)5365ffd83dbSDimitry Andric CommandObjectLogTimerReset(CommandInterpreter &interpreter)
5375ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "log timers reset",
5385ffd83dbSDimitry Andric "reset LLDB internal performance timers", nullptr) {
5395ffd83dbSDimitry Andric }
5405ffd83dbSDimitry Andric
5415ffd83dbSDimitry Andric ~CommandObjectLogTimerReset() override = default;
5425ffd83dbSDimitry Andric
5435ffd83dbSDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)544*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
5455ffd83dbSDimitry Andric Timer::ResetCategoryTimes();
5465ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
5475ffd83dbSDimitry Andric
5485ffd83dbSDimitry Andric if (!result.Succeeded()) {
5495ffd83dbSDimitry Andric result.AppendError("Missing subcommand");
5505ffd83dbSDimitry Andric result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5515ffd83dbSDimitry Andric }
5525ffd83dbSDimitry Andric }
5535ffd83dbSDimitry Andric };
5545ffd83dbSDimitry Andric
5555ffd83dbSDimitry Andric class CommandObjectLogTimerIncrement : public CommandObjectParsed {
5565ffd83dbSDimitry Andric public:
5575ffd83dbSDimitry Andric // Constructors and Destructors
CommandObjectLogTimerIncrement(CommandInterpreter & interpreter)5585ffd83dbSDimitry Andric CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
5595ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "log timers increment",
5605ffd83dbSDimitry Andric "increment LLDB internal performance timers",
5615ffd83dbSDimitry Andric "log timers increment <bool>") {
5625ffd83dbSDimitry Andric CommandArgumentEntry arg;
5635ffd83dbSDimitry Andric CommandArgumentData bool_arg;
5645ffd83dbSDimitry Andric
5655ffd83dbSDimitry Andric // Define the first (and only) variant of this arg.
5665ffd83dbSDimitry Andric bool_arg.arg_type = eArgTypeBoolean;
5675ffd83dbSDimitry Andric bool_arg.arg_repetition = eArgRepeatPlain;
5685ffd83dbSDimitry Andric
5695ffd83dbSDimitry Andric // There is only one variant this argument could be; put it into the
5705ffd83dbSDimitry Andric // argument entry.
5715ffd83dbSDimitry Andric arg.push_back(bool_arg);
5725ffd83dbSDimitry Andric
5735ffd83dbSDimitry Andric // Push the data for the first argument into the m_arguments vector.
5745ffd83dbSDimitry Andric m_arguments.push_back(arg);
5755ffd83dbSDimitry Andric }
5765ffd83dbSDimitry Andric
5775ffd83dbSDimitry Andric ~CommandObjectLogTimerIncrement() override = default;
5785ffd83dbSDimitry Andric
5795ffd83dbSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)5805ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
5815ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override {
5825ffd83dbSDimitry Andric request.TryCompleteCurrentArg("true");
5835ffd83dbSDimitry Andric request.TryCompleteCurrentArg("false");
5845ffd83dbSDimitry Andric }
5855ffd83dbSDimitry Andric
5865ffd83dbSDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)587*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
5885ffd83dbSDimitry Andric result.SetStatus(eReturnStatusFailed);
5895ffd83dbSDimitry Andric
5905ffd83dbSDimitry Andric if (args.GetArgumentCount() == 1) {
5915ffd83dbSDimitry Andric bool success;
5925ffd83dbSDimitry Andric bool increment =
5935ffd83dbSDimitry Andric OptionArgParser::ToBoolean(args[0].ref(), false, &success);
5945ffd83dbSDimitry Andric
5955ffd83dbSDimitry Andric if (success) {
5965ffd83dbSDimitry Andric Timer::SetQuiet(!increment);
5975ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
5985ffd83dbSDimitry Andric } else
5995ffd83dbSDimitry Andric result.AppendError("Could not convert increment value to boolean.");
6005ffd83dbSDimitry Andric }
6015ffd83dbSDimitry Andric
6025ffd83dbSDimitry Andric if (!result.Succeeded()) {
6035ffd83dbSDimitry Andric result.AppendError("Missing subcommand");
6045ffd83dbSDimitry Andric result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
6055ffd83dbSDimitry Andric }
6065ffd83dbSDimitry Andric }
6075ffd83dbSDimitry Andric };
6085ffd83dbSDimitry Andric
6095ffd83dbSDimitry Andric class CommandObjectLogTimer : public CommandObjectMultiword {
6105ffd83dbSDimitry Andric public:
CommandObjectLogTimer(CommandInterpreter & interpreter)6115ffd83dbSDimitry Andric CommandObjectLogTimer(CommandInterpreter &interpreter)
6125ffd83dbSDimitry Andric : CommandObjectMultiword(interpreter, "log timers",
6135ffd83dbSDimitry Andric "Enable, disable, dump, and reset LLDB internal "
6145ffd83dbSDimitry Andric "performance timers.",
6155ffd83dbSDimitry Andric "log timers < enable <depth> | disable | dump | "
6165ffd83dbSDimitry Andric "increment <bool> | reset >") {
6175ffd83dbSDimitry Andric LoadSubCommand("enable", CommandObjectSP(
6185ffd83dbSDimitry Andric new CommandObjectLogTimerEnable(interpreter)));
6195ffd83dbSDimitry Andric LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
6205ffd83dbSDimitry Andric interpreter)));
6215ffd83dbSDimitry Andric LoadSubCommand("dump",
6225ffd83dbSDimitry Andric CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
6235ffd83dbSDimitry Andric LoadSubCommand(
6245ffd83dbSDimitry Andric "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
6255ffd83dbSDimitry Andric LoadSubCommand(
6265ffd83dbSDimitry Andric "increment",
6275ffd83dbSDimitry Andric CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
6285ffd83dbSDimitry Andric }
6295ffd83dbSDimitry Andric
6305ffd83dbSDimitry Andric ~CommandObjectLogTimer() override = default;
6315ffd83dbSDimitry Andric };
6325ffd83dbSDimitry Andric
CommandObjectLog(CommandInterpreter & interpreter)6330b57cec5SDimitry Andric CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
6340b57cec5SDimitry Andric : CommandObjectMultiword(interpreter, "log",
6350b57cec5SDimitry Andric "Commands controlling LLDB internal logging.",
6360b57cec5SDimitry Andric "log <subcommand> [<command-options>]") {
6370b57cec5SDimitry Andric LoadSubCommand("enable",
6380b57cec5SDimitry Andric CommandObjectSP(new CommandObjectLogEnable(interpreter)));
6390b57cec5SDimitry Andric LoadSubCommand("disable",
6400b57cec5SDimitry Andric CommandObjectSP(new CommandObjectLogDisable(interpreter)));
6410b57cec5SDimitry Andric LoadSubCommand("list",
6420b57cec5SDimitry Andric CommandObjectSP(new CommandObjectLogList(interpreter)));
64381ad6265SDimitry Andric LoadSubCommand("dump",
64481ad6265SDimitry Andric CommandObjectSP(new CommandObjectLogDump(interpreter)));
6450b57cec5SDimitry Andric LoadSubCommand("timers",
6460b57cec5SDimitry Andric CommandObjectSP(new CommandObjectLogTimer(interpreter)));
6470b57cec5SDimitry Andric }
6480b57cec5SDimitry Andric
6490b57cec5SDimitry Andric CommandObjectLog::~CommandObjectLog() = default;
650