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