blob: 8513444221331c4845fa7c0784f8cd62a56a523e [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandObjectLog.cpp ------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Eugene Zelenko26cac3a2016-02-20 00:58:29 +000014#include "CommandObjectLog.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000015#include "lldb/Core/Debugger.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000016#include "lldb/Core/Debugger.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include "lldb/Core/Log.h"
18#include "lldb/Core/Module.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019#include "lldb/Core/RegularExpression.h"
20#include "lldb/Core/Stream.h"
21#include "lldb/Core/StreamFile.h"
22#include "lldb/Core/Timer.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000023#include "lldb/Host/FileSpec.h"
Vince Harron5275aaa2015-01-15 20:08:35 +000024#include "lldb/Host/StringConvert.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000025#include "lldb/Interpreter/Args.h"
Sean Callanan4be39902010-06-23 21:28:25 +000026#include "lldb/Interpreter/CommandInterpreter.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027#include "lldb/Interpreter/CommandReturnObject.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000028#include "lldb/Interpreter/Options.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029#include "lldb/Symbol/LineTable.h"
30#include "lldb/Symbol/ObjectFile.h"
31#include "lldb/Symbol/SymbolFile.h"
32#include "lldb/Symbol/SymbolVendor.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033#include "lldb/Target/Process.h"
34#include "lldb/Target/Target.h"
35
36using namespace lldb;
37using namespace lldb_private;
38
Kate Stoneb9c1b512016-09-06 20:57:50 +000039class CommandObjectLogEnable : public CommandObjectParsed {
Chris Lattner30fdc8d2010-06-08 16:52:24 +000040public:
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 //------------------------------------------------------------------
42 // Constructors and Destructors
43 //------------------------------------------------------------------
44 CommandObjectLogEnable(CommandInterpreter &interpreter)
45 : CommandObjectParsed(interpreter, "log enable",
Eugene Zelenko26cac3a2016-02-20 00:58:29 +000046 "Enable logging for a single log channel.",
47 nullptr),
Kate Stoneb9c1b512016-09-06 20:57:50 +000048 m_options() {
49 CommandArgumentEntry arg1;
50 CommandArgumentEntry arg2;
51 CommandArgumentData channel_arg;
52 CommandArgumentData category_arg;
Caroline Ticeceb6b132010-10-26 03:11:13 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054 // Define the first (and only) variant of this arg.
55 channel_arg.arg_type = eArgTypeLogChannel;
56 channel_arg.arg_repetition = eArgRepeatPlain;
Caroline Ticeceb6b132010-10-26 03:11:13 +000057
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 // There is only one variant this argument could be; put it into the
59 // argument entry.
60 arg1.push_back(channel_arg);
61
62 category_arg.arg_type = eArgTypeLogCategory;
63 category_arg.arg_repetition = eArgRepeatPlus;
64
65 arg2.push_back(category_arg);
66
67 // Push the data for the first argument into the m_arguments vector.
68 m_arguments.push_back(arg1);
69 m_arguments.push_back(arg2);
70 }
71
72 ~CommandObjectLogEnable() override = default;
73
74 Options *GetOptions() override { return &m_options; }
75
76 // int
77 // HandleArgumentCompletion (Args &input,
78 // int &cursor_index,
79 // int &cursor_char_position,
80 // OptionElementVector &opt_element_vector,
81 // int match_start_point,
82 // int max_return_elements,
83 // bool &word_complete,
84 // StringList &matches)
85 // {
86 // std::string completion_str (input.GetArgumentAtIndex(cursor_index));
87 // completion_str.erase (cursor_char_position);
88 //
89 // if (cursor_index == 1)
90 // {
91 // //
92 // Log::AutoCompleteChannelName (completion_str.c_str(), matches);
93 // }
94 // return matches.GetSize();
95 // }
96 //
97
98 class CommandOptions : public Options {
99 public:
100 CommandOptions() : Options(), log_file(), log_options(0) {}
101
102 ~CommandOptions() override = default;
103
104 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
105 ExecutionContext *execution_context) override {
106 Error error;
107 const int short_option = m_getopt_table[option_idx].val;
108
109 switch (short_option) {
110 case 'f':
111 log_file.SetFile(option_arg, true);
112 break;
113 case 't':
114 log_options |= LLDB_LOG_OPTION_THREADSAFE;
115 break;
116 case 'v':
117 log_options |= LLDB_LOG_OPTION_VERBOSE;
118 break;
119 case 'g':
120 log_options |= LLDB_LOG_OPTION_DEBUG;
121 break;
122 case 's':
123 log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
124 break;
125 case 'T':
126 log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
127 break;
128 case 'p':
129 log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;
130 break;
131 case 'n':
132 log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
133 break;
134 case 'S':
135 log_options |= LLDB_LOG_OPTION_BACKTRACE;
136 break;
137 case 'a':
138 log_options |= LLDB_LOG_OPTION_APPEND;
139 break;
140 default:
141 error.SetErrorStringWithFormat("unrecognized option '%c'",
142 short_option);
143 break;
144 }
145
146 return error;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000147 }
148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 void OptionParsingStarting(ExecutionContext *execution_context) override {
150 log_file.Clear();
151 log_options = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 }
153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 const OptionDefinition *GetDefinitions() override { return g_option_table; }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000155
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 // Options table: Required for subclasses of Options.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 static OptionDefinition g_option_table[];
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000159
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 // Instance variables to hold the values for command options.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000161
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 FileSpec log_file;
163 uint32_t log_options;
164 };
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000165
166protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 bool DoExecute(Args &args, CommandReturnObject &result) override {
168 if (args.GetArgumentCount() < 2) {
169 result.AppendErrorWithFormat(
170 "%s takes a log channel and one or more log types.\n",
171 m_cmd_name.c_str());
172 } else {
173 std::string channel(args.GetArgumentAtIndex(0));
174 args.Shift(); // Shift off the channel
175 char log_file[PATH_MAX];
176 if (m_options.log_file)
177 m_options.log_file.GetPath(log_file, sizeof(log_file));
178 else
179 log_file[0] = '\0';
180 bool success = m_interpreter.GetDebugger().EnableLog(
181 channel.c_str(), args.GetConstArgumentVector(), log_file,
182 m_options.log_options, result.GetErrorStream());
183 if (success)
184 result.SetStatus(eReturnStatusSuccessFinishNoResult);
185 else
186 result.SetStatus(eReturnStatusFailed);
Jim Ingham5a988412012-06-08 21:56:10 +0000187 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 return result.Succeeded();
189 }
Jim Ingham5a988412012-06-08 21:56:10 +0000190
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 CommandOptions m_options;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000192};
193
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194OptionDefinition CommandObjectLogEnable::CommandOptions::g_option_table[] = {
195 // clang-format off
Kate Stoneac9c3a62016-08-26 23:28:47 +0000196 {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Set the destination file to log to."},
197 {LLDB_OPT_SET_1, false, "threadsafe", 't', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines."},
198 {LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable verbose logging."},
199 {LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable debug logging."},
200 {LLDB_OPT_SET_1, false, "sequence", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id."},
201 {LLDB_OPT_SET_1, false, "timestamp", 'T', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with a timestamp."},
202 {LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line."},
203 {LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line."},
204 {LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Append a stack backtrace to each log line."},
205 {LLDB_OPT_SET_1, false, "append", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Append to the log file instead of overwriting."},
206 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000207 // clang-format on
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000208};
209
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210class CommandObjectLogDisable : public CommandObjectParsed {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000211public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212 //------------------------------------------------------------------
213 // Constructors and Destructors
214 //------------------------------------------------------------------
215 CommandObjectLogDisable(CommandInterpreter &interpreter)
216 : CommandObjectParsed(interpreter, "log disable",
Eugene Zelenko26cac3a2016-02-20 00:58:29 +0000217 "Disable one or more log channel categories.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 nullptr) {
219 CommandArgumentEntry arg1;
220 CommandArgumentEntry arg2;
221 CommandArgumentData channel_arg;
222 CommandArgumentData category_arg;
Caroline Tice7149fab2010-10-29 21:56:41 +0000223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 // Define the first (and only) variant of this arg.
225 channel_arg.arg_type = eArgTypeLogChannel;
226 channel_arg.arg_repetition = eArgRepeatPlain;
Caroline Tice7149fab2010-10-29 21:56:41 +0000227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 // There is only one variant this argument could be; put it into the
229 // argument entry.
230 arg1.push_back(channel_arg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000231
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232 category_arg.arg_type = eArgTypeLogCategory;
233 category_arg.arg_repetition = eArgRepeatPlus;
234
235 arg2.push_back(category_arg);
236
237 // Push the data for the first argument into the m_arguments vector.
238 m_arguments.push_back(arg1);
239 m_arguments.push_back(arg2);
240 }
241
242 ~CommandObjectLogDisable() override = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000243
Jim Ingham5a988412012-06-08 21:56:10 +0000244protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000245 bool DoExecute(Args &args, CommandReturnObject &result) override {
246 const size_t argc = args.GetArgumentCount();
247 if (argc == 0) {
248 result.AppendErrorWithFormat(
249 "%s takes a log channel and one or more log types.\n",
250 m_cmd_name.c_str());
251 } else {
252 Log::Callbacks log_callbacks;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000253
Kate Stoneb9c1b512016-09-06 20:57:50 +0000254 std::string channel(args.GetArgumentAtIndex(0));
255 args.Shift(); // Shift off the channel
256 if (Log::GetLogChannelCallbacks(ConstString(channel.c_str()),
257 log_callbacks)) {
258 log_callbacks.disable(args.GetConstArgumentVector(),
259 &result.GetErrorStream());
260 result.SetStatus(eReturnStatusSuccessFinishNoResult);
261 } else if (channel == "all") {
262 Log::DisableAllLogChannels(&result.GetErrorStream());
263 } else {
264 LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.c_str()));
265 if (log_channel_sp) {
266 log_channel_sp->Disable(args.GetConstArgumentVector(),
267 &result.GetErrorStream());
268 result.SetStatus(eReturnStatusSuccessFinishNoResult);
269 } else
270 result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
271 args.GetArgumentAtIndex(0));
272 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000273 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000274 return result.Succeeded();
275 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000276};
277
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278class CommandObjectLogList : public CommandObjectParsed {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000279public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280 //------------------------------------------------------------------
281 // Constructors and Destructors
282 //------------------------------------------------------------------
283 CommandObjectLogList(CommandInterpreter &interpreter)
284 : CommandObjectParsed(interpreter, "log list",
285 "List the log categories for one or more log "
286 "channels. If none specified, lists them all.",
287 nullptr) {
288 CommandArgumentEntry arg;
289 CommandArgumentData channel_arg;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000290
Kate Stoneb9c1b512016-09-06 20:57:50 +0000291 // Define the first (and only) variant of this arg.
292 channel_arg.arg_type = eArgTypeLogChannel;
293 channel_arg.arg_repetition = eArgRepeatStar;
294
295 // There is only one variant this argument could be; put it into the
296 // argument entry.
297 arg.push_back(channel_arg);
298
299 // Push the data for the first argument into the m_arguments vector.
300 m_arguments.push_back(arg);
301 }
302
303 ~CommandObjectLogList() override = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000304
Jim Ingham5a988412012-06-08 21:56:10 +0000305protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000306 bool DoExecute(Args &args, CommandReturnObject &result) override {
307 const size_t argc = args.GetArgumentCount();
308 if (argc == 0) {
309 Log::ListAllLogChannels(&result.GetOutputStream());
310 result.SetStatus(eReturnStatusSuccessFinishResult);
311 } else {
312 for (size_t i = 0; i < argc; ++i) {
313 Log::Callbacks log_callbacks;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000314
Kate Stoneb9c1b512016-09-06 20:57:50 +0000315 std::string channel(args.GetArgumentAtIndex(i));
316 if (Log::GetLogChannelCallbacks(ConstString(channel.c_str()),
317 log_callbacks)) {
318 log_callbacks.list_categories(&result.GetOutputStream());
319 result.SetStatus(eReturnStatusSuccessFinishResult);
320 } else if (channel == "all") {
321 Log::ListAllLogChannels(&result.GetOutputStream());
322 result.SetStatus(eReturnStatusSuccessFinishResult);
323 } else {
324 LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.c_str()));
325 if (log_channel_sp) {
326 log_channel_sp->ListCategories(&result.GetOutputStream());
327 result.SetStatus(eReturnStatusSuccessFinishNoResult);
328 } else
329 result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
330 args.GetArgumentAtIndex(0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000331 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000332 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000333 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000334 return result.Succeeded();
335 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000336};
337
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338class CommandObjectLogTimer : public CommandObjectParsed {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000339public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340 //------------------------------------------------------------------
341 // Constructors and Destructors
342 //------------------------------------------------------------------
343 CommandObjectLogTimer(CommandInterpreter &interpreter)
344 : CommandObjectParsed(interpreter, "log timers",
345 "Enable, disable, dump, and reset LLDB internal "
346 "performance timers.",
347 "log timers < enable <depth> | disable | dump | "
348 "increment <bool> | reset >") {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000349
Kate Stoneb9c1b512016-09-06 20:57:50 +0000350 ~CommandObjectLogTimer() override = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000351
Jim Ingham5a988412012-06-08 21:56:10 +0000352protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000353 bool DoExecute(Args &args, CommandReturnObject &result) override {
354 const size_t argc = args.GetArgumentCount();
355 result.SetStatus(eReturnStatusFailed);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000356
Kate Stoneb9c1b512016-09-06 20:57:50 +0000357 if (argc == 1) {
358 const char *sub_command = args.GetArgumentAtIndex(0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000359
Kate Stoneb9c1b512016-09-06 20:57:50 +0000360 if (strcasecmp(sub_command, "enable") == 0) {
361 Timer::SetDisplayDepth(UINT32_MAX);
362 result.SetStatus(eReturnStatusSuccessFinishNoResult);
363 } else if (strcasecmp(sub_command, "disable") == 0) {
364 Timer::DumpCategoryTimes(&result.GetOutputStream());
365 Timer::SetDisplayDepth(0);
366 result.SetStatus(eReturnStatusSuccessFinishResult);
367 } else if (strcasecmp(sub_command, "dump") == 0) {
368 Timer::DumpCategoryTimes(&result.GetOutputStream());
369 result.SetStatus(eReturnStatusSuccessFinishResult);
370 } else if (strcasecmp(sub_command, "reset") == 0) {
371 Timer::ResetCategoryTimes();
372 result.SetStatus(eReturnStatusSuccessFinishResult);
373 }
374 } else if (argc == 2) {
375 const char *sub_command = args.GetArgumentAtIndex(0);
Jim Ingham932725f2010-11-04 23:08:26 +0000376
Kate Stoneb9c1b512016-09-06 20:57:50 +0000377 if (strcasecmp(sub_command, "enable") == 0) {
378 bool success;
379 uint32_t depth =
380 StringConvert::ToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success);
381 if (success) {
382 Timer::SetDisplayDepth(depth);
383 result.SetStatus(eReturnStatusSuccessFinishNoResult);
384 } else
385 result.AppendError(
386 "Could not convert enable depth to an unsigned integer.");
387 }
388 if (strcasecmp(sub_command, "increment") == 0) {
389 bool success;
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000390 bool increment = Args::StringToBoolean(
391 llvm::StringRef::withNullAsEmpty(args.GetArgumentAtIndex(1)), false,
392 &success);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000393 if (success) {
394 Timer::SetQuiet(!increment);
395 result.SetStatus(eReturnStatusSuccessFinishNoResult);
396 } else
397 result.AppendError("Could not convert increment value to boolean.");
398 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000399 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000400
401 if (!result.Succeeded()) {
402 result.AppendError("Missing subcommand");
403 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
404 }
405 return result.Succeeded();
406 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000407};
408
Kate Stone7428a182016-07-14 22:03:10 +0000409CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000410 : CommandObjectMultiword(interpreter, "log",
411 "Commands controlling LLDB internal logging.",
412 "log <subcommand> [<command-options>]") {
413 LoadSubCommand("enable",
414 CommandObjectSP(new CommandObjectLogEnable(interpreter)));
415 LoadSubCommand("disable",
416 CommandObjectSP(new CommandObjectLogDisable(interpreter)));
417 LoadSubCommand("list",
418 CommandObjectSP(new CommandObjectLogList(interpreter)));
419 LoadSubCommand("timers",
420 CommandObjectSP(new CommandObjectLogTimer(interpreter)));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000421}
422
Eugene Zelenko26cac3a2016-02-20 00:58:29 +0000423CommandObjectLog::~CommandObjectLog() = default;