blob: 5616fb1a0648964683bf5a03b8d91d1615e08dd5 [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"
Chris Lattner24943d22010-06-08 16:52:24 +000030#include "lldb/Interpreter/CommandReturnObject.h"
31
32#include "lldb/Symbol/LineTable.h"
33#include "lldb/Symbol/ObjectFile.h"
34#include "lldb/Symbol/SymbolFile.h"
35#include "lldb/Symbol/SymbolVendor.h"
36
37#include "lldb/Target/Process.h"
38#include "lldb/Target/Target.h"
39
40using namespace lldb;
41using namespace lldb_private;
42
43
44static LogChannelSP
45GetLogChannelPluginForChannel (const char *channel)
46{
47 std::string log_channel_plugin_name(channel);
48 log_channel_plugin_name += LogChannel::GetPluginSuffix();
49 LogChannelSP log_channel_sp (LogChannel::FindPlugin (log_channel_plugin_name.c_str()));
50 return log_channel_sp;
51}
52
53
54class CommandObjectLogEnable : public CommandObject
55{
56public:
57 //------------------------------------------------------------------
58 // Constructors and Destructors
59 //------------------------------------------------------------------
60 CommandObjectLogEnable() :
61 CommandObject ("log enable",
62 "Enable logging for a single log channel.",
63 "log enable [<cmd-options>] <channel>")
64 {
65 }
66
67 virtual
68 ~CommandObjectLogEnable()
69 {
70 }
71
72 Options *
73 GetOptions ()
74 {
75 return &m_options;
76 }
77
78 virtual bool
Greg Clayton63094e02010-06-23 01:19:29 +000079 Execute (CommandInterpreter &interpreter,
80 Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +000081 CommandReturnObject &result)
82 {
83 if (args.GetArgumentCount() < 1)
84 {
85 result.GetErrorStream() << m_cmd_syntax.c_str();
86 }
87 else
88 {
89 Log::Callbacks log_callbacks;
90
91 std::string channel(args.GetArgumentAtIndex(0));
92 args.Shift (); // Shift off the channel
93 StreamSP log_stream_sp;
94
95 if (m_options.log_file.empty())
96 {
97 std::string log_file("<lldb.debugger>");
98 LogStreamMap::iterator pos = m_log_streams.find(log_file);
99 if (pos == m_log_streams.end())
100 {
101 log_stream_sp = Log::GetStreamForSTDOUT ();
102 if (log_stream_sp)
103 m_log_streams[log_file] = log_stream_sp;
104 }
105 else
106 log_stream_sp = pos->second;
107 }
108 else
109 {
110 LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file);
111 if (pos == m_log_streams.end())
112 {
113 log_stream_sp.reset (new StreamFile (m_options.log_file.c_str(), "w"));
114 m_log_streams[m_options.log_file] = log_stream_sp;
115 }
116 else
117 log_stream_sp = pos->second;
118 }
119 assert (log_stream_sp.get());
120 uint32_t log_options = m_options.log_options;
121 if (log_options == 0)
122 log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
123 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
124 {
125 log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream());
126 result.SetStatus(eReturnStatusSuccessFinishNoResult);
127 }
128 else
129 {
130 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
131 if (log_channel_sp)
132 {
133 if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args))
134 {
135 result.SetStatus (eReturnStatusSuccessFinishNoResult);
136 }
137 else
138 {
139 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
140 result.SetStatus (eReturnStatusFailed);
141 }
142 }
143 else
144 {
145 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str());
146 result.SetStatus (eReturnStatusFailed);
147 }
148 }
149 }
150 return result.Succeeded();
151 }
152
153
154 class CommandOptions : public Options
155 {
156 public:
157
158 CommandOptions () :
159 Options (),
160 log_file (),
161 log_options (0)
162 {
163 }
164
165
166 virtual
167 ~CommandOptions ()
168 {
169 }
170
171 virtual Error
172 SetOptionValue (int option_idx, const char *option_arg)
173 {
174 Error error;
175 char short_option = (char) m_getopt_table[option_idx].val;
176
177 switch (short_option)
178 {
179 case 'f': log_file = option_arg; break;
180 case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break;
181 case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break;
182 case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break;
183 case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break;
184 case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break;
185 case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
186 case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
187 default:
188 error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option);
189 break;
190 }
191
192 return error;
193 }
194
195 void
196 ResetOptionValues ()
197 {
198 Options::ResetOptionValues();
199 log_file.clear();
200 log_options = 0;
201 }
202
203 const lldb::OptionDefinition*
204 GetDefinitions ()
205 {
206 return g_option_table;
207 }
208
209 // Options table: Required for subclasses of Options.
210
211 static lldb::OptionDefinition g_option_table[];
212
213 // Instance variables to hold the values for command options.
214
215 std::string log_file;
216 uint32_t log_options;
217 };
218
219protected:
220 typedef std::map<std::string, StreamSP> LogStreamMap;
221 CommandOptions m_options;
222 LogStreamMap m_log_streams;
223};
224
225lldb::OptionDefinition
226CommandObjectLogEnable::CommandOptions::g_option_table[] =
227{
Jim Ingham34e9a982010-06-15 18:47:14 +0000228{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, "<filename>", "Set the destination file to log to."},
229{ LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, NULL, "Enable thread safe logging to avoid interweaved log lines." },
230{ LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, NULL, "Enable verbose logging." },
231{ LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable debug logging." },
232{ LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, NULL, "Prepend all log lines with an increasing integer sequence id." },
233{ LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, NULL, "Prepend all log lines with a timestamp." },
234{ LLDB_OPT_SET_1, false, "pid-tid", 'p', no_argument, NULL, 0, NULL, "Prepend all log lines with the process and thread ID that generates the log line." },
235{ LLDB_OPT_SET_1, false, "thread-name",'n', no_argument, NULL, 0, NULL, "Prepend all log lines with the thread name for the thread that generates the log line." },
Chris Lattner24943d22010-06-08 16:52:24 +0000236{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
237};
238
239class CommandObjectLogDisable : public CommandObject
240{
241public:
242 //------------------------------------------------------------------
243 // Constructors and Destructors
244 //------------------------------------------------------------------
245 CommandObjectLogDisable() :
246 CommandObject ("log disable",
247 "Disable one or more log channels.",
248 "log disable <channel> [<channel> ...]")
249 {
250 }
251
252 virtual
253 ~CommandObjectLogDisable()
254 {
255 }
256
257 virtual bool
Greg Clayton63094e02010-06-23 01:19:29 +0000258 Execute (CommandInterpreter &interpreter,
259 Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000260 CommandReturnObject &result)
261 {
262 const size_t argc = args.GetArgumentCount();
263 if (argc == 0)
264 {
265 result.GetErrorStream() << m_cmd_syntax.c_str();
266 }
267 else
268 {
269 for (size_t i=0; i<argc; ++i)
270 {
271 Log::Callbacks log_callbacks;
272
273 std::string channel(args.GetArgumentAtIndex(i));
274 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
275 {
276 log_callbacks.disable ();
277 result.SetStatus(eReturnStatusSuccessFinishNoResult);
278 }
279 else if (channel == "all")
280 {
281 Log::DisableAllLogChannels();
282 }
283 else
284 {
285 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
286 if (log_channel_sp)
287 {
288 log_channel_sp->Disable();
289 result.SetStatus(eReturnStatusSuccessFinishNoResult);
290 }
291 else
292 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
293 }
294 }
295 }
296 return result.Succeeded();
297 }
298};
299
300class CommandObjectLogList : public CommandObject
301{
302public:
303 //------------------------------------------------------------------
304 // Constructors and Destructors
305 //------------------------------------------------------------------
306 CommandObjectLogList() :
307 CommandObject ("log list",
308 "List the log categories for one or more log channels.",
309 "log list <channel> [<channel> ...]")
310 {
311 }
312
313 virtual
314 ~CommandObjectLogList()
315 {
316 }
317
318 virtual bool
Greg Clayton63094e02010-06-23 01:19:29 +0000319 Execute (CommandInterpreter &interpreter,
320 Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000321 CommandReturnObject &result)
322 {
323 const size_t argc = args.GetArgumentCount();
324 if (argc == 0)
325 {
326 Log::ListAllLogChannels (&result.GetOutputStream());
327 result.SetStatus(eReturnStatusSuccessFinishResult);
328 }
329 else
330 {
331 for (size_t i=0; i<argc; ++i)
332 {
333 Log::Callbacks log_callbacks;
334
335 std::string channel(args.GetArgumentAtIndex(i));
336 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks))
337 {
338 log_callbacks.list_categories (&result.GetOutputStream());
339 result.SetStatus(eReturnStatusSuccessFinishResult);
340 }
341 else if (channel == "all")
342 {
343 Log::ListAllLogChannels (&result.GetOutputStream());
344 result.SetStatus(eReturnStatusSuccessFinishResult);
345 }
346 else
347 {
348 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str()));
349 if (log_channel_sp)
350 {
351 log_channel_sp->ListCategories(&result.GetOutputStream());
352 result.SetStatus(eReturnStatusSuccessFinishNoResult);
353 }
354 else
355 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
356 }
357 }
358 }
359 return result.Succeeded();
360 }
361};
362
363class CommandObjectLogTimer : public CommandObject
364{
365public:
366 //------------------------------------------------------------------
367 // Constructors and Destructors
368 //------------------------------------------------------------------
369 CommandObjectLogTimer() :
370 CommandObject ("log timers",
371 "Enable, disable, dump, and reset LLDB internal performance timers.",
372 "log timers < enable | disable | dump | reset >")
373 {
374 }
375
376 virtual
377 ~CommandObjectLogTimer()
378 {
379 }
380
381 virtual bool
Greg Clayton63094e02010-06-23 01:19:29 +0000382 Execute (CommandInterpreter &interpreter,
383 Args& args,
Chris Lattner24943d22010-06-08 16:52:24 +0000384 CommandReturnObject &result)
385 {
386 const size_t argc = args.GetArgumentCount();
387 result.SetStatus(eReturnStatusFailed);
388
389 if (argc == 1)
390 {
391 const char *sub_command = args.GetArgumentAtIndex(0);
392
393 if (strcasecmp(sub_command, "enable") == 0)
394 {
395 Timer::SetDisplayDepth (UINT32_MAX);
396 result.SetStatus(eReturnStatusSuccessFinishNoResult);
397 }
398 else if (strcasecmp(sub_command, "disable") == 0)
399 {
400 Timer::DumpCategoryTimes (&result.GetOutputStream());
401 Timer::SetDisplayDepth (0);
402 result.SetStatus(eReturnStatusSuccessFinishResult);
403 }
404 else if (strcasecmp(sub_command, "dump") == 0)
405 {
406 Timer::DumpCategoryTimes (&result.GetOutputStream());
407 result.SetStatus(eReturnStatusSuccessFinishResult);
408 }
409 else if (strcasecmp(sub_command, "reset") == 0)
410 {
411 Timer::ResetCategoryTimes ();
412 result.SetStatus(eReturnStatusSuccessFinishResult);
413 }
414
415 }
416 if (!result.Succeeded())
417 {
418 result.AppendError("Missing subcommand");
419 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
420 }
421 return result.Succeeded();
422 }
423};
424
425//----------------------------------------------------------------------
426// CommandObjectLog constructor
427//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +0000428CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
Chris Lattner24943d22010-06-08 16:52:24 +0000429 CommandObjectMultiword ("log",
430 "A set of commands for operating on logs.",
431 "log <command> [<command-options>]")
432{
Greg Clayton63094e02010-06-23 01:19:29 +0000433 LoadSubCommand (interpreter, "enable", CommandObjectSP (new CommandObjectLogEnable));
434 LoadSubCommand (interpreter, "disable", CommandObjectSP (new CommandObjectLogDisable));
435 LoadSubCommand (interpreter, "list", CommandObjectSP (new CommandObjectLogList));
436 LoadSubCommand (interpreter, "timers", CommandObjectSP (new CommandObjectLogTimer));
Chris Lattner24943d22010-06-08 16:52:24 +0000437}
438
439//----------------------------------------------------------------------
440// Destructor
441//----------------------------------------------------------------------
442CommandObjectLog::~CommandObjectLog()
443{
444}
445
446
447
448