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