xref: /freebsd-src/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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.
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
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 
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 
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 
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 
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
1599dba64beSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1609dba64beSDimitry Andric                            OptionElementVector &opt_element_vector) override {
1619dba64beSDimitry Andric     CompleteEnableDisable(request);
1629dba64beSDimitry Andric   }
1639dba64beSDimitry Andric 
1640b57cec5SDimitry Andric protected:
1655f757f3fSDimitry 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());
1705f757f3fSDimitry 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");
1775f757f3fSDimitry Andric       return;
17881ad6265SDimitry Andric     }
17981ad6265SDimitry Andric 
18006c3fb27SDimitry Andric     if ((m_options.handler != eLogHandlerCircular &&
18106c3fb27SDimitry Andric          m_options.handler != eLogHandlerStream) &&
18206c3fb27SDimitry Andric         m_options.buffer_size.GetCurrentValue() != 0) {
18306c3fb27SDimitry Andric       result.AppendError("a buffer size can only be specified for the circular "
18406c3fb27SDimitry Andric                          "and stream buffer handler.\n");
1855f757f3fSDimitry Andric       return;
18606c3fb27SDimitry Andric     }
18706c3fb27SDimitry Andric 
18806c3fb27SDimitry Andric     if (m_options.handler != eLogHandlerStream && m_options.log_file) {
18906c3fb27SDimitry Andric       result.AppendError(
19006c3fb27SDimitry Andric           "a file name can only be specified for the stream handler.\n");
1915f757f3fSDimitry Andric       return;
19206c3fb27SDimitry Andric     }
19306c3fb27SDimitry 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
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
2539dba64beSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
2549dba64beSDimitry Andric                            OptionElementVector &opt_element_vector) override {
2559dba64beSDimitry Andric     CompleteEnableDisable(request);
2569dba64beSDimitry Andric   }
2579dba64beSDimitry Andric 
2580b57cec5SDimitry Andric protected:
2595f757f3fSDimitry 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());
2645f757f3fSDimitry 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
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) {
291*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeLogChannel, eArgRepeatStar);
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   ~CommandObjectLogList() override = default;
2950b57cec5SDimitry Andric 
2969dba64beSDimitry Andric   void
2979dba64beSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
2989dba64beSDimitry Andric                            OptionElementVector &opt_element_vector) override {
2999dba64beSDimitry Andric     for (llvm::StringRef channel : Log::ListChannels())
3009dba64beSDimitry Andric       request.TryCompleteCurrentArg(channel);
3019dba64beSDimitry Andric   }
3029dba64beSDimitry Andric 
3030b57cec5SDimitry Andric protected:
3045f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
3050b57cec5SDimitry Andric     std::string output;
3060b57cec5SDimitry Andric     llvm::raw_string_ostream output_stream(output);
3070b57cec5SDimitry Andric     if (args.empty()) {
3080b57cec5SDimitry Andric       Log::ListAllLogChannels(output_stream);
3090b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
3100b57cec5SDimitry Andric     } else {
3110b57cec5SDimitry Andric       bool success = true;
3120b57cec5SDimitry Andric       for (const auto &entry : args.entries())
3130b57cec5SDimitry Andric         success =
3149dba64beSDimitry Andric             success && Log::ListChannelCategories(entry.ref(), output_stream);
3150b57cec5SDimitry Andric       if (success)
3160b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishResult);
3170b57cec5SDimitry Andric     }
3180b57cec5SDimitry Andric     result.GetOutputStream() << output_stream.str();
3190b57cec5SDimitry Andric   }
3200b57cec5SDimitry Andric };
32181ad6265SDimitry Andric class CommandObjectLogDump : public CommandObjectParsed {
32281ad6265SDimitry Andric public:
32381ad6265SDimitry Andric   CommandObjectLogDump(CommandInterpreter &interpreter)
32481ad6265SDimitry Andric       : CommandObjectParsed(interpreter, "log dump",
32581ad6265SDimitry Andric                             "dump circular buffer logs", nullptr) {
326*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeLogChannel);
32781ad6265SDimitry Andric   }
32881ad6265SDimitry Andric 
32981ad6265SDimitry Andric   ~CommandObjectLogDump() override = default;
33081ad6265SDimitry Andric 
33181ad6265SDimitry Andric   Options *GetOptions() override { return &m_options; }
33281ad6265SDimitry Andric 
33381ad6265SDimitry Andric   class CommandOptions : public Options {
33481ad6265SDimitry Andric   public:
33581ad6265SDimitry Andric     CommandOptions() = default;
33681ad6265SDimitry Andric 
33781ad6265SDimitry Andric     ~CommandOptions() override = default;
33881ad6265SDimitry Andric 
33981ad6265SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
34081ad6265SDimitry Andric                           ExecutionContext *execution_context) override {
34181ad6265SDimitry Andric       Status error;
34281ad6265SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
34381ad6265SDimitry Andric 
34481ad6265SDimitry Andric       switch (short_option) {
34581ad6265SDimitry Andric       case 'f':
34681ad6265SDimitry Andric         log_file.SetFile(option_arg, FileSpec::Style::native);
34781ad6265SDimitry Andric         FileSystem::Instance().Resolve(log_file);
34881ad6265SDimitry Andric         break;
34981ad6265SDimitry Andric       default:
35081ad6265SDimitry Andric         llvm_unreachable("Unimplemented option");
35181ad6265SDimitry Andric       }
35281ad6265SDimitry Andric 
35381ad6265SDimitry Andric       return error;
35481ad6265SDimitry Andric     }
35581ad6265SDimitry Andric 
35681ad6265SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
35781ad6265SDimitry Andric       log_file.Clear();
35881ad6265SDimitry Andric     }
35981ad6265SDimitry Andric 
36081ad6265SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
361bdd1243dSDimitry Andric       return llvm::ArrayRef(g_log_dump_options);
36281ad6265SDimitry Andric     }
36381ad6265SDimitry Andric 
36481ad6265SDimitry Andric     FileSpec log_file;
36581ad6265SDimitry Andric   };
36681ad6265SDimitry Andric 
36781ad6265SDimitry Andric   void
36881ad6265SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
36981ad6265SDimitry Andric                            OptionElementVector &opt_element_vector) override {
37081ad6265SDimitry Andric     CompleteEnableDisable(request);
37181ad6265SDimitry Andric   }
37281ad6265SDimitry Andric 
37381ad6265SDimitry Andric protected:
3745f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
37581ad6265SDimitry Andric     if (args.empty()) {
37681ad6265SDimitry Andric       result.AppendErrorWithFormat(
37781ad6265SDimitry Andric           "%s takes a log channel and one or more log types.\n",
37881ad6265SDimitry Andric           m_cmd_name.c_str());
3795f757f3fSDimitry Andric       return;
38081ad6265SDimitry Andric     }
38181ad6265SDimitry Andric 
38281ad6265SDimitry Andric     std::unique_ptr<llvm::raw_ostream> stream_up;
38381ad6265SDimitry Andric     if (m_options.log_file) {
38481ad6265SDimitry Andric       const File::OpenOptions flags = File::eOpenOptionWriteOnly |
38581ad6265SDimitry Andric                                       File::eOpenOptionCanCreate |
38681ad6265SDimitry Andric                                       File::eOpenOptionTruncate;
38781ad6265SDimitry Andric       llvm::Expected<FileUP> file = FileSystem::Instance().Open(
38881ad6265SDimitry Andric           m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
38981ad6265SDimitry Andric       if (!file) {
39081ad6265SDimitry Andric         result.AppendErrorWithFormat("Unable to open log file '%s': %s",
391bdd1243dSDimitry Andric                                      m_options.log_file.GetPath().c_str(),
39281ad6265SDimitry Andric                                      llvm::toString(file.takeError()).c_str());
3935f757f3fSDimitry Andric         return;
39481ad6265SDimitry Andric       }
39581ad6265SDimitry Andric       stream_up = std::make_unique<llvm::raw_fd_ostream>(
39681ad6265SDimitry Andric           (*file)->GetDescriptor(), /*shouldClose=*/true);
39781ad6265SDimitry Andric     } else {
39881ad6265SDimitry Andric       stream_up = std::make_unique<llvm::raw_fd_ostream>(
39981ad6265SDimitry Andric           GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
40081ad6265SDimitry Andric     }
40181ad6265SDimitry Andric 
40281ad6265SDimitry Andric     const std::string channel = std::string(args[0].ref());
40381ad6265SDimitry Andric     std::string error;
40481ad6265SDimitry Andric     llvm::raw_string_ostream error_stream(error);
40581ad6265SDimitry Andric     if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
40681ad6265SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
40781ad6265SDimitry Andric     } else {
40881ad6265SDimitry Andric       result.SetStatus(eReturnStatusFailed);
40981ad6265SDimitry Andric       result.GetErrorStream() << error_stream.str();
41081ad6265SDimitry Andric     }
41181ad6265SDimitry Andric   }
41281ad6265SDimitry Andric 
41381ad6265SDimitry Andric   CommandOptions m_options;
41481ad6265SDimitry Andric };
4150b57cec5SDimitry Andric 
4165ffd83dbSDimitry Andric class CommandObjectLogTimerEnable : public CommandObjectParsed {
4170b57cec5SDimitry Andric public:
4180b57cec5SDimitry Andric   // Constructors and Destructors
4195ffd83dbSDimitry Andric   CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
4205ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "log timers enable",
4215ffd83dbSDimitry Andric                             "enable LLDB internal performance timers",
4225ffd83dbSDimitry Andric                             "log timers enable <depth>") {
423*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeCount, eArgRepeatOptional);
4245ffd83dbSDimitry Andric   }
4255ffd83dbSDimitry Andric 
4265ffd83dbSDimitry Andric   ~CommandObjectLogTimerEnable() override = default;
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric protected:
4295f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
4300b57cec5SDimitry Andric     result.SetStatus(eReturnStatusFailed);
4310b57cec5SDimitry Andric 
4325ffd83dbSDimitry Andric     if (args.GetArgumentCount() == 0) {
4330b57cec5SDimitry Andric       Timer::SetDisplayDepth(UINT32_MAX);
4340b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
4355ffd83dbSDimitry Andric     } else if (args.GetArgumentCount() == 1) {
4360b57cec5SDimitry Andric       uint32_t depth;
4375ffd83dbSDimitry Andric       if (args[0].ref().consumeInteger(0, depth)) {
4380b57cec5SDimitry Andric         result.AppendError(
4390b57cec5SDimitry Andric             "Could not convert enable depth to an unsigned integer.");
4400b57cec5SDimitry Andric       } else {
4410b57cec5SDimitry Andric         Timer::SetDisplayDepth(depth);
4420b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
4430b57cec5SDimitry Andric       }
4440b57cec5SDimitry Andric     }
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric     if (!result.Succeeded()) {
4470b57cec5SDimitry Andric       result.AppendError("Missing subcommand");
4480b57cec5SDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
4490b57cec5SDimitry Andric     }
4500b57cec5SDimitry Andric   }
4510b57cec5SDimitry Andric };
4520b57cec5SDimitry Andric 
4535ffd83dbSDimitry Andric class CommandObjectLogTimerDisable : public CommandObjectParsed {
4545ffd83dbSDimitry Andric public:
4555ffd83dbSDimitry Andric   // Constructors and Destructors
4565ffd83dbSDimitry Andric   CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
4575ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "log timers disable",
4585ffd83dbSDimitry Andric                             "disable LLDB internal performance timers",
4595ffd83dbSDimitry Andric                             nullptr) {}
4605ffd83dbSDimitry Andric 
4615ffd83dbSDimitry Andric   ~CommandObjectLogTimerDisable() override = default;
4625ffd83dbSDimitry Andric 
4635ffd83dbSDimitry Andric protected:
4645f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
46506c3fb27SDimitry Andric     Timer::DumpCategoryTimes(result.GetOutputStream());
4665ffd83dbSDimitry Andric     Timer::SetDisplayDepth(0);
4675ffd83dbSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
4685ffd83dbSDimitry Andric 
4695ffd83dbSDimitry Andric     if (!result.Succeeded()) {
4705ffd83dbSDimitry Andric       result.AppendError("Missing subcommand");
4715ffd83dbSDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
4725ffd83dbSDimitry Andric     }
4735ffd83dbSDimitry Andric   }
4745ffd83dbSDimitry Andric };
4755ffd83dbSDimitry Andric 
4765ffd83dbSDimitry Andric class CommandObjectLogTimerDump : public CommandObjectParsed {
4775ffd83dbSDimitry Andric public:
4785ffd83dbSDimitry Andric   // Constructors and Destructors
4795ffd83dbSDimitry Andric   CommandObjectLogTimerDump(CommandInterpreter &interpreter)
4805ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "log timers dump",
4815ffd83dbSDimitry Andric                             "dump LLDB internal performance timers", nullptr) {}
4825ffd83dbSDimitry Andric 
4835ffd83dbSDimitry Andric   ~CommandObjectLogTimerDump() override = default;
4845ffd83dbSDimitry Andric 
4855ffd83dbSDimitry Andric protected:
4865f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
48706c3fb27SDimitry Andric     Timer::DumpCategoryTimes(result.GetOutputStream());
4885ffd83dbSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
4895ffd83dbSDimitry Andric 
4905ffd83dbSDimitry Andric     if (!result.Succeeded()) {
4915ffd83dbSDimitry Andric       result.AppendError("Missing subcommand");
4925ffd83dbSDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
4935ffd83dbSDimitry Andric     }
4945ffd83dbSDimitry Andric   }
4955ffd83dbSDimitry Andric };
4965ffd83dbSDimitry Andric 
4975ffd83dbSDimitry Andric class CommandObjectLogTimerReset : public CommandObjectParsed {
4985ffd83dbSDimitry Andric public:
4995ffd83dbSDimitry Andric   // Constructors and Destructors
5005ffd83dbSDimitry Andric   CommandObjectLogTimerReset(CommandInterpreter &interpreter)
5015ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "log timers reset",
5025ffd83dbSDimitry Andric                             "reset LLDB internal performance timers", nullptr) {
5035ffd83dbSDimitry Andric   }
5045ffd83dbSDimitry Andric 
5055ffd83dbSDimitry Andric   ~CommandObjectLogTimerReset() override = default;
5065ffd83dbSDimitry Andric 
5075ffd83dbSDimitry Andric protected:
5085f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
5095ffd83dbSDimitry Andric     Timer::ResetCategoryTimes();
5105ffd83dbSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
5115ffd83dbSDimitry Andric 
5125ffd83dbSDimitry Andric     if (!result.Succeeded()) {
5135ffd83dbSDimitry Andric       result.AppendError("Missing subcommand");
5145ffd83dbSDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5155ffd83dbSDimitry Andric     }
5165ffd83dbSDimitry Andric   }
5175ffd83dbSDimitry Andric };
5185ffd83dbSDimitry Andric 
5195ffd83dbSDimitry Andric class CommandObjectLogTimerIncrement : public CommandObjectParsed {
5205ffd83dbSDimitry Andric public:
5215ffd83dbSDimitry Andric   // Constructors and Destructors
5225ffd83dbSDimitry Andric   CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
5235ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "log timers increment",
5245ffd83dbSDimitry Andric                             "increment LLDB internal performance timers",
5255ffd83dbSDimitry Andric                             "log timers increment <bool>") {
526*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeBoolean);
5275ffd83dbSDimitry Andric   }
5285ffd83dbSDimitry Andric 
5295ffd83dbSDimitry Andric   ~CommandObjectLogTimerIncrement() override = default;
5305ffd83dbSDimitry Andric 
5315ffd83dbSDimitry Andric   void
5325ffd83dbSDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
5335ffd83dbSDimitry Andric                            OptionElementVector &opt_element_vector) override {
5345ffd83dbSDimitry Andric     request.TryCompleteCurrentArg("true");
5355ffd83dbSDimitry Andric     request.TryCompleteCurrentArg("false");
5365ffd83dbSDimitry Andric   }
5375ffd83dbSDimitry Andric 
5385ffd83dbSDimitry Andric protected:
5395f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
5405ffd83dbSDimitry Andric     result.SetStatus(eReturnStatusFailed);
5415ffd83dbSDimitry Andric 
5425ffd83dbSDimitry Andric     if (args.GetArgumentCount() == 1) {
5435ffd83dbSDimitry Andric       bool success;
5445ffd83dbSDimitry Andric       bool increment =
5455ffd83dbSDimitry Andric           OptionArgParser::ToBoolean(args[0].ref(), false, &success);
5465ffd83dbSDimitry Andric 
5475ffd83dbSDimitry Andric       if (success) {
5485ffd83dbSDimitry Andric         Timer::SetQuiet(!increment);
5495ffd83dbSDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
5505ffd83dbSDimitry Andric       } else
5515ffd83dbSDimitry Andric         result.AppendError("Could not convert increment value to boolean.");
5525ffd83dbSDimitry Andric     }
5535ffd83dbSDimitry Andric 
5545ffd83dbSDimitry Andric     if (!result.Succeeded()) {
5555ffd83dbSDimitry Andric       result.AppendError("Missing subcommand");
5565ffd83dbSDimitry Andric       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5575ffd83dbSDimitry Andric     }
5585ffd83dbSDimitry Andric   }
5595ffd83dbSDimitry Andric };
5605ffd83dbSDimitry Andric 
5615ffd83dbSDimitry Andric class CommandObjectLogTimer : public CommandObjectMultiword {
5625ffd83dbSDimitry Andric public:
5635ffd83dbSDimitry Andric   CommandObjectLogTimer(CommandInterpreter &interpreter)
5645ffd83dbSDimitry Andric       : CommandObjectMultiword(interpreter, "log timers",
5655ffd83dbSDimitry Andric                                "Enable, disable, dump, and reset LLDB internal "
5665ffd83dbSDimitry Andric                                "performance timers.",
5675ffd83dbSDimitry Andric                                "log timers < enable <depth> | disable | dump | "
5685ffd83dbSDimitry Andric                                "increment <bool> | reset >") {
5695ffd83dbSDimitry Andric     LoadSubCommand("enable", CommandObjectSP(
5705ffd83dbSDimitry Andric                                  new CommandObjectLogTimerEnable(interpreter)));
5715ffd83dbSDimitry Andric     LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
5725ffd83dbSDimitry Andric                                   interpreter)));
5735ffd83dbSDimitry Andric     LoadSubCommand("dump",
5745ffd83dbSDimitry Andric                    CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
5755ffd83dbSDimitry Andric     LoadSubCommand(
5765ffd83dbSDimitry Andric         "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
5775ffd83dbSDimitry Andric     LoadSubCommand(
5785ffd83dbSDimitry Andric         "increment",
5795ffd83dbSDimitry Andric         CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
5805ffd83dbSDimitry Andric   }
5815ffd83dbSDimitry Andric 
5825ffd83dbSDimitry Andric   ~CommandObjectLogTimer() override = default;
5835ffd83dbSDimitry Andric };
5845ffd83dbSDimitry Andric 
5850b57cec5SDimitry Andric CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
5860b57cec5SDimitry Andric     : CommandObjectMultiword(interpreter, "log",
5870b57cec5SDimitry Andric                              "Commands controlling LLDB internal logging.",
5880b57cec5SDimitry Andric                              "log <subcommand> [<command-options>]") {
5890b57cec5SDimitry Andric   LoadSubCommand("enable",
5900b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectLogEnable(interpreter)));
5910b57cec5SDimitry Andric   LoadSubCommand("disable",
5920b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectLogDisable(interpreter)));
5930b57cec5SDimitry Andric   LoadSubCommand("list",
5940b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectLogList(interpreter)));
59581ad6265SDimitry Andric   LoadSubCommand("dump",
59681ad6265SDimitry Andric                  CommandObjectSP(new CommandObjectLogDump(interpreter)));
5970b57cec5SDimitry Andric   LoadSubCommand("timers",
5980b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectLogTimer(interpreter)));
5990b57cec5SDimitry Andric }
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric CommandObjectLog::~CommandObjectLog() = default;
602