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 "lldb/lldb-python.h" 11 12 #include "CommandObjectLog.h" 13 14 // C Includes 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/lldb-private-log.h" 19 20 #include "lldb/Interpreter/Args.h" 21 #include "lldb/Core/Debugger.h" 22 #include "lldb/Host/FileSpec.h" 23 #include "lldb/Core/Log.h" 24 #include "lldb/Core/Module.h" 25 #include "lldb/Interpreter/Options.h" 26 #include "lldb/Core/RegularExpression.h" 27 #include "lldb/Core/Stream.h" 28 #include "lldb/Core/StreamFile.h" 29 #include "lldb/Core/Timer.h" 30 31 #include "lldb/Core/Debugger.h" 32 #include "lldb/Interpreter/CommandInterpreter.h" 33 #include "lldb/Interpreter/CommandReturnObject.h" 34 35 #include "lldb/Symbol/LineTable.h" 36 #include "lldb/Symbol/ObjectFile.h" 37 #include "lldb/Symbol/SymbolFile.h" 38 #include "lldb/Symbol/SymbolVendor.h" 39 40 #include "lldb/Target/Process.h" 41 #include "lldb/Target/Target.h" 42 43 using namespace lldb; 44 using namespace lldb_private; 45 46 47 class CommandObjectLogEnable : public CommandObjectParsed 48 { 49 public: 50 //------------------------------------------------------------------ 51 // Constructors and Destructors 52 //------------------------------------------------------------------ 53 CommandObjectLogEnable(CommandInterpreter &interpreter) : 54 CommandObjectParsed (interpreter, 55 "log enable", 56 "Enable logging for a single log channel.", 57 NULL), 58 m_options (interpreter) 59 { 60 61 CommandArgumentEntry arg1; 62 CommandArgumentEntry arg2; 63 CommandArgumentData channel_arg; 64 CommandArgumentData category_arg; 65 66 // Define the first (and only) variant of this arg. 67 channel_arg.arg_type = eArgTypeLogChannel; 68 channel_arg.arg_repetition = eArgRepeatPlain; 69 70 // There is only one variant this argument could be; put it into the argument entry. 71 arg1.push_back (channel_arg); 72 73 category_arg.arg_type = eArgTypeLogCategory; 74 category_arg.arg_repetition = eArgRepeatPlus; 75 76 arg2.push_back (category_arg); 77 78 // Push the data for the first argument into the m_arguments vector. 79 m_arguments.push_back (arg1); 80 m_arguments.push_back (arg2); 81 } 82 83 virtual 84 ~CommandObjectLogEnable() 85 { 86 } 87 88 Options * 89 GetOptions () 90 { 91 return &m_options; 92 } 93 94 // int 95 // HandleArgumentCompletion (Args &input, 96 // int &cursor_index, 97 // int &cursor_char_position, 98 // OptionElementVector &opt_element_vector, 99 // int match_start_point, 100 // int max_return_elements, 101 // bool &word_complete, 102 // StringList &matches) 103 // { 104 // std::string completion_str (input.GetArgumentAtIndex(cursor_index)); 105 // completion_str.erase (cursor_char_position); 106 // 107 // if (cursor_index == 1) 108 // { 109 // // 110 // Log::AutoCompleteChannelName (completion_str.c_str(), matches); 111 // } 112 // return matches.GetSize(); 113 // } 114 // 115 116 class CommandOptions : public Options 117 { 118 public: 119 120 CommandOptions (CommandInterpreter &interpreter) : 121 Options (interpreter), 122 log_file (), 123 log_options (0) 124 { 125 } 126 127 128 virtual 129 ~CommandOptions () 130 { 131 } 132 133 virtual Error 134 SetOptionValue (uint32_t option_idx, const char *option_arg) 135 { 136 Error error; 137 const int short_option = m_getopt_table[option_idx].val; 138 139 switch (short_option) 140 { 141 case 'f': log_file = option_arg; break; 142 case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break; 143 case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break; 144 case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break; 145 case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break; 146 case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break; 147 case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break; 148 case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break; 149 case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break; 150 default: 151 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 152 break; 153 } 154 155 return error; 156 } 157 158 void 159 OptionParsingStarting () 160 { 161 log_file.clear(); 162 log_options = 0; 163 } 164 165 const OptionDefinition* 166 GetDefinitions () 167 { 168 return g_option_table; 169 } 170 171 // Options table: Required for subclasses of Options. 172 173 static OptionDefinition g_option_table[]; 174 175 // Instance variables to hold the values for command options. 176 177 std::string log_file; 178 uint32_t log_options; 179 }; 180 181 protected: 182 virtual bool 183 DoExecute (Args& args, 184 CommandReturnObject &result) 185 { 186 if (args.GetArgumentCount() < 2) 187 { 188 result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str()); 189 } 190 else 191 { 192 std::string channel(args.GetArgumentAtIndex(0)); 193 args.Shift (); // Shift off the channel 194 bool success = m_interpreter.GetDebugger().EnableLog (channel.c_str(), 195 args.GetConstArgumentVector(), 196 m_options.log_file.c_str(), 197 m_options.log_options, 198 result.GetErrorStream()); 199 if (success) 200 result.SetStatus (eReturnStatusSuccessFinishNoResult); 201 else 202 result.SetStatus (eReturnStatusFailed); 203 } 204 return result.Succeeded(); 205 } 206 207 CommandOptions m_options; 208 }; 209 210 OptionDefinition 211 CommandObjectLogEnable::CommandOptions::g_option_table[] = 212 { 213 { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."}, 214 { LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." }, 215 { LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose logging." }, 216 { LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable debug logging." }, 217 { LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." }, 218 { LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." }, 219 { 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." }, 220 { 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." }, 221 { LLDB_OPT_SET_1, false, "stack", 'S', no_argument, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." }, 222 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 223 }; 224 225 class CommandObjectLogDisable : public CommandObjectParsed 226 { 227 public: 228 //------------------------------------------------------------------ 229 // Constructors and Destructors 230 //------------------------------------------------------------------ 231 CommandObjectLogDisable(CommandInterpreter &interpreter) : 232 CommandObjectParsed (interpreter, 233 "log disable", 234 "Disable one or more log channel categories.", 235 NULL) 236 { 237 CommandArgumentEntry arg1; 238 CommandArgumentEntry arg2; 239 CommandArgumentData channel_arg; 240 CommandArgumentData category_arg; 241 242 // Define the first (and only) variant of this arg. 243 channel_arg.arg_type = eArgTypeLogChannel; 244 channel_arg.arg_repetition = eArgRepeatPlain; 245 246 // There is only one variant this argument could be; put it into the argument entry. 247 arg1.push_back (channel_arg); 248 249 category_arg.arg_type = eArgTypeLogCategory; 250 category_arg.arg_repetition = eArgRepeatPlus; 251 252 arg2.push_back (category_arg); 253 254 // Push the data for the first argument into the m_arguments vector. 255 m_arguments.push_back (arg1); 256 m_arguments.push_back (arg2); 257 } 258 259 virtual 260 ~CommandObjectLogDisable() 261 { 262 } 263 264 protected: 265 virtual bool 266 DoExecute (Args& args, 267 CommandReturnObject &result) 268 { 269 const size_t argc = args.GetArgumentCount(); 270 if (argc == 0) 271 { 272 result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str()); 273 } 274 else 275 { 276 Log::Callbacks log_callbacks; 277 278 std::string channel(args.GetArgumentAtIndex(0)); 279 args.Shift (); // Shift off the channel 280 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) 281 { 282 log_callbacks.disable (args.GetConstArgumentVector(), &result.GetErrorStream()); 283 result.SetStatus(eReturnStatusSuccessFinishNoResult); 284 } 285 else if (channel == "all") 286 { 287 Log::DisableAllLogChannels(&result.GetErrorStream()); 288 } 289 else 290 { 291 LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str())); 292 if (log_channel_sp) 293 { 294 log_channel_sp->Disable(args.GetConstArgumentVector(), &result.GetErrorStream()); 295 result.SetStatus(eReturnStatusSuccessFinishNoResult); 296 } 297 else 298 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); 299 } 300 } 301 return result.Succeeded(); 302 } 303 }; 304 305 class CommandObjectLogList : public CommandObjectParsed 306 { 307 public: 308 //------------------------------------------------------------------ 309 // Constructors and Destructors 310 //------------------------------------------------------------------ 311 CommandObjectLogList(CommandInterpreter &interpreter) : 312 CommandObjectParsed (interpreter, 313 "log list", 314 "List the log categories for one or more log channels. If none specified, lists them all.", 315 NULL) 316 { 317 CommandArgumentEntry arg; 318 CommandArgumentData channel_arg; 319 320 // Define the first (and only) variant of this arg. 321 channel_arg.arg_type = eArgTypeLogChannel; 322 channel_arg.arg_repetition = eArgRepeatStar; 323 324 // There is only one variant this argument could be; put it into the argument entry. 325 arg.push_back (channel_arg); 326 327 // Push the data for the first argument into the m_arguments vector. 328 m_arguments.push_back (arg); 329 } 330 331 virtual 332 ~CommandObjectLogList() 333 { 334 } 335 336 protected: 337 virtual bool 338 DoExecute (Args& args, 339 CommandReturnObject &result) 340 { 341 const size_t argc = args.GetArgumentCount(); 342 if (argc == 0) 343 { 344 Log::ListAllLogChannels (&result.GetOutputStream()); 345 result.SetStatus(eReturnStatusSuccessFinishResult); 346 } 347 else 348 { 349 for (size_t i=0; i<argc; ++i) 350 { 351 Log::Callbacks log_callbacks; 352 353 std::string channel(args.GetArgumentAtIndex(i)); 354 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) 355 { 356 log_callbacks.list_categories (&result.GetOutputStream()); 357 result.SetStatus(eReturnStatusSuccessFinishResult); 358 } 359 else if (channel == "all") 360 { 361 Log::ListAllLogChannels (&result.GetOutputStream()); 362 result.SetStatus(eReturnStatusSuccessFinishResult); 363 } 364 else 365 { 366 LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str())); 367 if (log_channel_sp) 368 { 369 log_channel_sp->ListCategories(&result.GetOutputStream()); 370 result.SetStatus(eReturnStatusSuccessFinishNoResult); 371 } 372 else 373 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); 374 } 375 } 376 } 377 return result.Succeeded(); 378 } 379 }; 380 381 class CommandObjectLogTimer : public CommandObjectParsed 382 { 383 public: 384 //------------------------------------------------------------------ 385 // Constructors and Destructors 386 //------------------------------------------------------------------ 387 CommandObjectLogTimer(CommandInterpreter &interpreter) : 388 CommandObjectParsed (interpreter, 389 "log timers", 390 "Enable, disable, dump, and reset LLDB internal performance timers.", 391 "log timers < enable <depth> | disable | dump | increment <bool> | reset >") 392 { 393 } 394 395 virtual 396 ~CommandObjectLogTimer() 397 { 398 } 399 400 protected: 401 virtual bool 402 DoExecute (Args& args, 403 CommandReturnObject &result) 404 { 405 const size_t argc = args.GetArgumentCount(); 406 result.SetStatus(eReturnStatusFailed); 407 408 if (argc == 1) 409 { 410 const char *sub_command = args.GetArgumentAtIndex(0); 411 412 if (strcasecmp(sub_command, "enable") == 0) 413 { 414 Timer::SetDisplayDepth (UINT32_MAX); 415 result.SetStatus(eReturnStatusSuccessFinishNoResult); 416 } 417 else if (strcasecmp(sub_command, "disable") == 0) 418 { 419 Timer::DumpCategoryTimes (&result.GetOutputStream()); 420 Timer::SetDisplayDepth (0); 421 result.SetStatus(eReturnStatusSuccessFinishResult); 422 } 423 else if (strcasecmp(sub_command, "dump") == 0) 424 { 425 Timer::DumpCategoryTimes (&result.GetOutputStream()); 426 result.SetStatus(eReturnStatusSuccessFinishResult); 427 } 428 else if (strcasecmp(sub_command, "reset") == 0) 429 { 430 Timer::ResetCategoryTimes (); 431 result.SetStatus(eReturnStatusSuccessFinishResult); 432 } 433 434 } 435 else if (argc == 2) 436 { 437 const char *sub_command = args.GetArgumentAtIndex(0); 438 439 if (strcasecmp(sub_command, "enable") == 0) 440 { 441 bool success; 442 uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success); 443 if (success) 444 { 445 Timer::SetDisplayDepth (depth); 446 result.SetStatus(eReturnStatusSuccessFinishNoResult); 447 } 448 else 449 result.AppendError("Could not convert enable depth to an unsigned integer."); 450 } 451 if (strcasecmp(sub_command, "increment") == 0) 452 { 453 bool success; 454 bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success); 455 if (success) 456 { 457 Timer::SetQuiet (!increment); 458 result.SetStatus(eReturnStatusSuccessFinishNoResult); 459 } 460 else 461 result.AppendError("Could not convert increment value to boolean."); 462 } 463 } 464 465 if (!result.Succeeded()) 466 { 467 result.AppendError("Missing subcommand"); 468 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 469 } 470 return result.Succeeded(); 471 } 472 }; 473 474 //---------------------------------------------------------------------- 475 // CommandObjectLog constructor 476 //---------------------------------------------------------------------- 477 CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) : 478 CommandObjectMultiword (interpreter, 479 "log", 480 "A set of commands for operating on logs.", 481 "log <command> [<command-options>]") 482 { 483 LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter))); 484 LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter))); 485 LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter))); 486 LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter))); 487 } 488 489 //---------------------------------------------------------------------- 490 // Destructor 491 //---------------------------------------------------------------------- 492 CommandObjectLog::~CommandObjectLog() 493 { 494 } 495 496 497 498 499