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