180814287SRaphael Isemann //===-- CommandObjectLog.cpp ----------------------------------------------===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 926cac3afSEugene Zelenko #include "CommandObjectLog.h" 1030fdc8d8SChris Lattner #include "lldb/Core/Debugger.h" 113eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h" 1230fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 1347cbf4a0SPavel Labath #include "lldb/Interpreter/OptionArgParser.h" 14be265d25SJonas Devlieghere #include "lldb/Interpreter/OptionValueEnumeration.h" 1509dea546SJonas Devlieghere #include "lldb/Interpreter/OptionValueUInt64.h" 16b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 17145d95c9SPavel Labath #include "lldb/Utility/Args.h" 185713a05bSZachary Turner #include "lldb/Utility/FileSpec.h" 196f9e6901SZachary Turner #include "lldb/Utility/Log.h" 20bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 2138d0632eSPavel Labath #include "lldb/Utility/Timer.h" 2230fdc8d8SChris Lattner 2330fdc8d8SChris Lattner using namespace lldb; 2430fdc8d8SChris Lattner using namespace lldb_private; 2530fdc8d8SChris Lattner 26be265d25SJonas Devlieghere static constexpr OptionEnumValueElement g_log_handler_type[] = { 27be265d25SJonas Devlieghere { 28be265d25SJonas Devlieghere eLogHandlerDefault, 29be265d25SJonas Devlieghere "default", 30be265d25SJonas Devlieghere "Use the default (stream) log handler", 31be265d25SJonas Devlieghere }, 32be265d25SJonas Devlieghere { 33be265d25SJonas Devlieghere eLogHandlerStream, 34be265d25SJonas Devlieghere "stream", 35be265d25SJonas Devlieghere "Write log messages to the debugger output stream or to a file if one " 36be265d25SJonas Devlieghere "is specified. A buffer size (in bytes) can be specified with -b. If " 37be265d25SJonas Devlieghere "no buffer size is specified the output is unbuffered.", 38be265d25SJonas Devlieghere }, 39be265d25SJonas Devlieghere { 40be265d25SJonas Devlieghere eLogHandlerCircular, 41be265d25SJonas Devlieghere "circular", 42be265d25SJonas Devlieghere "Write log messages to a fixed size circular buffer. A buffer size " 43be265d25SJonas Devlieghere "(number of messages) must be specified with -b.", 44be265d25SJonas Devlieghere }, 45be265d25SJonas Devlieghere { 46be265d25SJonas Devlieghere eLogHandlerSystem, 47be265d25SJonas Devlieghere "os", 48be265d25SJonas Devlieghere "Write log messages to the operating system log.", 49be265d25SJonas Devlieghere }, 50be265d25SJonas Devlieghere }; 51be265d25SJonas Devlieghere 52be265d25SJonas Devlieghere static constexpr OptionEnumValues LogHandlerType() { 53be265d25SJonas Devlieghere return OptionEnumValues(g_log_handler_type); 54be265d25SJonas Devlieghere } 55be265d25SJonas Devlieghere 5609dea546SJonas Devlieghere #define LLDB_OPTIONS_log_enable 57ec67e734SRaphael Isemann #include "CommandOptions.inc" 581f0f5b5bSZachary Turner 59*9bdb7e57SJonas Devlieghere #define LLDB_OPTIONS_log_dump 60*9bdb7e57SJonas Devlieghere #include "CommandOptions.inc" 61*9bdb7e57SJonas Devlieghere 626ba63d88SRaphael Isemann /// Common completion logic for log enable/disable. 636ba63d88SRaphael Isemann static void CompleteEnableDisable(CompletionRequest &request) { 646ba63d88SRaphael Isemann size_t arg_index = request.GetCursorIndex(); 656ba63d88SRaphael Isemann if (arg_index == 0) { // We got: log enable/disable x[tab] 666ba63d88SRaphael Isemann for (llvm::StringRef channel : Log::ListChannels()) 676ba63d88SRaphael Isemann request.TryCompleteCurrentArg(channel); 686ba63d88SRaphael Isemann } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab] 696ba63d88SRaphael Isemann llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0); 706ba63d88SRaphael Isemann Log::ForEachChannelCategory( 716ba63d88SRaphael Isemann channel, [&request](llvm::StringRef name, llvm::StringRef desc) { 726ba63d88SRaphael Isemann request.TryCompleteCurrentArg(name, desc); 736ba63d88SRaphael Isemann }); 746ba63d88SRaphael Isemann } 756ba63d88SRaphael Isemann } 766ba63d88SRaphael Isemann 77b9c1b51eSKate Stone class CommandObjectLogEnable : public CommandObjectParsed { 7830fdc8d8SChris Lattner public: 7930fdc8d8SChris Lattner // Constructors and Destructors 80b9c1b51eSKate Stone CommandObjectLogEnable(CommandInterpreter &interpreter) 81b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "log enable", 8230fdc8d8SChris Lattner "Enable logging for a single log channel.", 83abb0ed44SKazu Hirata nullptr) { 84ceb6b139SCaroline Tice CommandArgumentEntry arg1; 85ceb6b139SCaroline Tice CommandArgumentEntry arg2; 86405fe67fSCaroline Tice CommandArgumentData channel_arg; 87ceb6b139SCaroline Tice CommandArgumentData category_arg; 88405fe67fSCaroline Tice 89405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 90405fe67fSCaroline Tice channel_arg.arg_type = eArgTypeLogChannel; 91405fe67fSCaroline Tice channel_arg.arg_repetition = eArgRepeatPlain; 92405fe67fSCaroline Tice 93b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 94b9c1b51eSKate Stone // argument entry. 95ceb6b139SCaroline Tice arg1.push_back(channel_arg); 96ceb6b139SCaroline Tice 97ceb6b139SCaroline Tice category_arg.arg_type = eArgTypeLogCategory; 98ceb6b139SCaroline Tice category_arg.arg_repetition = eArgRepeatPlus; 99ceb6b139SCaroline Tice 100ceb6b139SCaroline Tice arg2.push_back(category_arg); 101405fe67fSCaroline Tice 102405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 103ceb6b139SCaroline Tice m_arguments.push_back(arg1); 104ceb6b139SCaroline Tice m_arguments.push_back(arg2); 10530fdc8d8SChris Lattner } 10630fdc8d8SChris Lattner 10726cac3afSEugene Zelenko ~CommandObjectLogEnable() override = default; 10830fdc8d8SChris Lattner 109b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 11030fdc8d8SChris Lattner 111b9c1b51eSKate Stone class CommandOptions : public Options { 11230fdc8d8SChris Lattner public: 11324f9a2f5SShafik Yaghmour CommandOptions() = default; 11430fdc8d8SChris Lattner 11526cac3afSEugene Zelenko ~CommandOptions() override = default; 11630fdc8d8SChris Lattner 11797206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 118b9c1b51eSKate Stone ExecutionContext *execution_context) override { 11997206d57SZachary Turner Status error; 1203bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 12130fdc8d8SChris Lattner 122b9c1b51eSKate Stone switch (short_option) { 123b9c1b51eSKate Stone case 'f': 1248f3be7a3SJonas Devlieghere log_file.SetFile(option_arg, FileSpec::Style::native); 1258f3be7a3SJonas Devlieghere FileSystem::Instance().Resolve(log_file); 126b9c1b51eSKate Stone break; 127be265d25SJonas Devlieghere case 'h': 128be265d25SJonas Devlieghere handler = (LogHandlerKind)OptionArgParser::ToOptionEnum( 129be265d25SJonas Devlieghere option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 130be265d25SJonas Devlieghere if (!error.Success()) 131be265d25SJonas Devlieghere error.SetErrorStringWithFormat( 132be265d25SJonas Devlieghere "unrecognized value for log handler '%s'", 133be265d25SJonas Devlieghere option_arg.str().c_str()); 134be265d25SJonas Devlieghere break; 13509dea546SJonas Devlieghere case 'b': 13609dea546SJonas Devlieghere error = 13709dea546SJonas Devlieghere buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign); 13809dea546SJonas Devlieghere break; 139b9c1b51eSKate Stone case 'v': 140b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_VERBOSE; 141b9c1b51eSKate Stone break; 142b9c1b51eSKate Stone case 's': 143b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; 144b9c1b51eSKate Stone break; 145b9c1b51eSKate Stone case 'T': 146b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; 147b9c1b51eSKate Stone break; 148b9c1b51eSKate Stone case 'p': 149b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD; 150b9c1b51eSKate Stone break; 151b9c1b51eSKate Stone case 'n': 152b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; 153b9c1b51eSKate Stone break; 154b9c1b51eSKate Stone case 'S': 155b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_BACKTRACE; 156b9c1b51eSKate Stone break; 157b9c1b51eSKate Stone case 'a': 158b9c1b51eSKate Stone log_options |= LLDB_LOG_OPTION_APPEND; 159b9c1b51eSKate Stone break; 160107d9bbdSPavel Labath case 'F': 161107d9bbdSPavel Labath log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION; 16290505a0aSPavel Labath break; 16330fdc8d8SChris Lattner default: 16436162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 16530fdc8d8SChris Lattner } 16630fdc8d8SChris Lattner 16730fdc8d8SChris Lattner return error; 16830fdc8d8SChris Lattner } 16930fdc8d8SChris Lattner 170b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 171889037d7SGreg Clayton log_file.Clear(); 17209dea546SJonas Devlieghere buffer_size.Clear(); 173be265d25SJonas Devlieghere handler = eLogHandlerStream; 17430fdc8d8SChris Lattner log_options = 0; 17530fdc8d8SChris Lattner } 17630fdc8d8SChris Lattner 1771f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 17809dea546SJonas Devlieghere return llvm::makeArrayRef(g_log_enable_options); 1791f0f5b5bSZachary Turner } 18030fdc8d8SChris Lattner 181889037d7SGreg Clayton FileSpec log_file; 18209dea546SJonas Devlieghere OptionValueUInt64 buffer_size; 183be265d25SJonas Devlieghere LogHandlerKind handler = eLogHandlerStream; 1849494c510SJonas Devlieghere uint32_t log_options = 0; 18530fdc8d8SChris Lattner }; 18630fdc8d8SChris Lattner 1876ba63d88SRaphael Isemann void 1886ba63d88SRaphael Isemann HandleArgumentCompletion(CompletionRequest &request, 1896ba63d88SRaphael Isemann OptionElementVector &opt_element_vector) override { 1906ba63d88SRaphael Isemann CompleteEnableDisable(request); 1916ba63d88SRaphael Isemann } 1926ba63d88SRaphael Isemann 19330fdc8d8SChris Lattner protected: 194b9c1b51eSKate Stone bool DoExecute(Args &args, CommandReturnObject &result) override { 195b9c1b51eSKate Stone if (args.GetArgumentCount() < 2) { 196b9c1b51eSKate Stone result.AppendErrorWithFormat( 197b9c1b51eSKate Stone "%s takes a log channel and one or more log types.\n", 198b9c1b51eSKate Stone m_cmd_name.c_str()); 19911eb9c64SZachary Turner return false; 20011eb9c64SZachary Turner } 20111eb9c64SZachary Turner 202be265d25SJonas Devlieghere if (m_options.handler == eLogHandlerCircular && 203be265d25SJonas Devlieghere m_options.buffer_size.GetCurrentValue() == 0) { 204be265d25SJonas Devlieghere result.AppendError( 205be265d25SJonas Devlieghere "the circular buffer handler requires a non-zero buffer size.\n"); 206be265d25SJonas Devlieghere return false; 207be265d25SJonas Devlieghere } 208be265d25SJonas Devlieghere 20911eb9c64SZachary Turner // Store into a std::string since we're about to shift the channel off. 210adcd0268SBenjamin Kramer const std::string channel = std::string(args[0].ref()); 2115a988416SJim Ingham args.Shift(); // Shift off the channel 212889037d7SGreg Clayton char log_file[PATH_MAX]; 213889037d7SGreg Clayton if (m_options.log_file) 214889037d7SGreg Clayton m_options.log_file.GetPath(log_file, sizeof(log_file)); 215889037d7SGreg Clayton else 216889037d7SGreg Clayton log_file[0] = '\0'; 217775588c0SPavel Labath 218775588c0SPavel Labath std::string error; 219775588c0SPavel Labath llvm::raw_string_ostream error_stream(error); 22009dea546SJonas Devlieghere bool success = GetDebugger().EnableLog( 22109dea546SJonas Devlieghere channel, args.GetArgumentArrayRef(), log_file, m_options.log_options, 222be265d25SJonas Devlieghere m_options.buffer_size.GetCurrentValue(), m_options.handler, 223be265d25SJonas Devlieghere error_stream); 224775588c0SPavel Labath result.GetErrorStream() << error_stream.str(); 225775588c0SPavel Labath 2265a988416SJim Ingham if (success) 2275a988416SJim Ingham result.SetStatus(eReturnStatusSuccessFinishNoResult); 2285a988416SJim Ingham else 2295a988416SJim Ingham result.SetStatus(eReturnStatusFailed); 2305a988416SJim Ingham return result.Succeeded(); 2315a988416SJim Ingham } 2325a988416SJim Ingham 23330fdc8d8SChris Lattner CommandOptions m_options; 23430fdc8d8SChris Lattner }; 23530fdc8d8SChris Lattner 236b9c1b51eSKate Stone class CommandObjectLogDisable : public CommandObjectParsed { 23730fdc8d8SChris Lattner public: 23830fdc8d8SChris Lattner // Constructors and Destructors 239b9c1b51eSKate Stone CommandObjectLogDisable(CommandInterpreter &interpreter) 240b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "log disable", 2417149fab4SCaroline Tice "Disable one or more log channel categories.", 242b9c1b51eSKate Stone nullptr) { 2437149fab4SCaroline Tice CommandArgumentEntry arg1; 2447149fab4SCaroline Tice CommandArgumentEntry arg2; 245405fe67fSCaroline Tice CommandArgumentData channel_arg; 2467149fab4SCaroline Tice CommandArgumentData category_arg; 247405fe67fSCaroline Tice 248405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 249405fe67fSCaroline Tice channel_arg.arg_type = eArgTypeLogChannel; 2507149fab4SCaroline Tice channel_arg.arg_repetition = eArgRepeatPlain; 251405fe67fSCaroline Tice 252b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 253b9c1b51eSKate Stone // argument entry. 2547149fab4SCaroline Tice arg1.push_back(channel_arg); 2557149fab4SCaroline Tice 2567149fab4SCaroline Tice category_arg.arg_type = eArgTypeLogCategory; 2577149fab4SCaroline Tice category_arg.arg_repetition = eArgRepeatPlus; 2587149fab4SCaroline Tice 2597149fab4SCaroline Tice arg2.push_back(category_arg); 260405fe67fSCaroline Tice 261405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 2627149fab4SCaroline Tice m_arguments.push_back(arg1); 2637149fab4SCaroline Tice m_arguments.push_back(arg2); 26430fdc8d8SChris Lattner } 26530fdc8d8SChris Lattner 26626cac3afSEugene Zelenko ~CommandObjectLogDisable() override = default; 26730fdc8d8SChris Lattner 2686ba63d88SRaphael Isemann void 2696ba63d88SRaphael Isemann HandleArgumentCompletion(CompletionRequest &request, 2706ba63d88SRaphael Isemann OptionElementVector &opt_element_vector) override { 2716ba63d88SRaphael Isemann CompleteEnableDisable(request); 2726ba63d88SRaphael Isemann } 2736ba63d88SRaphael Isemann 2745a988416SJim Ingham protected: 275b9c1b51eSKate Stone bool DoExecute(Args &args, CommandReturnObject &result) override { 27611eb9c64SZachary Turner if (args.empty()) { 277b9c1b51eSKate Stone result.AppendErrorWithFormat( 278b9c1b51eSKate Stone "%s takes a log channel and one or more log types.\n", 279b9c1b51eSKate Stone m_cmd_name.c_str()); 28011eb9c64SZachary Turner return false; 28111eb9c64SZachary Turner } 28211eb9c64SZachary Turner 283adcd0268SBenjamin Kramer const std::string channel = std::string(args[0].ref()); 28420ad3c40SCaroline Tice args.Shift(); // Shift off the channel 285fb0d22d6SPavel Labath if (channel == "all") { 286775588c0SPavel Labath Log::DisableAllLogChannels(); 2875fb8af40SPavel Labath result.SetStatus(eReturnStatusSuccessFinishNoResult); 288fb0d22d6SPavel Labath } else { 289775588c0SPavel Labath std::string error; 290775588c0SPavel Labath llvm::raw_string_ostream error_stream(error); 2915e336903SPavel Labath if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(), 292775588c0SPavel Labath error_stream)) 293fb0d22d6SPavel Labath result.SetStatus(eReturnStatusSuccessFinishNoResult); 294775588c0SPavel Labath result.GetErrorStream() << error_stream.str(); 29530fdc8d8SChris Lattner } 29630fdc8d8SChris Lattner return result.Succeeded(); 29730fdc8d8SChris Lattner } 29830fdc8d8SChris Lattner }; 29930fdc8d8SChris Lattner 300b9c1b51eSKate Stone class CommandObjectLogList : public CommandObjectParsed { 30130fdc8d8SChris Lattner public: 30230fdc8d8SChris Lattner // Constructors and Destructors 303b9c1b51eSKate Stone CommandObjectLogList(CommandInterpreter &interpreter) 304b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "log list", 305b9c1b51eSKate Stone "List the log categories for one or more log " 306b9c1b51eSKate Stone "channels. If none specified, lists them all.", 307b9c1b51eSKate Stone nullptr) { 308405fe67fSCaroline Tice CommandArgumentEntry arg; 309405fe67fSCaroline Tice CommandArgumentData channel_arg; 310405fe67fSCaroline Tice 311405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 312405fe67fSCaroline Tice channel_arg.arg_type = eArgTypeLogChannel; 313405fe67fSCaroline Tice channel_arg.arg_repetition = eArgRepeatStar; 314405fe67fSCaroline Tice 315b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 316b9c1b51eSKate Stone // argument entry. 317405fe67fSCaroline Tice arg.push_back(channel_arg); 318405fe67fSCaroline Tice 319405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 320405fe67fSCaroline Tice m_arguments.push_back(arg); 32130fdc8d8SChris Lattner } 32230fdc8d8SChris Lattner 32326cac3afSEugene Zelenko ~CommandObjectLogList() override = default; 32430fdc8d8SChris Lattner 3256ba63d88SRaphael Isemann void 3266ba63d88SRaphael Isemann HandleArgumentCompletion(CompletionRequest &request, 3276ba63d88SRaphael Isemann OptionElementVector &opt_element_vector) override { 3286ba63d88SRaphael Isemann for (llvm::StringRef channel : Log::ListChannels()) 3296ba63d88SRaphael Isemann request.TryCompleteCurrentArg(channel); 3306ba63d88SRaphael Isemann } 3316ba63d88SRaphael Isemann 3325a988416SJim Ingham protected: 333b9c1b51eSKate Stone bool DoExecute(Args &args, CommandReturnObject &result) override { 334775588c0SPavel Labath std::string output; 335775588c0SPavel Labath llvm::raw_string_ostream output_stream(output); 33611eb9c64SZachary Turner if (args.empty()) { 337775588c0SPavel Labath Log::ListAllLogChannels(output_stream); 33830fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 339b9c1b51eSKate Stone } else { 340fb0d22d6SPavel Labath bool success = true; 341fb0d22d6SPavel Labath for (const auto &entry : args.entries()) 342775588c0SPavel Labath success = 3430d9a201eSRaphael Isemann success && Log::ListChannelCategories(entry.ref(), output_stream); 344fb0d22d6SPavel Labath if (success) 34530fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 34630fdc8d8SChris Lattner } 347775588c0SPavel Labath result.GetOutputStream() << output_stream.str(); 34830fdc8d8SChris Lattner return result.Succeeded(); 34930fdc8d8SChris Lattner } 35030fdc8d8SChris Lattner }; 351*9bdb7e57SJonas Devlieghere class CommandObjectLogDump : public CommandObjectParsed { 352*9bdb7e57SJonas Devlieghere public: 353*9bdb7e57SJonas Devlieghere CommandObjectLogDump(CommandInterpreter &interpreter) 354*9bdb7e57SJonas Devlieghere : CommandObjectParsed(interpreter, "log dump", 355*9bdb7e57SJonas Devlieghere "dump circular buffer logs", nullptr) { 356*9bdb7e57SJonas Devlieghere CommandArgumentEntry arg1; 357*9bdb7e57SJonas Devlieghere CommandArgumentData channel_arg; 358*9bdb7e57SJonas Devlieghere 359*9bdb7e57SJonas Devlieghere // Define the first (and only) variant of this arg. 360*9bdb7e57SJonas Devlieghere channel_arg.arg_type = eArgTypeLogChannel; 361*9bdb7e57SJonas Devlieghere channel_arg.arg_repetition = eArgRepeatPlain; 362*9bdb7e57SJonas Devlieghere 363*9bdb7e57SJonas Devlieghere // There is only one variant this argument could be; put it into the 364*9bdb7e57SJonas Devlieghere // argument entry. 365*9bdb7e57SJonas Devlieghere arg1.push_back(channel_arg); 366*9bdb7e57SJonas Devlieghere 367*9bdb7e57SJonas Devlieghere // Push the data for the first argument into the m_arguments vector. 368*9bdb7e57SJonas Devlieghere m_arguments.push_back(arg1); 369*9bdb7e57SJonas Devlieghere } 370*9bdb7e57SJonas Devlieghere 371*9bdb7e57SJonas Devlieghere ~CommandObjectLogDump() override = default; 372*9bdb7e57SJonas Devlieghere 373*9bdb7e57SJonas Devlieghere Options *GetOptions() override { return &m_options; } 374*9bdb7e57SJonas Devlieghere 375*9bdb7e57SJonas Devlieghere class CommandOptions : public Options { 376*9bdb7e57SJonas Devlieghere public: 377*9bdb7e57SJonas Devlieghere CommandOptions() = default; 378*9bdb7e57SJonas Devlieghere 379*9bdb7e57SJonas Devlieghere ~CommandOptions() override = default; 380*9bdb7e57SJonas Devlieghere 381*9bdb7e57SJonas Devlieghere Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 382*9bdb7e57SJonas Devlieghere ExecutionContext *execution_context) override { 383*9bdb7e57SJonas Devlieghere Status error; 384*9bdb7e57SJonas Devlieghere const int short_option = m_getopt_table[option_idx].val; 385*9bdb7e57SJonas Devlieghere 386*9bdb7e57SJonas Devlieghere switch (short_option) { 387*9bdb7e57SJonas Devlieghere case 'f': 388*9bdb7e57SJonas Devlieghere log_file.SetFile(option_arg, FileSpec::Style::native); 389*9bdb7e57SJonas Devlieghere FileSystem::Instance().Resolve(log_file); 390*9bdb7e57SJonas Devlieghere break; 391*9bdb7e57SJonas Devlieghere default: 392*9bdb7e57SJonas Devlieghere llvm_unreachable("Unimplemented option"); 393*9bdb7e57SJonas Devlieghere } 394*9bdb7e57SJonas Devlieghere 395*9bdb7e57SJonas Devlieghere return error; 396*9bdb7e57SJonas Devlieghere } 397*9bdb7e57SJonas Devlieghere 398*9bdb7e57SJonas Devlieghere void OptionParsingStarting(ExecutionContext *execution_context) override { 399*9bdb7e57SJonas Devlieghere log_file.Clear(); 400*9bdb7e57SJonas Devlieghere } 401*9bdb7e57SJonas Devlieghere 402*9bdb7e57SJonas Devlieghere llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 403*9bdb7e57SJonas Devlieghere return llvm::makeArrayRef(g_log_dump_options); 404*9bdb7e57SJonas Devlieghere } 405*9bdb7e57SJonas Devlieghere 406*9bdb7e57SJonas Devlieghere FileSpec log_file; 407*9bdb7e57SJonas Devlieghere }; 408*9bdb7e57SJonas Devlieghere 409*9bdb7e57SJonas Devlieghere void 410*9bdb7e57SJonas Devlieghere HandleArgumentCompletion(CompletionRequest &request, 411*9bdb7e57SJonas Devlieghere OptionElementVector &opt_element_vector) override { 412*9bdb7e57SJonas Devlieghere CompleteEnableDisable(request); 413*9bdb7e57SJonas Devlieghere } 414*9bdb7e57SJonas Devlieghere 415*9bdb7e57SJonas Devlieghere protected: 416*9bdb7e57SJonas Devlieghere bool DoExecute(Args &args, CommandReturnObject &result) override { 417*9bdb7e57SJonas Devlieghere if (args.empty()) { 418*9bdb7e57SJonas Devlieghere result.AppendErrorWithFormat( 419*9bdb7e57SJonas Devlieghere "%s takes a log channel and one or more log types.\n", 420*9bdb7e57SJonas Devlieghere m_cmd_name.c_str()); 421*9bdb7e57SJonas Devlieghere return false; 422*9bdb7e57SJonas Devlieghere } 423*9bdb7e57SJonas Devlieghere 424*9bdb7e57SJonas Devlieghere std::unique_ptr<llvm::raw_ostream> stream_up; 425*9bdb7e57SJonas Devlieghere if (m_options.log_file) { 426*9bdb7e57SJonas Devlieghere const File::OpenOptions flags = File::eOpenOptionWriteOnly | 427*9bdb7e57SJonas Devlieghere File::eOpenOptionCanCreate | 428*9bdb7e57SJonas Devlieghere File::eOpenOptionTruncate; 429*9bdb7e57SJonas Devlieghere llvm::Expected<FileUP> file = FileSystem::Instance().Open( 430*9bdb7e57SJonas Devlieghere m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false); 431*9bdb7e57SJonas Devlieghere if (!file) { 432*9bdb7e57SJonas Devlieghere result.AppendErrorWithFormat("Unable to open log file '%s': %s", 433*9bdb7e57SJonas Devlieghere m_options.log_file.GetCString(), 434*9bdb7e57SJonas Devlieghere llvm::toString(file.takeError()).c_str()); 435*9bdb7e57SJonas Devlieghere return false; 436*9bdb7e57SJonas Devlieghere } 437*9bdb7e57SJonas Devlieghere stream_up = std::make_unique<llvm::raw_fd_ostream>( 438*9bdb7e57SJonas Devlieghere (*file)->GetDescriptor(), /*shouldClose=*/true); 439*9bdb7e57SJonas Devlieghere } else { 440*9bdb7e57SJonas Devlieghere stream_up = std::make_unique<llvm::raw_fd_ostream>( 441*9bdb7e57SJonas Devlieghere GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false); 442*9bdb7e57SJonas Devlieghere } 443*9bdb7e57SJonas Devlieghere 444*9bdb7e57SJonas Devlieghere const std::string channel = std::string(args[0].ref()); 445*9bdb7e57SJonas Devlieghere std::string error; 446*9bdb7e57SJonas Devlieghere llvm::raw_string_ostream error_stream(error); 447*9bdb7e57SJonas Devlieghere if (Log::DumpLogChannel(channel, *stream_up, error_stream)) { 448*9bdb7e57SJonas Devlieghere result.SetStatus(eReturnStatusSuccessFinishNoResult); 449*9bdb7e57SJonas Devlieghere } else { 450*9bdb7e57SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 451*9bdb7e57SJonas Devlieghere result.GetErrorStream() << error_stream.str(); 452*9bdb7e57SJonas Devlieghere } 453*9bdb7e57SJonas Devlieghere 454*9bdb7e57SJonas Devlieghere return result.Succeeded(); 455*9bdb7e57SJonas Devlieghere } 456*9bdb7e57SJonas Devlieghere 457*9bdb7e57SJonas Devlieghere CommandOptions m_options; 458*9bdb7e57SJonas Devlieghere }; 45930fdc8d8SChris Lattner 4601d3b7370SShu Anzai class CommandObjectLogTimerEnable : public CommandObjectParsed { 46130fdc8d8SChris Lattner public: 46230fdc8d8SChris Lattner // Constructors and Destructors 4631d3b7370SShu Anzai CommandObjectLogTimerEnable(CommandInterpreter &interpreter) 4641d3b7370SShu Anzai : CommandObjectParsed(interpreter, "log timers enable", 4651d3b7370SShu Anzai "enable LLDB internal performance timers", 4661d3b7370SShu Anzai "log timers enable <depth>") { 4671d3b7370SShu Anzai CommandArgumentEntry arg; 4681d3b7370SShu Anzai CommandArgumentData depth_arg; 46930fdc8d8SChris Lattner 4701d3b7370SShu Anzai // Define the first (and only) variant of this arg. 4711d3b7370SShu Anzai depth_arg.arg_type = eArgTypeCount; 4721d3b7370SShu Anzai depth_arg.arg_repetition = eArgRepeatOptional; 4731d3b7370SShu Anzai 4741d3b7370SShu Anzai // There is only one variant this argument could be; put it into the 4751d3b7370SShu Anzai // argument entry. 4761d3b7370SShu Anzai arg.push_back(depth_arg); 4771d3b7370SShu Anzai 4781d3b7370SShu Anzai // Push the data for the first argument into the m_arguments vector. 4791d3b7370SShu Anzai m_arguments.push_back(arg); 4801d3b7370SShu Anzai } 4811d3b7370SShu Anzai 4821d3b7370SShu Anzai ~CommandObjectLogTimerEnable() override = default; 48330fdc8d8SChris Lattner 4845a988416SJim Ingham protected: 485b9c1b51eSKate Stone bool DoExecute(Args &args, CommandReturnObject &result) override { 48630fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 48730fdc8d8SChris Lattner 4881d3b7370SShu Anzai if (args.GetArgumentCount() == 0) { 48930fdc8d8SChris Lattner Timer::SetDisplayDepth(UINT32_MAX); 49030fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishNoResult); 4911d3b7370SShu Anzai } else if (args.GetArgumentCount() == 1) { 49211eb9c64SZachary Turner uint32_t depth; 4931d3b7370SShu Anzai if (args[0].ref().consumeInteger(0, depth)) { 494b9c1b51eSKate Stone result.AppendError( 495b9c1b51eSKate Stone "Could not convert enable depth to an unsigned integer."); 49611eb9c64SZachary Turner } else { 49711eb9c64SZachary Turner Timer::SetDisplayDepth(depth); 49811eb9c64SZachary Turner result.SetStatus(eReturnStatusSuccessFinishNoResult); 499932725faSJim Ingham } 500932725faSJim Ingham } 501932725faSJim Ingham 502b9c1b51eSKate Stone if (!result.Succeeded()) { 50330fdc8d8SChris Lattner result.AppendError("Missing subcommand"); 50430fdc8d8SChris Lattner result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 50530fdc8d8SChris Lattner } 50630fdc8d8SChris Lattner return result.Succeeded(); 50730fdc8d8SChris Lattner } 50830fdc8d8SChris Lattner }; 50930fdc8d8SChris Lattner 5101d3b7370SShu Anzai class CommandObjectLogTimerDisable : public CommandObjectParsed { 5111d3b7370SShu Anzai public: 5121d3b7370SShu Anzai // Constructors and Destructors 5131d3b7370SShu Anzai CommandObjectLogTimerDisable(CommandInterpreter &interpreter) 5141d3b7370SShu Anzai : CommandObjectParsed(interpreter, "log timers disable", 5151d3b7370SShu Anzai "disable LLDB internal performance timers", 5161d3b7370SShu Anzai nullptr) {} 5171d3b7370SShu Anzai 5181d3b7370SShu Anzai ~CommandObjectLogTimerDisable() override = default; 5191d3b7370SShu Anzai 5201d3b7370SShu Anzai protected: 5211d3b7370SShu Anzai bool DoExecute(Args &args, CommandReturnObject &result) override { 5221d3b7370SShu Anzai Timer::DumpCategoryTimes(&result.GetOutputStream()); 5231d3b7370SShu Anzai Timer::SetDisplayDepth(0); 5241d3b7370SShu Anzai result.SetStatus(eReturnStatusSuccessFinishResult); 5251d3b7370SShu Anzai 5261d3b7370SShu Anzai if (!result.Succeeded()) { 5271d3b7370SShu Anzai result.AppendError("Missing subcommand"); 5281d3b7370SShu Anzai result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 5291d3b7370SShu Anzai } 5301d3b7370SShu Anzai return result.Succeeded(); 5311d3b7370SShu Anzai } 5321d3b7370SShu Anzai }; 5331d3b7370SShu Anzai 5341d3b7370SShu Anzai class CommandObjectLogTimerDump : public CommandObjectParsed { 5351d3b7370SShu Anzai public: 5361d3b7370SShu Anzai // Constructors and Destructors 5371d3b7370SShu Anzai CommandObjectLogTimerDump(CommandInterpreter &interpreter) 5381d3b7370SShu Anzai : CommandObjectParsed(interpreter, "log timers dump", 5391d3b7370SShu Anzai "dump LLDB internal performance timers", nullptr) {} 5401d3b7370SShu Anzai 5411d3b7370SShu Anzai ~CommandObjectLogTimerDump() override = default; 5421d3b7370SShu Anzai 5431d3b7370SShu Anzai protected: 5441d3b7370SShu Anzai bool DoExecute(Args &args, CommandReturnObject &result) override { 5451d3b7370SShu Anzai Timer::DumpCategoryTimes(&result.GetOutputStream()); 5461d3b7370SShu Anzai result.SetStatus(eReturnStatusSuccessFinishResult); 5471d3b7370SShu Anzai 5481d3b7370SShu Anzai if (!result.Succeeded()) { 5491d3b7370SShu Anzai result.AppendError("Missing subcommand"); 5501d3b7370SShu Anzai result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 5511d3b7370SShu Anzai } 5521d3b7370SShu Anzai return result.Succeeded(); 5531d3b7370SShu Anzai } 5541d3b7370SShu Anzai }; 5551d3b7370SShu Anzai 5561d3b7370SShu Anzai class CommandObjectLogTimerReset : public CommandObjectParsed { 5571d3b7370SShu Anzai public: 5581d3b7370SShu Anzai // Constructors and Destructors 5591d3b7370SShu Anzai CommandObjectLogTimerReset(CommandInterpreter &interpreter) 5601d3b7370SShu Anzai : CommandObjectParsed(interpreter, "log timers reset", 5611d3b7370SShu Anzai "reset LLDB internal performance timers", nullptr) { 5621d3b7370SShu Anzai } 5631d3b7370SShu Anzai 5641d3b7370SShu Anzai ~CommandObjectLogTimerReset() override = default; 5651d3b7370SShu Anzai 5661d3b7370SShu Anzai protected: 5671d3b7370SShu Anzai bool DoExecute(Args &args, CommandReturnObject &result) override { 5681d3b7370SShu Anzai Timer::ResetCategoryTimes(); 5691d3b7370SShu Anzai result.SetStatus(eReturnStatusSuccessFinishResult); 5701d3b7370SShu Anzai 5711d3b7370SShu Anzai if (!result.Succeeded()) { 5721d3b7370SShu Anzai result.AppendError("Missing subcommand"); 5731d3b7370SShu Anzai result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 5741d3b7370SShu Anzai } 5751d3b7370SShu Anzai return result.Succeeded(); 5761d3b7370SShu Anzai } 5771d3b7370SShu Anzai }; 5781d3b7370SShu Anzai 5791d3b7370SShu Anzai class CommandObjectLogTimerIncrement : public CommandObjectParsed { 5801d3b7370SShu Anzai public: 5811d3b7370SShu Anzai // Constructors and Destructors 5821d3b7370SShu Anzai CommandObjectLogTimerIncrement(CommandInterpreter &interpreter) 5831d3b7370SShu Anzai : CommandObjectParsed(interpreter, "log timers increment", 5841d3b7370SShu Anzai "increment LLDB internal performance timers", 5851d3b7370SShu Anzai "log timers increment <bool>") { 5861d3b7370SShu Anzai CommandArgumentEntry arg; 5871d3b7370SShu Anzai CommandArgumentData bool_arg; 5881d3b7370SShu Anzai 5891d3b7370SShu Anzai // Define the first (and only) variant of this arg. 5901d3b7370SShu Anzai bool_arg.arg_type = eArgTypeBoolean; 5911d3b7370SShu Anzai bool_arg.arg_repetition = eArgRepeatPlain; 5921d3b7370SShu Anzai 5931d3b7370SShu Anzai // There is only one variant this argument could be; put it into the 5941d3b7370SShu Anzai // argument entry. 5951d3b7370SShu Anzai arg.push_back(bool_arg); 5961d3b7370SShu Anzai 5971d3b7370SShu Anzai // Push the data for the first argument into the m_arguments vector. 5981d3b7370SShu Anzai m_arguments.push_back(arg); 5991d3b7370SShu Anzai } 6001d3b7370SShu Anzai 6011d3b7370SShu Anzai ~CommandObjectLogTimerIncrement() override = default; 6021d3b7370SShu Anzai 6031d3b7370SShu Anzai void 6041d3b7370SShu Anzai HandleArgumentCompletion(CompletionRequest &request, 6051d3b7370SShu Anzai OptionElementVector &opt_element_vector) override { 6061d3b7370SShu Anzai request.TryCompleteCurrentArg("true"); 6071d3b7370SShu Anzai request.TryCompleteCurrentArg("false"); 6081d3b7370SShu Anzai } 6091d3b7370SShu Anzai 6101d3b7370SShu Anzai protected: 6111d3b7370SShu Anzai bool DoExecute(Args &args, CommandReturnObject &result) override { 6121d3b7370SShu Anzai result.SetStatus(eReturnStatusFailed); 6131d3b7370SShu Anzai 6141d3b7370SShu Anzai if (args.GetArgumentCount() == 1) { 6151d3b7370SShu Anzai bool success; 6161d3b7370SShu Anzai bool increment = 6171d3b7370SShu Anzai OptionArgParser::ToBoolean(args[0].ref(), false, &success); 6181d3b7370SShu Anzai 6191d3b7370SShu Anzai if (success) { 6201d3b7370SShu Anzai Timer::SetQuiet(!increment); 6211d3b7370SShu Anzai result.SetStatus(eReturnStatusSuccessFinishNoResult); 6221d3b7370SShu Anzai } else 6231d3b7370SShu Anzai result.AppendError("Could not convert increment value to boolean."); 6241d3b7370SShu Anzai } 6251d3b7370SShu Anzai 6261d3b7370SShu Anzai if (!result.Succeeded()) { 6271d3b7370SShu Anzai result.AppendError("Missing subcommand"); 6281d3b7370SShu Anzai result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 6291d3b7370SShu Anzai } 6301d3b7370SShu Anzai return result.Succeeded(); 6311d3b7370SShu Anzai } 6321d3b7370SShu Anzai }; 6331d3b7370SShu Anzai 6341d3b7370SShu Anzai class CommandObjectLogTimer : public CommandObjectMultiword { 6351d3b7370SShu Anzai public: 6361d3b7370SShu Anzai CommandObjectLogTimer(CommandInterpreter &interpreter) 6371d3b7370SShu Anzai : CommandObjectMultiword(interpreter, "log timers", 6381d3b7370SShu Anzai "Enable, disable, dump, and reset LLDB internal " 6391d3b7370SShu Anzai "performance timers.", 6401d3b7370SShu Anzai "log timers < enable <depth> | disable | dump | " 6411d3b7370SShu Anzai "increment <bool> | reset >") { 6421d3b7370SShu Anzai LoadSubCommand("enable", CommandObjectSP( 6431d3b7370SShu Anzai new CommandObjectLogTimerEnable(interpreter))); 6441d3b7370SShu Anzai LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable( 6451d3b7370SShu Anzai interpreter))); 6461d3b7370SShu Anzai LoadSubCommand("dump", 6471d3b7370SShu Anzai CommandObjectSP(new CommandObjectLogTimerDump(interpreter))); 6481d3b7370SShu Anzai LoadSubCommand( 6491d3b7370SShu Anzai "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter))); 6501d3b7370SShu Anzai LoadSubCommand( 6511d3b7370SShu Anzai "increment", 6521d3b7370SShu Anzai CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter))); 6531d3b7370SShu Anzai } 6541d3b7370SShu Anzai 6551d3b7370SShu Anzai ~CommandObjectLogTimer() override = default; 6561d3b7370SShu Anzai }; 6571d3b7370SShu Anzai 6587428a18cSKate Stone CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) 659b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "log", 660b9c1b51eSKate Stone "Commands controlling LLDB internal logging.", 661b9c1b51eSKate Stone "log <subcommand> [<command-options>]") { 662b9c1b51eSKate Stone LoadSubCommand("enable", 663b9c1b51eSKate Stone CommandObjectSP(new CommandObjectLogEnable(interpreter))); 664b9c1b51eSKate Stone LoadSubCommand("disable", 665b9c1b51eSKate Stone CommandObjectSP(new CommandObjectLogDisable(interpreter))); 666b9c1b51eSKate Stone LoadSubCommand("list", 667b9c1b51eSKate Stone CommandObjectSP(new CommandObjectLogList(interpreter))); 668*9bdb7e57SJonas Devlieghere LoadSubCommand("dump", 669*9bdb7e57SJonas Devlieghere CommandObjectSP(new CommandObjectLogDump(interpreter))); 670b9c1b51eSKate Stone LoadSubCommand("timers", 671b9c1b51eSKate Stone CommandObjectSP(new CommandObjectLogTimer(interpreter))); 67230fdc8d8SChris Lattner } 67330fdc8d8SChris Lattner 67426cac3afSEugene Zelenko CommandObjectLog::~CommandObjectLog() = default; 675