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"
127ced9fffSJonas Devlieghere #include "lldb/Interpreter/CommandOptionArgumentTable.h"
1330fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
1447cbf4a0SPavel Labath #include "lldb/Interpreter/OptionArgParser.h"
15be265d25SJonas Devlieghere #include "lldb/Interpreter/OptionValueEnumeration.h"
1609dea546SJonas Devlieghere #include "lldb/Interpreter/OptionValueUInt64.h"
17b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
18145d95c9SPavel Labath #include "lldb/Utility/Args.h"
195713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
206f9e6901SZachary Turner #include "lldb/Utility/Log.h"
21bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2238d0632eSPavel Labath #include "lldb/Utility/Timer.h"
2330fdc8d8SChris Lattner 
2430fdc8d8SChris Lattner using namespace lldb;
2530fdc8d8SChris Lattner using namespace lldb_private;
2630fdc8d8SChris Lattner 
2709dea546SJonas Devlieghere #define LLDB_OPTIONS_log_enable
28ec67e734SRaphael Isemann #include "CommandOptions.inc"
291f0f5b5bSZachary Turner 
309bdb7e57SJonas Devlieghere #define LLDB_OPTIONS_log_dump
319bdb7e57SJonas Devlieghere #include "CommandOptions.inc"
329bdb7e57SJonas Devlieghere 
336ba63d88SRaphael Isemann /// Common completion logic for log enable/disable.
CompleteEnableDisable(CompletionRequest & request)346ba63d88SRaphael Isemann static void CompleteEnableDisable(CompletionRequest &request) {
356ba63d88SRaphael Isemann   size_t arg_index = request.GetCursorIndex();
366ba63d88SRaphael Isemann   if (arg_index == 0) { // We got: log enable/disable x[tab]
376ba63d88SRaphael Isemann     for (llvm::StringRef channel : Log::ListChannels())
386ba63d88SRaphael Isemann       request.TryCompleteCurrentArg(channel);
396ba63d88SRaphael Isemann   } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]
406ba63d88SRaphael Isemann     llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);
416ba63d88SRaphael Isemann     Log::ForEachChannelCategory(
426ba63d88SRaphael Isemann         channel, [&request](llvm::StringRef name, llvm::StringRef desc) {
436ba63d88SRaphael Isemann           request.TryCompleteCurrentArg(name, desc);
446ba63d88SRaphael Isemann         });
456ba63d88SRaphael Isemann   }
466ba63d88SRaphael Isemann }
476ba63d88SRaphael Isemann 
48b9c1b51eSKate Stone class CommandObjectLogEnable : public CommandObjectParsed {
4930fdc8d8SChris Lattner public:
5030fdc8d8SChris Lattner   // Constructors and Destructors
CommandObjectLogEnable(CommandInterpreter & interpreter)51b9c1b51eSKate Stone   CommandObjectLogEnable(CommandInterpreter &interpreter)
52b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "log enable",
5330fdc8d8SChris Lattner                             "Enable logging for a single log channel.",
54abb0ed44SKazu Hirata                             nullptr) {
55ceb6b139SCaroline Tice     CommandArgumentEntry arg1;
56ceb6b139SCaroline Tice     CommandArgumentEntry arg2;
57405fe67fSCaroline Tice     CommandArgumentData channel_arg;
58ceb6b139SCaroline Tice     CommandArgumentData category_arg;
59405fe67fSCaroline Tice 
60405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
61405fe67fSCaroline Tice     channel_arg.arg_type = eArgTypeLogChannel;
62405fe67fSCaroline Tice     channel_arg.arg_repetition = eArgRepeatPlain;
63405fe67fSCaroline Tice 
64b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
65b9c1b51eSKate Stone     // argument entry.
66ceb6b139SCaroline Tice     arg1.push_back(channel_arg);
67ceb6b139SCaroline Tice 
68ceb6b139SCaroline Tice     category_arg.arg_type = eArgTypeLogCategory;
69ceb6b139SCaroline Tice     category_arg.arg_repetition = eArgRepeatPlus;
70ceb6b139SCaroline Tice 
71ceb6b139SCaroline Tice     arg2.push_back(category_arg);
72405fe67fSCaroline Tice 
73405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
74ceb6b139SCaroline Tice     m_arguments.push_back(arg1);
75ceb6b139SCaroline Tice     m_arguments.push_back(arg2);
7630fdc8d8SChris Lattner   }
7730fdc8d8SChris Lattner 
7826cac3afSEugene Zelenko   ~CommandObjectLogEnable() override = default;
7930fdc8d8SChris Lattner 
GetOptions()80b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
8130fdc8d8SChris Lattner 
82b9c1b51eSKate Stone   class CommandOptions : public Options {
8330fdc8d8SChris Lattner   public:
8424f9a2f5SShafik Yaghmour     CommandOptions() = default;
8530fdc8d8SChris Lattner 
8626cac3afSEugene Zelenko     ~CommandOptions() override = default;
8730fdc8d8SChris Lattner 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)8897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
89b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
9097206d57SZachary Turner       Status error;
913bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
9230fdc8d8SChris Lattner 
93b9c1b51eSKate Stone       switch (short_option) {
94b9c1b51eSKate Stone       case 'f':
958f3be7a3SJonas Devlieghere         log_file.SetFile(option_arg, FileSpec::Style::native);
968f3be7a3SJonas Devlieghere         FileSystem::Instance().Resolve(log_file);
97b9c1b51eSKate Stone         break;
98be265d25SJonas Devlieghere       case 'h':
99be265d25SJonas Devlieghere         handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(
100be265d25SJonas Devlieghere             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
101be265d25SJonas Devlieghere         if (!error.Success())
102be265d25SJonas Devlieghere           error.SetErrorStringWithFormat(
103be265d25SJonas Devlieghere               "unrecognized value for log handler '%s'",
104be265d25SJonas Devlieghere               option_arg.str().c_str());
105be265d25SJonas Devlieghere         break;
10609dea546SJonas Devlieghere       case 'b':
10709dea546SJonas Devlieghere         error =
10809dea546SJonas Devlieghere             buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign);
10909dea546SJonas Devlieghere         break;
110b9c1b51eSKate Stone       case 'v':
111b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_VERBOSE;
112b9c1b51eSKate Stone         break;
113b9c1b51eSKate Stone       case 's':
114b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
115b9c1b51eSKate Stone         break;
116b9c1b51eSKate Stone       case 'T':
117b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
118b9c1b51eSKate Stone         break;
119b9c1b51eSKate Stone       case 'p':
120b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
121b9c1b51eSKate Stone         break;
122b9c1b51eSKate Stone       case 'n':
123b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
124b9c1b51eSKate Stone         break;
125b9c1b51eSKate Stone       case 'S':
126b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_BACKTRACE;
127b9c1b51eSKate Stone         break;
128b9c1b51eSKate Stone       case 'a':
129b9c1b51eSKate Stone         log_options |= LLDB_LOG_OPTION_APPEND;
130b9c1b51eSKate Stone         break;
131107d9bbdSPavel Labath       case 'F':
132107d9bbdSPavel Labath         log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
13390505a0aSPavel Labath         break;
13430fdc8d8SChris Lattner       default:
13536162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
13630fdc8d8SChris Lattner       }
13730fdc8d8SChris Lattner 
13830fdc8d8SChris Lattner       return error;
13930fdc8d8SChris Lattner     }
14030fdc8d8SChris Lattner 
OptionParsingStarting(ExecutionContext * execution_context)141b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
142889037d7SGreg Clayton       log_file.Clear();
14309dea546SJonas Devlieghere       buffer_size.Clear();
144be265d25SJonas Devlieghere       handler = eLogHandlerStream;
14530fdc8d8SChris Lattner       log_options = 0;
14630fdc8d8SChris Lattner     }
14730fdc8d8SChris Lattner 
GetDefinitions()1481f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
14909dea546SJonas Devlieghere       return llvm::makeArrayRef(g_log_enable_options);
1501f0f5b5bSZachary Turner     }
15130fdc8d8SChris Lattner 
152889037d7SGreg Clayton     FileSpec log_file;
15309dea546SJonas Devlieghere     OptionValueUInt64 buffer_size;
154be265d25SJonas Devlieghere     LogHandlerKind handler = eLogHandlerStream;
1559494c510SJonas Devlieghere     uint32_t log_options = 0;
15630fdc8d8SChris Lattner   };
15730fdc8d8SChris Lattner 
1586ba63d88SRaphael Isemann   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1596ba63d88SRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
1606ba63d88SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
1616ba63d88SRaphael Isemann     CompleteEnableDisable(request);
1626ba63d88SRaphael Isemann   }
1636ba63d88SRaphael Isemann 
16430fdc8d8SChris Lattner protected:
DoExecute(Args & args,CommandReturnObject & result)165b9c1b51eSKate Stone   bool DoExecute(Args &args, CommandReturnObject &result) override {
166b9c1b51eSKate Stone     if (args.GetArgumentCount() < 2) {
167b9c1b51eSKate Stone       result.AppendErrorWithFormat(
168b9c1b51eSKate Stone           "%s takes a log channel and one or more log types.\n",
169b9c1b51eSKate Stone           m_cmd_name.c_str());
17011eb9c64SZachary Turner       return false;
17111eb9c64SZachary Turner     }
17211eb9c64SZachary Turner 
173be265d25SJonas Devlieghere     if (m_options.handler == eLogHandlerCircular &&
174be265d25SJonas Devlieghere         m_options.buffer_size.GetCurrentValue() == 0) {
175be265d25SJonas Devlieghere       result.AppendError(
176be265d25SJonas Devlieghere           "the circular buffer handler requires a non-zero buffer size.\n");
177be265d25SJonas Devlieghere       return false;
178be265d25SJonas Devlieghere     }
179be265d25SJonas Devlieghere 
18011eb9c64SZachary Turner     // Store into a std::string since we're about to shift the channel off.
181adcd0268SBenjamin Kramer     const std::string channel = std::string(args[0].ref());
1825a988416SJim Ingham     args.Shift(); // Shift off the channel
183889037d7SGreg Clayton     char log_file[PATH_MAX];
184889037d7SGreg Clayton     if (m_options.log_file)
185889037d7SGreg Clayton       m_options.log_file.GetPath(log_file, sizeof(log_file));
186889037d7SGreg Clayton     else
187889037d7SGreg Clayton       log_file[0] = '\0';
188775588c0SPavel Labath 
189775588c0SPavel Labath     std::string error;
190775588c0SPavel Labath     llvm::raw_string_ostream error_stream(error);
19109dea546SJonas Devlieghere     bool success = GetDebugger().EnableLog(
19209dea546SJonas Devlieghere         channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
193be265d25SJonas Devlieghere         m_options.buffer_size.GetCurrentValue(), m_options.handler,
194be265d25SJonas Devlieghere         error_stream);
195775588c0SPavel Labath     result.GetErrorStream() << error_stream.str();
196775588c0SPavel Labath 
1975a988416SJim Ingham     if (success)
1985a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1995a988416SJim Ingham     else
2005a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
2015a988416SJim Ingham     return result.Succeeded();
2025a988416SJim Ingham   }
2035a988416SJim Ingham 
20430fdc8d8SChris Lattner   CommandOptions m_options;
20530fdc8d8SChris Lattner };
20630fdc8d8SChris Lattner 
207b9c1b51eSKate Stone class CommandObjectLogDisable : public CommandObjectParsed {
20830fdc8d8SChris Lattner public:
20930fdc8d8SChris Lattner   // Constructors and Destructors
CommandObjectLogDisable(CommandInterpreter & interpreter)210b9c1b51eSKate Stone   CommandObjectLogDisable(CommandInterpreter &interpreter)
211b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "log disable",
2127149fab4SCaroline Tice                             "Disable one or more log channel categories.",
213b9c1b51eSKate Stone                             nullptr) {
2147149fab4SCaroline Tice     CommandArgumentEntry arg1;
2157149fab4SCaroline Tice     CommandArgumentEntry arg2;
216405fe67fSCaroline Tice     CommandArgumentData channel_arg;
2177149fab4SCaroline Tice     CommandArgumentData category_arg;
218405fe67fSCaroline Tice 
219405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
220405fe67fSCaroline Tice     channel_arg.arg_type = eArgTypeLogChannel;
2217149fab4SCaroline Tice     channel_arg.arg_repetition = eArgRepeatPlain;
222405fe67fSCaroline Tice 
223b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
224b9c1b51eSKate Stone     // argument entry.
2257149fab4SCaroline Tice     arg1.push_back(channel_arg);
2267149fab4SCaroline Tice 
2277149fab4SCaroline Tice     category_arg.arg_type = eArgTypeLogCategory;
2287149fab4SCaroline Tice     category_arg.arg_repetition = eArgRepeatPlus;
2297149fab4SCaroline Tice 
2307149fab4SCaroline Tice     arg2.push_back(category_arg);
231405fe67fSCaroline Tice 
232405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
2337149fab4SCaroline Tice     m_arguments.push_back(arg1);
2347149fab4SCaroline Tice     m_arguments.push_back(arg2);
23530fdc8d8SChris Lattner   }
23630fdc8d8SChris Lattner 
23726cac3afSEugene Zelenko   ~CommandObjectLogDisable() override = default;
23830fdc8d8SChris Lattner 
2396ba63d88SRaphael Isemann   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2406ba63d88SRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
2416ba63d88SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
2426ba63d88SRaphael Isemann     CompleteEnableDisable(request);
2436ba63d88SRaphael Isemann   }
2446ba63d88SRaphael Isemann 
2455a988416SJim Ingham protected:
DoExecute(Args & args,CommandReturnObject & result)246b9c1b51eSKate Stone   bool DoExecute(Args &args, CommandReturnObject &result) override {
24711eb9c64SZachary Turner     if (args.empty()) {
248b9c1b51eSKate Stone       result.AppendErrorWithFormat(
249b9c1b51eSKate Stone           "%s takes a log channel and one or more log types.\n",
250b9c1b51eSKate Stone           m_cmd_name.c_str());
25111eb9c64SZachary Turner       return false;
25211eb9c64SZachary Turner     }
25311eb9c64SZachary Turner 
254adcd0268SBenjamin Kramer     const std::string channel = std::string(args[0].ref());
25520ad3c40SCaroline Tice     args.Shift(); // Shift off the channel
256fb0d22d6SPavel Labath     if (channel == "all") {
257775588c0SPavel Labath       Log::DisableAllLogChannels();
2585fb8af40SPavel Labath       result.SetStatus(eReturnStatusSuccessFinishNoResult);
259fb0d22d6SPavel Labath     } else {
260775588c0SPavel Labath       std::string error;
261775588c0SPavel Labath       llvm::raw_string_ostream error_stream(error);
2625e336903SPavel Labath       if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
263775588c0SPavel Labath                                  error_stream))
264fb0d22d6SPavel Labath         result.SetStatus(eReturnStatusSuccessFinishNoResult);
265775588c0SPavel Labath       result.GetErrorStream() << error_stream.str();
26630fdc8d8SChris Lattner     }
26730fdc8d8SChris Lattner     return result.Succeeded();
26830fdc8d8SChris Lattner   }
26930fdc8d8SChris Lattner };
27030fdc8d8SChris Lattner 
271b9c1b51eSKate Stone class CommandObjectLogList : public CommandObjectParsed {
27230fdc8d8SChris Lattner public:
27330fdc8d8SChris Lattner   // Constructors and Destructors
CommandObjectLogList(CommandInterpreter & interpreter)274b9c1b51eSKate Stone   CommandObjectLogList(CommandInterpreter &interpreter)
275b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "log list",
276b9c1b51eSKate Stone                             "List the log categories for one or more log "
277b9c1b51eSKate Stone                             "channels.  If none specified, lists them all.",
278b9c1b51eSKate Stone                             nullptr) {
279405fe67fSCaroline Tice     CommandArgumentEntry arg;
280405fe67fSCaroline Tice     CommandArgumentData channel_arg;
281405fe67fSCaroline Tice 
282405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
283405fe67fSCaroline Tice     channel_arg.arg_type = eArgTypeLogChannel;
284405fe67fSCaroline Tice     channel_arg.arg_repetition = eArgRepeatStar;
285405fe67fSCaroline Tice 
286b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
287b9c1b51eSKate Stone     // argument entry.
288405fe67fSCaroline Tice     arg.push_back(channel_arg);
289405fe67fSCaroline Tice 
290405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
291405fe67fSCaroline Tice     m_arguments.push_back(arg);
29230fdc8d8SChris Lattner   }
29330fdc8d8SChris Lattner 
29426cac3afSEugene Zelenko   ~CommandObjectLogList() override = default;
29530fdc8d8SChris Lattner 
2966ba63d88SRaphael Isemann   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2976ba63d88SRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
2986ba63d88SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
2996ba63d88SRaphael Isemann     for (llvm::StringRef channel : Log::ListChannels())
3006ba63d88SRaphael Isemann       request.TryCompleteCurrentArg(channel);
3016ba63d88SRaphael Isemann   }
3026ba63d88SRaphael Isemann 
3035a988416SJim Ingham protected:
DoExecute(Args & args,CommandReturnObject & result)304b9c1b51eSKate Stone   bool DoExecute(Args &args, CommandReturnObject &result) override {
305775588c0SPavel Labath     std::string output;
306775588c0SPavel Labath     llvm::raw_string_ostream output_stream(output);
30711eb9c64SZachary Turner     if (args.empty()) {
308775588c0SPavel Labath       Log::ListAllLogChannels(output_stream);
30930fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
310b9c1b51eSKate Stone     } else {
311fb0d22d6SPavel Labath       bool success = true;
312fb0d22d6SPavel Labath       for (const auto &entry : args.entries())
313775588c0SPavel Labath         success =
3140d9a201eSRaphael Isemann             success && Log::ListChannelCategories(entry.ref(), output_stream);
315fb0d22d6SPavel Labath       if (success)
31630fdc8d8SChris Lattner         result.SetStatus(eReturnStatusSuccessFinishResult);
31730fdc8d8SChris Lattner     }
318775588c0SPavel Labath     result.GetOutputStream() << output_stream.str();
31930fdc8d8SChris Lattner     return result.Succeeded();
32030fdc8d8SChris Lattner   }
32130fdc8d8SChris Lattner };
3229bdb7e57SJonas Devlieghere class CommandObjectLogDump : public CommandObjectParsed {
3239bdb7e57SJonas Devlieghere public:
CommandObjectLogDump(CommandInterpreter & interpreter)3249bdb7e57SJonas Devlieghere   CommandObjectLogDump(CommandInterpreter &interpreter)
3259bdb7e57SJonas Devlieghere       : CommandObjectParsed(interpreter, "log dump",
3269bdb7e57SJonas Devlieghere                             "dump circular buffer logs", nullptr) {
3279bdb7e57SJonas Devlieghere     CommandArgumentEntry arg1;
3289bdb7e57SJonas Devlieghere     CommandArgumentData channel_arg;
3299bdb7e57SJonas Devlieghere 
3309bdb7e57SJonas Devlieghere     // Define the first (and only) variant of this arg.
3319bdb7e57SJonas Devlieghere     channel_arg.arg_type = eArgTypeLogChannel;
3329bdb7e57SJonas Devlieghere     channel_arg.arg_repetition = eArgRepeatPlain;
3339bdb7e57SJonas Devlieghere 
3349bdb7e57SJonas Devlieghere     // There is only one variant this argument could be; put it into the
3359bdb7e57SJonas Devlieghere     // argument entry.
3369bdb7e57SJonas Devlieghere     arg1.push_back(channel_arg);
3379bdb7e57SJonas Devlieghere 
3389bdb7e57SJonas Devlieghere     // Push the data for the first argument into the m_arguments vector.
3399bdb7e57SJonas Devlieghere     m_arguments.push_back(arg1);
3409bdb7e57SJonas Devlieghere   }
3419bdb7e57SJonas Devlieghere 
3429bdb7e57SJonas Devlieghere   ~CommandObjectLogDump() override = default;
3439bdb7e57SJonas Devlieghere 
GetOptions()3449bdb7e57SJonas Devlieghere   Options *GetOptions() override { return &m_options; }
3459bdb7e57SJonas Devlieghere 
3469bdb7e57SJonas Devlieghere   class CommandOptions : public Options {
3479bdb7e57SJonas Devlieghere   public:
3489bdb7e57SJonas Devlieghere     CommandOptions() = default;
3499bdb7e57SJonas Devlieghere 
3509bdb7e57SJonas Devlieghere     ~CommandOptions() override = default;
3519bdb7e57SJonas Devlieghere 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)3529bdb7e57SJonas Devlieghere     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
3539bdb7e57SJonas Devlieghere                           ExecutionContext *execution_context) override {
3549bdb7e57SJonas Devlieghere       Status error;
3559bdb7e57SJonas Devlieghere       const int short_option = m_getopt_table[option_idx].val;
3569bdb7e57SJonas Devlieghere 
3579bdb7e57SJonas Devlieghere       switch (short_option) {
3589bdb7e57SJonas Devlieghere       case 'f':
3599bdb7e57SJonas Devlieghere         log_file.SetFile(option_arg, FileSpec::Style::native);
3609bdb7e57SJonas Devlieghere         FileSystem::Instance().Resolve(log_file);
3619bdb7e57SJonas Devlieghere         break;
3629bdb7e57SJonas Devlieghere       default:
3639bdb7e57SJonas Devlieghere         llvm_unreachable("Unimplemented option");
3649bdb7e57SJonas Devlieghere       }
3659bdb7e57SJonas Devlieghere 
3669bdb7e57SJonas Devlieghere       return error;
3679bdb7e57SJonas Devlieghere     }
3689bdb7e57SJonas Devlieghere 
OptionParsingStarting(ExecutionContext * execution_context)3699bdb7e57SJonas Devlieghere     void OptionParsingStarting(ExecutionContext *execution_context) override {
3709bdb7e57SJonas Devlieghere       log_file.Clear();
3719bdb7e57SJonas Devlieghere     }
3729bdb7e57SJonas Devlieghere 
GetDefinitions()3739bdb7e57SJonas Devlieghere     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
3749bdb7e57SJonas Devlieghere       return llvm::makeArrayRef(g_log_dump_options);
3759bdb7e57SJonas Devlieghere     }
3769bdb7e57SJonas Devlieghere 
3779bdb7e57SJonas Devlieghere     FileSpec log_file;
3789bdb7e57SJonas Devlieghere   };
3799bdb7e57SJonas Devlieghere 
3809bdb7e57SJonas Devlieghere   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)3819bdb7e57SJonas Devlieghere   HandleArgumentCompletion(CompletionRequest &request,
3829bdb7e57SJonas Devlieghere                            OptionElementVector &opt_element_vector) override {
3839bdb7e57SJonas Devlieghere     CompleteEnableDisable(request);
3849bdb7e57SJonas Devlieghere   }
3859bdb7e57SJonas Devlieghere 
3869bdb7e57SJonas Devlieghere protected:
DoExecute(Args & args,CommandReturnObject & result)3879bdb7e57SJonas Devlieghere   bool DoExecute(Args &args, CommandReturnObject &result) override {
3889bdb7e57SJonas Devlieghere     if (args.empty()) {
3899bdb7e57SJonas Devlieghere       result.AppendErrorWithFormat(
3909bdb7e57SJonas Devlieghere           "%s takes a log channel and one or more log types.\n",
3919bdb7e57SJonas Devlieghere           m_cmd_name.c_str());
3929bdb7e57SJonas Devlieghere       return false;
3939bdb7e57SJonas Devlieghere     }
3949bdb7e57SJonas Devlieghere 
3959bdb7e57SJonas Devlieghere     std::unique_ptr<llvm::raw_ostream> stream_up;
3969bdb7e57SJonas Devlieghere     if (m_options.log_file) {
3979bdb7e57SJonas Devlieghere       const File::OpenOptions flags = File::eOpenOptionWriteOnly |
3989bdb7e57SJonas Devlieghere                                       File::eOpenOptionCanCreate |
3999bdb7e57SJonas Devlieghere                                       File::eOpenOptionTruncate;
4009bdb7e57SJonas Devlieghere       llvm::Expected<FileUP> file = FileSystem::Instance().Open(
4019bdb7e57SJonas Devlieghere           m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);
4029bdb7e57SJonas Devlieghere       if (!file) {
4039bdb7e57SJonas Devlieghere         result.AppendErrorWithFormat("Unable to open log file '%s': %s",
404*1b4b12a3SNico Weber                                      m_options.log_file.GetCString(),
4059bdb7e57SJonas Devlieghere                                      llvm::toString(file.takeError()).c_str());
4069bdb7e57SJonas Devlieghere         return false;
4079bdb7e57SJonas Devlieghere       }
4089bdb7e57SJonas Devlieghere       stream_up = std::make_unique<llvm::raw_fd_ostream>(
4099bdb7e57SJonas Devlieghere           (*file)->GetDescriptor(), /*shouldClose=*/true);
4109bdb7e57SJonas Devlieghere     } else {
4119bdb7e57SJonas Devlieghere       stream_up = std::make_unique<llvm::raw_fd_ostream>(
4129bdb7e57SJonas Devlieghere           GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false);
4139bdb7e57SJonas Devlieghere     }
4149bdb7e57SJonas Devlieghere 
4159bdb7e57SJonas Devlieghere     const std::string channel = std::string(args[0].ref());
4169bdb7e57SJonas Devlieghere     std::string error;
4179bdb7e57SJonas Devlieghere     llvm::raw_string_ostream error_stream(error);
4189bdb7e57SJonas Devlieghere     if (Log::DumpLogChannel(channel, *stream_up, error_stream)) {
4199bdb7e57SJonas Devlieghere       result.SetStatus(eReturnStatusSuccessFinishNoResult);
4209bdb7e57SJonas Devlieghere     } else {
4219bdb7e57SJonas Devlieghere       result.SetStatus(eReturnStatusFailed);
4229bdb7e57SJonas Devlieghere       result.GetErrorStream() << error_stream.str();
4239bdb7e57SJonas Devlieghere     }
4249bdb7e57SJonas Devlieghere 
4259bdb7e57SJonas Devlieghere     return result.Succeeded();
4269bdb7e57SJonas Devlieghere   }
4279bdb7e57SJonas Devlieghere 
4289bdb7e57SJonas Devlieghere   CommandOptions m_options;
4299bdb7e57SJonas Devlieghere };
43030fdc8d8SChris Lattner 
4311d3b7370SShu Anzai class CommandObjectLogTimerEnable : public CommandObjectParsed {
43230fdc8d8SChris Lattner public:
43330fdc8d8SChris Lattner   // Constructors and Destructors
CommandObjectLogTimerEnable(CommandInterpreter & interpreter)4341d3b7370SShu Anzai   CommandObjectLogTimerEnable(CommandInterpreter &interpreter)
4351d3b7370SShu Anzai       : CommandObjectParsed(interpreter, "log timers enable",
4361d3b7370SShu Anzai                             "enable LLDB internal performance timers",
4371d3b7370SShu Anzai                             "log timers enable <depth>") {
4381d3b7370SShu Anzai     CommandArgumentEntry arg;
4391d3b7370SShu Anzai     CommandArgumentData depth_arg;
44030fdc8d8SChris Lattner 
4411d3b7370SShu Anzai     // Define the first (and only) variant of this arg.
4421d3b7370SShu Anzai     depth_arg.arg_type = eArgTypeCount;
4431d3b7370SShu Anzai     depth_arg.arg_repetition = eArgRepeatOptional;
4441d3b7370SShu Anzai 
4451d3b7370SShu Anzai     // There is only one variant this argument could be; put it into the
4461d3b7370SShu Anzai     // argument entry.
4471d3b7370SShu Anzai     arg.push_back(depth_arg);
4481d3b7370SShu Anzai 
4491d3b7370SShu Anzai     // Push the data for the first argument into the m_arguments vector.
4501d3b7370SShu Anzai     m_arguments.push_back(arg);
4511d3b7370SShu Anzai   }
4521d3b7370SShu Anzai 
4531d3b7370SShu Anzai   ~CommandObjectLogTimerEnable() override = default;
45430fdc8d8SChris Lattner 
4555a988416SJim Ingham protected:
DoExecute(Args & args,CommandReturnObject & result)456b9c1b51eSKate Stone   bool DoExecute(Args &args, CommandReturnObject &result) override {
45730fdc8d8SChris Lattner     result.SetStatus(eReturnStatusFailed);
45830fdc8d8SChris Lattner 
4591d3b7370SShu Anzai     if (args.GetArgumentCount() == 0) {
46030fdc8d8SChris Lattner       Timer::SetDisplayDepth(UINT32_MAX);
46130fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishNoResult);
4621d3b7370SShu Anzai     } else if (args.GetArgumentCount() == 1) {
46311eb9c64SZachary Turner       uint32_t depth;
4641d3b7370SShu Anzai       if (args[0].ref().consumeInteger(0, depth)) {
465b9c1b51eSKate Stone         result.AppendError(
466b9c1b51eSKate Stone             "Could not convert enable depth to an unsigned integer.");
46711eb9c64SZachary Turner       } else {
46811eb9c64SZachary Turner         Timer::SetDisplayDepth(depth);
46911eb9c64SZachary Turner         result.SetStatus(eReturnStatusSuccessFinishNoResult);
470932725faSJim Ingham       }
471932725faSJim Ingham     }
472932725faSJim Ingham 
473b9c1b51eSKate Stone     if (!result.Succeeded()) {
47430fdc8d8SChris Lattner       result.AppendError("Missing subcommand");
47530fdc8d8SChris Lattner       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
47630fdc8d8SChris Lattner     }
47730fdc8d8SChris Lattner     return result.Succeeded();
47830fdc8d8SChris Lattner   }
47930fdc8d8SChris Lattner };
48030fdc8d8SChris Lattner 
4811d3b7370SShu Anzai class CommandObjectLogTimerDisable : public CommandObjectParsed {
4821d3b7370SShu Anzai public:
4831d3b7370SShu Anzai   // Constructors and Destructors
CommandObjectLogTimerDisable(CommandInterpreter & interpreter)4841d3b7370SShu Anzai   CommandObjectLogTimerDisable(CommandInterpreter &interpreter)
4851d3b7370SShu Anzai       : CommandObjectParsed(interpreter, "log timers disable",
4861d3b7370SShu Anzai                             "disable LLDB internal performance timers",
4871d3b7370SShu Anzai                             nullptr) {}
4881d3b7370SShu Anzai 
4891d3b7370SShu Anzai   ~CommandObjectLogTimerDisable() override = default;
4901d3b7370SShu Anzai 
4911d3b7370SShu Anzai protected:
DoExecute(Args & args,CommandReturnObject & result)4921d3b7370SShu Anzai   bool DoExecute(Args &args, CommandReturnObject &result) override {
4931d3b7370SShu Anzai     Timer::DumpCategoryTimes(&result.GetOutputStream());
4941d3b7370SShu Anzai     Timer::SetDisplayDepth(0);
4951d3b7370SShu Anzai     result.SetStatus(eReturnStatusSuccessFinishResult);
4961d3b7370SShu Anzai 
4971d3b7370SShu Anzai     if (!result.Succeeded()) {
4981d3b7370SShu Anzai       result.AppendError("Missing subcommand");
4991d3b7370SShu Anzai       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5001d3b7370SShu Anzai     }
5011d3b7370SShu Anzai     return result.Succeeded();
5021d3b7370SShu Anzai   }
5031d3b7370SShu Anzai };
5041d3b7370SShu Anzai 
5051d3b7370SShu Anzai class CommandObjectLogTimerDump : public CommandObjectParsed {
5061d3b7370SShu Anzai public:
5071d3b7370SShu Anzai   // Constructors and Destructors
CommandObjectLogTimerDump(CommandInterpreter & interpreter)5081d3b7370SShu Anzai   CommandObjectLogTimerDump(CommandInterpreter &interpreter)
5091d3b7370SShu Anzai       : CommandObjectParsed(interpreter, "log timers dump",
5101d3b7370SShu Anzai                             "dump LLDB internal performance timers", nullptr) {}
5111d3b7370SShu Anzai 
5121d3b7370SShu Anzai   ~CommandObjectLogTimerDump() override = default;
5131d3b7370SShu Anzai 
5141d3b7370SShu Anzai protected:
DoExecute(Args & args,CommandReturnObject & result)5151d3b7370SShu Anzai   bool DoExecute(Args &args, CommandReturnObject &result) override {
5161d3b7370SShu Anzai     Timer::DumpCategoryTimes(&result.GetOutputStream());
5171d3b7370SShu Anzai     result.SetStatus(eReturnStatusSuccessFinishResult);
5181d3b7370SShu Anzai 
5191d3b7370SShu Anzai     if (!result.Succeeded()) {
5201d3b7370SShu Anzai       result.AppendError("Missing subcommand");
5211d3b7370SShu Anzai       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5221d3b7370SShu Anzai     }
5231d3b7370SShu Anzai     return result.Succeeded();
5241d3b7370SShu Anzai   }
5251d3b7370SShu Anzai };
5261d3b7370SShu Anzai 
5271d3b7370SShu Anzai class CommandObjectLogTimerReset : public CommandObjectParsed {
5281d3b7370SShu Anzai public:
5291d3b7370SShu Anzai   // Constructors and Destructors
CommandObjectLogTimerReset(CommandInterpreter & interpreter)5301d3b7370SShu Anzai   CommandObjectLogTimerReset(CommandInterpreter &interpreter)
5311d3b7370SShu Anzai       : CommandObjectParsed(interpreter, "log timers reset",
5321d3b7370SShu Anzai                             "reset LLDB internal performance timers", nullptr) {
5331d3b7370SShu Anzai   }
5341d3b7370SShu Anzai 
5351d3b7370SShu Anzai   ~CommandObjectLogTimerReset() override = default;
5361d3b7370SShu Anzai 
5371d3b7370SShu Anzai protected:
DoExecute(Args & args,CommandReturnObject & result)5381d3b7370SShu Anzai   bool DoExecute(Args &args, CommandReturnObject &result) override {
5391d3b7370SShu Anzai     Timer::ResetCategoryTimes();
5401d3b7370SShu Anzai     result.SetStatus(eReturnStatusSuccessFinishResult);
5411d3b7370SShu Anzai 
5421d3b7370SShu Anzai     if (!result.Succeeded()) {
5431d3b7370SShu Anzai       result.AppendError("Missing subcommand");
5441d3b7370SShu Anzai       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
5451d3b7370SShu Anzai     }
5461d3b7370SShu Anzai     return result.Succeeded();
5471d3b7370SShu Anzai   }
5481d3b7370SShu Anzai };
5491d3b7370SShu Anzai 
5501d3b7370SShu Anzai class CommandObjectLogTimerIncrement : public CommandObjectParsed {
5511d3b7370SShu Anzai public:
5521d3b7370SShu Anzai   // Constructors and Destructors
CommandObjectLogTimerIncrement(CommandInterpreter & interpreter)5531d3b7370SShu Anzai   CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)
5541d3b7370SShu Anzai       : CommandObjectParsed(interpreter, "log timers increment",
5551d3b7370SShu Anzai                             "increment LLDB internal performance timers",
5561d3b7370SShu Anzai                             "log timers increment <bool>") {
5571d3b7370SShu Anzai     CommandArgumentEntry arg;
5581d3b7370SShu Anzai     CommandArgumentData bool_arg;
5591d3b7370SShu Anzai 
5601d3b7370SShu Anzai     // Define the first (and only) variant of this arg.
5611d3b7370SShu Anzai     bool_arg.arg_type = eArgTypeBoolean;
5621d3b7370SShu Anzai     bool_arg.arg_repetition = eArgRepeatPlain;
5631d3b7370SShu Anzai 
5641d3b7370SShu Anzai     // There is only one variant this argument could be; put it into the
5651d3b7370SShu Anzai     // argument entry.
5661d3b7370SShu Anzai     arg.push_back(bool_arg);
5671d3b7370SShu Anzai 
5681d3b7370SShu Anzai     // Push the data for the first argument into the m_arguments vector.
5691d3b7370SShu Anzai     m_arguments.push_back(arg);
5701d3b7370SShu Anzai   }
5711d3b7370SShu Anzai 
5721d3b7370SShu Anzai   ~CommandObjectLogTimerIncrement() override = default;
5731d3b7370SShu Anzai 
5741d3b7370SShu Anzai   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)5751d3b7370SShu Anzai   HandleArgumentCompletion(CompletionRequest &request,
5761d3b7370SShu Anzai                            OptionElementVector &opt_element_vector) override {
5771d3b7370SShu Anzai     request.TryCompleteCurrentArg("true");
5781d3b7370SShu Anzai     request.TryCompleteCurrentArg("false");
5791d3b7370SShu Anzai   }
5801d3b7370SShu Anzai 
5811d3b7370SShu Anzai protected:
DoExecute(Args & args,CommandReturnObject & result)5821d3b7370SShu Anzai   bool DoExecute(Args &args, CommandReturnObject &result) override {
5831d3b7370SShu Anzai     result.SetStatus(eReturnStatusFailed);
5841d3b7370SShu Anzai 
5851d3b7370SShu Anzai     if (args.GetArgumentCount() == 1) {
5861d3b7370SShu Anzai       bool success;
5871d3b7370SShu Anzai       bool increment =
5881d3b7370SShu Anzai           OptionArgParser::ToBoolean(args[0].ref(), false, &success);
5891d3b7370SShu Anzai 
5901d3b7370SShu Anzai       if (success) {
5911d3b7370SShu Anzai         Timer::SetQuiet(!increment);
5921d3b7370SShu Anzai         result.SetStatus(eReturnStatusSuccessFinishNoResult);
5931d3b7370SShu Anzai       } else
5941d3b7370SShu Anzai         result.AppendError("Could not convert increment value to boolean.");
5951d3b7370SShu Anzai     }
5961d3b7370SShu Anzai 
5971d3b7370SShu Anzai     if (!result.Succeeded()) {
5981d3b7370SShu Anzai       result.AppendError("Missing subcommand");
5991d3b7370SShu Anzai       result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
6001d3b7370SShu Anzai     }
6011d3b7370SShu Anzai     return result.Succeeded();
6021d3b7370SShu Anzai   }
6031d3b7370SShu Anzai };
6041d3b7370SShu Anzai 
6051d3b7370SShu Anzai class CommandObjectLogTimer : public CommandObjectMultiword {
6061d3b7370SShu Anzai public:
CommandObjectLogTimer(CommandInterpreter & interpreter)6071d3b7370SShu Anzai   CommandObjectLogTimer(CommandInterpreter &interpreter)
6081d3b7370SShu Anzai       : CommandObjectMultiword(interpreter, "log timers",
6091d3b7370SShu Anzai                                "Enable, disable, dump, and reset LLDB internal "
6101d3b7370SShu Anzai                                "performance timers.",
6111d3b7370SShu Anzai                                "log timers < enable <depth> | disable | dump | "
6121d3b7370SShu Anzai                                "increment <bool> | reset >") {
6131d3b7370SShu Anzai     LoadSubCommand("enable", CommandObjectSP(
6141d3b7370SShu Anzai                                  new CommandObjectLogTimerEnable(interpreter)));
6151d3b7370SShu Anzai     LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(
6161d3b7370SShu Anzai                                   interpreter)));
6171d3b7370SShu Anzai     LoadSubCommand("dump",
6181d3b7370SShu Anzai                    CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));
6191d3b7370SShu Anzai     LoadSubCommand(
6201d3b7370SShu Anzai         "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));
6211d3b7370SShu Anzai     LoadSubCommand(
6221d3b7370SShu Anzai         "increment",
6231d3b7370SShu Anzai         CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));
6241d3b7370SShu Anzai   }
6251d3b7370SShu Anzai 
6261d3b7370SShu Anzai   ~CommandObjectLogTimer() override = default;
6271d3b7370SShu Anzai };
6281d3b7370SShu Anzai 
CommandObjectLog(CommandInterpreter & interpreter)6297428a18cSKate Stone CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
630b9c1b51eSKate Stone     : CommandObjectMultiword(interpreter, "log",
631b9c1b51eSKate Stone                              "Commands controlling LLDB internal logging.",
632b9c1b51eSKate Stone                              "log <subcommand> [<command-options>]") {
633b9c1b51eSKate Stone   LoadSubCommand("enable",
634b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectLogEnable(interpreter)));
635b9c1b51eSKate Stone   LoadSubCommand("disable",
636b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectLogDisable(interpreter)));
637b9c1b51eSKate Stone   LoadSubCommand("list",
638b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectLogList(interpreter)));
6399bdb7e57SJonas Devlieghere   LoadSubCommand("dump",
6409bdb7e57SJonas Devlieghere                  CommandObjectSP(new CommandObjectLogDump(interpreter)));
641b9c1b51eSKate Stone   LoadSubCommand("timers",
642b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectLogTimer(interpreter)));
64330fdc8d8SChris Lattner }
64430fdc8d8SChris Lattner 
64526cac3afSEugene Zelenko CommandObjectLog::~CommandObjectLog() = default;
646