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