blob: 383e29974f8880a5c5959a39467db27049f289a2 [file] [log] [blame]
Chris Lattner24943d22010-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
10#include "CommandObjectLog.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/lldb-private-log.h"
17
Jim Ingham84cdc152010-06-15 19:49:27 +000018#include "lldb/Interpreter/Args.h"
Chris Lattner24943d22010-06-08 16:52:24 +000019#include "lldb/Core/Debugger.h"
Greg Clayton5f54ac32011-02-08 05:05:52 +000020#include "lldb/Host/FileSpec.h"
Chris Lattner24943d22010-06-08 16:52:24 +000021#include "lldb/Core/Log.h"
22#include "lldb/Core/Module.h"
Jim Ingham84cdc152010-06-15 19:49:27 +000023#include "lldb/Interpreter/Options.h"
Chris Lattner24943d22010-06-08 16:52:24 +000024#include "lldb/Core/RegularExpression.h"
25#include "lldb/Core/Stream.h"
26#include "lldb/Core/StreamFile.h"
27#include "lldb/Core/Timer.h"
28
Greg Clayton63094e02010-06-23 01:19:29 +000029#include "lldb/Core/Debugger.h"
Sean Callanan705d6782010-06-23 21:28:25 +000030#include "lldb/Interpreter/CommandInterpreter.h"
Chris Lattner24943d22010-06-08 16:52:24 +000031#include "lldb/Interpreter/CommandReturnObject.h"
32
33#include "lldb/Symbol/LineTable.h"
34#include "lldb/Symbol/ObjectFile.h"
35#include "lldb/Symbol/SymbolFile.h"
36#include "lldb/Symbol/SymbolVendor.h"
37
38#include "lldb/Target/Process.h"
39#include "lldb/Target/Target.h"
40
41using namespace lldb;
42using namespace lldb_private;
43
44
45static LogChannelSP
46GetLogChannelPluginForChannel (const char *channel)
47{
48 std::string log_channel_plugin_name(channel);
49 log_channel_plugin_name += LogChannel::GetPluginSuffix();
50 LogChannelSP log_channel_sp (LogChannel::FindPlugin (log_channel_plugin_name.c_str()));
51 return log_channel_sp;
52}
53
54
55class CommandObjectLogEnable : public CommandObject
56{
57public:
58 //------------------------------------------------------------------
59 // Constructors and Destructors
60 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +000061 CommandObjectLogEnable(CommandInterpreter &interpreter) :
62 CommandObject (interpreter,
63 "log enable",
Chris Lattner24943d22010-06-08 16:52:24 +000064 "Enable logging for a single log channel.",
Caroline Tice43b014a2010-10-04 22:28:36 +000065 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +000066 {
Caroline Tice7826c882010-10-26 03:11:13 +000067
68 CommandArgumentEntry arg1;
69 CommandArgumentEntry arg2;
Caroline Tice43b014a2010-10-04 22:28:36 +000070 CommandArgumentData channel_arg;
Caroline Tice7826c882010-10-26 03:11:13 +000071 CommandArgumentData category_arg;
Caroline Tice43b014a2010-10-04 22:28:36 +000072
73 // Define the first (and only) variant of this arg.
74 channel_arg.arg_type = eArgTypeLogChannel;
75 channel_arg.arg_repetition = eArgRepeatPlain;
76
77 // There is only one variant this argument could be; put it into the argument entry.
Caroline Tice7826c882010-10-26 03:11:13 +000078 arg1.push_back (channel_arg);
Caroline Tice43b014a2010-10-04 22:28:36 +000079
Caroline Tice7826c882010-10-26 03:11:13 +000080 category_arg.arg_type = eArgTypeLogCategory;
81 category_arg.arg_repetition = eArgRepeatPlus;
82
83 arg2.push_back (category_arg);
84
Caroline Tice43b014a2010-10-04 22:28:36 +000085 // Push the data for the first argument into the m_arguments vector.
Caroline Tice7826c882010-10-26 03:11:13 +000086 m_arguments.push_back (arg1);
87 m_arguments.push_back (arg2);
Chris Lattner24943d22010-06-08 16:52:24 +000088 }
89
90 virtual
91 ~CommandObjectLogEnable()
92 {
93 }
94
95 Options *
96 GetOptions ()
97 {
98 return &m_options;
99 }
100
101 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000102 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000103 CommandReturnObject &result)
104 {
105 if (args.GetArgumentCount() < 1)
106 {
Caroline Ticeabb507a2010-09-08 21:06:11 +0000107 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000108 }
109 else
110 {
111 Log::Callbacks log_callbacks;
112
113 std::string channel(args.GetArgumentAtIndex(0));
114 args.Shift (); // Shift off the channel
115 StreamSP log_stream_sp;
Chris Lattner24943d22010-06-08 16:52:24 +0000116 if (m_options.log_file.empty())
117 {
Greg Clayton58928562011-02-09 01:08:52 +0000118 log_stream_sp.reset(new StreamFile(m_interpreter.GetDebugger().GetOutputFile().GetDescriptor(), false));
Chris Lattner24943d22010-06-08 16:52:24 +0000119 }
120 else
121 {
122 LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file);
123 if (pos == m_log_streams.end())
124 {
Greg Clayton58928562011-02-09 01:08:52 +0000125 log_stream_sp.reset (new StreamFile (m_options.log_file.c_str()));
Chris Lattner24943d22010-06-08 16:52:24 +0000126 m_log_streams[m_options.log_file] = log_stream_sp;
127 }
128 else
129 log_stream_sp = pos->second;
130 }
131 assert (log_stream_sp.get());
Jim Inghamd1eb73f2011-01-24 04:09:25 +0000132
Chris Lattner24943d22010-06-08 16:52:24 +0000133 uint32_t log_options = m_options.log_options;
134 if (log_options == 0)
135 log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
136 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
137 {
138 log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream());
139 result.SetStatus(eReturnStatusSuccessFinishNoResult);
140 }
141 else
142 {
143 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
144 if (log_channel_sp)
145 {
146 if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args))
147 {
148 result.SetStatus (eReturnStatusSuccessFinishNoResult);
149 }
150 else
151 {
152 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
153 result.SetStatus (eReturnStatusFailed);
154 }
155 }
156 else
157 {
158 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
159 result.SetStatus (eReturnStatusFailed);
160 }
161 }
162 }
163 return result.Succeeded();
164 }
165
166
167 class CommandOptions : public Options
168 {
169 public:
170
171 CommandOptions () :
172 Options (),
173 log_file (),
174 log_options (0)
175 {
176 }
177
178
179 virtual
180 ~CommandOptions ()
181 {
182 }
183
184 virtual Error
185 SetOptionValue (int option_idx, const char *option_arg)
186 {
187 Error error;
188 char short_option = (char) m_getopt_table[option_idx].val;
189
190 switch (short_option)
191 {
192 case 'f': log_file = option_arg; break;
193 case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break;
194 case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break;
195 case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break;
196 case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break;
197 case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break;
198 case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
199 case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
200 default:
201 error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option);
202 break;
203 }
204
205 return error;
206 }
207
208 void
209 ResetOptionValues ()
210 {
Chris Lattner24943d22010-06-08 16:52:24 +0000211 log_file.clear();
212 log_options = 0;
213 }
214
Greg Claytonb3448432011-03-24 21:19:54 +0000215 const OptionDefinition*
Chris Lattner24943d22010-06-08 16:52:24 +0000216 GetDefinitions ()
217 {
218 return g_option_table;
219 }
220
221 // Options table: Required for subclasses of Options.
222
Greg Claytonb3448432011-03-24 21:19:54 +0000223 static OptionDefinition g_option_table[];
Chris Lattner24943d22010-06-08 16:52:24 +0000224
225 // Instance variables to hold the values for command options.
226
227 std::string log_file;
228 uint32_t log_options;
229 };
230
231protected:
232 typedef std::map<std::string, StreamSP> LogStreamMap;
233 CommandOptions m_options;
234 LogStreamMap m_log_streams;
235};
236
Greg Claytonb3448432011-03-24 21:19:54 +0000237OptionDefinition
Chris Lattner24943d22010-06-08 16:52:24 +0000238CommandObjectLogEnable::CommandOptions::g_option_table[] =
239{
Caroline Tice4d6675c2010-10-01 19:59:14 +0000240{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
241{ LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
242{ LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose logging." },
243{ LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable debug logging." },
244{ LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
245{ LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
246{ LLDB_OPT_SET_1, false, "pid-tid", 'p', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." },
247{ LLDB_OPT_SET_1, false, "thread-name",'n', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." },
248{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
Chris Lattner24943d22010-06-08 16:52:24 +0000249};
250
251class CommandObjectLogDisable : public CommandObject
252{
253public:
254 //------------------------------------------------------------------
255 // Constructors and Destructors
256 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000257 CommandObjectLogDisable(CommandInterpreter &interpreter) :
258 CommandObject (interpreter,
259 "log disable",
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000260 "Disable one or more log channel categories.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000261 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000262 {
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000263 CommandArgumentEntry arg1;
264 CommandArgumentEntry arg2;
Caroline Tice43b014a2010-10-04 22:28:36 +0000265 CommandArgumentData channel_arg;
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000266 CommandArgumentData category_arg;
Caroline Tice43b014a2010-10-04 22:28:36 +0000267
268 // Define the first (and only) variant of this arg.
269 channel_arg.arg_type = eArgTypeLogChannel;
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000270 channel_arg.arg_repetition = eArgRepeatPlain;
Caroline Tice43b014a2010-10-04 22:28:36 +0000271
272 // There is only one variant this argument could be; put it into the argument entry.
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000273 arg1.push_back (channel_arg);
Caroline Tice43b014a2010-10-04 22:28:36 +0000274
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000275 category_arg.arg_type = eArgTypeLogCategory;
276 category_arg.arg_repetition = eArgRepeatPlus;
277
278 arg2.push_back (category_arg);
279
Caroline Tice43b014a2010-10-04 22:28:36 +0000280 // Push the data for the first argument into the m_arguments vector.
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000281 m_arguments.push_back (arg1);
282 m_arguments.push_back (arg2);
Chris Lattner24943d22010-06-08 16:52:24 +0000283 }
284
285 virtual
286 ~CommandObjectLogDisable()
287 {
288 }
289
290 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000291 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000292 CommandReturnObject &result)
293 {
294 const size_t argc = args.GetArgumentCount();
295 if (argc == 0)
296 {
Caroline Ticeabb507a2010-09-08 21:06:11 +0000297 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000298 }
299 else
300 {
Caroline Tice926060e2010-10-29 21:48:37 +0000301 Log::Callbacks log_callbacks;
Chris Lattner24943d22010-06-08 16:52:24 +0000302
Caroline Tice926060e2010-10-29 21:48:37 +0000303 std::string channel(args.GetArgumentAtIndex(0));
304 args.Shift (); // Shift off the channel
305 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
306 {
307 log_callbacks.disable (args, &result.GetErrorStream());
308 result.SetStatus(eReturnStatusSuccessFinishNoResult);
309 }
310 else if (channel == "all")
311 {
312 Log::DisableAllLogChannels(&result.GetErrorStream());
313 }
314 else
315 {
316 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
317 if (log_channel_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000318 {
Caroline Tice926060e2010-10-29 21:48:37 +0000319 log_channel_sp->Disable(args, &result.GetErrorStream());
Chris Lattner24943d22010-06-08 16:52:24 +0000320 result.SetStatus(eReturnStatusSuccessFinishNoResult);
321 }
Chris Lattner24943d22010-06-08 16:52:24 +0000322 else
Caroline Tice926060e2010-10-29 21:48:37 +0000323 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
Chris Lattner24943d22010-06-08 16:52:24 +0000324 }
325 }
326 return result.Succeeded();
327 }
328};
329
330class CommandObjectLogList : public CommandObject
331{
332public:
333 //------------------------------------------------------------------
334 // Constructors and Destructors
335 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000336 CommandObjectLogList(CommandInterpreter &interpreter) :
337 CommandObject (interpreter,
338 "log list",
Caroline Tice43b014a2010-10-04 22:28:36 +0000339 "List the log categories for one or more log channels. If none specified, lists them all.",
340 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000341 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000342 CommandArgumentEntry arg;
343 CommandArgumentData channel_arg;
344
345 // Define the first (and only) variant of this arg.
346 channel_arg.arg_type = eArgTypeLogChannel;
347 channel_arg.arg_repetition = eArgRepeatStar;
348
349 // There is only one variant this argument could be; put it into the argument entry.
350 arg.push_back (channel_arg);
351
352 // Push the data for the first argument into the m_arguments vector.
353 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000354 }
355
356 virtual
357 ~CommandObjectLogList()
358 {
359 }
360
361 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000362 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000363 CommandReturnObject &result)
364 {
365 const size_t argc = args.GetArgumentCount();
366 if (argc == 0)
367 {
368 Log::ListAllLogChannels (&result.GetOutputStream());
369 result.SetStatus(eReturnStatusSuccessFinishResult);
370 }
371 else
372 {
373 for (size_t i=0; i<argc; ++i)
374 {
375 Log::Callbacks log_callbacks;
376
377 std::string channel(args.GetArgumentAtIndex(i));
378 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
379 {
380 log_callbacks.list_categories (&result.GetOutputStream());
381 result.SetStatus(eReturnStatusSuccessFinishResult);
382 }
383 else if (channel == "all")
384 {
385 Log::ListAllLogChannels (&result.GetOutputStream());
386 result.SetStatus(eReturnStatusSuccessFinishResult);
387 }
388 else
389 {
390 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
391 if (log_channel_sp)
392 {
393 log_channel_sp->ListCategories(&result.GetOutputStream());
394 result.SetStatus(eReturnStatusSuccessFinishNoResult);
395 }
396 else
397 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
398 }
399 }
400 }
401 return result.Succeeded();
402 }
403};
404
405class CommandObjectLogTimer : public CommandObject
406{
407public:
408 //------------------------------------------------------------------
409 // Constructors and Destructors
410 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000411 CommandObjectLogTimer(CommandInterpreter &interpreter) :
412 CommandObject (interpreter,
413 "log timers",
Chris Lattner24943d22010-06-08 16:52:24 +0000414 "Enable, disable, dump, and reset LLDB internal performance timers.",
Jim Ingham4ba39992010-11-04 23:19:21 +0000415 "log timers < enable <depth> | disable | dump | increment <bool> | reset >")
Chris Lattner24943d22010-06-08 16:52:24 +0000416 {
417 }
418
419 virtual
420 ~CommandObjectLogTimer()
421 {
422 }
423
424 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000425 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000426 CommandReturnObject &result)
427 {
428 const size_t argc = args.GetArgumentCount();
429 result.SetStatus(eReturnStatusFailed);
430
431 if (argc == 1)
432 {
433 const char *sub_command = args.GetArgumentAtIndex(0);
434
435 if (strcasecmp(sub_command, "enable") == 0)
436 {
437 Timer::SetDisplayDepth (UINT32_MAX);
438 result.SetStatus(eReturnStatusSuccessFinishNoResult);
439 }
440 else if (strcasecmp(sub_command, "disable") == 0)
441 {
442 Timer::DumpCategoryTimes (&result.GetOutputStream());
443 Timer::SetDisplayDepth (0);
444 result.SetStatus(eReturnStatusSuccessFinishResult);
445 }
446 else if (strcasecmp(sub_command, "dump") == 0)
447 {
448 Timer::DumpCategoryTimes (&result.GetOutputStream());
449 result.SetStatus(eReturnStatusSuccessFinishResult);
450 }
451 else if (strcasecmp(sub_command, "reset") == 0)
452 {
453 Timer::ResetCategoryTimes ();
454 result.SetStatus(eReturnStatusSuccessFinishResult);
455 }
456
457 }
Jim Ingham19e29a82010-11-04 23:08:26 +0000458 else if (argc == 2)
459 {
460 const char *sub_command = args.GetArgumentAtIndex(0);
461
462 if (strcasecmp(sub_command, "enable") == 0)
463 {
464 bool success;
465 uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success);
466 if (success)
467 {
468 Timer::SetDisplayDepth (depth);
469 result.SetStatus(eReturnStatusSuccessFinishNoResult);
470 }
471 else
472 result.AppendError("Could not convert enable depth to an unsigned integer.");
473 }
Jim Ingham4ba39992010-11-04 23:19:21 +0000474 if (strcasecmp(sub_command, "increment") == 0)
475 {
476 bool success;
477 bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success);
478 if (success)
479 {
480 Timer::SetQuiet (!increment);
481 result.SetStatus(eReturnStatusSuccessFinishNoResult);
482 }
483 else
484 result.AppendError("Could not convert increment value to boolean.");
485 }
Jim Ingham19e29a82010-11-04 23:08:26 +0000486 }
487
Chris Lattner24943d22010-06-08 16:52:24 +0000488 if (!result.Succeeded())
489 {
490 result.AppendError("Missing subcommand");
491 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
492 }
493 return result.Succeeded();
494 }
495};
496
497//----------------------------------------------------------------------
498// CommandObjectLog constructor
499//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +0000500CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000501 CommandObjectMultiword (interpreter,
502 "log",
Chris Lattner24943d22010-06-08 16:52:24 +0000503 "A set of commands for operating on logs.",
504 "log <command> [<command-options>]")
505{
Greg Clayton238c0a12010-09-18 01:14:36 +0000506 LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter)));
507 LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter)));
508 LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter)));
509 LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter)));
Chris Lattner24943d22010-06-08 16:52:24 +0000510}
511
512//----------------------------------------------------------------------
513// Destructor
514//----------------------------------------------------------------------
515CommandObjectLog::~CommandObjectLog()
516{
517}
518
519
520
521