2013-08-23 13:46:38 -04:00
//===-- CommandObjectExpression.cpp -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/lldb-python.h"
# include "CommandObjectExpression.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
# include "lldb/Interpreter/Args.h"
# include "lldb/Core/Value.h"
# include "lldb/Core/ValueObjectVariable.h"
2013-11-06 11:48:53 -05:00
# include "lldb/DataFormatters/ValueObjectPrinter.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Expression/ClangExpressionVariable.h"
# include "lldb/Expression/ClangUserExpression.h"
# include "lldb/Expression/ClangFunction.h"
# include "lldb/Expression/DWARFExpression.h"
# include "lldb/Host/Host.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
# include "lldb/Target/ObjCLanguageRuntime.h"
# include "lldb/Symbol/ObjectFile.h"
# include "lldb/Symbol/Variable.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/StackFrame.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
2014-11-25 16:00:58 -05:00
# include "llvm/ADT/STLExtras.h"
2013-08-23 13:46:38 -04:00
# include "llvm/ADT/StringRef.h"
using namespace lldb ;
using namespace lldb_private ;
CommandObjectExpression : : CommandOptions : : CommandOptions ( ) :
OptionGroup ( )
{
}
CommandObjectExpression : : CommandOptions : : ~ CommandOptions ( )
{
}
2013-11-06 11:48:53 -05:00
static OptionEnumValueElement g_description_verbosity_type [ ] =
{
{ eLanguageRuntimeDescriptionDisplayVerbosityCompact , " compact " , " Only show the description string " } ,
{ eLanguageRuntimeDescriptionDisplayVerbosityFull , " full " , " Show the full output, including persistent variable's name and type " } ,
{ 0 , NULL , NULL }
} ;
2013-08-23 13:46:38 -04:00
OptionDefinition
CommandObjectExpression : : CommandOptions : : g_option_table [ ] =
{
2014-11-25 16:00:58 -05:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " all-threads " , ' a ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean , " Should we run all threads if the execution doesn't complete on one thread. " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " ignore-breakpoints " , ' i ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean , " Ignore breakpoint hits while running expressions " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " timeout " , ' t ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeUnsignedInteger , " Timeout value (in microseconds) for running the expression. " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " unwind-on-error " , ' u ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeBoolean , " Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i). " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " debug " , ' g ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0). " } ,
{ LLDB_OPT_SET_1 , false , " description-verbosity " , ' v ' , OptionParser : : eOptionalArgument , NULL , g_description_verbosity_type , 0 , eArgTypeDescriptionVerbosity , " How verbose should the output of this expression be, if the object description is asked for. " } ,
2013-08-23 13:46:38 -04:00
} ;
uint32_t
CommandObjectExpression : : CommandOptions : : GetNumDefinitions ( )
{
2014-11-25 16:00:58 -05:00
return llvm : : array_lengthof ( g_option_table ) ;
2013-08-23 13:46:38 -04:00
}
Error
CommandObjectExpression : : CommandOptions : : SetOptionValue ( CommandInterpreter & interpreter ,
uint32_t option_idx ,
const char * option_arg )
{
Error error ;
const int short_option = g_option_table [ option_idx ] . short_option ;
switch ( short_option )
{
//case 'l':
//if (language.SetLanguageFromCString (option_arg) == false)
//{
// error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
//}
//break;
case ' a ' :
{
bool success ;
bool result ;
result = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( ! success )
error . SetErrorStringWithFormat ( " invalid all-threads value setting: \" %s \" " , option_arg ) ;
else
try_all_threads = result ;
}
break ;
case ' i ' :
{
bool success ;
bool tmp_value = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( success )
ignore_breakpoints = tmp_value ;
else
error . SetErrorStringWithFormat ( " could not convert \" %s \" to a boolean value. " , option_arg ) ;
break ;
}
case ' t ' :
{
bool success ;
uint32_t result ;
result = Args : : StringToUInt32 ( option_arg , 0 , 0 , & success ) ;
if ( success )
timeout = result ;
else
error . SetErrorStringWithFormat ( " invalid timeout setting \" %s \" " , option_arg ) ;
}
break ;
case ' u ' :
{
bool success ;
bool tmp_value = Args : : StringToBoolean ( option_arg , true , & success ) ;
if ( success )
unwind_on_error = tmp_value ;
else
error . SetErrorStringWithFormat ( " could not convert \" %s \" to a boolean value. " , option_arg ) ;
break ;
}
2013-11-06 11:48:53 -05:00
case ' v ' :
if ( ! option_arg )
{
m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull ;
break ;
}
m_verbosity = ( LanguageRuntimeDescriptionDisplayVerbosity ) Args : : StringToOptionEnum ( option_arg , g_option_table [ option_idx ] . enum_values , 0 , error ) ;
if ( ! error . Success ( ) )
error . SetErrorStringWithFormat ( " unrecognized value for description-verbosity '%s' " , option_arg ) ;
break ;
case ' g ' :
debug = true ;
unwind_on_error = false ;
ignore_breakpoints = false ;
break ;
2013-08-23 13:46:38 -04:00
default :
error . SetErrorStringWithFormat ( " invalid short option character '%c' " , short_option ) ;
break ;
}
return error ;
}
void
CommandObjectExpression : : CommandOptions : : OptionParsingStarting ( CommandInterpreter & interpreter )
{
Process * process = interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
if ( process ! = NULL )
{
ignore_breakpoints = process - > GetIgnoreBreakpointsInExpressions ( ) ;
unwind_on_error = process - > GetUnwindOnErrorInExpressions ( ) ;
}
else
{
2014-11-25 16:00:58 -05:00
ignore_breakpoints = true ;
2013-08-23 13:46:38 -04:00
unwind_on_error = true ;
}
show_summary = true ;
try_all_threads = true ;
timeout = 0 ;
2013-11-06 11:48:53 -05:00
debug = false ;
m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact ;
2013-08-23 13:46:38 -04:00
}
const OptionDefinition *
CommandObjectExpression : : CommandOptions : : GetDefinitions ( )
{
return g_option_table ;
}
CommandObjectExpression : : CommandObjectExpression ( CommandInterpreter & interpreter ) :
CommandObjectRaw ( interpreter ,
" expression " ,
" Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope. " ,
NULL ,
eFlagProcessMustBePaused | eFlagTryTargetAPILock ) ,
2014-02-18 11:23:10 -05:00
IOHandlerDelegate ( IOHandlerDelegate : : Completion : : Expression ) ,
2013-08-23 13:46:38 -04:00
m_option_group ( interpreter ) ,
m_format_options ( eFormatDefault ) ,
m_command_options ( ) ,
m_expr_line_count ( 0 ) ,
m_expr_lines ( )
{
SetHelpLong (
" Timeouts: \n \
2014-11-25 16:00:58 -05:00
If the expression can be evaluated statically ( without running code ) then it will be . \ n \
2013-08-23 13:46:38 -04:00
Otherwise , by default the expression will run on the current thread with a short timeout : \ n \
currently .25 seconds . If it doesn ' t return in that time , the evaluation will be interrupted \ n \
and resumed with all threads running . You can use the - a option to disable retrying on all \ n \
threads . You can use the - t option to set a shorter timeout . \ n \
\ n \
User defined variables : \ n \
You can define your own variables for convenience or to be used in subsequent expressions . \ n \
You define them the same way you would define variables in C . If the first character of \ n \
your user defined variable is a $ , then the variable ' s value will be available in future \ n \
expressions , otherwise it will just be available in the current expression . \ n \
\ n \
2014-11-25 16:00:58 -05:00
\ n \
Continuing evaluation after a breakpoint : \ n \
If the \ " -i false \" option is used, and execution is interrupted by a breakpoint hit, once \n \
you are done with your investigation , you can either remove the expression execution frames \ n \
from the stack with \ " thread return -x \" or if you are still interested in the expression result \n \
you can issue the \ " continue \" command and the expression evaluation will complete and the \n \
expression result will be available using the \ " thread.completed-expression \" key in the thread \n \
format . \ n \
\ n \
2013-08-23 13:46:38 -04:00
Examples : \ n \
\ n \
expr my_struct - > a = my_array [ 3 ] \ n \
expr - f bin - - ( index * 8 ) + 5 \ n \
expr unsigned int $ foo = 5 \ n \
expr char c [ ] = \ " foo \" ; c[0] \n " ) ;
CommandArgumentEntry arg ;
CommandArgumentData expression_arg ;
// Define the first (and only) variant of this arg.
expression_arg . arg_type = eArgTypeExpression ;
expression_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg . push_back ( expression_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg ) ;
// Add the "--format" and "--gdb-format"
m_option_group . Append ( & m_format_options , OptionGroupFormat : : OPTION_GROUP_FORMAT | OptionGroupFormat : : OPTION_GROUP_GDB_FMT , LLDB_OPT_SET_1 ) ;
m_option_group . Append ( & m_command_options ) ;
m_option_group . Append ( & m_varobj_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 | LLDB_OPT_SET_2 ) ;
m_option_group . Finalize ( ) ;
}
CommandObjectExpression : : ~ CommandObjectExpression ( )
{
}
Options *
CommandObjectExpression : : GetOptions ( )
{
return & m_option_group ;
}
bool
CommandObjectExpression : : EvaluateExpression
(
const char * expr ,
Stream * output_stream ,
Stream * error_stream ,
CommandReturnObject * result
)
{
// Don't use m_exe_ctx as this might be called asynchronously
// after the command object DoExecute has finished when doing
// multi-line expression that use an input reader...
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
if ( ! target )
2015-02-06 16:38:51 -05:00
target = GetDummyTarget ( ) ;
2013-08-23 13:46:38 -04:00
if ( target )
{
lldb : : ValueObjectSP result_valobj_sp ;
bool keep_in_memory = true ;
EvaluateExpressionOptions options ;
2013-12-03 13:51:59 -05:00
options . SetCoerceToId ( m_varobj_options . use_objc ) ;
options . SetUnwindOnError ( m_command_options . unwind_on_error ) ;
options . SetIgnoreBreakpoints ( m_command_options . ignore_breakpoints ) ;
options . SetKeepInMemory ( keep_in_memory ) ;
options . SetUseDynamic ( m_varobj_options . use_dynamic ) ;
options . SetTryAllThreads ( m_command_options . try_all_threads ) ;
options . SetDebug ( m_command_options . debug ) ;
2013-11-06 11:48:53 -05:00
2014-11-25 16:00:58 -05:00
// If there is any chance we are going to stop and want to see
// what went wrong with our expression, we should generate debug info
if ( ! m_command_options . ignore_breakpoints | |
! m_command_options . unwind_on_error )
options . SetGenerateDebugInfo ( true ) ;
2013-11-06 11:48:53 -05:00
if ( m_command_options . timeout > 0 )
options . SetTimeoutUsec ( m_command_options . timeout ) ;
2014-02-18 11:23:10 -05:00
else
options . SetTimeoutUsec ( 0 ) ;
2014-11-25 16:00:58 -05:00
target - > EvaluateExpression ( expr , exe_ctx . GetFramePtr ( ) ,
result_valobj_sp , options ) ;
2013-08-23 13:46:38 -04:00
if ( result_valobj_sp )
{
Format format = m_format_options . GetFormat ( ) ;
if ( result_valobj_sp - > GetError ( ) . Success ( ) )
{
if ( format ! = eFormatVoid )
{
if ( format ! = eFormatDefault )
result_valobj_sp - > SetFormat ( format ) ;
2013-11-06 11:48:53 -05:00
DumpValueObjectOptions options ( m_varobj_options . GetAsDumpOptions ( m_command_options . m_verbosity , format ) ) ;
2013-08-23 13:46:38 -04:00
2013-11-06 11:48:53 -05:00
result_valobj_sp - > Dump ( * output_stream , options ) ;
2013-08-23 13:46:38 -04:00
if ( result )
result - > SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
}
else
{
if ( result_valobj_sp - > GetError ( ) . GetError ( ) = = ClangUserExpression : : kNoResult )
{
if ( format ! = eFormatVoid & & m_interpreter . GetDebugger ( ) . GetNotifyVoid ( ) )
{
error_stream - > PutCString ( " (void) \n " ) ;
}
if ( result )
result - > SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
const char * error_cstr = result_valobj_sp - > GetError ( ) . AsCString ( ) ;
if ( error_cstr & & error_cstr [ 0 ] )
{
const size_t error_cstr_len = strlen ( error_cstr ) ;
const bool ends_with_newline = error_cstr [ error_cstr_len - 1 ] = = ' \n ' ;
if ( strstr ( error_cstr , " error: " ) ! = error_cstr )
error_stream - > PutCString ( " error: " ) ;
error_stream - > Write ( error_cstr , error_cstr_len ) ;
if ( ! ends_with_newline )
error_stream - > EOL ( ) ;
}
else
{
error_stream - > PutCString ( " error: unknown error \n " ) ;
}
if ( result )
result - > SetStatus ( eReturnStatusFailed ) ;
}
}
}
}
else
{
error_stream - > Printf ( " error: invalid execution context for expression \n " ) ;
return false ;
}
return true ;
}
2014-02-18 11:23:10 -05:00
void
CommandObjectExpression : : IOHandlerInputComplete ( IOHandler & io_handler , std : : string & line )
{
io_handler . SetIsDone ( true ) ;
// StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream();
// StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
StreamFileSP output_sp ( io_handler . GetOutputStreamFile ( ) ) ;
StreamFileSP error_sp ( io_handler . GetErrorStreamFile ( ) ) ;
EvaluateExpression ( line . c_str ( ) ,
output_sp . get ( ) ,
error_sp . get ( ) ) ;
if ( output_sp )
output_sp - > Flush ( ) ;
if ( error_sp )
error_sp - > Flush ( ) ;
}
LineStatus
CommandObjectExpression : : IOHandlerLinesUpdated ( IOHandler & io_handler ,
StringList & lines ,
uint32_t line_idx ,
Error & error )
{
if ( line_idx = = UINT32_MAX )
{
// Remove the last line from "lines" so it doesn't appear
// in our final expression
lines . PopBack ( ) ;
error . Clear ( ) ;
return LineStatus : : Done ;
}
else if ( line_idx + 1 = = lines . GetSize ( ) )
{
// The last line was edited, if this line is empty, then we are done
// getting our multiple lines.
if ( lines [ line_idx ] . empty ( ) )
return LineStatus : : Done ;
}
return LineStatus : : Success ;
}
2014-11-25 16:00:58 -05:00
void
CommandObjectExpression : : GetMultilineExpression ( )
{
m_expr_lines . clear ( ) ;
m_expr_line_count = 0 ;
Debugger & debugger = GetCommandInterpreter ( ) . GetDebugger ( ) ;
2015-02-06 16:38:51 -05:00
bool color_prompt = debugger . GetUseColor ( ) ;
2014-11-25 16:00:58 -05:00
const bool multiple_lines = true ; // Get multiple lines
IOHandlerSP io_handler_sp ( new IOHandlerEditline ( debugger ,
2015-02-06 16:38:51 -05:00
IOHandler : : Type : : Expression ,
2014-11-25 16:00:58 -05:00
" lldb-expr " , // Name of input reader for history
NULL , // No prompt
2015-02-06 16:38:51 -05:00
NULL , // Continuation prompt
2014-11-25 16:00:58 -05:00
multiple_lines ,
2015-02-06 16:38:51 -05:00
color_prompt ,
2014-11-25 16:00:58 -05:00
1 , // Show line numbers starting at 1
* this ) ) ;
StreamFileSP output_sp ( io_handler_sp - > GetOutputStreamFile ( ) ) ;
if ( output_sp )
{
output_sp - > PutCString ( " Enter expressions, then terminate with an empty line to evaluate: \n " ) ;
output_sp - > Flush ( ) ;
}
debugger . PushIOHandler ( io_handler_sp ) ;
}
2013-08-23 13:46:38 -04:00
bool
CommandObjectExpression : : DoExecute
(
const char * command ,
CommandReturnObject & result
)
{
m_option_group . NotifyOptionParsingStarting ( ) ;
const char * expr = NULL ;
if ( command [ 0 ] = = ' \0 ' )
{
2014-11-25 16:00:58 -05:00
GetMultilineExpression ( ) ;
2013-08-23 13:46:38 -04:00
return result . Succeeded ( ) ;
}
if ( command [ 0 ] = = ' - ' )
{
// We have some options and these options MUST end with --.
const char * end_options = NULL ;
const char * s = command ;
while ( s & & s [ 0 ] )
{
end_options = : : strstr ( s , " -- " ) ;
if ( end_options )
{
end_options + = 2 ; // Get past the "--"
if ( : : isspace ( end_options [ 0 ] ) )
{
expr = end_options ;
while ( : : isspace ( * expr ) )
+ + expr ;
break ;
}
}
s = end_options ;
}
if ( end_options )
{
Args args ( command , end_options - command ) ;
if ( ! ParseOptions ( args , result ) )
return false ;
Error error ( m_option_group . NotifyOptionParsingFinished ( ) ) ;
if ( error . Fail ( ) )
{
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2014-11-25 16:00:58 -05:00
// No expression following options
if ( expr = = NULL | | expr [ 0 ] = = ' \0 ' )
{
GetMultilineExpression ( ) ;
return result . Succeeded ( ) ;
}
2013-08-23 13:46:38 -04:00
}
}
if ( expr = = NULL )
expr = command ;
if ( EvaluateExpression ( expr , & ( result . GetOutputStream ( ) ) , & ( result . GetErrorStream ( ) ) , & result ) )
return true ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}