blob: 9bf458dc6bcd7ae7bc7c9ea4104d9014219d03bf [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"
20#include "lldb/Core/FileSpec.h"
21#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 Tice43b014a2010-10-04 22:28:36 +000067 CommandArgumentEntry arg;
68 CommandArgumentData channel_arg;
69
70 // Define the first (and only) variant of this arg.
71 channel_arg.arg_type = eArgTypeLogChannel;
72 channel_arg.arg_repetition = eArgRepeatPlain;
73
74 // There is only one variant this argument could be; put it into the argument entry.
75 arg.push_back (channel_arg);
76
77 // Push the data for the first argument into the m_arguments vector.
78 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +000079 }
80
81 virtual
82 ~CommandObjectLogEnable()
83 {
84 }
85
86 Options *
87 GetOptions ()
88 {
89 return &m_options;
90 }
91
92 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +000093 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +000094 CommandReturnObject &result)
95 {
96 if (args.GetArgumentCount() < 1)
97 {
Caroline Ticeabb507a2010-09-08 21:06:11 +000098 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +000099 }
100 else
101 {
102 Log::Callbacks log_callbacks;
103
104 std::string channel(args.GetArgumentAtIndex(0));
105 args.Shift (); // Shift off the channel
106 StreamSP log_stream_sp;
107
108 if (m_options.log_file.empty())
109 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000110 log_stream_sp.reset(new StreamFile(m_interpreter.GetDebugger().GetOutputFileHandle()));
Chris Lattner24943d22010-06-08 16:52:24 +0000111 }
112 else
113 {
114 LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file);
115 if (pos == m_log_streams.end())
116 {
117 log_stream_sp.reset (new StreamFile (m_options.log_file.c_str(), "w"));
118 m_log_streams[m_options.log_file] = log_stream_sp;
119 }
120 else
121 log_stream_sp = pos->second;
122 }
123 assert (log_stream_sp.get());
124 uint32_t log_options = m_options.log_options;
125 if (log_options == 0)
126 log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
127 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
128 {
129 log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream());
130 result.SetStatus(eReturnStatusSuccessFinishNoResult);
131 }
132 else
133 {
134 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
135 if (log_channel_sp)
136 {
137 if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args))
138 {
139 result.SetStatus (eReturnStatusSuccessFinishNoResult);
140 }
141 else
142 {
143 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
144 result.SetStatus (eReturnStatusFailed);
145 }
146 }
147 else
148 {
149 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
150 result.SetStatus (eReturnStatusFailed);
151 }
152 }
153 }
154 return result.Succeeded();
155 }
156
157
158 class CommandOptions : public Options
159 {
160 public:
161
162 CommandOptions () :
163 Options (),
164 log_file (),
165 log_options (0)
166 {
167 }
168
169
170 virtual
171 ~CommandOptions ()
172 {
173 }
174
175 virtual Error
176 SetOptionValue (int option_idx, const char *option_arg)
177 {
178 Error error;
179 char short_option = (char) m_getopt_table[option_idx].val;
180
181 switch (short_option)
182 {
183 case 'f': log_file = option_arg; break;
184 case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break;
185 case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break;
186 case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break;
187 case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break;
188 case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break;
189 case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
190 case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
191 default:
192 error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option);
193 break;
194 }
195
196 return error;
197 }
198
199 void
200 ResetOptionValues ()
201 {
202 Options::ResetOptionValues();
203 log_file.clear();
204 log_options = 0;
205 }
206
207 const lldb::OptionDefinition*
208 GetDefinitions ()
209 {
210 return g_option_table;
211 }
212
213 // Options table: Required for subclasses of Options.
214
215 static lldb::OptionDefinition g_option_table[];
216
217 // Instance variables to hold the values for command options.
218
219 std::string log_file;
220 uint32_t log_options;
221 };
222
223protected:
224 typedef std::map<std::string, StreamSP> LogStreamMap;
225 CommandOptions m_options;
226 LogStreamMap m_log_streams;
227};
228
229lldb::OptionDefinition
230CommandObjectLogEnable::CommandOptions::g_option_table[] =
231{
Caroline Tice4d6675c2010-10-01 19:59:14 +0000232{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
233{ LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
234{ LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose logging." },
235{ LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable debug logging." },
236{ LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
237{ LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
238{ 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." },
239{ 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." },
240{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
Chris Lattner24943d22010-06-08 16:52:24 +0000241};
242
243class CommandObjectLogDisable : public CommandObject
244{
245public:
246 //------------------------------------------------------------------
247 // Constructors and Destructors
248 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000249 CommandObjectLogDisable(CommandInterpreter &interpreter) :
250 CommandObject (interpreter,
251 "log disable",
252 "Disable one or more log channels.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000253 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000254 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000255 CommandArgumentEntry arg;
256 CommandArgumentData channel_arg;
257
258 // Define the first (and only) variant of this arg.
259 channel_arg.arg_type = eArgTypeLogChannel;
260 channel_arg.arg_repetition = eArgRepeatPlus;
261
262 // There is only one variant this argument could be; put it into the argument entry.
263 arg.push_back (channel_arg);
264
265 // Push the data for the first argument into the m_arguments vector.
266 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000267 }
268
269 virtual
270 ~CommandObjectLogDisable()
271 {
272 }
273
274 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000275 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000276 CommandReturnObject &result)
277 {
278 const size_t argc = args.GetArgumentCount();
279 if (argc == 0)
280 {
Caroline Ticeabb507a2010-09-08 21:06:11 +0000281 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000282 }
283 else
284 {
285 for (size_t i=0; i<argc; ++i)
286 {
287 Log::Callbacks log_callbacks;
288
289 std::string channel(args.GetArgumentAtIndex(i));
290 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
291 {
292 log_callbacks.disable ();
293 result.SetStatus(eReturnStatusSuccessFinishNoResult);
294 }
295 else if (channel == "all")
296 {
297 Log::DisableAllLogChannels();
298 }
299 else
300 {
301 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
302 if (log_channel_sp)
303 {
304 log_channel_sp->Disable();
305 result.SetStatus(eReturnStatusSuccessFinishNoResult);
306 }
307 else
308 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
309 }
310 }
311 }
312 return result.Succeeded();
313 }
314};
315
316class CommandObjectLogList : public CommandObject
317{
318public:
319 //------------------------------------------------------------------
320 // Constructors and Destructors
321 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000322 CommandObjectLogList(CommandInterpreter &interpreter) :
323 CommandObject (interpreter,
324 "log list",
Caroline Tice43b014a2010-10-04 22:28:36 +0000325 "List the log categories for one or more log channels. If none specified, lists them all.",
326 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000327 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000328 CommandArgumentEntry arg;
329 CommandArgumentData channel_arg;
330
331 // Define the first (and only) variant of this arg.
332 channel_arg.arg_type = eArgTypeLogChannel;
333 channel_arg.arg_repetition = eArgRepeatStar;
334
335 // There is only one variant this argument could be; put it into the argument entry.
336 arg.push_back (channel_arg);
337
338 // Push the data for the first argument into the m_arguments vector.
339 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000340 }
341
342 virtual
343 ~CommandObjectLogList()
344 {
345 }
346
347 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000348 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000349 CommandReturnObject &result)
350 {
351 const size_t argc = args.GetArgumentCount();
352 if (argc == 0)
353 {
354 Log::ListAllLogChannels (&result.GetOutputStream());
355 result.SetStatus(eReturnStatusSuccessFinishResult);
356 }
357 else
358 {
359 for (size_t i=0; i<argc; ++i)
360 {
361 Log::Callbacks log_callbacks;
362
363 std::string channel(args.GetArgumentAtIndex(i));
364 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
365 {
366 log_callbacks.list_categories (&result.GetOutputStream());
367 result.SetStatus(eReturnStatusSuccessFinishResult);
368 }
369 else if (channel == "all")
370 {
371 Log::ListAllLogChannels (&result.GetOutputStream());
372 result.SetStatus(eReturnStatusSuccessFinishResult);
373 }
374 else
375 {
376 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
377 if (log_channel_sp)
378 {
379 log_channel_sp->ListCategories(&result.GetOutputStream());
380 result.SetStatus(eReturnStatusSuccessFinishNoResult);
381 }
382 else
383 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
384 }
385 }
386 }
387 return result.Succeeded();
388 }
389};
390
391class CommandObjectLogTimer : public CommandObject
392{
393public:
394 //------------------------------------------------------------------
395 // Constructors and Destructors
396 //------------------------------------------------------------------
Greg Clayton238c0a12010-09-18 01:14:36 +0000397 CommandObjectLogTimer(CommandInterpreter &interpreter) :
398 CommandObject (interpreter,
399 "log timers",
Chris Lattner24943d22010-06-08 16:52:24 +0000400 "Enable, disable, dump, and reset LLDB internal performance timers.",
401 "log timers < enable | disable | dump | reset >")
402 {
403 }
404
405 virtual
406 ~CommandObjectLogTimer()
407 {
408 }
409
410 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000411 Execute (Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000412 CommandReturnObject &result)
413 {
414 const size_t argc = args.GetArgumentCount();
415 result.SetStatus(eReturnStatusFailed);
416
417 if (argc == 1)
418 {
419 const char *sub_command = args.GetArgumentAtIndex(0);
420
421 if (strcasecmp(sub_command, "enable") == 0)
422 {
423 Timer::SetDisplayDepth (UINT32_MAX);
424 result.SetStatus(eReturnStatusSuccessFinishNoResult);
425 }
426 else if (strcasecmp(sub_command, "disable") == 0)
427 {
428 Timer::DumpCategoryTimes (&result.GetOutputStream());
429 Timer::SetDisplayDepth (0);
430 result.SetStatus(eReturnStatusSuccessFinishResult);
431 }
432 else if (strcasecmp(sub_command, "dump") == 0)
433 {
434 Timer::DumpCategoryTimes (&result.GetOutputStream());
435 result.SetStatus(eReturnStatusSuccessFinishResult);
436 }
437 else if (strcasecmp(sub_command, "reset") == 0)
438 {
439 Timer::ResetCategoryTimes ();
440 result.SetStatus(eReturnStatusSuccessFinishResult);
441 }
442
443 }
444 if (!result.Succeeded())
445 {
446 result.AppendError("Missing subcommand");
447 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
448 }
449 return result.Succeeded();
450 }
451};
452
453//----------------------------------------------------------------------
454// CommandObjectLog constructor
455//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +0000456CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000457 CommandObjectMultiword (interpreter,
458 "log",
Chris Lattner24943d22010-06-08 16:52:24 +0000459 "A set of commands for operating on logs.",
460 "log <command> [<command-options>]")
461{
Greg Clayton238c0a12010-09-18 01:14:36 +0000462 LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter)));
463 LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter)));
464 LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter)));
465 LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter)));
Chris Lattner24943d22010-06-08 16:52:24 +0000466}
467
468//----------------------------------------------------------------------
469// Destructor
470//----------------------------------------------------------------------
471CommandObjectLog::~CommandObjectLog()
472{
473}
474
475
476
477