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