1254721Semaste//===-- CommandObjectLog.cpp ------------------------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10254721Semaste#include "lldb/lldb-python.h" 11254721Semaste 12254721Semaste#include "CommandObjectLog.h" 13254721Semaste 14254721Semaste// C Includes 15254721Semaste// C++ Includes 16254721Semaste// Other libraries and framework includes 17254721Semaste// Project includes 18254721Semaste#include "lldb/lldb-private-log.h" 19254721Semaste 20254721Semaste#include "lldb/Interpreter/Args.h" 21254721Semaste#include "lldb/Core/Debugger.h" 22254721Semaste#include "lldb/Host/FileSpec.h" 23254721Semaste#include "lldb/Core/Log.h" 24254721Semaste#include "lldb/Core/Module.h" 25254721Semaste#include "lldb/Interpreter/Options.h" 26254721Semaste#include "lldb/Core/RegularExpression.h" 27254721Semaste#include "lldb/Core/Stream.h" 28254721Semaste#include "lldb/Core/StreamFile.h" 29254721Semaste#include "lldb/Core/Timer.h" 30254721Semaste 31254721Semaste#include "lldb/Core/Debugger.h" 32254721Semaste#include "lldb/Interpreter/CommandInterpreter.h" 33254721Semaste#include "lldb/Interpreter/CommandReturnObject.h" 34254721Semaste 35254721Semaste#include "lldb/Symbol/LineTable.h" 36254721Semaste#include "lldb/Symbol/ObjectFile.h" 37254721Semaste#include "lldb/Symbol/SymbolFile.h" 38254721Semaste#include "lldb/Symbol/SymbolVendor.h" 39254721Semaste 40254721Semaste#include "lldb/Target/Process.h" 41254721Semaste#include "lldb/Target/Target.h" 42254721Semaste 43254721Semasteusing namespace lldb; 44254721Semasteusing namespace lldb_private; 45254721Semaste 46254721Semaste 47254721Semasteclass CommandObjectLogEnable : public CommandObjectParsed 48254721Semaste{ 49254721Semastepublic: 50254721Semaste //------------------------------------------------------------------ 51254721Semaste // Constructors and Destructors 52254721Semaste //------------------------------------------------------------------ 53254721Semaste CommandObjectLogEnable(CommandInterpreter &interpreter) : 54254721Semaste CommandObjectParsed (interpreter, 55254721Semaste "log enable", 56254721Semaste "Enable logging for a single log channel.", 57254721Semaste NULL), 58254721Semaste m_options (interpreter) 59254721Semaste { 60254721Semaste 61254721Semaste CommandArgumentEntry arg1; 62254721Semaste CommandArgumentEntry arg2; 63254721Semaste CommandArgumentData channel_arg; 64254721Semaste CommandArgumentData category_arg; 65254721Semaste 66254721Semaste // Define the first (and only) variant of this arg. 67254721Semaste channel_arg.arg_type = eArgTypeLogChannel; 68254721Semaste channel_arg.arg_repetition = eArgRepeatPlain; 69254721Semaste 70254721Semaste // There is only one variant this argument could be; put it into the argument entry. 71254721Semaste arg1.push_back (channel_arg); 72254721Semaste 73254721Semaste category_arg.arg_type = eArgTypeLogCategory; 74254721Semaste category_arg.arg_repetition = eArgRepeatPlus; 75254721Semaste 76254721Semaste arg2.push_back (category_arg); 77254721Semaste 78254721Semaste // Push the data for the first argument into the m_arguments vector. 79254721Semaste m_arguments.push_back (arg1); 80254721Semaste m_arguments.push_back (arg2); 81254721Semaste } 82254721Semaste 83254721Semaste virtual 84254721Semaste ~CommandObjectLogEnable() 85254721Semaste { 86254721Semaste } 87254721Semaste 88254721Semaste Options * 89254721Semaste GetOptions () 90254721Semaste { 91254721Semaste return &m_options; 92254721Semaste } 93254721Semaste 94254721Semaste// int 95254721Semaste// HandleArgumentCompletion (Args &input, 96254721Semaste// int &cursor_index, 97254721Semaste// int &cursor_char_position, 98254721Semaste// OptionElementVector &opt_element_vector, 99254721Semaste// int match_start_point, 100254721Semaste// int max_return_elements, 101254721Semaste// bool &word_complete, 102254721Semaste// StringList &matches) 103254721Semaste// { 104254721Semaste// std::string completion_str (input.GetArgumentAtIndex(cursor_index)); 105254721Semaste// completion_str.erase (cursor_char_position); 106254721Semaste// 107254721Semaste// if (cursor_index == 1) 108254721Semaste// { 109254721Semaste// // 110254721Semaste// Log::AutoCompleteChannelName (completion_str.c_str(), matches); 111254721Semaste// } 112254721Semaste// return matches.GetSize(); 113254721Semaste// } 114254721Semaste// 115254721Semaste 116254721Semaste class CommandOptions : public Options 117254721Semaste { 118254721Semaste public: 119254721Semaste 120254721Semaste CommandOptions (CommandInterpreter &interpreter) : 121254721Semaste Options (interpreter), 122254721Semaste log_file (), 123254721Semaste log_options (0) 124254721Semaste { 125254721Semaste } 126254721Semaste 127254721Semaste 128254721Semaste virtual 129254721Semaste ~CommandOptions () 130254721Semaste { 131254721Semaste } 132254721Semaste 133254721Semaste virtual Error 134254721Semaste SetOptionValue (uint32_t option_idx, const char *option_arg) 135254721Semaste { 136254721Semaste Error error; 137254721Semaste const int short_option = m_getopt_table[option_idx].val; 138254721Semaste 139254721Semaste switch (short_option) 140254721Semaste { 141254721Semaste case 'f': log_file.SetFile(option_arg, true); break; 142254721Semaste case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break; 143254721Semaste case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break; 144254721Semaste case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break; 145254721Semaste case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break; 146254721Semaste case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break; 147254721Semaste case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break; 148254721Semaste case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break; 149254721Semaste case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break; 150254721Semaste default: 151254721Semaste error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 152254721Semaste break; 153254721Semaste } 154254721Semaste 155254721Semaste return error; 156254721Semaste } 157254721Semaste 158254721Semaste void 159254721Semaste OptionParsingStarting () 160254721Semaste { 161254721Semaste log_file.Clear(); 162254721Semaste log_options = 0; 163254721Semaste } 164254721Semaste 165254721Semaste const OptionDefinition* 166254721Semaste GetDefinitions () 167254721Semaste { 168254721Semaste return g_option_table; 169254721Semaste } 170254721Semaste 171254721Semaste // Options table: Required for subclasses of Options. 172254721Semaste 173254721Semaste static OptionDefinition g_option_table[]; 174254721Semaste 175254721Semaste // Instance variables to hold the values for command options. 176254721Semaste 177254721Semaste FileSpec log_file; 178254721Semaste uint32_t log_options; 179254721Semaste }; 180254721Semaste 181254721Semasteprotected: 182254721Semaste virtual bool 183254721Semaste DoExecute (Args& args, 184254721Semaste CommandReturnObject &result) 185254721Semaste { 186254721Semaste if (args.GetArgumentCount() < 2) 187254721Semaste { 188254721Semaste result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str()); 189254721Semaste } 190254721Semaste else 191254721Semaste { 192254721Semaste std::string channel(args.GetArgumentAtIndex(0)); 193254721Semaste args.Shift (); // Shift off the channel 194254721Semaste char log_file[PATH_MAX]; 195254721Semaste if (m_options.log_file) 196254721Semaste m_options.log_file.GetPath(log_file, sizeof(log_file)); 197254721Semaste else 198254721Semaste log_file[0] = '\0'; 199254721Semaste bool success = m_interpreter.GetDebugger().EnableLog (channel.c_str(), 200254721Semaste args.GetConstArgumentVector(), 201254721Semaste log_file, 202254721Semaste m_options.log_options, 203254721Semaste result.GetErrorStream()); 204254721Semaste if (success) 205254721Semaste result.SetStatus (eReturnStatusSuccessFinishNoResult); 206254721Semaste else 207254721Semaste result.SetStatus (eReturnStatusFailed); 208254721Semaste } 209254721Semaste return result.Succeeded(); 210254721Semaste } 211254721Semaste 212254721Semaste CommandOptions m_options; 213254721Semaste}; 214254721Semaste 215254721SemasteOptionDefinition 216254721SemasteCommandObjectLogEnable::CommandOptions::g_option_table[] = 217254721Semaste{ 218263363Semaste{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."}, 219263363Semaste{ LLDB_OPT_SET_1, false, "threadsafe", 't', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." }, 220263363Semaste{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable verbose logging." }, 221263363Semaste{ LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Enable debug logging." }, 222263363Semaste{ LLDB_OPT_SET_1, false, "sequence", 's', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." }, 223263363Semaste{ LLDB_OPT_SET_1, false, "timestamp", 'T', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." }, 224263363Semaste{ LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." }, 225263363Semaste{ LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." }, 226263363Semaste{ LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." }, 227254721Semaste{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 228254721Semaste}; 229254721Semaste 230254721Semasteclass CommandObjectLogDisable : public CommandObjectParsed 231254721Semaste{ 232254721Semastepublic: 233254721Semaste //------------------------------------------------------------------ 234254721Semaste // Constructors and Destructors 235254721Semaste //------------------------------------------------------------------ 236254721Semaste CommandObjectLogDisable(CommandInterpreter &interpreter) : 237254721Semaste CommandObjectParsed (interpreter, 238254721Semaste "log disable", 239254721Semaste "Disable one or more log channel categories.", 240254721Semaste NULL) 241254721Semaste { 242254721Semaste CommandArgumentEntry arg1; 243254721Semaste CommandArgumentEntry arg2; 244254721Semaste CommandArgumentData channel_arg; 245254721Semaste CommandArgumentData category_arg; 246254721Semaste 247254721Semaste // Define the first (and only) variant of this arg. 248254721Semaste channel_arg.arg_type = eArgTypeLogChannel; 249254721Semaste channel_arg.arg_repetition = eArgRepeatPlain; 250254721Semaste 251254721Semaste // There is only one variant this argument could be; put it into the argument entry. 252254721Semaste arg1.push_back (channel_arg); 253254721Semaste 254254721Semaste category_arg.arg_type = eArgTypeLogCategory; 255254721Semaste category_arg.arg_repetition = eArgRepeatPlus; 256254721Semaste 257254721Semaste arg2.push_back (category_arg); 258254721Semaste 259254721Semaste // Push the data for the first argument into the m_arguments vector. 260254721Semaste m_arguments.push_back (arg1); 261254721Semaste m_arguments.push_back (arg2); 262254721Semaste } 263254721Semaste 264254721Semaste virtual 265254721Semaste ~CommandObjectLogDisable() 266254721Semaste { 267254721Semaste } 268254721Semaste 269254721Semasteprotected: 270254721Semaste virtual bool 271254721Semaste DoExecute (Args& args, 272254721Semaste CommandReturnObject &result) 273254721Semaste { 274254721Semaste const size_t argc = args.GetArgumentCount(); 275254721Semaste if (argc == 0) 276254721Semaste { 277254721Semaste result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str()); 278254721Semaste } 279254721Semaste else 280254721Semaste { 281254721Semaste Log::Callbacks log_callbacks; 282254721Semaste 283254721Semaste std::string channel(args.GetArgumentAtIndex(0)); 284254721Semaste args.Shift (); // Shift off the channel 285254721Semaste if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks)) 286254721Semaste { 287254721Semaste log_callbacks.disable (args.GetConstArgumentVector(), &result.GetErrorStream()); 288254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 289254721Semaste } 290254721Semaste else if (channel == "all") 291254721Semaste { 292254721Semaste Log::DisableAllLogChannels(&result.GetErrorStream()); 293254721Semaste } 294254721Semaste else 295254721Semaste { 296254721Semaste LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str())); 297254721Semaste if (log_channel_sp) 298254721Semaste { 299254721Semaste log_channel_sp->Disable(args.GetConstArgumentVector(), &result.GetErrorStream()); 300254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 301254721Semaste } 302254721Semaste else 303254721Semaste result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); 304254721Semaste } 305254721Semaste } 306254721Semaste return result.Succeeded(); 307254721Semaste } 308254721Semaste}; 309254721Semaste 310254721Semasteclass CommandObjectLogList : public CommandObjectParsed 311254721Semaste{ 312254721Semastepublic: 313254721Semaste //------------------------------------------------------------------ 314254721Semaste // Constructors and Destructors 315254721Semaste //------------------------------------------------------------------ 316254721Semaste CommandObjectLogList(CommandInterpreter &interpreter) : 317254721Semaste CommandObjectParsed (interpreter, 318254721Semaste "log list", 319254721Semaste "List the log categories for one or more log channels. If none specified, lists them all.", 320254721Semaste NULL) 321254721Semaste { 322254721Semaste CommandArgumentEntry arg; 323254721Semaste CommandArgumentData channel_arg; 324254721Semaste 325254721Semaste // Define the first (and only) variant of this arg. 326254721Semaste channel_arg.arg_type = eArgTypeLogChannel; 327254721Semaste channel_arg.arg_repetition = eArgRepeatStar; 328254721Semaste 329254721Semaste // There is only one variant this argument could be; put it into the argument entry. 330254721Semaste arg.push_back (channel_arg); 331254721Semaste 332254721Semaste // Push the data for the first argument into the m_arguments vector. 333254721Semaste m_arguments.push_back (arg); 334254721Semaste } 335254721Semaste 336254721Semaste virtual 337254721Semaste ~CommandObjectLogList() 338254721Semaste { 339254721Semaste } 340254721Semaste 341254721Semasteprotected: 342254721Semaste virtual bool 343254721Semaste DoExecute (Args& args, 344254721Semaste CommandReturnObject &result) 345254721Semaste { 346254721Semaste const size_t argc = args.GetArgumentCount(); 347254721Semaste if (argc == 0) 348254721Semaste { 349254721Semaste Log::ListAllLogChannels (&result.GetOutputStream()); 350254721Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 351254721Semaste } 352254721Semaste else 353254721Semaste { 354254721Semaste for (size_t i=0; i<argc; ++i) 355254721Semaste { 356254721Semaste Log::Callbacks log_callbacks; 357254721Semaste 358254721Semaste std::string channel(args.GetArgumentAtIndex(i)); 359254721Semaste if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks)) 360254721Semaste { 361254721Semaste log_callbacks.list_categories (&result.GetOutputStream()); 362254721Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 363254721Semaste } 364254721Semaste else if (channel == "all") 365254721Semaste { 366254721Semaste Log::ListAllLogChannels (&result.GetOutputStream()); 367254721Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 368254721Semaste } 369254721Semaste else 370254721Semaste { 371254721Semaste LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str())); 372254721Semaste if (log_channel_sp) 373254721Semaste { 374254721Semaste log_channel_sp->ListCategories(&result.GetOutputStream()); 375254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 376254721Semaste } 377254721Semaste else 378254721Semaste result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); 379254721Semaste } 380254721Semaste } 381254721Semaste } 382254721Semaste return result.Succeeded(); 383254721Semaste } 384254721Semaste}; 385254721Semaste 386254721Semasteclass CommandObjectLogTimer : public CommandObjectParsed 387254721Semaste{ 388254721Semastepublic: 389254721Semaste //------------------------------------------------------------------ 390254721Semaste // Constructors and Destructors 391254721Semaste //------------------------------------------------------------------ 392254721Semaste CommandObjectLogTimer(CommandInterpreter &interpreter) : 393254721Semaste CommandObjectParsed (interpreter, 394254721Semaste "log timers", 395254721Semaste "Enable, disable, dump, and reset LLDB internal performance timers.", 396254721Semaste "log timers < enable <depth> | disable | dump | increment <bool> | reset >") 397254721Semaste { 398254721Semaste } 399254721Semaste 400254721Semaste virtual 401254721Semaste ~CommandObjectLogTimer() 402254721Semaste { 403254721Semaste } 404254721Semaste 405254721Semasteprotected: 406254721Semaste virtual bool 407254721Semaste DoExecute (Args& args, 408254721Semaste CommandReturnObject &result) 409254721Semaste { 410254721Semaste const size_t argc = args.GetArgumentCount(); 411254721Semaste result.SetStatus(eReturnStatusFailed); 412254721Semaste 413254721Semaste if (argc == 1) 414254721Semaste { 415254721Semaste const char *sub_command = args.GetArgumentAtIndex(0); 416254721Semaste 417254721Semaste if (strcasecmp(sub_command, "enable") == 0) 418254721Semaste { 419254721Semaste Timer::SetDisplayDepth (UINT32_MAX); 420254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 421254721Semaste } 422254721Semaste else if (strcasecmp(sub_command, "disable") == 0) 423254721Semaste { 424254721Semaste Timer::DumpCategoryTimes (&result.GetOutputStream()); 425254721Semaste Timer::SetDisplayDepth (0); 426254721Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 427254721Semaste } 428254721Semaste else if (strcasecmp(sub_command, "dump") == 0) 429254721Semaste { 430254721Semaste Timer::DumpCategoryTimes (&result.GetOutputStream()); 431254721Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 432254721Semaste } 433254721Semaste else if (strcasecmp(sub_command, "reset") == 0) 434254721Semaste { 435254721Semaste Timer::ResetCategoryTimes (); 436254721Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 437254721Semaste } 438254721Semaste 439254721Semaste } 440254721Semaste else if (argc == 2) 441254721Semaste { 442254721Semaste const char *sub_command = args.GetArgumentAtIndex(0); 443254721Semaste 444254721Semaste if (strcasecmp(sub_command, "enable") == 0) 445254721Semaste { 446254721Semaste bool success; 447254721Semaste uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success); 448254721Semaste if (success) 449254721Semaste { 450254721Semaste Timer::SetDisplayDepth (depth); 451254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 452254721Semaste } 453254721Semaste else 454254721Semaste result.AppendError("Could not convert enable depth to an unsigned integer."); 455254721Semaste } 456254721Semaste if (strcasecmp(sub_command, "increment") == 0) 457254721Semaste { 458254721Semaste bool success; 459254721Semaste bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success); 460254721Semaste if (success) 461254721Semaste { 462254721Semaste Timer::SetQuiet (!increment); 463254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 464254721Semaste } 465254721Semaste else 466254721Semaste result.AppendError("Could not convert increment value to boolean."); 467254721Semaste } 468254721Semaste } 469254721Semaste 470254721Semaste if (!result.Succeeded()) 471254721Semaste { 472254721Semaste result.AppendError("Missing subcommand"); 473254721Semaste result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 474254721Semaste } 475254721Semaste return result.Succeeded(); 476254721Semaste } 477254721Semaste}; 478254721Semaste 479254721Semaste//---------------------------------------------------------------------- 480254721Semaste// CommandObjectLog constructor 481254721Semaste//---------------------------------------------------------------------- 482254721SemasteCommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) : 483254721Semaste CommandObjectMultiword (interpreter, 484254721Semaste "log", 485254721Semaste "A set of commands for operating on logs.", 486254721Semaste "log <command> [<command-options>]") 487254721Semaste{ 488254721Semaste LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter))); 489254721Semaste LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter))); 490254721Semaste LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter))); 491254721Semaste LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter))); 492254721Semaste} 493254721Semaste 494254721Semaste//---------------------------------------------------------------------- 495254721Semaste// Destructor 496254721Semaste//---------------------------------------------------------------------- 497254721SemasteCommandObjectLog::~CommandObjectLog() 498254721Semaste{ 499254721Semaste} 500254721Semaste 501254721Semaste 502254721Semaste 503254721Semaste 504