2010-06-09 00:52:24 +08: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 "CommandObjectExpression.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
2010-07-23 08:16:21 +08:00
# include "lldb/Interpreter/Args.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Value.h"
# include "lldb/Core/InputReader.h"
# include "lldb/Expression/ClangExpression.h"
# include "lldb/Expression/ClangExpressionDeclMap.h"
# include "lldb/Expression/ClangExpressionVariable.h"
2010-08-11 11:57:18 +08:00
# include "lldb/Expression/ClangPersistentVariables.h"
2010-07-24 05:47:22 +08:00
# include "lldb/Expression/ClangFunction.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Expression/DWARFExpression.h"
# include "lldb/Host/Host.h"
2010-07-23 08:16:21 +08:00
# include "lldb/Core/Debugger.h"
2010-06-23 09:19:29 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandReturnObject.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"
2010-07-23 08:16:21 +08:00
# include "llvm/ADT/StringRef.h"
2010-06-09 00:52:24 +08:00
using namespace lldb ;
using namespace lldb_private ;
CommandObjectExpression : : CommandOptions : : CommandOptions ( ) :
Options ( )
{
// Keep only one place to reset the values to their defaults
ResetOptionValues ( ) ;
}
CommandObjectExpression : : CommandOptions : : ~ CommandOptions ( )
{
}
Error
CommandObjectExpression : : CommandOptions : : SetOptionValue ( int option_idx , const char * option_arg )
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' l ' :
if ( language . SetLanguageFromCString ( option_arg ) = = false )
{
error . SetErrorStringWithFormat ( " Invalid language option argument '%s'. \n " , option_arg ) ;
}
break ;
case ' g ' :
debug = true ;
break ;
case ' f ' :
error = Args : : StringToFormat ( option_arg , format ) ;
break ;
default :
error . SetErrorStringWithFormat ( " Invalid short option character '%c'. \n " , short_option ) ;
break ;
}
return error ;
}
void
CommandObjectExpression : : CommandOptions : : ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
language . Clear ( ) ;
debug = false ;
format = eFormatDefault ;
show_types = true ;
show_summary = true ;
}
const lldb : : OptionDefinition *
CommandObjectExpression : : CommandOptions : : GetDefinitions ( )
{
return g_option_table ;
}
CommandObjectExpression : : CommandObjectExpression ( ) :
CommandObject (
" expression " ,
" Evaluate a C expression in the current program context, using variables currently in scope. " ,
" expression [<cmd-options>] <expr> " ) ,
m_expr_line_count ( 0 ) ,
m_expr_lines ( )
{
SetHelpLong (
" Examples: \n \
\ n \
expr my_struct - > a = my_array [ 3 ] \ n \
expr - f bin - - ( index * 8 ) + 5 \ n \
expr char c [ ] = \ " foo \" ; c[0] \n " ) ;
}
CommandObjectExpression : : ~ CommandObjectExpression ( )
{
}
Options *
CommandObjectExpression : : GetOptions ( )
{
return & m_options ;
}
bool
CommandObjectExpression : : Execute
(
2010-06-23 09:19:29 +08:00
CommandInterpreter & interpreter ,
2010-06-09 00:52:24 +08:00
Args & command ,
CommandReturnObject & result
)
{
return false ;
}
size_t
CommandObjectExpression : : MultiLineExpressionCallback
(
void * baton ,
2010-06-23 09:19:29 +08:00
InputReader & reader ,
2010-06-09 00:52:24 +08:00
lldb : : InputReaderAction notification ,
const char * bytes ,
size_t bytes_len
)
{
CommandObjectExpression * cmd_object_expr = ( CommandObjectExpression * ) baton ;
switch ( notification )
{
case eInputReaderActivate :
2010-06-23 09:19:29 +08:00
reader . GetDebugger ( ) . GetOutputStream ( ) . Printf ( " %s \n " , " Enter expressions, then terminate with an empty line to evaluate: " ) ;
2010-06-09 00:52:24 +08:00
// Fall through
case eInputReaderReactivate :
//if (out_fh)
2010-06-23 09:19:29 +08:00
// reader.GetDebugger().GetOutputStream().Printf ("%3u: ", cmd_object_expr->m_expr_line_count);
2010-06-09 00:52:24 +08:00
break ;
case eInputReaderDeactivate :
break ;
case eInputReaderGotToken :
+ + cmd_object_expr - > m_expr_line_count ;
if ( bytes & & bytes_len )
{
cmd_object_expr - > m_expr_lines . append ( bytes , bytes_len + 1 ) ;
}
if ( bytes_len = = 0 )
2010-06-23 09:19:29 +08:00
reader . SetIsDone ( true ) ;
2010-06-09 00:52:24 +08:00
//else if (out_fh && !reader->IsDone())
// ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
break ;
case eInputReaderDone :
{
bool bare = false ;
cmd_object_expr - > EvaluateExpression ( cmd_object_expr - > m_expr_lines . c_str ( ) ,
bare ,
2010-06-23 09:19:29 +08:00
reader . GetDebugger ( ) . GetOutputStream ( ) ,
reader . GetDebugger ( ) . GetErrorStream ( ) ) ;
2010-06-09 00:52:24 +08:00
}
break ;
}
return bytes_len ;
}
bool
CommandObjectExpression : : EvaluateExpression ( const char * expr , bool bare , Stream & output_stream , Stream & error_stream )
{
2010-06-24 08:16:27 +08:00
Log * log = lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_EXPRESSIONS ) ;
////////////////////////////////////
// Set up the target and compiler
//
2010-06-09 00:52:24 +08:00
Target * target = m_exe_ctx . target ;
2010-06-24 08:16:27 +08:00
if ( ! target )
{
error_stream . PutCString ( " error: invalid target \n " ) ;
return false ;
}
ConstString target_triple ;
target - > GetTargetTriple ( target_triple ) ;
2010-06-09 00:52:24 +08:00
if ( ! target_triple )
target_triple = Host : : GetTargetTriple ( ) ;
2010-06-24 08:16:27 +08:00
if ( ! target_triple )
{
error_stream . PutCString ( " error: invalid target triple \n " ) ;
return false ;
}
2010-08-11 11:57:18 +08:00
ClangExpressionDeclMap expr_decl_map ( & m_exe_ctx ) ;
2010-06-24 08:16:27 +08:00
ClangExpression clang_expr ( target_triple . AsCString ( ) , & expr_decl_map ) ;
//////////////////////////
// Parse the expression
//
unsigned num_errors ;
if ( bare )
num_errors = clang_expr . ParseBareExpression ( llvm : : StringRef ( expr ) , error_stream ) ;
else
2010-08-06 08:35:32 +08:00
num_errors = clang_expr . ParseExpression ( expr , error_stream , true ) ;
2010-06-24 08:16:27 +08:00
if ( num_errors )
{
error_stream . Printf ( " error: %d errors parsing expression \n " , num_errors ) ;
return false ;
}
///////////////////////////////////////////////
// Convert the output of the parser to DWARF
//
StreamString dwarf_opcodes ;
dwarf_opcodes . SetByteOrder ( eByteOrderHost ) ;
dwarf_opcodes . GetFlags ( ) . Set ( Stream : : eBinary ) ;
ClangExpressionVariableList expr_local_vars ;
bool success ;
2010-07-03 09:35:46 +08:00
bool canInterpret = false ;
2010-06-24 08:16:27 +08:00
2010-07-23 08:16:21 +08:00
clang : : ASTContext * ast_context = clang_expr . GetASTContext ( ) ;
2010-08-12 09:56:52 +08:00
ClangPersistentVariable * expr_result = 0 ;
2010-07-23 08:16:21 +08:00
Error expr_error ;
2010-08-06 08:35:32 +08:00
canInterpret = clang_expr . ConvertIRToDWARF ( expr_local_vars , dwarf_opcodes ) ;
if ( canInterpret )
2010-07-03 09:35:46 +08:00
{
2010-08-06 08:35:32 +08:00
if ( log )
log - > Printf ( " Code can be interpreted. " ) ;
success = true ;
}
else
{
if ( log )
log - > Printf ( " Code cannot be interpreted and must be run in the target. " ) ;
2010-08-13 08:28:39 +08:00
success = clang_expr . PrepareIRForTarget ( ) ;
2010-08-06 08:35:32 +08:00
}
if ( ! success )
{
error_stream . PutCString ( " error: expression couldn't be converted to IR \n " ) ;
return false ;
}
if ( canInterpret )
{
// TODO interpret IR
return false ;
}
else
{
2010-08-13 08:28:39 +08:00
if ( ! clang_expr . JITFunction ( ) )
2010-07-03 09:35:46 +08:00
{
2010-08-06 08:35:32 +08:00
error_stream . PutCString ( " error: IR could not be JIT compiled \n " ) ;
return false ;
2010-07-03 09:35:46 +08:00
}
2010-08-06 08:35:32 +08:00
if ( ! clang_expr . WriteJITCode ( m_exe_ctx ) )
2010-07-03 09:35:46 +08:00
{
2010-08-06 08:35:32 +08:00
error_stream . PutCString ( " error: JIT code could not be written to the target \n " ) ;
return false ;
2010-07-03 09:35:46 +08:00
}
2010-07-15 07:40:29 +08:00
2010-08-13 08:28:39 +08:00
lldb : : addr_t function_address ( clang_expr . GetFunctionAddress ( ) ) ;
2010-08-06 08:35:32 +08:00
if ( function_address = = LLDB_INVALID_ADDRESS )
2010-07-15 07:40:29 +08:00
{
2010-08-06 08:35:32 +08:00
error_stream . PutCString ( " JIT compiled code's address couldn't be found \n " ) ;
2010-07-15 07:40:29 +08:00
return false ;
}
2010-08-06 08:35:32 +08:00
lldb : : addr_t struct_address ;
if ( ! expr_decl_map . Materialize ( & m_exe_ctx , struct_address , expr_error ) )
2010-07-15 07:40:29 +08:00
{
2010-08-06 08:35:32 +08:00
error_stream . Printf ( " Couldn't materialize struct: %s \n " , expr_error . AsCString ( " unknown error " ) ) ;
2010-07-15 07:40:29 +08:00
return false ;
}
2010-08-06 08:35:32 +08:00
if ( log )
2010-07-15 07:40:29 +08:00
{
2010-08-06 08:35:32 +08:00
log - > Printf ( " Function address : 0x%llx " , ( uint64_t ) function_address ) ;
log - > Printf ( " Structure address : 0x%llx " , ( uint64_t ) struct_address ) ;
2010-07-15 07:40:29 +08:00
2010-08-06 08:35:32 +08:00
StreamString insns ;
2010-08-13 08:28:39 +08:00
Error err = clang_expr . DisassembleFunction ( insns , m_exe_ctx ) ;
2010-07-15 07:40:29 +08:00
2010-08-06 08:35:32 +08:00
if ( ! err . Success ( ) )
2010-07-15 07:40:29 +08:00
{
2010-08-06 08:35:32 +08:00
log - > Printf ( " Couldn't disassemble function : %s " , err . AsCString ( " unknown error " ) ) ;
2010-07-15 07:40:29 +08:00
}
2010-08-06 08:35:32 +08:00
else
2010-07-16 08:09:46 +08:00
{
2010-08-06 08:35:32 +08:00
log - > Printf ( " Function disassembly: \n %s " , insns . GetData ( ) ) ;
2010-07-16 08:09:46 +08:00
}
2010-08-06 08:35:32 +08:00
StreamString args ;
2010-07-23 08:16:21 +08:00
2010-08-06 08:35:32 +08:00
if ( ! expr_decl_map . DumpMaterializedStruct ( & m_exe_ctx , args , err ) )
2010-07-23 08:16:21 +08:00
{
2010-08-06 08:35:32 +08:00
log - > Printf ( " Couldn't extract variable values : %s " , err . AsCString ( " unknown error " ) ) ;
2010-07-23 08:16:21 +08:00
}
2010-08-06 08:35:32 +08:00
else
2010-07-23 08:16:21 +08:00
{
2010-08-06 08:35:32 +08:00
log - > Printf ( " Structure contents: \n %s " , args . GetData ( ) ) ;
2010-07-23 08:16:21 +08:00
}
2010-07-15 07:40:29 +08:00
}
2010-08-06 08:35:32 +08:00
ClangFunction : : ExecutionResults execution_result =
ClangFunction : : ExecuteFunction ( m_exe_ctx , function_address , struct_address , true , true , 10000 , error_stream ) ;
2010-07-15 07:40:29 +08:00
2010-08-06 08:35:32 +08:00
if ( execution_result ! = ClangFunction : : eExecutionCompleted )
2010-07-15 07:40:29 +08:00
{
2010-08-06 08:35:32 +08:00
const char * result_name ;
2010-07-15 07:40:29 +08:00
2010-08-06 08:35:32 +08:00
switch ( execution_result )
{
case ClangFunction : : eExecutionCompleted :
result_name = " eExecutionCompleted " ;
break ;
case ClangFunction : : eExecutionDiscarded :
result_name = " eExecutionDiscarded " ;
break ;
case ClangFunction : : eExecutionInterrupted :
result_name = " eExecutionInterrupted " ;
break ;
case ClangFunction : : eExecutionSetupError :
result_name = " eExecutionSetupError " ;
break ;
case ClangFunction : : eExecutionTimedOut :
result_name = " eExecutionTimedOut " ;
break ;
}
2010-07-15 07:40:29 +08:00
2010-08-06 08:35:32 +08:00
error_stream . Printf ( " Couldn't execute function; result was %s \n " , result_name ) ;
return false ;
2010-07-15 07:40:29 +08:00
}
2010-08-06 08:35:32 +08:00
if ( ! expr_decl_map . Dematerialize ( & m_exe_ctx , expr_result , expr_error ) )
2010-07-15 07:40:29 +08:00
{
2010-08-12 09:56:52 +08:00
error_stream . Printf ( " Couldn't dematerialize struct : %s \n " , expr_error . AsCString ( " unknown error " ) ) ;
2010-07-15 07:40:29 +08:00
return false ;
}
2010-07-23 08:16:21 +08:00
}
2010-08-12 09:56:52 +08:00
if ( expr_result )
2010-07-23 08:16:21 +08:00
{
2010-08-12 09:56:52 +08:00
StreamString ss ;
Error err = expr_result - > Print ( ss ,
m_exe_ctx ,
m_options . format ,
m_options . show_types ,
m_options . show_summary ,
m_options . debug ) ;
2010-07-23 08:16:21 +08:00
2010-08-12 09:56:52 +08:00
if ( err . Success ( ) )
output_stream . PutCString ( ss . GetString ( ) . c_str ( ) ) ;
else
error_stream . Printf ( " Couldn't print result : %s \n " , err . AsCString ( " unknown error " ) ) ;
2010-07-23 08:16:21 +08:00
}
else
{
2010-08-12 09:56:52 +08:00
error_stream . Printf ( " Expression produced no result \n " ) ;
2010-07-23 08:16:21 +08:00
}
2010-08-12 09:56:52 +08:00
2010-07-23 08:16:21 +08:00
return true ;
2010-06-09 00:52:24 +08:00
}
bool
CommandObjectExpression : : ExecuteRawCommandString
(
2010-06-23 09:19:29 +08:00
CommandInterpreter & interpreter ,
2010-06-09 00:52:24 +08:00
const char * command ,
CommandReturnObject & result
)
{
2010-06-24 08:16:27 +08:00
m_exe_ctx = interpreter . GetDebugger ( ) . GetExecutionContext ( ) ;
2010-06-09 00:52:24 +08:00
m_options . ResetOptionValues ( ) ;
const char * expr = NULL ;
if ( command [ 0 ] = = ' \0 ' )
{
m_expr_lines . clear ( ) ;
m_expr_line_count = 0 ;
2010-06-23 09:19:29 +08:00
InputReaderSP reader_sp ( new InputReader ( interpreter . GetDebugger ( ) ) ) ;
2010-06-09 00:52:24 +08:00
if ( reader_sp )
{
Error err ( reader_sp - > Initialize ( CommandObjectExpression : : MultiLineExpressionCallback ,
this , // baton
eInputReaderGranularityLine , // token size, to pass to callback function
2010-06-23 09:19:29 +08:00
NULL , // end token
2010-06-09 00:52:24 +08:00
NULL , // prompt
true ) ) ; // echo input
if ( err . Success ( ) )
{
2010-06-23 09:19:29 +08:00
interpreter . GetDebugger ( ) . PushInputReader ( reader_sp ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . AppendError ( err . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendError ( " out of memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
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 )
{
2010-06-23 09:19:29 +08:00
Args args ( command , end_options - command ) ;
if ( ! ParseOptions ( interpreter , args , result ) )
2010-06-09 00:52:24 +08:00
return false ;
}
}
if ( expr = = NULL )
expr = command ;
2010-06-24 08:16:27 +08:00
return EvaluateExpression ( expr , false , result . GetOutputStream ( ) , result . GetErrorStream ( ) ) ;
2010-06-09 00:52:24 +08:00
}
lldb : : OptionDefinition
CommandObjectExpression : : CommandOptions : : g_option_table [ ] =
{
2010-06-29 05:30:43 +08:00
{ LLDB_OPT_SET_ALL , false , " language " , ' l ' , required_argument , NULL , 0 , " [c|c++|objc|objc++] " , " Sets the language to use when parsing the expression. " } ,
2010-06-24 07:18:04 +08:00
{ LLDB_OPT_SET_ALL , false , " format " , ' f ' , required_argument , NULL , 0 , " [ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ] " , " Specify the format that the expression output should use. " } ,
{ LLDB_OPT_SET_ALL , false , " debug " , ' g ' , no_argument , NULL , 0 , NULL , " Enable verbose debug logging of the expression parsing and evaluation. " } ,
{ LLDB_OPT_SET_ALL , false , " use-ir " , ' i ' , no_argument , NULL , 0 , NULL , " [Temporary] Instructs the expression evaluator to use IR instead of ASTs. " } ,
2010-06-09 00:52:24 +08:00
{ 0 , false , NULL , 0 , 0 , NULL , NULL , NULL , NULL }
} ;