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.
//
//===----------------------------------------------------------------------===//
2016-07-23 16:50:09 -04:00
# include "llvm/ADT/STLExtras.h"
# include "llvm/ADT/StringRef.h"
# include "CommandObjectExpression.h"
2017-01-02 14:26:05 -05:00
# include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
# include "lldb/Core/Debugger.h"
2013-08-23 13:46:38 -04:00
# 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/DWARFExpression.h"
2015-12-30 06:55:28 -05:00
# include "lldb/Expression/REPL.h"
2017-01-02 14:26:05 -05:00
# include "lldb/Expression/UserExpression.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Host.h"
2017-04-16 12:04:10 -04:00
# include "lldb/Host/OptionParser.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
2018-07-28 07:09:23 -04:00
# include "lldb/Interpreter/OptionArgParser.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Symbol/ObjectFile.h"
# include "lldb/Symbol/Variable.h"
2017-01-02 14:26:05 -05:00
# include "lldb/Target/Language.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/Process.h"
# include "lldb/Target/StackFrame.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
using namespace lldb ;
using namespace lldb_private ;
2017-01-02 14:26:05 -05:00
CommandObjectExpression : : CommandOptions : : CommandOptions ( ) : OptionGroup ( ) { }
2013-08-23 13:46:38 -04:00
2016-07-23 16:50:09 -04:00
CommandObjectExpression : : CommandOptions : : ~ CommandOptions ( ) = default ;
2013-08-23 13:46:38 -04:00
2019-01-19 05:06:29 -05:00
static constexpr OptionEnumValueElement g_description_verbosity_type [ ] = {
2017-01-02 14:26:05 -05:00
{ eLanguageRuntimeDescriptionDisplayVerbosityCompact , " compact " ,
" Only show the description string " } ,
{ eLanguageRuntimeDescriptionDisplayVerbosityFull , " full " ,
2019-01-19 05:06:29 -05:00
" Show the full output, including persistent variable's name and type " } } ;
2017-01-02 14:26:05 -05:00
2019-01-19 05:06:29 -05:00
static constexpr OptionEnumValues DescriptionVerbosityTypes ( ) {
return OptionEnumValues ( g_description_verbosity_type ) ;
}
static constexpr OptionDefinition g_expression_options [ ] = {
2017-01-02 14:26:05 -05:00
// clang-format off
2019-01-19 05:06:29 -05:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " all-threads " , ' a ' , OptionParser : : eRequiredArgument , nullptr , { } , 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 , nullptr , { } , 0 , eArgTypeBoolean , " Ignore breakpoint hits while running expressions " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " timeout " , ' t ' , OptionParser : : eRequiredArgument , nullptr , { } , 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 , nullptr , { } , 0 , eArgTypeBoolean , " Clean up program state if the expression causes a crash, or raises a signal. "
2017-01-02 14:26:05 -05:00
" Note, unlike gdb hitting a breakpoint is controlled by another option (-i). " } ,
2019-01-19 05:06:29 -05:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " debug " , ' g ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " When specified, debug the JIT code by setting a breakpoint on the first instruction "
2017-01-02 14:26:05 -05:00
" and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0). " } ,
2019-01-19 05:06:29 -05:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " language " , ' l ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeLanguage , " Specifies the Language to use when parsing the expression. If not set the target.language "
2017-01-02 14:26:05 -05:00
" setting is used. " } ,
2019-01-19 05:06:29 -05:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " apply-fixits " , ' X ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeLanguage , " If true, simple fix-it hints will be automatically applied to the expression. " } ,
{ LLDB_OPT_SET_1 , false , " description-verbosity " , ' v ' , OptionParser : : eOptionalArgument , nullptr , DescriptionVerbosityTypes ( ) , 0 , eArgTypeDescriptionVerbosity , " How verbose should the output of this expression be, if the object description is asked for. " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " top-level " , ' p ' , OptionParser : : eNoArgument , nullptr , { } , 0 , eArgTypeNone , " Interpret the expression as a complete translation unit, without injecting it into the local "
2017-01-02 14:26:05 -05:00
" context. Allows declaration of persistent, top-level entities without a $ prefix. " } ,
2019-01-19 05:06:29 -05:00
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " allow-jit " , ' j ' , OptionParser : : eRequiredArgument , nullptr , { } , 0 , eArgTypeBoolean , " Controls whether the expression can fall back to being JITted if it's not supported by "
2017-01-02 14:26:05 -05:00
" the interpreter (defaults to true). " }
// clang-format on
2013-08-23 13:46:38 -04:00
} ;
2017-05-16 15:47:58 -04:00
Status CommandObjectExpression : : CommandOptions : : SetOptionValue (
2017-01-02 14:26:05 -05:00
uint32_t option_idx , llvm : : StringRef option_arg ,
ExecutionContext * execution_context ) {
2017-05-16 15:47:58 -04:00
Status error ;
2017-01-02 14:26:05 -05:00
const int short_option = GetDefinitions ( ) [ option_idx ] . short_option ;
switch ( short_option ) {
case ' l ' :
language = Language : : GetLanguageTypeFromString ( option_arg ) ;
if ( language = = eLanguageTypeUnknown )
error . SetErrorStringWithFormat (
" unknown language type: '%s' for expression " ,
option_arg . str ( ) . c_str ( ) ) ;
break ;
case ' a ' : {
bool success ;
bool result ;
2018-07-28 07:09:23 -04:00
result = OptionArgParser : : ToBoolean ( option_arg , true , & success ) ;
2017-01-02 14:26:05 -05:00
if ( ! success )
error . SetErrorStringWithFormat (
" invalid all-threads value setting: \" %s \" " ,
option_arg . str ( ) . c_str ( ) ) ;
else
try_all_threads = result ;
} break ;
case ' i ' : {
bool success ;
2018-07-28 07:09:23 -04:00
bool tmp_value = OptionArgParser : : ToBoolean ( option_arg , true , & success ) ;
2017-01-02 14:26:05 -05:00
if ( success )
ignore_breakpoints = tmp_value ;
else
error . SetErrorStringWithFormat (
" could not convert \" %s \" to a boolean value. " ,
option_arg . str ( ) . c_str ( ) ) ;
break ;
}
case ' j ' : {
bool success ;
2018-07-28 07:09:23 -04:00
bool tmp_value = OptionArgParser : : ToBoolean ( option_arg , true , & success ) ;
2017-01-02 14:26:05 -05:00
if ( success )
allow_jit = tmp_value ;
else
error . SetErrorStringWithFormat (
" could not convert \" %s \" to a boolean value. " ,
option_arg . str ( ) . c_str ( ) ) ;
break ;
}
case ' t ' :
if ( option_arg . getAsInteger ( 0 , timeout ) ) {
timeout = 0 ;
error . SetErrorStringWithFormat ( " invalid timeout setting \" %s \" " ,
option_arg . str ( ) . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
break ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
case ' u ' : {
bool success ;
2018-07-28 07:09:23 -04:00
bool tmp_value = OptionArgParser : : ToBoolean ( option_arg , true , & success ) ;
2017-01-02 14:26:05 -05:00
if ( success )
unwind_on_error = tmp_value ;
2013-08-23 13:46:38 -04:00
else
2017-01-02 14:26:05 -05:00
error . SetErrorStringWithFormat (
" could not convert \" %s \" to a boolean value. " ,
option_arg . str ( ) . c_str ( ) ) ;
break ;
}
case ' v ' :
if ( option_arg . empty ( ) ) {
m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull ;
break ;
2013-08-23 13:46:38 -04:00
}
2018-07-28 07:09:23 -04:00
m_verbosity = ( LanguageRuntimeDescriptionDisplayVerbosity )
OptionArgParser : : ToOptionEnum (
2017-01-02 14:26:05 -05:00
option_arg , GetDefinitions ( ) [ option_idx ] . enum_values , 0 , error ) ;
if ( ! error . Success ( ) )
error . SetErrorStringWithFormat (
" unrecognized value for description-verbosity '%s' " ,
option_arg . str ( ) . c_str ( ) ) ;
break ;
case ' g ' :
debug = true ;
unwind_on_error = false ;
ignore_breakpoints = false ;
break ;
case ' p ' :
top_level = true ;
break ;
case ' X ' : {
bool success ;
2018-07-28 07:09:23 -04:00
bool tmp_value = OptionArgParser : : ToBoolean ( option_arg , true , & success ) ;
2017-01-02 14:26:05 -05:00
if ( success )
auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo ;
else
error . SetErrorStringWithFormat (
" could not convert \" %s \" to a boolean value. " ,
option_arg . str ( ) . c_str ( ) ) ;
break ;
}
default :
error . SetErrorStringWithFormat ( " invalid short option character '%c' " ,
short_option ) ;
break ;
}
return error ;
}
void CommandObjectExpression : : CommandOptions : : OptionParsingStarting (
ExecutionContext * execution_context ) {
auto process_sp =
execution_context ? execution_context - > GetProcessSP ( ) : ProcessSP ( ) ;
if ( process_sp ) {
ignore_breakpoints = process_sp - > GetIgnoreBreakpointsInExpressions ( ) ;
unwind_on_error = process_sp - > GetUnwindOnErrorInExpressions ( ) ;
} else {
ignore_breakpoints = true ;
unwind_on_error = true ;
}
show_summary = true ;
try_all_threads = true ;
timeout = 0 ;
debug = false ;
language = eLanguageTypeUnknown ;
m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact ;
auto_apply_fixits = eLazyBoolCalculate ;
top_level = false ;
allow_jit = true ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
llvm : : ArrayRef < OptionDefinition >
CommandObjectExpression : : CommandOptions : : GetDefinitions ( ) {
return llvm : : makeArrayRef ( g_expression_options ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
CommandObjectExpression : : CommandObjectExpression (
CommandInterpreter & interpreter )
2016-07-23 16:50:09 -04:00
: CommandObjectRaw (
2017-01-02 14:26:05 -05:00
interpreter , " expression " , " Evaluate an expression on the current "
" thread. Displays any returned value "
" with LLDB's default formatting. " ,
" " , eCommandProcessMustBePaused | eCommandTryTargetAPILock ) ,
2016-07-23 16:50:09 -04:00
IOHandlerDelegate ( IOHandlerDelegate : : Completion : : Expression ) ,
2017-01-02 14:26:05 -05:00
m_option_group ( ) , m_format_options ( eFormatDefault ) ,
m_repl_option ( LLDB_OPT_SET_1 , false , " repl " , ' r ' , " Drop into REPL " , false ,
true ) ,
m_command_options ( ) , m_expr_line_count ( 0 ) , m_expr_lines ( ) {
SetHelpLong (
R " (
2017-12-18 15:12:36 -05:00
Single and multi - line expressions :
) "
" The expression provided on the command line must be a complete expression \
with no newlines . To evaluate a multi - line expression , \
hit a return after an empty expression , and lldb will enter the multi - line expression editor . \
Hit return on an empty line to end the multi - line expression . "
R " (
2015-09-06 10:32:30 -04:00
Timeouts :
2017-01-02 14:26:05 -05:00
) "
" If the expression can be evaluated statically (without running code) then it will be. \
2015-09-06 10:32:30 -04:00
Otherwise , by default the expression will run on the current thread with a short timeout : \
currently .25 seconds . If it doesn ' t return in that time , the evaluation will be interrupted \
and resumed with all threads running . You can use the - a option to disable retrying on all \
2017-01-02 14:26:05 -05:00
threads . You can use the - t option to set a shorter timeout . "
R " (
2015-09-06 10:32:30 -04:00
User defined variables :
2017-01-02 14:26:05 -05:00
) "
" You can define your own variables for convenience or to be used in subsequent expressions. \
2015-09-06 10:32:30 -04:00
You define them the same way you would define variables in C . If the first character of \
your user defined variable is a $ , then the variable ' s value will be available in future \
2017-01-02 14:26:05 -05:00
expressions , otherwise it will just be available in the current expression . "
R " (
2015-09-06 10:32:30 -04:00
Continuing evaluation after a breakpoint :
2017-01-02 14:26:05 -05:00
) "
" If the \" -i false \" option is used, and execution is interrupted by a breakpoint hit, once \
2015-09-06 10:32:30 -04:00
you are done with your investigation , you can either remove the expression execution frames \
from the stack with \ " thread return -x \" or if you are still interested in the expression result \
you can issue the \ " continue \" command and the expression evaluation will complete and the \
expression result will be available using the \ " thread.completed-expression \" key in the thread \
2017-01-02 14:26:05 -05:00
format . "
2017-12-18 15:12:36 -05:00
2017-01-02 14:26:05 -05:00
R " (
2015-09-06 10:32:30 -04:00
Examples :
expr my_struct - > a = my_array [ 3 ]
expr - f bin - - ( index * 8 ) + 5
expr unsigned int $ foo = 5
2017-01-02 14:26:05 -05:00
expr char c [ ] = \ " foo \" ; c[0]) " ) ;
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 . Append ( & m_repl_option , LLDB_OPT_SET_ALL , LLDB_OPT_SET_3 ) ;
m_option_group . Finalize ( ) ;
2013-08-23 13:46:38 -04:00
}
2016-07-23 16:50:09 -04:00
CommandObjectExpression : : ~ CommandObjectExpression ( ) = default ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
Options * CommandObjectExpression : : GetOptions ( ) { return & m_option_group ; }
2013-08-23 13:46:38 -04:00
2019-01-19 05:06:29 -05:00
int CommandObjectExpression : : HandleCompletion ( CompletionRequest & request ) {
EvaluateExpressionOptions options ;
options . SetCoerceToId ( m_varobj_options . use_objc ) ;
options . SetLanguage ( m_command_options . language ) ;
options . SetExecutionPolicy ( lldb_private : : eExecutionPolicyNever ) ;
options . SetAutoApplyFixIts ( false ) ;
options . SetGenerateDebugInfo ( false ) ;
// We need a valid execution context with a frame pointer for this
// completion, so if we don't have one we should try to make a valid
// execution context.
if ( m_interpreter . GetExecutionContext ( ) . GetFramePtr ( ) = = nullptr )
m_interpreter . UpdateExecutionContext ( nullptr ) ;
// This didn't work, so let's get out before we start doing things that
// expect a valid frame pointer.
if ( m_interpreter . GetExecutionContext ( ) . GetFramePtr ( ) = = nullptr )
return 0 ;
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
if ( ! target )
target = GetDummyTarget ( ) ;
if ( ! target )
return 0 ;
unsigned cursor_pos = request . GetRawCursorPos ( ) ;
llvm : : StringRef code = request . GetRawLine ( ) ;
const std : : size_t original_code_size = code . size ( ) ;
// Remove the first token which is 'expr' or some alias/abbreviation of that.
code = llvm : : getToken ( code ) . second . ltrim ( ) ;
OptionsWithRaw args ( code ) ;
code = args . GetRawPart ( ) ;
// The position where the expression starts in the command line.
assert ( original_code_size > = code . size ( ) ) ;
std : : size_t raw_start = original_code_size - code . size ( ) ;
// Check if the cursor is actually in the expression string, and if not, we
// exit.
// FIXME: We should complete the options here.
if ( cursor_pos < raw_start )
return 0 ;
// Make the cursor_pos again relative to the start of the code string.
assert ( cursor_pos > = raw_start ) ;
cursor_pos - = raw_start ;
auto language = exe_ctx . GetFrameRef ( ) . GetLanguage ( ) ;
Status error ;
lldb : : UserExpressionSP expr ( target - > GetUserExpressionForLanguage (
code , llvm : : StringRef ( ) , language , UserExpression : : eResultTypeAny ,
options , error ) ) ;
if ( error . Fail ( ) )
return 0 ;
expr - > Complete ( exe_ctx , request , cursor_pos ) ;
return request . GetNumberOfMatches ( ) ;
}
2017-05-16 15:47:58 -04:00
static lldb_private : : Status
2017-01-02 14:26:05 -05:00
CanBeUsedForElementCountPrinting ( ValueObject & valobj ) {
CompilerType type ( valobj . GetCompilerType ( ) ) ;
CompilerType pointee ;
if ( ! type . IsPointerType ( & pointee ) )
2017-05-16 15:47:58 -04:00
return Status ( " as it does not refer to a pointer " ) ;
2017-01-02 14:26:05 -05:00
if ( pointee . IsVoidType ( ) )
2017-05-16 15:47:58 -04:00
return Status ( " as it refers to a pointer to void " ) ;
return Status ( ) ;
2016-07-23 16:50:09 -04:00
}
2018-07-28 07:09:23 -04:00
bool CommandObjectExpression : : EvaluateExpression ( llvm : : StringRef expr ,
2017-01-02 14:26:05 -05:00
Stream * output_stream ,
Stream * error_stream ,
CommandReturnObject * result ) {
2018-07-28 07:09:23 -04:00
// 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...
2017-01-02 14:26:05 -05:00
ExecutionContext exe_ctx ( m_interpreter . GetExecutionContext ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
if ( ! target )
target = GetDummyTarget ( ) ;
if ( target ) {
lldb : : ValueObjectSP result_valobj_sp ;
bool keep_in_memory = true ;
StackFrame * frame = exe_ctx . GetFramePtr ( ) ;
EvaluateExpressionOptions options ;
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 ) ;
options . SetLanguage ( m_command_options . language ) ;
options . SetExecutionPolicy (
m_command_options . allow_jit
? EvaluateExpressionOptions : : default_execution_policy
: lldb_private : : eExecutionPolicyNever ) ;
bool auto_apply_fixits ;
if ( m_command_options . auto_apply_fixits = = eLazyBoolCalculate )
auto_apply_fixits = target - > GetEnableAutoApplyFixIts ( ) ;
else
2019-01-19 05:06:29 -05:00
auto_apply_fixits = m_command_options . auto_apply_fixits = = eLazyBoolYes ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
options . SetAutoApplyFixIts ( auto_apply_fixits ) ;
if ( m_command_options . top_level )
options . SetExecutionPolicy ( eExecutionPolicyTopLevel ) ;
2018-07-28 07:09:23 -04: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
2017-01-02 14:26:05 -05:00
if ( ! m_command_options . ignore_breakpoints | |
! m_command_options . unwind_on_error )
options . SetGenerateDebugInfo ( true ) ;
if ( m_command_options . timeout > 0 )
options . SetTimeout ( std : : chrono : : microseconds ( m_command_options . timeout ) ) ;
2013-08-23 13:46:38 -04:00
else
2017-01-02 14:26:05 -05:00
options . SetTimeout ( llvm : : None ) ;
ExpressionResults success = target - > EvaluateExpression (
expr , frame , result_valobj_sp , options , & m_fixed_expression ) ;
// We only tell you about the FixIt if we applied it. The compiler errors
// will suggest the FixIt if it parsed.
if ( error_stream & & ! m_fixed_expression . empty ( ) & &
target - > GetEnableNotifyAboutFixIts ( ) ) {
if ( success = = eExpressionCompleted )
error_stream - > Printf (
" Fix-it applied, fixed expression was: \n %s \n " ,
m_fixed_expression . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05: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 ) ;
if ( m_varobj_options . elem_count > 0 ) {
2017-05-16 15:47:58 -04:00
Status error ( CanBeUsedForElementCountPrinting ( * result_valobj_sp ) ) ;
2017-01-02 14:26:05 -05:00
if ( error . Fail ( ) ) {
result - > AppendErrorWithFormat (
" expression cannot be used with --element-count %s \n " ,
error . AsCString ( " " ) ) ;
result - > SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
DumpValueObjectOptions options ( m_varobj_options . GetAsDumpOptions (
m_command_options . m_verbosity , format ) ) ;
options . SetVariableFormatDisplayLanguage (
result_valobj_sp - > GetPreferredDisplayLanguage ( ) ) ;
result_valobj_sp - > Dump ( * output_stream , options ) ;
2014-02-18 11:23:10 -05:00
2017-01-02 14:26:05 -05:00
if ( result )
result - > SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
} else {
if ( result_valobj_sp - > GetError ( ) . GetError ( ) = =
UserExpression : : 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 ) ;
}
}
2014-02-18 11:23:10 -05:00
}
2017-01-02 14:26:05 -05:00
} else {
error_stream - > Printf ( " error: invalid execution context for expression \n " ) ;
2016-07-23 16:50:09 -04:00
return false ;
2017-01-02 14:26:05 -05:00
}
return true ;
2014-02-18 11:23:10 -05:00
}
2017-01-02 14:26:05 -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 ( ) ;
2014-11-25 16:00:58 -05:00
}
2017-01-02 14:26:05 -05:00
bool CommandObjectExpression : : IOHandlerIsInputComplete ( IOHandler & io_handler ,
StringList & lines ) {
// An empty lines is used to indicate the end of input
const size_t num_lines = lines . GetSize ( ) ;
if ( num_lines > 0 & & lines [ num_lines - 1 ] . empty ( ) ) {
2018-07-28 07:09:23 -04:00
// Remove the last empty line from "lines" so it doesn't appear in our
// resulting input and return true to indicate we are done getting lines
2017-01-02 14:26:05 -05:00
lines . PopBack ( ) ;
return true ;
}
return false ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
void CommandObjectExpression : : GetMultilineExpression ( ) {
m_expr_lines . clear ( ) ;
m_expr_line_count = 0 ;
Debugger & debugger = GetCommandInterpreter ( ) . GetDebugger ( ) ;
bool color_prompt = debugger . GetUseColor ( ) ;
const bool multiple_lines = true ; // Get multiple lines
IOHandlerSP io_handler_sp (
new IOHandlerEditline ( debugger , IOHandler : : Type : : Expression ,
" lldb-expr " , // Name of input reader for history
llvm : : StringRef ( ) , // No prompt
llvm : : StringRef ( ) , // Continuation prompt
multiple_lines , color_prompt ,
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
2018-07-28 07:09:23 -04:00
bool CommandObjectExpression : : DoExecute ( llvm : : StringRef command ,
2017-01-02 14:26:05 -05:00
CommandReturnObject & result ) {
m_fixed_expression . clear ( ) ;
auto exe_ctx = GetCommandInterpreter ( ) . GetExecutionContext ( ) ;
m_option_group . NotifyOptionParsingStarting ( & exe_ctx ) ;
2018-07-28 07:09:23 -04:00
if ( command . empty ( ) ) {
2017-01-02 14:26:05 -05:00
GetMultilineExpression ( ) ;
return result . Succeeded ( ) ;
}
2018-07-28 07:09:23 -04:00
OptionsWithRaw args ( command ) ;
llvm : : StringRef expr = args . GetRawPart ( ) ;
if ( args . HasArgs ( ) ) {
if ( ! ParseOptionsAndNotify ( args . GetArgs ( ) , result , m_option_group , exe_ctx ) )
return false ;
if ( m_repl_option . GetOptionValue ( ) . GetCurrentValue ( ) ) {
Target * target = m_interpreter . GetExecutionContext ( ) . GetTargetPtr ( ) ;
if ( target ) {
// Drop into REPL
m_expr_lines . clear ( ) ;
m_expr_line_count = 0 ;
Debugger & debugger = target - > GetDebugger ( ) ;
// Check if the LLDB command interpreter is sitting on top of a REPL
// that launched it...
if ( debugger . CheckTopIOHandlerTypes ( IOHandler : : Type : : CommandInterpreter ,
IOHandler : : Type : : REPL ) ) {
// the LLDB command interpreter is sitting on top of a REPL that
// launched it, so just say the command interpreter is done and
// fall back to the existing REPL
m_interpreter . GetIOHandler ( false ) - > SetIsDone ( true ) ;
} else {
// We are launching the REPL on top of the current LLDB command
// interpreter, so just push one
bool initialize = false ;
Status repl_error ;
REPLSP repl_sp ( target - > GetREPL ( repl_error , m_command_options . language ,
nullptr , false ) ) ;
if ( ! repl_sp ) {
initialize = true ;
repl_sp = target - > GetREPL ( repl_error , m_command_options . language ,
nullptr , true ) ;
if ( ! repl_error . Success ( ) ) {
result . SetError ( repl_error ) ;
return result . Succeeded ( ) ;
2014-11-25 16:00:58 -05:00
}
2018-07-28 07:09:23 -04:00
}
2013-08-23 13:46:38 -04:00
2018-07-28 07:09:23 -04:00
if ( repl_sp ) {
if ( initialize ) {
repl_sp - > SetCommandOptions ( m_command_options ) ;
repl_sp - > SetFormatOptions ( m_format_options ) ;
repl_sp - > SetValueObjectDisplayOptions ( m_varobj_options ) ;
}
2017-01-02 14:26:05 -05:00
2018-07-28 07:09:23 -04:00
IOHandlerSP io_handler_sp ( repl_sp - > GetIOHandler ( ) ) ;
2017-01-02 14:26:05 -05:00
2018-07-28 07:09:23 -04:00
io_handler_sp - > SetIsDone ( false ) ;
2017-01-02 14:26:05 -05:00
2018-07-28 07:09:23 -04:00
debugger . PushIOHandler ( io_handler_sp ) ;
} else {
repl_error . SetErrorStringWithFormat (
" Couldn't create a REPL for %s " ,
Language : : GetNameForLanguageType ( m_command_options . language ) ) ;
result . SetError ( repl_error ) ;
return result . Succeeded ( ) ;
2017-01-02 14:26:05 -05:00
}
2016-07-23 16:50:09 -04:00
}
2017-01-02 14:26:05 -05:00
}
2018-07-28 07:09:23 -04:00
}
// No expression following options
else if ( expr . empty ( ) ) {
GetMultilineExpression ( ) ;
return result . Succeeded ( ) ;
2016-07-23 16:50:09 -04:00
}
2017-01-02 14:26:05 -05:00
}
2013-08-23 13:46:38 -04:00
2018-07-28 07:09:23 -04:00
Target * target = GetSelectedOrDummyTarget ( ) ;
2017-01-02 14:26:05 -05:00
if ( EvaluateExpression ( expr , & ( result . GetOutputStream ( ) ) ,
& ( result . GetErrorStream ( ) ) , & result ) ) {
if ( ! m_fixed_expression . empty ( ) & & target - > GetEnableNotifyAboutFixIts ( ) ) {
CommandHistory & history = m_interpreter . GetCommandHistory ( ) ;
// FIXME: Can we figure out what the user actually typed (e.g. some alias
// for expr???)
// If we can it would be nice to show that.
std : : string fixed_command ( " expression " ) ;
2018-07-28 07:09:23 -04:00
if ( args . HasArgs ( ) ) {
2017-01-02 14:26:05 -05:00
// Add in any options that might have been in the original command:
2018-07-28 07:09:23 -04:00
fixed_command . append ( args . GetArgStringWithDelimiter ( ) ) ;
fixed_command . append ( m_fixed_expression ) ;
} else
2017-01-02 14:26:05 -05:00
fixed_command . append ( m_fixed_expression ) ;
history . AppendString ( fixed_command ) ;
}
2018-07-28 07:09:23 -04:00
// Increment statistics to record this expression evaluation success.
target - > IncrementStats ( StatisticKind : : ExpressionSuccessful ) ;
2017-01-02 14:26:05 -05:00
return true ;
}
2018-07-28 07:09:23 -04:00
// Increment statistics to record this expression evaluation failure.
target - > IncrementStats ( StatisticKind : : ExpressionFailure ) ;
2017-01-02 14:26:05 -05:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}