1 //===-- 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/Interpreter/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/Interpreter/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/Core/Debugger.h" 30 #include "lldb/Interpreter/CommandInterpreter.h" 31 #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 41 using namespace lldb; 42 using namespace lldb_private; 43 44 45 static LogChannelSP 46 GetLogChannelPluginForChannel (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 55 class CommandObjectLogEnable : public CommandObject 56 { 57 public: 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 80 Execute (CommandInterpreter &interpreter, 81 Args& args, 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 log_stream_sp.reset(new StreamFile(interpreter.GetDebugger().GetOutputFileHandle())); 99 } 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 211 protected: 212 typedef std::map<std::string, StreamSP> LogStreamMap; 213 CommandOptions m_options; 214 LogStreamMap m_log_streams; 215 }; 216 217 lldb::OptionDefinition 218 CommandObjectLogEnable::CommandOptions::g_option_table[] = 219 { 220 { 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." }, 228 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 229 }; 230 231 class CommandObjectLogDisable : public CommandObject 232 { 233 public: 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 250 Execute (CommandInterpreter &interpreter, 251 Args& args, 252 CommandReturnObject &result) 253 { 254 const size_t argc = args.GetArgumentCount(); 255 if (argc == 0) 256 { 257 result.GetErrorStream() << m_cmd_syntax.c_str(); 258 } 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 292 class CommandObjectLogList : public CommandObject 293 { 294 public: 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 311 Execute (CommandInterpreter &interpreter, 312 Args& args, 313 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 355 class CommandObjectLogTimer : public CommandObject 356 { 357 public: 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 374 Execute (CommandInterpreter &interpreter, 375 Args& args, 376 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 //---------------------------------------------------------------------- 420 CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) : 421 CommandObjectMultiword ("log", 422 "A set of commands for operating on logs.", 423 "log <command> [<command-options>]") 424 { 425 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)); 429 } 430 431 //---------------------------------------------------------------------- 432 // Destructor 433 //---------------------------------------------------------------------- 434 CommandObjectLog::~CommandObjectLog() 435 { 436 } 437 438 439 440 441