blob: cf090af05e6156fb83bad69e5b8a49a38732b5c2 [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;
Jim Inghamd1eb73f2011-01-24 04:09:25 +0000116 StreamFile *log_file_ptr = NULL; // This will get put in the log_stream_sp, no need to free it.
Chris Lattner24943d22010-06-08 16:52:24 +0000117 if (m_options.log_file.empty())
118 {
Jim Inghamd1eb73f2011-01-24 04:09:25 +0000119 log_file_ptr = new StreamFile(m_interpreter.GetDebugger().GetOutputFileHandle());
120 log_stream_sp.reset(log_file_ptr);
Chris Lattner24943d22010-06-08 16:52:24 +0000121 }
122 else
123 {
124 LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file);
125 if (pos == m_log_streams.end())
126 {
Jim Inghamd1eb73f2011-01-24 04:09:25 +0000127 log_file_ptr = new StreamFile (m_options.log_file.c_str(), "w");
128 log_stream_sp.reset (log_file_ptr);
Chris Lattner24943d22010-06-08 16:52:24 +0000129 m_log_streams[m_options.log_file] = log_stream_sp;
130 }
131 else
132 log_stream_sp = pos->second;
133 }
134 assert (log_stream_sp.get());
Jim Inghamd1eb73f2011-01-24 04:09:25 +0000135
136 // If we ended up making a StreamFile for log output, line buffer it.
137 if (log_file_ptr != NULL)
138 log_file_ptr->SetLineBuffered();
139
Chris Lattner24943d22010-06-08 16:52:24 +0000140 uint32_t log_options = m_options.log_options;
141 if (log_options == 0)
142 log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
143 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
144 {
145 log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream());
146 result.SetStatus(eReturnStatusSuccessFinishNoResult);
147 }
148 else
149 {
150 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
151 if (log_channel_sp)
152 {
153 if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args))
154 {
155 result.SetStatus (eReturnStatusSuccessFinishNoResult);
156 }
157 else
158 {
159 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
160 result.SetStatus (eReturnStatusFailed);
161 }
162 }
163 else
164 {
165 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
166 result.SetStatus (eReturnStatusFailed);
167 }
168 }
169 }
170 return result.Succeeded();
171 }
172
173
174 class CommandOptions : public Options
175 {
176 public:
177
178 CommandOptions () :
179 Options (),
180 log_file (),
181 log_options (0)
182 {
183 }
184
185
186 virtual
187 ~CommandOptions ()
188 {
189 }
190
191 virtual Error
192 SetOptionValue (int option_idx, const char *option_arg)
193 {
194 Error error;
195 char short_option = (char) m_getopt_table[option_idx].val;
196
197 switch (short_option)
198 {
199 case 'f': log_file = option_arg; break;
200 case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break;
201 case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break;
202 case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break;
203 case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break;
204 case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break;
205 case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
206 case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
207 default:
208 error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option);
209 break;
210 }
211
212 return error;
213 }
214
215 void
216 ResetOptionValues ()
217 {
218 Options::ResetOptionValues();
219 log_file.clear();
220 log_options = 0;
221 }
222
223 const lldb::OptionDefinition*
224 GetDefinitions ()
225 {
226 return g_option_table;
227 }
228
229 // Options table: Required for subclasses of Options.
230
231 static lldb::OptionDefinition g_option_table[];
232
233 // Instance variables to hold the values for command options.
234
235 std::string log_file;
236 uint32_t log_options;
237 };
238
239protected:
240 typedef std::map<std::string, StreamSP> LogStreamMap;
241 CommandOptions m_options;
242 LogStreamMap m_log_streams;
243};
244
245lldb::OptionDefinition
246CommandObjectLogEnable::CommandOptions::g_option_table[] =
247{
Caroline Tice4d6675c2010-10-01 19:59:14 +0000248{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
249{ LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
250{ LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose logging." },
251{ LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable debug logging." },
252{ LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
253{ LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
254{ 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." },
255{ 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." },
256{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
Chris Lattner24943d22010-06-08 16:52:24 +0000257};
258
259class CommandObjectLogDisable : public CommandObject
260{
261public:
262 //------------------------------------------------------------------
263 // Constructors and Destructors
264 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000265 CommandObjectLogDisable(CommandInterpreter &interpreter) :
266 CommandObject (interpreter,
267 "log disable",
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000268 "Disable one or more log channel categories.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000269 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000270 {
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000271 CommandArgumentEntry arg1;
272 CommandArgumentEntry arg2;
Caroline Tice43b014a2010-10-04 22:28:36 +0000273 CommandArgumentData channel_arg;
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000274 CommandArgumentData category_arg;
Caroline Tice43b014a2010-10-04 22:28:36 +0000275
276 // Define the first (and only) variant of this arg.
277 channel_arg.arg_type = eArgTypeLogChannel;
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000278 channel_arg.arg_repetition = eArgRepeatPlain;
Caroline Tice43b014a2010-10-04 22:28:36 +0000279
280 // There is only one variant this argument could be; put it into the argument entry.
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000281 arg1.push_back (channel_arg);
Caroline Tice43b014a2010-10-04 22:28:36 +0000282
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000283 category_arg.arg_type = eArgTypeLogCategory;
284 category_arg.arg_repetition = eArgRepeatPlus;
285
286 arg2.push_back (category_arg);
287
Caroline Tice43b014a2010-10-04 22:28:36 +0000288 // Push the data for the first argument into the m_arguments vector.
Caroline Tice6a9e5c22010-10-29 21:56:41 +0000289 m_arguments.push_back (arg1);
290 m_arguments.push_back (arg2);
Chris Lattner24943d22010-06-08 16:52:24 +0000291 }
292
293 virtual
294 ~CommandObjectLogDisable()
295 {
296 }
297
298 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000299 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000300 CommandReturnObject &result)
301 {
302 const size_t argc = args.GetArgumentCount();
303 if (argc == 0)
304 {
Caroline Ticeabb507a2010-09-08 21:06:11 +0000305 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000306 }
307 else
308 {
Caroline Tice926060e2010-10-29 21:48:37 +0000309 Log::Callbacks log_callbacks;
Chris Lattner24943d22010-06-08 16:52:24 +0000310
Caroline Tice926060e2010-10-29 21:48:37 +0000311 std::string channel(args.GetArgumentAtIndex(0));
312 args.Shift (); // Shift off the channel
313 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
314 {
315 log_callbacks.disable (args, &result.GetErrorStream());
316 result.SetStatus(eReturnStatusSuccessFinishNoResult);
317 }
318 else if (channel == "all")
319 {
320 Log::DisableAllLogChannels(&result.GetErrorStream());
321 }
322 else
323 {
324 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
325 if (log_channel_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000326 {
Caroline Tice926060e2010-10-29 21:48:37 +0000327 log_channel_sp->Disable(args, &result.GetErrorStream());
Chris Lattner24943d22010-06-08 16:52:24 +0000328 result.SetStatus(eReturnStatusSuccessFinishNoResult);
329 }
Chris Lattner24943d22010-06-08 16:52:24 +0000330 else
Caroline Tice926060e2010-10-29 21:48:37 +0000331 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
Chris Lattner24943d22010-06-08 16:52:24 +0000332 }
333 }
334 return result.Succeeded();
335 }
336};
337
338class CommandObjectLogList : public CommandObject
339{
340public:
341 //------------------------------------------------------------------
342 // Constructors and Destructors
343 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000344 CommandObjectLogList(CommandInterpreter &interpreter) :
345 CommandObject (interpreter,
346 "log list",
Caroline Tice43b014a2010-10-04 22:28:36 +0000347 "List the log categories for one or more log channels. If none specified, lists them all.",
348 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000349 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000350 CommandArgumentEntry arg;
351 CommandArgumentData channel_arg;
352
353 // Define the first (and only) variant of this arg.
354 channel_arg.arg_type = eArgTypeLogChannel;
355 channel_arg.arg_repetition = eArgRepeatStar;
356
357 // There is only one variant this argument could be; put it into the argument entry.
358 arg.push_back (channel_arg);
359
360 // Push the data for the first argument into the m_arguments vector.
361 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000362 }
363
364 virtual
365 ~CommandObjectLogList()
366 {
367 }
368
369 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000370 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000371 CommandReturnObject &result)
372 {
373 const size_t argc = args.GetArgumentCount();
374 if (argc == 0)
375 {
376 Log::ListAllLogChannels (&result.GetOutputStream());
377 result.SetStatus(eReturnStatusSuccessFinishResult);
378 }
379 else
380 {
381 for (size_t i=0; i<argc; ++i)
382 {
383 Log::Callbacks log_callbacks;
384
385 std::string channel(args.GetArgumentAtIndex(i));
386 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
387 {
388 log_callbacks.list_categories (&result.GetOutputStream());
389 result.SetStatus(eReturnStatusSuccessFinishResult);
390 }
391 else if (channel == "all")
392 {
393 Log::ListAllLogChannels (&result.GetOutputStream());
394 result.SetStatus(eReturnStatusSuccessFinishResult);
395 }
396 else
397 {
398 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
399 if (log_channel_sp)
400 {
401 log_channel_sp->ListCategories(&result.GetOutputStream());
402 result.SetStatus(eReturnStatusSuccessFinishNoResult);
403 }
404 else
405 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
406 }
407 }
408 }
409 return result.Succeeded();
410 }
411};
412
413class CommandObjectLogTimer : public CommandObject
414{
415public:
416 //------------------------------------------------------------------
417 // Constructors and Destructors
418 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000419 CommandObjectLogTimer(CommandInterpreter &interpreter) :
420 CommandObject (interpreter,
421 "log timers",
Chris Lattner24943d22010-06-08 16:52:24 +0000422 "Enable, disable, dump, and reset LLDB internal performance timers.",
Jim Ingham4ba39992010-11-04 23:19:21 +0000423 "log timers < enable <depth> | disable | dump | increment <bool> | reset >")
Chris Lattner24943d22010-06-08 16:52:24 +0000424 {
425 }
426
427 virtual
428 ~CommandObjectLogTimer()
429 {
430 }
431
432 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000433 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000434 CommandReturnObject &result)
435 {
436 const size_t argc = args.GetArgumentCount();
437 result.SetStatus(eReturnStatusFailed);
438
439 if (argc == 1)
440 {
441 const char *sub_command = args.GetArgumentAtIndex(0);
442
443 if (strcasecmp(sub_command, "enable") == 0)
444 {
445 Timer::SetDisplayDepth (UINT32_MAX);
446 result.SetStatus(eReturnStatusSuccessFinishNoResult);
447 }
448 else if (strcasecmp(sub_command, "disable") == 0)
449 {
450 Timer::DumpCategoryTimes (&result.GetOutputStream());
451 Timer::SetDisplayDepth (0);
452 result.SetStatus(eReturnStatusSuccessFinishResult);
453 }
454 else if (strcasecmp(sub_command, "dump") == 0)
455 {
456 Timer::DumpCategoryTimes (&result.GetOutputStream());
457 result.SetStatus(eReturnStatusSuccessFinishResult);
458 }
459 else if (strcasecmp(sub_command, "reset") == 0)
460 {
461 Timer::ResetCategoryTimes ();
462 result.SetStatus(eReturnStatusSuccessFinishResult);
463 }
464
465 }
Jim Ingham19e29a82010-11-04 23:08:26 +0000466 else if (argc == 2)
467 {
468 const char *sub_command = args.GetArgumentAtIndex(0);
469
470 if (strcasecmp(sub_command, "enable") == 0)
471 {
472 bool success;
473 uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success);
474 if (success)
475 {
476 Timer::SetDisplayDepth (depth);
477 result.SetStatus(eReturnStatusSuccessFinishNoResult);
478 }
479 else
480 result.AppendError("Could not convert enable depth to an unsigned integer.");
481 }
Jim Ingham4ba39992010-11-04 23:19:21 +0000482 if (strcasecmp(sub_command, "increment") == 0)
483 {
484 bool success;
485 bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success);
486 if (success)
487 {
488 Timer::SetQuiet (!increment);
489 result.SetStatus(eReturnStatusSuccessFinishNoResult);
490 }
491 else
492 result.AppendError("Could not convert increment value to boolean.");
493 }
Jim Ingham19e29a82010-11-04 23:08:26 +0000494 }
495
Chris Lattner24943d22010-06-08 16:52:24 +0000496 if (!result.Succeeded())
497 {
498 result.AppendError("Missing subcommand");
499 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
500 }
501 return result.Succeeded();
502 }
503};
504
505//----------------------------------------------------------------------
506// CommandObjectLog constructor
507//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +0000508CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000509 CommandObjectMultiword (interpreter,
510 "log",
Chris Lattner24943d22010-06-08 16:52:24 +0000511 "A set of commands for operating on logs.",
512 "log <command> [<command-options>]")
513{
Greg Clayton238c0a12010-09-18 01:14:36 +0000514 LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter)));
515 LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter)));
516 LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter)));
517 LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter)));
Chris Lattner24943d22010-06-08 16:52:24 +0000518}
519
520//----------------------------------------------------------------------
521// Destructor
522//----------------------------------------------------------------------
523CommandObjectLog::~CommandObjectLog()
524{
525}
526
527
528
529