2013-08-23 13:46:38 -04:00
//===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "CommandObjectFrame.h"
// C Includes
// C++ Includes
# include <string>
// Other libraries and framework includes
// Project includes
# include "lldb/Core/Debugger.h"
# include "lldb/Core/Module.h"
# include "lldb/Core/StreamFile.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Core/Timer.h"
# include "lldb/Core/Value.h"
# include "lldb/Core/ValueObject.h"
# include "lldb/Core/ValueObjectVariable.h"
# include "lldb/DataFormatters/DataVisualization.h"
2013-11-06 11:48:53 -05:00
# include "lldb/DataFormatters/ValueObjectPrinter.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Host.h"
2015-02-08 20:44:09 -05:00
# include "lldb/Host/StringConvert.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/Args.h"
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
# include "lldb/Interpreter/Options.h"
# include "lldb/Interpreter/OptionGroupFormat.h"
# include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
# include "lldb/Interpreter/OptionGroupVariable.h"
# include "lldb/Symbol/ClangASTType.h"
# include "lldb/Symbol/ClangASTContext.h"
# include "lldb/Symbol/ObjectFile.h"
# include "lldb/Symbol/SymbolContext.h"
# include "lldb/Symbol/Type.h"
# include "lldb/Symbol/Variable.h"
# include "lldb/Symbol/VariableList.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/StackFrame.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/Target.h"
using namespace lldb ;
using namespace lldb_private ;
# pragma mark CommandObjectFrameInfo
//-------------------------------------------------------------------------
// CommandObjectFrameInfo
//-------------------------------------------------------------------------
class CommandObjectFrameInfo : public CommandObjectParsed
{
public :
CommandObjectFrameInfo ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" frame info " ,
" List information about the currently selected frame in the current thread. " ,
" frame info " ,
2015-07-03 12:57:06 -04:00
eCommandRequiresFrame |
eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused )
2013-08-23 13:46:38 -04:00
{
}
~ CommandObjectFrameInfo ( )
{
}
protected :
bool
DoExecute ( Args & command , CommandReturnObject & result )
{
m_exe_ctx . GetFrameRef ( ) . DumpUsingSettingsFormat ( & result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return result . Succeeded ( ) ;
}
} ;
# pragma mark CommandObjectFrameSelect
//-------------------------------------------------------------------------
// CommandObjectFrameSelect
//-------------------------------------------------------------------------
class CommandObjectFrameSelect : public CommandObjectParsed
{
public :
class CommandOptions : public Options
{
public :
CommandOptions ( CommandInterpreter & interpreter ) :
Options ( interpreter )
{
OptionParsingStarting ( ) ;
}
virtual
~ CommandOptions ( )
{
}
virtual Error
SetOptionValue ( uint32_t option_idx , const char * option_arg )
{
Error error ;
bool success = false ;
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' r ' :
2015-02-08 20:44:09 -05:00
relative_frame_offset = StringConvert : : ToSInt32 ( option_arg , INT32_MIN , 0 , & success ) ;
2013-08-23 13:46:38 -04:00
if ( ! success )
error . SetErrorStringWithFormat ( " invalid frame offset argument '%s' " , option_arg ) ;
break ;
default :
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
break ;
}
return error ;
}
void
OptionParsingStarting ( )
{
relative_frame_offset = INT32_MIN ;
}
const OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table [ ] ;
int32_t relative_frame_offset ;
} ;
CommandObjectFrameSelect ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" frame select " ,
" Select a frame by index from within the current thread and make it the current frame. " ,
NULL ,
2015-07-03 12:57:06 -04:00
eCommandRequiresThread |
eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused ) ,
2013-08-23 13:46:38 -04:00
m_options ( interpreter )
{
CommandArgumentEntry arg ;
CommandArgumentData index_arg ;
// Define the first (and only) variant of this arg.
index_arg . arg_type = eArgTypeFrameIndex ;
index_arg . arg_repetition = eArgRepeatOptional ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( index_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
}
~ CommandObjectFrameSelect ( )
{
}
virtual
Options *
GetOptions ( )
{
return & m_options ;
}
protected :
bool
DoExecute ( Args & command , CommandReturnObject & result )
{
2015-07-03 12:57:06 -04:00
// No need to check "thread" for validity as eCommandRequiresThread ensures it is valid
2013-08-23 13:46:38 -04:00
Thread * thread = m_exe_ctx . GetThreadPtr ( ) ;
uint32_t frame_idx = UINT32_MAX ;
if ( m_options . relative_frame_offset ! = INT32_MIN )
{
// The one and only argument is a signed relative frame index
frame_idx = thread - > GetSelectedFrameIndex ( ) ;
if ( frame_idx = = UINT32_MAX )
frame_idx = 0 ;
if ( m_options . relative_frame_offset < 0 )
{
2014-11-25 16:00:58 -05:00
if ( static_cast < int32_t > ( frame_idx ) > = - m_options . relative_frame_offset )
2013-08-23 13:46:38 -04:00
frame_idx + = m_options . relative_frame_offset ;
else
{
if ( frame_idx = = 0 )
{
//If you are already at the bottom of the stack, then just warn and don't reset the frame.
result . AppendError ( " Already at the bottom of the stack " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
frame_idx = 0 ;
}
}
else if ( m_options . relative_frame_offset > 0 )
{
// I don't want "up 20" where "20" takes you past the top of the stack to produce
// an error, but rather to just go to the top. So I have to count the stack here...
const uint32_t num_frames = thread - > GetStackFrameCount ( ) ;
2014-11-25 16:00:58 -05:00
if ( static_cast < int32_t > ( num_frames - frame_idx ) > m_options . relative_frame_offset )
2013-08-23 13:46:38 -04:00
frame_idx + = m_options . relative_frame_offset ;
else
{
if ( frame_idx = = num_frames - 1 )
{
//If we are already at the top of the stack, just warn and don't reset the frame.
result . AppendError ( " Already at the top of the stack " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
frame_idx = num_frames - 1 ;
}
}
}
else
{
if ( command . GetArgumentCount ( ) = = 1 )
{
const char * frame_idx_cstr = command . GetArgumentAtIndex ( 0 ) ;
2013-11-06 11:48:53 -05:00
bool success = false ;
2015-02-08 20:44:09 -05:00
frame_idx = StringConvert : : ToUInt32 ( frame_idx_cstr , UINT32_MAX , 0 , & success ) ;
2013-11-06 11:48:53 -05:00
if ( ! success )
{
result . AppendErrorWithFormat ( " invalid frame index argument '%s' " , frame_idx_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-08-23 13:46:38 -04:00
}
else if ( command . GetArgumentCount ( ) = = 0 )
{
frame_idx = thread - > GetSelectedFrameIndex ( ) ;
if ( frame_idx = = UINT32_MAX )
{
frame_idx = 0 ;
}
}
else
{
result . AppendError ( " invalid arguments. \n " ) ;
m_options . GenerateOptionUsage ( result . GetErrorStream ( ) , this ) ;
}
}
bool success = thread - > SetSelectedFrameByIndexNoisily ( frame_idx , result . GetOutputStream ( ) ) ;
if ( success )
{
m_exe_ctx . SetFrameSP ( thread - > GetSelectedFrame ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Frame index (%u) out of range. \n " , frame_idx ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
protected :
CommandOptions m_options ;
} ;
OptionDefinition
CommandObjectFrameSelect : : CommandOptions : : g_option_table [ ] =
{
2014-11-25 16:00:58 -05:00
{ LLDB_OPT_SET_1 , false , " relative " , ' r ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeOffset , " A relative frame index offset from the current frame index. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , NULL , 0 , eArgTypeNone , NULL }
2013-08-23 13:46:38 -04:00
} ;
# pragma mark CommandObjectFrameVariable
//----------------------------------------------------------------------
// List images with associated information
//----------------------------------------------------------------------
class CommandObjectFrameVariable : public CommandObjectParsed
{
public :
CommandObjectFrameVariable ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" frame variable " ,
" Show frame variables. All argument and local variables "
" that are in scope will be shown when no arguments are given. "
" If any arguments are specified, they can be names of "
" argument, local, file static and file global variables. "
" Children of aggregate variables can be specified such as "
" 'var->child.x'. " ,
NULL ,
2015-07-03 12:57:06 -04:00
eCommandRequiresFrame |
eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused |
eCommandRequiresProcess ) ,
2013-08-23 13:46:38 -04:00
m_option_group ( interpreter ) ,
m_option_variable ( true ) , // Include the frame specific options by passing "true"
m_option_format ( eFormatDefault ) ,
m_varobj_options ( )
{
CommandArgumentEntry arg ;
CommandArgumentData var_name_arg ;
// Define the first (and only) variant of this arg.
var_name_arg . arg_type = eArgTypeVarName ;
var_name_arg . arg_repetition = eArgRepeatStar ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( var_name_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
m_option_group . Append ( & m_option_variable , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 ) ;
m_option_group . Append ( & m_option_format , OptionGroupFormat : : OPTION_GROUP_FORMAT | OptionGroupFormat : : OPTION_GROUP_GDB_FMT , LLDB_OPT_SET_1 ) ;
m_option_group . Append ( & m_varobj_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 ) ;
m_option_group . Finalize ( ) ;
}
virtual
~ CommandObjectFrameVariable ( )
{
}
virtual
Options *
GetOptions ( )
{
return & m_option_group ;
}
virtual int
HandleArgumentCompletion ( Args & input ,
int & cursor_index ,
int & cursor_char_position ,
OptionElementVector & opt_element_vector ,
int match_start_point ,
int max_return_elements ,
bool & word_complete ,
StringList & matches )
{
// Arguments are the standard source file completer.
std : : string completion_str ( input . GetArgumentAtIndex ( cursor_index ) ) ;
completion_str . erase ( cursor_char_position ) ;
CommandCompletions : : InvokeCommonCompletionCallbacks ( m_interpreter ,
CommandCompletions : : eVariablePathCompletion ,
completion_str . c_str ( ) ,
match_start_point ,
max_return_elements ,
NULL ,
word_complete ,
matches ) ;
return matches . GetSize ( ) ;
}
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
2015-07-03 12:57:06 -04:00
// No need to check "frame" for validity as eCommandRequiresFrame ensures it is valid
2013-08-23 13:46:38 -04:00
StackFrame * frame = m_exe_ctx . GetFramePtr ( ) ;
Stream & s = result . GetOutputStream ( ) ;
bool get_file_globals = true ;
// Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList
// for the thread. So hold onto a shared pointer to the frame so it stays alive.
VariableList * variable_list = frame - > GetVariableList ( get_file_globals ) ;
VariableSP var_sp ;
ValueObjectSP valobj_sp ;
const char * name_cstr = NULL ;
size_t idx ;
TypeSummaryImplSP summary_format_sp ;
if ( ! m_option_variable . summary . IsCurrentValueEmpty ( ) )
DataVisualization : : NamedSummaryFormats : : GetSummaryFormat ( ConstString ( m_option_variable . summary . GetCurrentValue ( ) ) , summary_format_sp ) ;
else if ( ! m_option_variable . summary_string . IsCurrentValueEmpty ( ) )
summary_format_sp . reset ( new StringSummaryFormat ( TypeSummaryImpl : : Flags ( ) , m_option_variable . summary_string . GetCurrentValue ( ) ) ) ;
2013-11-06 11:48:53 -05:00
DumpValueObjectOptions options ( m_varobj_options . GetAsDumpOptions ( eLanguageRuntimeDescriptionDisplayVerbosityFull , eFormatDefault , summary_format_sp ) ) ;
2013-08-23 13:46:38 -04:00
if ( variable_list )
{
const Format format = m_option_format . GetFormat ( ) ;
options . SetFormat ( format ) ;
if ( command . GetArgumentCount ( ) > 0 )
{
VariableList regex_var_list ;
// If we have any args to the variable command, we will make
// variable objects from them...
for ( idx = 0 ; ( name_cstr = command . GetArgumentAtIndex ( idx ) ) ! = NULL ; + + idx )
{
if ( m_option_variable . use_regex )
{
const size_t regex_start_index = regex_var_list . GetSize ( ) ;
RegularExpression regex ( name_cstr ) ;
if ( regex . Compile ( name_cstr ) )
{
size_t num_matches = 0 ;
const size_t num_new_regex_vars = variable_list - > AppendVariablesIfUnique ( regex ,
regex_var_list ,
num_matches ) ;
if ( num_new_regex_vars > 0 )
{
for ( size_t regex_idx = regex_start_index , end_index = regex_var_list . GetSize ( ) ;
regex_idx < end_index ;
+ + regex_idx )
{
var_sp = regex_var_list . GetVariableAtIndex ( regex_idx ) ;
if ( var_sp )
{
valobj_sp = frame - > GetValueObjectForFrameVariable ( var_sp , m_varobj_options . use_dynamic ) ;
if ( valobj_sp )
{
// if (format != eFormatDefault)
// valobj_sp->SetFormat (format);
if ( m_option_variable . show_decl & & var_sp - > GetDeclaration ( ) . GetFile ( ) )
{
bool show_fullpaths = false ;
bool show_module = true ;
if ( var_sp - > DumpDeclaration ( & s , show_fullpaths , show_module ) )
s . PutCString ( " : " ) ;
}
2013-11-06 11:48:53 -05:00
valobj_sp - > Dump ( result . GetOutputStream ( ) , options ) ;
2013-08-23 13:46:38 -04:00
}
}
}
}
else if ( num_matches = = 0 )
{
result . GetErrorStream ( ) . Printf ( " error: no variables matched the regular expression '%s'. \n " , name_cstr ) ;
}
}
else
{
char regex_error [ 1024 ] ;
if ( regex . GetErrorAsCString ( regex_error , sizeof ( regex_error ) ) )
result . GetErrorStream ( ) . Printf ( " error: %s \n " , regex_error ) ;
else
2014-11-25 16:00:58 -05:00
result . GetErrorStream ( ) . Printf ( " error: unknown regex error when compiling '%s' \n " , name_cstr ) ;
2013-08-23 13:46:38 -04:00
}
}
else // No regex, either exact variable names or variable expressions.
{
Error error ;
uint32_t expr_path_options = StackFrame : : eExpressionPathOptionCheckPtrVsMember |
StackFrame : : eExpressionPathOptionsAllowDirectIVarAccess ;
lldb : : VariableSP var_sp ;
valobj_sp = frame - > GetValueForVariableExpressionPath ( name_cstr ,
m_varobj_options . use_dynamic ,
expr_path_options ,
var_sp ,
error ) ;
if ( valobj_sp )
{
// if (format != eFormatDefault)
// valobj_sp->SetFormat (format);
if ( m_option_variable . show_decl & & var_sp & & var_sp - > GetDeclaration ( ) . GetFile ( ) )
{
var_sp - > GetDeclaration ( ) . DumpStopContext ( & s , false ) ;
s . PutCString ( " : " ) ;
}
options . SetFormat ( format ) ;
Stream & output_stream = result . GetOutputStream ( ) ;
options . SetRootValueObjectName ( valobj_sp - > GetParent ( ) ? name_cstr : NULL ) ;
2013-11-06 11:48:53 -05:00
valobj_sp - > Dump ( output_stream , options ) ;
2013-08-23 13:46:38 -04:00
}
else
{
const char * error_cstr = error . AsCString ( NULL ) ;
if ( error_cstr )
result . GetErrorStream ( ) . Printf ( " error: %s \n " , error_cstr ) ;
else
result . GetErrorStream ( ) . Printf ( " error: unable to find any variable expression path that matches '%s' \n " , name_cstr ) ;
}
}
}
}
else // No command arg specified. Use variable_list, instead.
{
const size_t num_variables = variable_list - > GetSize ( ) ;
if ( num_variables > 0 )
{
for ( size_t i = 0 ; i < num_variables ; i + + )
{
var_sp = variable_list - > GetVariableAtIndex ( i ) ;
bool dump_variable = true ;
2015-07-03 12:57:06 -04:00
std : : string scope_string ;
2013-08-23 13:46:38 -04:00
switch ( var_sp - > GetScope ( ) )
{
case eValueTypeVariableGlobal :
dump_variable = m_option_variable . show_globals ;
if ( dump_variable & & m_option_variable . show_scope )
2015-07-03 12:57:06 -04:00
scope_string = " GLOBAL: " ;
2013-08-23 13:46:38 -04:00
break ;
case eValueTypeVariableStatic :
dump_variable = m_option_variable . show_globals ;
if ( dump_variable & & m_option_variable . show_scope )
2015-07-03 12:57:06 -04:00
scope_string = " STATIC: " ;
2013-08-23 13:46:38 -04:00
break ;
case eValueTypeVariableArgument :
dump_variable = m_option_variable . show_args ;
if ( dump_variable & & m_option_variable . show_scope )
2015-07-03 12:57:06 -04:00
scope_string = " ARG: " ;
2013-08-23 13:46:38 -04:00
break ;
case eValueTypeVariableLocal :
dump_variable = m_option_variable . show_locals ;
if ( dump_variable & & m_option_variable . show_scope )
2015-07-03 12:57:06 -04:00
scope_string = " LOCAL: " ;
2013-08-23 13:46:38 -04:00
break ;
default :
break ;
}
if ( dump_variable )
{
// Use the variable object code to make sure we are
2015-07-03 12:57:06 -04:00
// using the same APIs as the public API will be
2013-08-23 13:46:38 -04:00
// using...
valobj_sp = frame - > GetValueObjectForFrameVariable ( var_sp ,
m_varobj_options . use_dynamic ) ;
if ( valobj_sp )
{
// if (format != eFormatDefault)
// valobj_sp->SetFormat (format);
// When dumping all variables, don't print any variables
// that are not in scope to avoid extra unneeded output
if ( valobj_sp - > IsInScope ( ) )
{
2015-07-03 12:57:06 -04:00
if ( false = = valobj_sp - > GetTargetSP ( ) - > GetDisplayRuntimeSupportValues ( ) & &
true = = valobj_sp - > IsRuntimeSupportValue ( ) )
continue ;
if ( ! scope_string . empty ( ) )
s . PutCString ( scope_string . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
if ( m_option_variable . show_decl & & var_sp - > GetDeclaration ( ) . GetFile ( ) )
{
var_sp - > GetDeclaration ( ) . DumpStopContext ( & s , false ) ;
s . PutCString ( " : " ) ;
}
options . SetFormat ( format ) ;
options . SetRootValueObjectName ( name_cstr ) ;
2013-11-06 11:48:53 -05:00
valobj_sp - > Dump ( result . GetOutputStream ( ) , options ) ;
2013-08-23 13:46:38 -04:00
}
}
}
}
}
}
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
if ( m_interpreter . TruncationWarningNecessary ( ) )
{
result . GetOutputStream ( ) . Printf ( m_interpreter . TruncationWarningText ( ) ,
m_cmd_name . c_str ( ) ) ;
m_interpreter . TruncationWarningGiven ( ) ;
}
return result . Succeeded ( ) ;
}
protected :
OptionGroupOptions m_option_group ;
OptionGroupVariable m_option_variable ;
OptionGroupFormat m_option_format ;
OptionGroupValueObjectDisplay m_varobj_options ;
} ;
# pragma mark CommandObjectMultiwordFrame
//-------------------------------------------------------------------------
// CommandObjectMultiwordFrame
//-------------------------------------------------------------------------
CommandObjectMultiwordFrame : : CommandObjectMultiwordFrame ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( interpreter ,
" frame " ,
" A set of commands for operating on the current thread's frames. " ,
" frame <subcommand> [<subcommand-options>] " )
{
LoadSubCommand ( " info " , CommandObjectSP ( new CommandObjectFrameInfo ( interpreter ) ) ) ;
LoadSubCommand ( " select " , CommandObjectSP ( new CommandObjectFrameSelect ( interpreter ) ) ) ;
LoadSubCommand ( " variable " , CommandObjectSP ( new CommandObjectFrameVariable ( interpreter ) ) ) ;
}
CommandObjectMultiwordFrame : : ~ CommandObjectMultiwordFrame ( )
{
}