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/Core/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/Core/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/Interpreter/CommandContext.h" 30 #include "lldb/Interpreter/CommandReturnObject.h" 31 32 #include "lldb/Symbol/LineTable.h" 33 #include "lldb/Symbol/ObjectFile.h" 34 #include "lldb/Symbol/SymbolFile.h" 35 #include "lldb/Symbol/SymbolVendor.h" 36 37 #include "lldb/Target/Process.h" 38 #include "lldb/Target/Target.h" 39 40 using namespace lldb; 41 using namespace lldb_private; 42 43 44 static LogChannelSP 45 GetLogChannelPluginForChannel (const char *channel) 46 { 47 std::string log_channel_plugin_name(channel); 48 log_channel_plugin_name += LogChannel::GetPluginSuffix(); 49 LogChannelSP log_channel_sp (LogChannel::FindPlugin (log_channel_plugin_name.c_str())); 50 return log_channel_sp; 51 } 52 53 54 class CommandObjectLogEnable : public CommandObject 55 { 56 public: 57 //------------------------------------------------------------------ 58 // Constructors and Destructors 59 //------------------------------------------------------------------ 60 CommandObjectLogEnable() : 61 CommandObject ("log enable", 62 "Enable logging for a single log channel.", 63 "log enable [<cmd-options>] <channel>") 64 { 65 } 66 67 virtual 68 ~CommandObjectLogEnable() 69 { 70 } 71 72 Options * 73 GetOptions () 74 { 75 return &m_options; 76 } 77 78 virtual bool 79 Execute (Args& args, 80 CommandContext *context, 81 CommandInterpreter *interpreter, 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 std::string log_file("<lldb.debugger>"); 99 LogStreamMap::iterator pos = m_log_streams.find(log_file); 100 if (pos == m_log_streams.end()) 101 { 102 log_stream_sp = Log::GetStreamForSTDOUT (); 103 if (log_stream_sp) 104 m_log_streams[log_file] = log_stream_sp; 105 } 106 else 107 log_stream_sp = pos->second; 108 } 109 else 110 { 111 LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file); 112 if (pos == m_log_streams.end()) 113 { 114 log_stream_sp.reset (new StreamFile (m_options.log_file.c_str(), "w")); 115 m_log_streams[m_options.log_file] = log_stream_sp; 116 } 117 else 118 log_stream_sp = pos->second; 119 } 120 assert (log_stream_sp.get()); 121 uint32_t log_options = m_options.log_options; 122 if (log_options == 0) 123 log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; 124 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) 125 { 126 log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream()); 127 result.SetStatus(eReturnStatusSuccessFinishNoResult); 128 } 129 else 130 { 131 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str())); 132 if (log_channel_sp) 133 { 134 if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args)) 135 { 136 result.SetStatus (eReturnStatusSuccessFinishNoResult); 137 } 138 else 139 { 140 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str()); 141 result.SetStatus (eReturnStatusFailed); 142 } 143 } 144 else 145 { 146 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str()); 147 result.SetStatus (eReturnStatusFailed); 148 } 149 } 150 } 151 return result.Succeeded(); 152 } 153 154 155 class CommandOptions : public Options 156 { 157 public: 158 159 CommandOptions () : 160 Options (), 161 log_file (), 162 log_options (0) 163 { 164 } 165 166 167 virtual 168 ~CommandOptions () 169 { 170 } 171 172 virtual Error 173 SetOptionValue (int option_idx, const char *option_arg) 174 { 175 Error error; 176 char short_option = (char) m_getopt_table[option_idx].val; 177 178 switch (short_option) 179 { 180 case 'f': log_file = option_arg; break; 181 case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break; 182 case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break; 183 case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break; 184 case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break; 185 case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break; 186 case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break; 187 case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break; 188 default: 189 error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option); 190 break; 191 } 192 193 return error; 194 } 195 196 void 197 ResetOptionValues () 198 { 199 Options::ResetOptionValues(); 200 log_file.clear(); 201 log_options = 0; 202 } 203 204 const lldb::OptionDefinition* 205 GetDefinitions () 206 { 207 return g_option_table; 208 } 209 210 // Options table: Required for subclasses of Options. 211 212 static lldb::OptionDefinition g_option_table[]; 213 214 // Instance variables to hold the values for command options. 215 216 std::string log_file; 217 uint32_t log_options; 218 }; 219 220 protected: 221 typedef std::map<std::string, StreamSP> LogStreamMap; 222 CommandOptions m_options; 223 LogStreamMap m_log_streams; 224 }; 225 226 lldb::OptionDefinition 227 CommandObjectLogEnable::CommandOptions::g_option_table[] = 228 { 229 { 0, false, "file", 'f', required_argument, NULL, 0, "<filename>", "Set the destination file to log to."}, 230 { 0, false, "threadsafe", 't', no_argument, NULL, 0, NULL, "Enable thread safe logging to avoid interweaved log lines." }, 231 { 0, false, "verbose", 'v', no_argument, NULL, 0, NULL, "Enable verbose logging." }, 232 { 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable debug logging." }, 233 { 0, false, "sequence", 's', no_argument, NULL, 0, NULL, "Prepend all log lines with an increasing integer sequence id." }, 234 { 0, false, "timestamp", 'T', no_argument, NULL, 0, NULL, "Prepend all log lines with a timestamp." }, 235 { 0, false, "pid-tid", 'p', no_argument, NULL, 0, NULL, "Prepend all log lines with the process and thread ID that generates the log line." }, 236 { 0, 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." }, 237 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 238 }; 239 240 class CommandObjectLogDisable : public CommandObject 241 { 242 public: 243 //------------------------------------------------------------------ 244 // Constructors and Destructors 245 //------------------------------------------------------------------ 246 CommandObjectLogDisable() : 247 CommandObject ("log disable", 248 "Disable one or more log channels.", 249 "log disable <channel> [<channel> ...]") 250 { 251 } 252 253 virtual 254 ~CommandObjectLogDisable() 255 { 256 } 257 258 virtual bool 259 Execute (Args& args, 260 CommandContext *context, 261 CommandInterpreter *interpreter, 262 CommandReturnObject &result) 263 { 264 const size_t argc = args.GetArgumentCount(); 265 if (argc == 0) 266 { 267 result.GetErrorStream() << m_cmd_syntax.c_str(); 268 } 269 else 270 { 271 for (size_t i=0; i<argc; ++i) 272 { 273 Log::Callbacks log_callbacks; 274 275 std::string channel(args.GetArgumentAtIndex(i)); 276 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) 277 { 278 log_callbacks.disable (); 279 result.SetStatus(eReturnStatusSuccessFinishNoResult); 280 } 281 else if (channel == "all") 282 { 283 Log::DisableAllLogChannels(); 284 } 285 else 286 { 287 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str())); 288 if (log_channel_sp) 289 { 290 log_channel_sp->Disable(); 291 result.SetStatus(eReturnStatusSuccessFinishNoResult); 292 } 293 else 294 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); 295 } 296 } 297 } 298 return result.Succeeded(); 299 } 300 }; 301 302 class CommandObjectLogList : public CommandObject 303 { 304 public: 305 //------------------------------------------------------------------ 306 // Constructors and Destructors 307 //------------------------------------------------------------------ 308 CommandObjectLogList() : 309 CommandObject ("log list", 310 "List the log categories for one or more log channels.", 311 "log list <channel> [<channel> ...]") 312 { 313 } 314 315 virtual 316 ~CommandObjectLogList() 317 { 318 } 319 320 virtual bool 321 Execute (Args& args, 322 CommandContext *context, 323 CommandInterpreter *interpreter, 324 CommandReturnObject &result) 325 { 326 const size_t argc = args.GetArgumentCount(); 327 if (argc == 0) 328 { 329 Log::ListAllLogChannels (&result.GetOutputStream()); 330 result.SetStatus(eReturnStatusSuccessFinishResult); 331 } 332 else 333 { 334 for (size_t i=0; i<argc; ++i) 335 { 336 Log::Callbacks log_callbacks; 337 338 std::string channel(args.GetArgumentAtIndex(i)); 339 if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) 340 { 341 log_callbacks.list_categories (&result.GetOutputStream()); 342 result.SetStatus(eReturnStatusSuccessFinishResult); 343 } 344 else if (channel == "all") 345 { 346 Log::ListAllLogChannels (&result.GetOutputStream()); 347 result.SetStatus(eReturnStatusSuccessFinishResult); 348 } 349 else 350 { 351 LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str())); 352 if (log_channel_sp) 353 { 354 log_channel_sp->ListCategories(&result.GetOutputStream()); 355 result.SetStatus(eReturnStatusSuccessFinishNoResult); 356 } 357 else 358 result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); 359 } 360 } 361 } 362 return result.Succeeded(); 363 } 364 }; 365 366 class CommandObjectLogTimer : public CommandObject 367 { 368 public: 369 //------------------------------------------------------------------ 370 // Constructors and Destructors 371 //------------------------------------------------------------------ 372 CommandObjectLogTimer() : 373 CommandObject ("log timers", 374 "Enable, disable, dump, and reset LLDB internal performance timers.", 375 "log timers < enable | disable | dump | reset >") 376 { 377 } 378 379 virtual 380 ~CommandObjectLogTimer() 381 { 382 } 383 384 virtual bool 385 Execute (Args& args, 386 CommandContext *context, 387 CommandInterpreter *interpreter, 388 CommandReturnObject &result) 389 { 390 const size_t argc = args.GetArgumentCount(); 391 result.SetStatus(eReturnStatusFailed); 392 393 if (argc == 1) 394 { 395 const char *sub_command = args.GetArgumentAtIndex(0); 396 397 if (strcasecmp(sub_command, "enable") == 0) 398 { 399 Timer::SetDisplayDepth (UINT32_MAX); 400 result.SetStatus(eReturnStatusSuccessFinishNoResult); 401 } 402 else if (strcasecmp(sub_command, "disable") == 0) 403 { 404 Timer::DumpCategoryTimes (&result.GetOutputStream()); 405 Timer::SetDisplayDepth (0); 406 result.SetStatus(eReturnStatusSuccessFinishResult); 407 } 408 else if (strcasecmp(sub_command, "dump") == 0) 409 { 410 Timer::DumpCategoryTimes (&result.GetOutputStream()); 411 result.SetStatus(eReturnStatusSuccessFinishResult); 412 } 413 else if (strcasecmp(sub_command, "reset") == 0) 414 { 415 Timer::ResetCategoryTimes (); 416 result.SetStatus(eReturnStatusSuccessFinishResult); 417 } 418 419 } 420 if (!result.Succeeded()) 421 { 422 result.AppendError("Missing subcommand"); 423 result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); 424 } 425 return result.Succeeded(); 426 } 427 }; 428 429 //---------------------------------------------------------------------- 430 // CommandObjectLog constructor 431 //---------------------------------------------------------------------- 432 CommandObjectLog::CommandObjectLog(CommandInterpreter *interpreter) : 433 CommandObjectMultiword ("log", 434 "A set of commands for operating on logs.", 435 "log <command> [<command-options>]") 436 { 437 LoadSubCommand (CommandObjectSP (new CommandObjectLogEnable), "enable", interpreter); 438 LoadSubCommand (CommandObjectSP (new CommandObjectLogDisable), "disable", interpreter); 439 LoadSubCommand (CommandObjectSP (new CommandObjectLogList), "list", interpreter); 440 LoadSubCommand (CommandObjectSP (new CommandObjectLogTimer), "timers", interpreter); 441 } 442 443 //---------------------------------------------------------------------- 444 // Destructor 445 //---------------------------------------------------------------------- 446 CommandObjectLog::~CommandObjectLog() 447 { 448 } 449 450 451 452 453