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
2010-07-22 06:12:05 +08:00
# include "llvm/ADT/StringRef.h"
2010-06-09 00:52:24 +08:00
// Project includes
2010-07-22 06:12:05 +08:00
# include "lldb/Core/Debugger.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"
# include "lldb/Expression/DWARFExpression.h"
# include "lldb/Host/Host.h"
2010-07-22 06:12:05 +08:00
# include "lldb/Interpreter/Args.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"
2010-07-22 06:12:05 +08:00
# include "lldb/Symbol/ClangASTType.h"
2010-06-09 00:52:24 +08:00
# 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"
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 ;
2010-06-24 07:18:04 +08:00
case ' i ' :
use_ir = true ;
break ;
2010-06-09 00:52:24 +08:00
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 ;
2010-06-24 07:18:04 +08:00
use_ir = false ;
2010-06-09 00:52:24 +08:00
}
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 ;
}
ClangExpressionDeclMap expr_decl_map ( & m_exe_ctx ) ;
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-07-02 04:08:22 +08:00
num_errors = clang_expr . ParseExpression ( expr , error_stream , m_options . use_ir ) ;
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
if ( m_options . use_ir )
2010-07-03 09:35:46 +08:00
{
canInterpret = clang_expr . ConvertIRToDWARF ( expr_local_vars , dwarf_opcodes ) ;
if ( canInterpret )
{
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. " ) ;
success = clang_expr . PrepareIRForTarget ( expr_local_vars ) ;
}
2010-07-15 07:40:29 +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
{
if ( ! clang_expr . JITFunction ( m_exe_ctx , " ___clang_expr " ) )
{
error_stream . PutCString ( " error: IR could not be JIT compiled \n " ) ;
return false ;
}
if ( ! clang_expr . WriteJITCode ( m_exe_ctx ) )
{
error_stream . PutCString ( " error: JIT code could not be written to the target \n " ) ;
return false ;
}
lldb : : addr_t function_address ( clang_expr . GetFunctionAddress ( " ___clang_expr " ) ) ;
if ( function_address = = LLDB_INVALID_ADDRESS )
{
error_stream . PutCString ( " JIT compiled code's address couldn't be found \n " ) ;
return false ;
}
2010-07-16 08:09:46 +08:00
Error err ;
2010-07-21 07:31:16 +08:00
lldb : : addr_t struct_address ;
2010-07-16 08:09:46 +08:00
2010-07-21 07:31:16 +08:00
if ( ! expr_decl_map . Materialize ( & m_exe_ctx , struct_address , err ) )
2010-07-16 08:09:46 +08:00
{
error_stream . Printf ( " Couldn't materialize struct: %s \n " , err . AsCString ( " unknown error " ) ) ;
return false ;
}
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-07-16 08:09:46 +08:00
return true ;
2010-07-03 09:35:46 +08:00
}
2010-06-24 08:16:27 +08:00
else
2010-07-03 09:35:46 +08:00
{
2010-06-24 08:16:27 +08:00
success = ( clang_expr . ConvertExpressionToDWARF ( expr_local_vars , dwarf_opcodes ) = = 0 ) ;
2010-06-09 00:52:24 +08:00
2010-07-15 07:40:29 +08:00
if ( ! success )
{
error_stream . PutCString ( " error: expression couldn't be translated to DWARF \n " ) ;
return false ;
}
2010-06-09 00:52:24 +08:00
2010-07-15 07:40:29 +08:00
//////////////////////////////////////////
// Evaluate the generated DWARF opcodes
//
DataExtractor dwarf_opcodes_data ( dwarf_opcodes . GetData ( ) , dwarf_opcodes . GetSize ( ) , eByteOrderHost , 8 ) ;
DWARFExpression dwarf_expr ( dwarf_opcodes_data , 0 , dwarf_opcodes_data . GetByteSize ( ) , NULL ) ;
dwarf_expr . SetExpressionLocalVariableList ( & expr_local_vars ) ;
if ( log )
{
StreamString stream_string ;
log - > PutCString ( " Expression parsed ok, dwarf opcodes: " ) ;
stream_string . PutCString ( " \n " ) ;
stream_string . IndentMore ( ) ;
dwarf_expr . GetDescription ( & stream_string , lldb : : eDescriptionLevelVerbose ) ;
stream_string . IndentLess ( ) ;
stream_string . EOL ( ) ;
log - > PutCString ( stream_string . GetString ( ) . c_str ( ) ) ;
}
clang : : ASTContext * ast_context = clang_expr . GetASTContext ( ) ;
Value expr_result ;
Error expr_error ;
success = dwarf_expr . Evaluate ( & m_exe_ctx , ast_context , NULL , expr_result , & expr_error ) ;
if ( ! success )
{
error_stream . Printf ( " error: couldn't evaluate DWARF expression: %s \n " , expr_error . AsCString ( ) ) ;
return false ;
}
///////////////////////////////////////
// Interpret the result and print it
//
lldb : : Format format = m_options . format ;
// Resolve any values that are possible
expr_result . ResolveValue ( & m_exe_ctx , ast_context ) ;
if ( expr_result . GetContextType ( ) = = Value : : eContextTypeInvalid & &
expr_result . GetValueType ( ) = = Value : : eValueTypeScalar & &
format = = eFormatDefault )
{
// The expression result is just a scalar with no special formatting
expr_result . GetScalar ( ) . GetValue ( & output_stream , m_options . show_types ) ;
output_stream . EOL ( ) ;
return true ;
}
// The expression result is more complext and requires special handling
DataExtractor data ;
expr_error = expr_result . GetValueAsData ( & m_exe_ctx , ast_context , data , 0 ) ;
if ( ! expr_error . Success ( ) )
{
error_stream . Printf ( " error: couldn't resolve result value: %s \n " , expr_error . AsCString ( ) ) ;
return false ;
}
if ( format = = eFormatDefault )
format = expr_result . GetValueDefaultFormat ( ) ;
void * clang_type = expr_result . GetValueOpaqueClangQualType ( ) ;
if ( clang_type )
{
if ( m_options . show_types )
2010-07-22 06:12:05 +08:00
{
ConstString type_name ( ClangASTType : : GetClangTypeName ( clang_type ) ) ;
if ( type_name )
output_stream . Printf ( " (%s) " , type_name . AsCString ( " <invalid> " ) ) ;
}
2010-07-15 07:40:29 +08:00
2010-07-22 06:12:05 +08:00
ClangASTType : : DumpValue ( ast_context , // The ASTContext that the clang type belongs to
clang_type , // The opaque clang type we want to dump that value of
& m_exe_ctx , // The execution context for memory and variable access
& output_stream , // Stream to dump to
format , // Format to use when dumping
data , // A buffer containing the bytes for the clang type
0 , // Byte offset within "data" where value is
data . GetByteSize ( ) , // Size in bytes of the value we are dumping
0 , // Bitfield bit size
0 , // Bitfield bit offset
m_options . show_types , // Show types?
m_options . show_summary , // Show summary?
m_options . debug , // Debug logging output?
UINT32_MAX ) ; // Depth to dump in case this is an aggregate type
2010-07-15 07:40:29 +08:00
}
else
{
data . Dump ( & output_stream , // Stream to dump to
0 , // Byte offset within "data"
format , // Format to use when dumping
data . GetByteSize ( ) , // Size in bytes of each item we are dumping
1 , // Number of items to dump
UINT32_MAX , // Number of items per line
LLDB_INVALID_ADDRESS , // Invalid address, don't show any offset/address context
0 , // Bitfield bit size
0 ) ; // Bitfield bit offset
}
output_stream . EOL ( ) ;
2010-06-09 00:52:24 +08:00
2010-06-24 08:16:27 +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 }
} ;