2010-06-09 00:52:24 +08:00
//===-- CommandObjectLog.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "CommandObjectLog.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
# include "lldb/lldb-private-log.h"
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Args.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Debugger.h"
2011-02-08 13:05:52 +08:00
# include "lldb/Host/FileSpec.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Log.h"
# include "lldb/Core/Module.h"
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Options.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/RegularExpression.h"
# include "lldb/Core/Stream.h"
# include "lldb/Core/StreamFile.h"
# include "lldb/Core/Timer.h"
2010-06-23 09:19:29 +08:00
# include "lldb/Core/Debugger.h"
2010-06-24 05:28:25 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandReturnObject.h"
# include "lldb/Symbol/LineTable.h"
# include "lldb/Symbol/ObjectFile.h"
# include "lldb/Symbol/SymbolFile.h"
# include "lldb/Symbol/SymbolVendor.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/Target.h"
using namespace lldb ;
using namespace lldb_private ;
static LogChannelSP
GetLogChannelPluginForChannel ( const char * channel )
{
std : : string log_channel_plugin_name ( channel ) ;
log_channel_plugin_name + = LogChannel : : GetPluginSuffix ( ) ;
LogChannelSP log_channel_sp ( LogChannel : : FindPlugin ( log_channel_plugin_name . c_str ( ) ) ) ;
return log_channel_sp ;
}
class CommandObjectLogEnable : public CommandObject
{
public :
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
2010-09-18 09:14:36 +08:00
CommandObjectLogEnable ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" log enable " ,
2010-06-09 00:52:24 +08:00
" Enable logging for a single log channel. " ,
2010-10-05 06:28:36 +08:00
NULL )
2010-06-09 00:52:24 +08:00
{
2010-10-26 11:11:13 +08:00
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
2010-10-05 06:28:36 +08:00
CommandArgumentData channel_arg ;
2010-10-26 11:11:13 +08:00
CommandArgumentData category_arg ;
2010-10-05 06:28:36 +08:00
// Define the first (and only) variant of this arg.
channel_arg . arg_type = eArgTypeLogChannel ;
channel_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
2010-10-26 11:11:13 +08:00
arg1 . push_back ( channel_arg ) ;
2010-10-05 06:28:36 +08:00
2010-10-26 11:11:13 +08:00
category_arg . arg_type = eArgTypeLogCategory ;
category_arg . arg_repetition = eArgRepeatPlus ;
arg2 . push_back ( category_arg ) ;
2010-10-05 06:28:36 +08:00
// Push the data for the first argument into the m_arguments vector.
2010-10-26 11:11:13 +08:00
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandObjectLogEnable ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & args ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
if ( args . GetArgumentCount ( ) < 1 )
{
2010-09-09 05:06:11 +08:00
result . AppendErrorWithFormat ( " Usage: %s \n " , m_cmd_syntax . c_str ( ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
Log : : Callbacks log_callbacks ;
std : : string channel ( args . GetArgumentAtIndex ( 0 ) ) ;
args . Shift ( ) ; // Shift off the channel
StreamSP log_stream_sp ;
if ( m_options . log_file . empty ( ) )
{
2011-02-09 09:08:52 +08:00
log_stream_sp . reset ( new StreamFile ( m_interpreter . GetDebugger ( ) . GetOutputFile ( ) . GetDescriptor ( ) , false ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
LogStreamMap : : iterator pos = m_log_streams . find ( m_options . log_file ) ;
if ( pos = = m_log_streams . end ( ) )
{
2011-02-09 09:08:52 +08:00
log_stream_sp . reset ( new StreamFile ( m_options . log_file . c_str ( ) ) ) ;
2010-06-09 00:52:24 +08:00
m_log_streams [ m_options . log_file ] = log_stream_sp ;
}
else
log_stream_sp = pos - > second ;
}
assert ( log_stream_sp . get ( ) ) ;
2011-01-24 12:09:25 +08:00
2010-06-09 00:52:24 +08:00
uint32_t log_options = m_options . log_options ;
if ( log_options = = 0 )
log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE ;
if ( Log : : GetLogChannelCallbacks ( channel . c_str ( ) , log_callbacks ) )
{
log_callbacks . enable ( log_stream_sp , log_options , args , & result . GetErrorStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
LogChannelSP log_channel_sp ( GetLogChannelPluginForChannel ( channel . c_str ( ) ) ) ;
if ( log_channel_sp )
{
if ( log_channel_sp - > Enable ( log_stream_sp , log_options , & result . GetErrorStream ( ) , args ) )
{
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Invalid log channel '%s'. \n " , channel . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendErrorWithFormat ( " Invalid log channel '%s'. \n " , channel . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
}
return result . Succeeded ( ) ;
}
class CommandOptions : public Options
{
public :
CommandOptions ( ) :
Options ( ) ,
log_file ( ) ,
log_options ( 0 )
{
}
virtual
~ CommandOptions ( )
{
}
virtual Error
SetOptionValue ( int option_idx , const char * option_arg )
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' f ' : log_file = option_arg ; break ;
case ' t ' : log_options | = LLDB_LOG_OPTION_THREADSAFE ; break ;
case ' v ' : log_options | = LLDB_LOG_OPTION_VERBOSE ; break ;
case ' g ' : log_options | = LLDB_LOG_OPTION_DEBUG ; break ;
case ' s ' : log_options | = LLDB_LOG_OPTION_PREPEND_SEQUENCE ; break ;
case ' T ' : log_options | = LLDB_LOG_OPTION_PREPEND_TIMESTAMP ; break ;
case ' p ' : log_options | = LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD ; break ;
case ' n ' : log_options | = LLDB_LOG_OPTION_PREPEND_THREAD_NAME ; break ;
default :
error . SetErrorStringWithFormat ( " Unrecognized option '%c' \n " , short_option ) ;
break ;
}
return error ;
}
void
ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
log_file . clear ( ) ;
log_options = 0 ;
}
const lldb : : OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static lldb : : OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
std : : string log_file ;
uint32_t log_options ;
} ;
protected :
typedef std : : map < std : : string , StreamSP > LogStreamMap ;
CommandOptions m_options ;
LogStreamMap m_log_streams ;
} ;
lldb : : OptionDefinition
CommandObjectLogEnable : : CommandOptions : : g_option_table [ ] =
{
2010-10-02 03:59:14 +08:00
{ LLDB_OPT_SET_1 , false , " file " , ' f ' , required_argument , NULL , 0 , eArgTypeFilename , " Set the destination file to log to. " } ,
{ LLDB_OPT_SET_1 , false , " threadsafe " , ' t ' , no_argument , NULL , 0 , eArgTypeNone , " Enable thread safe logging to avoid interweaved log lines. " } ,
{ LLDB_OPT_SET_1 , false , " verbose " , ' v ' , no_argument , NULL , 0 , eArgTypeNone , " Enable verbose logging. " } ,
{ LLDB_OPT_SET_1 , false , " debug " , ' g ' , no_argument , NULL , 0 , eArgTypeNone , " Enable debug logging. " } ,
{ LLDB_OPT_SET_1 , false , " sequence " , ' s ' , no_argument , NULL , 0 , eArgTypeNone , " Prepend all log lines with an increasing integer sequence id. " } ,
{ LLDB_OPT_SET_1 , false , " timestamp " , ' T ' , no_argument , NULL , 0 , eArgTypeNone , " Prepend all log lines with a timestamp. " } ,
{ 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. " } ,
{ 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. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-06-09 00:52:24 +08:00
} ;
class CommandObjectLogDisable : public CommandObject
{
public :
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
2010-09-18 09:14:36 +08:00
CommandObjectLogDisable ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" log disable " ,
2010-10-30 05:56:41 +08:00
" Disable one or more log channel categories. " ,
2010-10-05 06:28:36 +08:00
NULL )
2010-06-09 00:52:24 +08:00
{
2010-10-30 05:56:41 +08:00
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
2010-10-05 06:28:36 +08:00
CommandArgumentData channel_arg ;
2010-10-30 05:56:41 +08:00
CommandArgumentData category_arg ;
2010-10-05 06:28:36 +08:00
// Define the first (and only) variant of this arg.
channel_arg . arg_type = eArgTypeLogChannel ;
2010-10-30 05:56:41 +08:00
channel_arg . arg_repetition = eArgRepeatPlain ;
2010-10-05 06:28:36 +08:00
// There is only one variant this argument could be; put it into the argument entry.
2010-10-30 05:56:41 +08:00
arg1 . push_back ( channel_arg ) ;
2010-10-05 06:28:36 +08:00
2010-10-30 05:56:41 +08:00
category_arg . arg_type = eArgTypeLogCategory ;
category_arg . arg_repetition = eArgRepeatPlus ;
arg2 . push_back ( category_arg ) ;
2010-10-05 06:28:36 +08:00
// Push the data for the first argument into the m_arguments vector.
2010-10-30 05:56:41 +08:00
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandObjectLogDisable ( )
{
}
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & args ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
const size_t argc = args . GetArgumentCount ( ) ;
if ( argc = = 0 )
{
2010-09-09 05:06:11 +08:00
result . AppendErrorWithFormat ( " Usage: %s \n " , m_cmd_syntax . c_str ( ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
2010-10-30 05:48:37 +08:00
Log : : Callbacks log_callbacks ;
2010-06-09 00:52:24 +08:00
2010-10-30 05:48:37 +08:00
std : : string channel ( args . GetArgumentAtIndex ( 0 ) ) ;
args . Shift ( ) ; // Shift off the channel
if ( Log : : GetLogChannelCallbacks ( channel . c_str ( ) , log_callbacks ) )
{
log_callbacks . disable ( args , & result . GetErrorStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else if ( channel = = " all " )
{
Log : : DisableAllLogChannels ( & result . GetErrorStream ( ) ) ;
}
else
{
LogChannelSP log_channel_sp ( GetLogChannelPluginForChannel ( channel . c_str ( ) ) ) ;
if ( log_channel_sp )
2010-06-09 00:52:24 +08:00
{
2010-10-30 05:48:37 +08:00
log_channel_sp - > Disable ( args , & result . GetErrorStream ( ) ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
2010-10-30 05:48:37 +08:00
result . AppendErrorWithFormat ( " Invalid log channel '%s'. \n " , args . GetArgumentAtIndex ( 0 ) ) ;
2010-06-09 00:52:24 +08:00
}
}
return result . Succeeded ( ) ;
}
} ;
class CommandObjectLogList : public CommandObject
{
public :
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
2010-09-18 09:14:36 +08:00
CommandObjectLogList ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" log list " ,
2010-10-05 06:28:36 +08:00
" List the log categories for one or more log channels. If none specified, lists them all. " ,
NULL )
2010-06-09 00:52:24 +08:00
{
2010-10-05 06:28:36 +08:00
CommandArgumentEntry arg ;
CommandArgumentData channel_arg ;
// Define the first (and only) variant of this arg.
channel_arg . arg_type = eArgTypeLogChannel ;
channel_arg . arg_repetition = eArgRepeatStar ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( channel_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandObjectLogList ( )
{
}
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & args ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
const size_t argc = args . GetArgumentCount ( ) ;
if ( argc = = 0 )
{
Log : : ListAllLogChannels ( & result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
for ( size_t i = 0 ; i < argc ; + + i )
{
Log : : Callbacks log_callbacks ;
std : : string channel ( args . GetArgumentAtIndex ( i ) ) ;
if ( Log : : GetLogChannelCallbacks ( channel . c_str ( ) , log_callbacks ) )
{
log_callbacks . list_categories ( & result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else if ( channel = = " all " )
{
Log : : ListAllLogChannels ( & result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
LogChannelSP log_channel_sp ( GetLogChannelPluginForChannel ( channel . c_str ( ) ) ) ;
if ( log_channel_sp )
{
log_channel_sp - > ListCategories ( & result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
result . AppendErrorWithFormat ( " Invalid log channel '%s'. \n " , args . GetArgumentAtIndex ( 0 ) ) ;
}
}
}
return result . Succeeded ( ) ;
}
} ;
class CommandObjectLogTimer : public CommandObject
{
public :
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
2010-09-18 09:14:36 +08:00
CommandObjectLogTimer ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" log timers " ,
2010-06-09 00:52:24 +08:00
" Enable, disable, dump, and reset LLDB internal performance timers. " ,
2010-11-05 07:19:21 +08:00
" log timers < enable <depth> | disable | dump | increment <bool> | reset > " )
2010-06-09 00:52:24 +08:00
{
}
virtual
~ CommandObjectLogTimer ( )
{
}
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & args ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
const size_t argc = args . GetArgumentCount ( ) ;
result . SetStatus ( eReturnStatusFailed ) ;
if ( argc = = 1 )
{
const char * sub_command = args . GetArgumentAtIndex ( 0 ) ;
if ( strcasecmp ( sub_command , " enable " ) = = 0 )
{
Timer : : SetDisplayDepth ( UINT32_MAX ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else if ( strcasecmp ( sub_command , " disable " ) = = 0 )
{
Timer : : DumpCategoryTimes ( & result . GetOutputStream ( ) ) ;
Timer : : SetDisplayDepth ( 0 ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else if ( strcasecmp ( sub_command , " dump " ) = = 0 )
{
Timer : : DumpCategoryTimes ( & result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else if ( strcasecmp ( sub_command , " reset " ) = = 0 )
{
Timer : : ResetCategoryTimes ( ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
}
2010-11-05 07:08:26 +08:00
else if ( argc = = 2 )
{
const char * sub_command = args . GetArgumentAtIndex ( 0 ) ;
if ( strcasecmp ( sub_command , " enable " ) = = 0 )
{
bool success ;
uint32_t depth = Args : : StringToUInt32 ( args . GetArgumentAtIndex ( 1 ) , 0 , 0 , & success ) ;
if ( success )
{
Timer : : SetDisplayDepth ( depth ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
result . AppendError ( " Could not convert enable depth to an unsigned integer. " ) ;
}
2010-11-05 07:19:21 +08:00
if ( strcasecmp ( sub_command , " increment " ) = = 0 )
{
bool success ;
bool increment = Args : : StringToBoolean ( args . GetArgumentAtIndex ( 1 ) , false , & success ) ;
if ( success )
{
Timer : : SetQuiet ( ! increment ) ;
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
result . AppendError ( " Could not convert increment value to boolean. " ) ;
}
2010-11-05 07:08:26 +08:00
}
2010-06-09 00:52:24 +08:00
if ( ! result . Succeeded ( ) )
{
result . AppendError ( " Missing subcommand " ) ;
result . AppendErrorWithFormat ( " Usage: %s \n " , m_cmd_syntax . c_str ( ) ) ;
}
return result . Succeeded ( ) ;
}
} ;
//----------------------------------------------------------------------
// CommandObjectLog constructor
//----------------------------------------------------------------------
2010-06-23 09:19:29 +08:00
CommandObjectLog : : CommandObjectLog ( CommandInterpreter & interpreter ) :
2010-09-18 09:14:36 +08:00
CommandObjectMultiword ( interpreter ,
" log " ,
2010-06-09 00:52:24 +08:00
" A set of commands for operating on logs. " ,
" log <command> [<command-options>] " )
{
2010-09-18 09:14:36 +08:00
LoadSubCommand ( " enable " , CommandObjectSP ( new CommandObjectLogEnable ( interpreter ) ) ) ;
LoadSubCommand ( " disable " , CommandObjectSP ( new CommandObjectLogDisable ( interpreter ) ) ) ;
LoadSubCommand ( " list " , CommandObjectSP ( new CommandObjectLogList ( interpreter ) ) ) ;
LoadSubCommand ( " timers " , CommandObjectSP ( new CommandObjectLogTimer ( interpreter ) ) ) ;
2010-06-09 00:52:24 +08:00
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
CommandObjectLog : : ~ CommandObjectLog ( )
{
}