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