2010-06-08 16:52:24 +00:00
//===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
2012-12-05 00:20:57 +00:00
# include "lldb/lldb-python.h"
2010-06-08 16:52:24 +00:00
# include "CommandObjectMemory.h"
// C Includes
2013-08-28 12:14:27 +00:00
# include <inttypes.h>
2010-06-08 16:52:24 +00:00
// C++ Includes
// Other libraries and framework includes
// Project includes
# include "lldb/Core/DataBufferHeap.h"
# include "lldb/Core/DataExtractor.h"
2010-06-23 01:19:29 +00:00
# include "lldb/Core/Debugger.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Core/Module.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/StreamString.h"
2011-04-27 22:04:39 +00:00
# include "lldb/Core/ValueObjectMemory.h"
2013-09-30 19:11:51 +00:00
# include "lldb/DataFormatters/ValueObjectPrinter.h"
2010-06-23 01:19:29 +00:00
# include "lldb/Interpreter/Args.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Interpreter/CommandReturnObject.h"
2010-06-23 01:19:29 +00:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/Options.h"
2011-04-27 22:04:39 +00:00
# include "lldb/Interpreter/OptionGroupFormat.h"
# include "lldb/Interpreter/OptionGroupOutputFile.h"
2011-04-28 20:55:26 +00:00
# include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
2012-08-22 17:17:09 +00:00
# include "lldb/Interpreter/OptionValueString.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Symbol/TypeList.h"
2014-09-04 01:03:18 +00:00
# include "lldb/Target/MemoryHistory.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Target/Process.h"
2013-11-04 09:33:30 +00:00
# include "lldb/Target/StackFrame.h"
2014-09-04 01:03:18 +00:00
# include "lldb/Target/Thread.h"
2010-06-08 16:52:24 +00:00
using namespace lldb ;
using namespace lldb_private ;
2011-04-28 20:55:26 +00:00
static OptionDefinition
2011-04-27 22:04:39 +00:00
g_option_table [ ] =
{
2014-07-09 16:31:49 +00:00
{ LLDB_OPT_SET_1 , false , " num-per-line " , ' l ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeNumberPerLine , " The number of items per line to display. " } ,
{ LLDB_OPT_SET_2 , false , " binary " , ' b ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings. " } ,
{ LLDB_OPT_SET_3 , true , " type " , ' t ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeNone , " The name of a type to view memory as. " } ,
2012-11-02 21:14:58 +00:00
{ LLDB_OPT_SET_1 |
LLDB_OPT_SET_2 |
2014-07-09 16:31:49 +00:00
LLDB_OPT_SET_3 , false , " force " , ' r ' , OptionParser : : eNoArgument , NULL , NULL , 0 , eArgTypeNone , " Necessary if reading over target.max-memory-read-size bytes. " } ,
2011-04-27 22:04:39 +00:00
} ;
class OptionGroupReadMemory : public OptionGroup
{
public :
OptionGroupReadMemory ( ) :
2011-04-28 20:55:26 +00:00
m_num_per_line ( 1 , 1 ) ,
2011-04-27 22:04:39 +00:00
m_output_as_binary ( false ) ,
m_view_as_type ( )
{
}
virtual
~ OptionGroupReadMemory ( )
{
}
virtual uint32_t
GetNumDefinitions ( )
{
return sizeof ( g_option_table ) / sizeof ( OptionDefinition ) ;
}
virtual const OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
virtual Error
SetOptionValue ( CommandInterpreter & interpreter ,
uint32_t option_idx ,
const char * option_arg )
{
Error error ;
2012-12-04 00:32:51 +00:00
const int short_option = g_option_table [ option_idx ] . short_option ;
2011-04-27 22:04:39 +00:00
switch ( short_option )
{
case ' l ' :
error = m_num_per_line . SetValueFromCString ( option_arg ) ;
if ( m_num_per_line . GetCurrentValue ( ) = = 0 )
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid value for --num-per-line option '%s' " , option_arg ) ;
2011-04-27 22:04:39 +00:00
break ;
2011-10-25 06:44:01 +00:00
2011-04-27 22:04:39 +00:00
case ' b ' :
m_output_as_binary = true ;
break ;
case ' t ' :
error = m_view_as_type . SetValueFromCString ( option_arg ) ;
break ;
2012-04-28 01:27:38 +00:00
case ' r ' :
m_force = true ;
break ;
2011-04-27 22:04:39 +00:00
default :
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " , short_option ) ;
2011-04-27 22:04:39 +00:00
break ;
}
return error ;
}
virtual void
OptionParsingStarting ( CommandInterpreter & interpreter )
{
m_num_per_line . Clear ( ) ;
m_output_as_binary = false ;
m_view_as_type . Clear ( ) ;
2013-06-04 22:54:16 +00:00
m_force = false ;
2011-04-27 22:04:39 +00:00
}
2011-04-28 20:55:26 +00:00
Error
2011-10-25 06:44:01 +00:00
FinalizeSettings ( Target * target , OptionGroupFormat & format_options )
2011-04-27 22:04:39 +00:00
{
2011-04-28 20:55:26 +00:00
Error error ;
2011-10-25 06:44:01 +00:00
OptionValueUInt64 & byte_size_value = format_options . GetByteSizeValue ( ) ;
OptionValueUInt64 & count_value = format_options . GetCountValue ( ) ;
2011-10-26 00:56:27 +00:00
const bool byte_size_option_set = byte_size_value . OptionWasSet ( ) ;
2011-04-28 20:55:26 +00:00
const bool num_per_line_option_set = m_num_per_line . OptionWasSet ( ) ;
2011-10-25 06:44:01 +00:00
const bool count_option_set = format_options . GetCountValue ( ) . OptionWasSet ( ) ;
2011-04-28 20:55:26 +00:00
switch ( format_options . GetFormat ( ) )
2011-04-27 22:04:39 +00:00
{
default :
break ;
case eFormatBoolean :
2011-04-28 20:55:26 +00:00
if ( ! byte_size_option_set )
2011-10-25 06:44:01 +00:00
byte_size_value = 1 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
format_options . GetCountValue ( ) = 8 ;
2011-04-27 22:04:39 +00:00
break ;
case eFormatCString :
break ;
2011-10-27 17:55:14 +00:00
case eFormatInstruction :
if ( count_option_set )
2012-11-07 01:52:04 +00:00
byte_size_value = target - > GetArchitecture ( ) . GetMaximumOpcodeByteSize ( ) ;
2011-10-27 17:55:14 +00:00
m_num_per_line = 1 ;
break ;
case eFormatAddressInfo :
if ( ! byte_size_option_set )
byte_size_value = target - > GetArchitecture ( ) . GetAddressByteSize ( ) ;
m_num_per_line = 1 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 8 ;
break ;
2011-04-27 22:04:39 +00:00
case eFormatPointer :
2011-10-25 06:44:01 +00:00
byte_size_value = target - > GetArchitecture ( ) . GetAddressByteSize ( ) ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 4 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
format_options . GetCountValue ( ) = 8 ;
2011-04-27 22:04:39 +00:00
break ;
case eFormatBinary :
case eFormatFloat :
case eFormatOctal :
case eFormatDecimal :
case eFormatEnum :
case eFormatUnicode16 :
case eFormatUnicode32 :
case eFormatUnsigned :
2011-10-27 17:55:14 +00:00
case eFormatHexFloat :
2011-04-28 20:55:26 +00:00
if ( ! byte_size_option_set )
2011-10-25 06:44:01 +00:00
byte_size_value = 4 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
format_options . GetCountValue ( ) = 8 ;
2011-04-27 22:04:39 +00:00
break ;
2011-10-27 17:55:14 +00:00
2011-04-27 22:04:39 +00:00
case eFormatBytes :
case eFormatBytesWithASCII :
2011-10-26 00:56:27 +00:00
if ( byte_size_option_set )
2011-04-28 20:55:26 +00:00
{
2011-10-25 06:44:01 +00:00
if ( byte_size_value > 1 )
2012-11-29 21:49:15 +00:00
error . SetErrorStringWithFormat ( " display format (bytes/bytes with ascii) conflicts with the specified byte size % " PRIu64 " \n "
2012-03-06 01:17:59 +00:00
" \t consider using a different display format or don't specify the byte size " ,
byte_size_value . GetCurrentValue ( ) ) ;
2011-04-28 20:55:26 +00:00
}
else
2011-10-25 06:44:01 +00:00
byte_size_value = 1 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 16 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
format_options . GetCountValue ( ) = 32 ;
2011-04-27 22:04:39 +00:00
break ;
2011-06-17 23:50:44 +00:00
case eFormatCharArray :
2011-04-27 22:04:39 +00:00
case eFormatChar :
case eFormatCharPrintable :
2011-04-28 20:55:26 +00:00
if ( ! byte_size_option_set )
2011-10-25 06:44:01 +00:00
byte_size_value = 1 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 32 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
format_options . GetCountValue ( ) = 64 ;
2011-04-27 22:04:39 +00:00
break ;
case eFormatComplex :
2011-04-28 20:55:26 +00:00
if ( ! byte_size_option_set )
2011-10-25 06:44:01 +00:00
byte_size_value = 8 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
format_options . GetCountValue ( ) = 8 ;
2013-03-23 05:16:54 +00:00
break ;
case eFormatComplexInteger :
if ( ! byte_size_option_set )
byte_size_value = 8 ;
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 8 ;
2011-04-27 22:04:39 +00:00
break ;
case eFormatHex :
2011-04-28 20:55:26 +00:00
if ( ! byte_size_option_set )
2011-10-25 06:44:01 +00:00
byte_size_value = 4 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
{
2011-10-25 06:44:01 +00:00
switch ( byte_size_value )
2011-04-28 20:55:26 +00:00
{
case 1 :
case 2 :
m_num_per_line = 8 ;
break ;
case 4 :
m_num_per_line = 4 ;
break ;
case 8 :
m_num_per_line = 2 ;
break ;
default :
m_num_per_line = 1 ;
break ;
}
}
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
count_value = 8 ;
2011-04-27 22:04:39 +00:00
break ;
case eFormatVectorOfChar :
case eFormatVectorOfSInt8 :
case eFormatVectorOfUInt8 :
case eFormatVectorOfSInt16 :
case eFormatVectorOfUInt16 :
case eFormatVectorOfSInt32 :
case eFormatVectorOfUInt32 :
case eFormatVectorOfSInt64 :
case eFormatVectorOfUInt64 :
case eFormatVectorOfFloat32 :
case eFormatVectorOfFloat64 :
case eFormatVectorOfUInt128 :
2011-04-28 20:55:26 +00:00
if ( ! byte_size_option_set )
2011-10-25 06:44:01 +00:00
byte_size_value = 128 ;
2011-04-28 20:55:26 +00:00
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
2011-10-25 06:44:01 +00:00
count_value = 4 ;
2011-04-27 22:04:39 +00:00
break ;
}
2011-04-28 20:55:26 +00:00
return error ;
2011-04-27 22:04:39 +00:00
}
2011-10-26 04:32:38 +00:00
bool
AnyOptionWasSet ( ) const
{
return m_num_per_line . OptionWasSet ( ) | |
m_output_as_binary | |
m_view_as_type . OptionWasSet ( ) ;
}
2011-04-27 22:04:39 +00:00
OptionValueUInt64 m_num_per_line ;
bool m_output_as_binary ;
OptionValueString m_view_as_type ;
2012-04-28 01:27:38 +00:00
bool m_force ;
2011-04-27 22:04:39 +00:00
} ;
2010-06-08 16:52:24 +00:00
//----------------------------------------------------------------------
// Read memory from the inferior process
//----------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectMemoryRead : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
2010-09-18 01:14:36 +00:00
CommandObjectMemoryRead ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" memory read " ,
" Read from the memory of the process being debugged. " ,
NULL ,
2013-01-09 19:44:40 +00:00
eFlagRequiresTarget | eFlagProcessMustBePaused ) ,
2011-04-27 22:04:39 +00:00
m_option_group ( interpreter ) ,
2011-10-25 06:44:01 +00:00
m_format_options ( eFormatBytesWithASCII , 1 , 8 ) ,
2011-04-27 22:04:39 +00:00
m_memory_options ( ) ,
2011-04-28 20:55:26 +00:00
m_outfile_options ( ) ,
2011-10-26 04:32:38 +00:00
m_varobj_options ( ) ,
m_next_addr ( LLDB_INVALID_ADDRESS ) ,
m_prev_byte_size ( 0 ) ,
m_prev_format_options ( eFormatBytesWithASCII , 1 , 8 ) ,
m_prev_memory_options ( ) ,
m_prev_outfile_options ( ) ,
m_prev_varobj_options ( )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData start_addr_arg ;
CommandArgumentData end_addr_arg ;
// Define the first (and only) variant of this arg.
2013-01-29 01:48:30 +00:00
start_addr_arg . arg_type = eArgTypeAddressOrExpression ;
2010-10-04 22:28:36 +00:00
start_addr_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg1 . push_back ( start_addr_arg ) ;
// Define the first (and only) variant of this arg.
2013-01-29 01:48:30 +00:00
end_addr_arg . arg_type = eArgTypeAddressOrExpression ;
2010-10-04 22:28:36 +00:00
end_addr_arg . arg_repetition = eArgRepeatOptional ;
// There is only one variant this argument could be; put it into the argument entry.
arg2 . push_back ( end_addr_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
2011-04-27 22:04:39 +00:00
2011-10-25 06:44:01 +00:00
// Add the "--format" and "--count" options to group 1 and 3
m_option_group . Append ( & m_format_options ,
OptionGroupFormat : : OPTION_GROUP_FORMAT | OptionGroupFormat : : OPTION_GROUP_COUNT ,
2011-11-22 18:07:35 +00:00
LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3 ) ;
2011-10-27 17:55:14 +00:00
m_option_group . Append ( & m_format_options ,
OptionGroupFormat : : OPTION_GROUP_GDB_FMT ,
2011-11-22 18:07:35 +00:00
LLDB_OPT_SET_1 | LLDB_OPT_SET_3 ) ;
2011-10-25 06:44:01 +00:00
// Add the "--size" option to group 1 and 2
m_option_group . Append ( & m_format_options ,
OptionGroupFormat : : OPTION_GROUP_SIZE ,
LLDB_OPT_SET_1 | LLDB_OPT_SET_2 ) ;
2011-04-27 22:04:39 +00:00
m_option_group . Append ( & m_memory_options ) ;
m_option_group . Append ( & m_outfile_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3 ) ;
2011-04-28 20:55:26 +00:00
m_option_group . Append ( & m_varobj_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_3 ) ;
2011-04-27 22:04:39 +00:00
m_option_group . Finalize ( ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandObjectMemoryRead ( )
{
}
Options *
GetOptions ( )
{
2011-04-27 22:04:39 +00:00
return & m_option_group ;
2010-06-08 16:52:24 +00:00
}
2011-10-26 04:32:38 +00:00
virtual const char * GetRepeatCommand ( Args & current_command_args , uint32_t index )
{
return m_cmd_name . c_str ( ) ;
}
2012-06-08 21:56:10 +00:00
protected :
2010-06-08 16:52:24 +00:00
virtual bool
2012-12-06 22:49:16 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-08 16:52:24 +00:00
{
2013-01-09 19:44:40 +00:00
// No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
Target * target = m_exe_ctx . GetTargetPtr ( ) ;
2010-06-08 16:52:24 +00:00
const size_t argc = command . GetArgumentCount ( ) ;
2011-10-26 04:32:38 +00:00
if ( ( argc = = 0 & & m_next_addr = = LLDB_INVALID_ADDRESS ) | | argc > 2 )
2010-06-08 16:52:24 +00:00
{
2012-12-06 22:49:16 +00:00
result . AppendErrorWithFormat ( " %s takes a start address expression with an optional end address expression. \n " , m_cmd_name . c_str ( ) ) ;
2012-12-15 02:08:17 +00:00
result . AppendRawWarning ( " Expressions should be quoted if they contain spaces or other special characters. \n " ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-04-28 20:55:26 +00:00
ClangASTType clang_ast_type ;
Error error ;
2011-04-27 22:04:39 +00:00
const char * view_as_type_cstr = m_memory_options . m_view_as_type . GetCurrentValue ( ) ;
if ( view_as_type_cstr & & view_as_type_cstr [ 0 ] )
2010-06-08 16:52:24 +00:00
{
2011-04-27 22:04:39 +00:00
// We are viewing memory as a type
2012-12-15 02:08:17 +00:00
2011-04-27 22:04:39 +00:00
SymbolContext sc ;
2012-03-26 23:03:23 +00:00
const bool exact_match = false ;
2011-04-27 22:04:39 +00:00
TypeList type_list ;
uint32_t reference_count = 0 ;
uint32_t pointer_count = 0 ;
size_t idx ;
2012-07-10 21:24:26 +00:00
# define ALL_KEYWORDS \
KEYWORD("const") \
KEYWORD("volatile") \
KEYWORD("restrict") \
KEYWORD("struct") \
KEYWORD("class") \
KEYWORD("union")
# define KEYWORD(s) s,
static const char * g_keywords [ ] =
{
ALL_KEYWORDS
} ;
# undef KEYWORD
# define KEYWORD(s) (sizeof(s) - 1),
static const int g_keyword_lengths [ ] =
{
ALL_KEYWORDS
} ;
# undef KEYWORD
# undef ALL_KEYWORDS
static size_t g_num_keywords = sizeof ( g_keywords ) / sizeof ( const char * ) ;
2011-04-27 22:04:39 +00:00
std : : string type_str ( view_as_type_cstr ) ;
// Remove all instances of g_keywords that are followed by spaces
for ( size_t i = 0 ; i < g_num_keywords ; + + i )
{
const char * keyword = g_keywords [ i ] ;
2012-07-10 21:24:26 +00:00
int keyword_len = g_keyword_lengths [ i ] ;
idx = 0 ;
while ( ( idx = type_str . find ( keyword , idx ) ) ! = std : : string : : npos )
2011-04-27 22:04:39 +00:00
{
if ( type_str [ idx + keyword_len ] = = ' ' | | type_str [ idx + keyword_len ] = = ' \t ' )
2012-07-10 21:24:26 +00:00
{
2011-04-27 22:04:39 +00:00
type_str . erase ( idx , keyword_len + 1 ) ;
2012-07-10 21:24:26 +00:00
idx = 0 ;
}
else
{
idx + = keyword_len ;
}
2011-04-27 22:04:39 +00:00
}
}
bool done = type_str . empty ( ) ;
//
idx = type_str . find_first_not_of ( " \t " ) ;
if ( idx > 0 & & idx ! = std : : string : : npos )
type_str . erase ( 0 , idx ) ;
while ( ! done )
{
// Strip trailing spaces
if ( type_str . empty ( ) )
done = true ;
else
{
switch ( type_str [ type_str . size ( ) - 1 ] )
{
case ' * ' :
+ + pointer_count ;
// fall through...
case ' ' :
case ' \t ' :
type_str . erase ( type_str . size ( ) - 1 ) ;
break ;
case ' & ' :
if ( reference_count = = 0 )
{
reference_count = 1 ;
type_str . erase ( type_str . size ( ) - 1 ) ;
}
else
{
result . AppendErrorWithFormat ( " invalid type string: '%s' \n " , view_as_type_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
break ;
default :
done = true ;
break ;
}
}
}
ConstString lookup_type_name ( type_str . c_str ( ) ) ;
2013-11-04 09:33:30 +00:00
StackFrame * frame = m_exe_ctx . GetFramePtr ( ) ;
2011-09-22 04:58:26 +00:00
if ( frame )
2011-04-27 22:04:39 +00:00
{
2011-09-22 04:58:26 +00:00
sc = frame - > GetSymbolContext ( eSymbolContextModule ) ;
2011-04-27 22:04:39 +00:00
if ( sc . module_sp )
{
2011-10-12 02:08:07 +00:00
sc . module_sp - > FindTypes ( sc ,
lookup_type_name ,
2012-03-26 23:03:23 +00:00
exact_match ,
2011-04-27 22:04:39 +00:00
1 ,
type_list ) ;
}
}
if ( type_list . GetSize ( ) = = 0 )
{
2012-04-06 17:41:13 +00:00
target - > GetImages ( ) . FindTypes ( sc ,
2011-09-22 04:58:26 +00:00
lookup_type_name ,
2012-03-26 23:03:23 +00:00
exact_match ,
2011-09-22 04:58:26 +00:00
1 ,
type_list ) ;
2011-04-27 22:04:39 +00:00
}
2013-06-11 18:47:55 +00:00
if ( type_list . GetSize ( ) = = 0 & & lookup_type_name . GetCString ( ) & & * lookup_type_name . GetCString ( ) = = ' $ ' )
2011-04-27 22:04:39 +00:00
{
2013-06-11 18:47:55 +00:00
clang : : TypeDecl * tdecl = target - > GetPersistentVariables ( ) . GetPersistentType ( ConstString ( lookup_type_name ) ) ;
if ( tdecl )
{
clang_ast_type . SetClangType ( & tdecl - > getASTContext ( ) , ( lldb : : clang_type_t ) tdecl - > getTypeForDecl ( ) ) ;
}
2011-04-27 22:04:39 +00:00
}
2013-06-11 18:47:55 +00:00
if ( clang_ast_type . IsValid ( ) = = false )
{
if ( type_list . GetSize ( ) = = 0 )
{
result . AppendErrorWithFormat ( " unable to find any types that match the raw type '%s' for full type '%s' \n " ,
lookup_type_name . GetCString ( ) ,
view_as_type_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else
{
TypeSP type_sp ( type_list . GetTypeAtIndex ( 0 ) ) ;
2013-07-11 22:46:58 +00:00
clang_ast_type = type_sp - > GetClangFullType ( ) ;
2013-06-11 18:47:55 +00:00
}
}
2011-04-27 22:04:39 +00:00
while ( pointer_count > 0 )
{
2013-07-11 22:46:58 +00:00
ClangASTType pointer_type = clang_ast_type . GetPointerType ( ) ;
if ( pointer_type . IsValid ( ) )
clang_ast_type = pointer_type ;
2011-04-27 22:04:39 +00:00
else
{
result . AppendError ( " unable make a pointer type \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
- - pointer_count ;
}
2013-07-11 22:46:58 +00:00
m_format_options . GetByteSizeValue ( ) = clang_ast_type . GetByteSize ( ) ;
2011-04-27 22:04:39 +00:00
2011-10-25 06:44:01 +00:00
if ( m_format_options . GetByteSizeValue ( ) = = 0 )
2011-04-27 22:04:39 +00:00
{
result . AppendErrorWithFormat ( " unable to get the byte size of the type '%s' \n " ,
view_as_type_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-04-28 20:55:26 +00:00
2011-10-25 06:44:01 +00:00
if ( ! m_format_options . GetCountValue ( ) . OptionWasSet ( ) )
m_format_options . GetCountValue ( ) = 1 ;
2011-04-27 22:04:39 +00:00
}
else
{
2011-09-22 04:58:26 +00:00
error = m_memory_options . FinalizeSettings ( target , m_format_options ) ;
2011-04-28 20:55:26 +00:00
}
// Look for invalid combinations of settings
if ( error . Fail ( ) )
{
2012-12-06 22:49:16 +00:00
result . AppendError ( error . AsCString ( ) ) ;
2011-04-28 20:55:26 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2010-06-08 16:52:24 +00:00
}
2011-10-26 04:32:38 +00:00
lldb : : addr_t addr ;
size_t total_byte_size = 0 ;
if ( argc = = 0 )
{
// Use the last address and byte size and all options as they were
// if no options have been set
addr = m_next_addr ;
total_byte_size = m_prev_byte_size ;
2012-12-15 02:08:17 +00:00
clang_ast_type = m_prev_clang_ast_type ;
if ( ! m_format_options . AnyOptionWasSet ( ) & &
2011-10-26 04:32:38 +00:00
! m_memory_options . AnyOptionWasSet ( ) & &
! m_outfile_options . AnyOptionWasSet ( ) & &
! m_varobj_options . AnyOptionWasSet ( ) )
{
m_format_options = m_prev_format_options ;
m_memory_options = m_prev_memory_options ;
m_outfile_options = m_prev_outfile_options ;
m_varobj_options = m_prev_varobj_options ;
}
}
2011-10-25 06:44:01 +00:00
size_t item_count = m_format_options . GetCountValue ( ) . GetCurrentValue ( ) ;
2014-09-29 08:02:24 +00:00
// TODO For non-8-bit byte addressable architectures this needs to be
// revisited to fully support all lldb's range of formatting options.
// Furthermore code memory reads (for those architectures) will not
// be correctly formatted even w/o formatting options.
size_t item_byte_size =
target - > GetArchitecture ( ) . GetDataByteSize ( ) > 1 ?
target - > GetArchitecture ( ) . GetDataByteSize ( ) :
m_format_options . GetByteSizeValue ( ) . GetCurrentValue ( ) ;
2011-04-28 20:55:26 +00:00
const size_t num_per_line = m_memory_options . m_num_per_line . GetCurrentValue ( ) ;
2010-06-08 16:52:24 +00:00
if ( total_byte_size = = 0 )
2011-10-26 04:32:38 +00:00
{
total_byte_size = item_count * item_byte_size ;
if ( total_byte_size = = 0 )
total_byte_size = 32 ;
}
2010-06-08 16:52:24 +00:00
2011-10-26 04:32:38 +00:00
if ( argc > 0 )
2013-01-09 19:44:40 +00:00
addr = Args : : StringToAddress ( & m_exe_ctx , command . GetArgumentAtIndex ( 0 ) , LLDB_INVALID_ADDRESS , & error ) ;
2010-06-08 16:52:24 +00:00
if ( addr = = LLDB_INVALID_ADDRESS )
{
2012-12-06 22:49:16 +00:00
result . AppendError ( " invalid start address expression. " ) ;
result . AppendError ( error . AsCString ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( argc = = 2 )
{
2013-01-09 19:44:40 +00:00
lldb : : addr_t end_addr = Args : : StringToAddress ( & m_exe_ctx , command . GetArgumentAtIndex ( 1 ) , LLDB_INVALID_ADDRESS , 0 ) ;
2010-06-08 16:52:24 +00:00
if ( end_addr = = LLDB_INVALID_ADDRESS )
{
2012-12-06 22:49:16 +00:00
result . AppendError ( " invalid end address expression. " ) ;
result . AppendError ( error . AsCString ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( end_addr < = addr )
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " end address (0x% " PRIx64 " ) must be greater that the start address (0x% " PRIx64 " ). \n " , end_addr , addr ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2011-10-25 06:44:01 +00:00
else if ( m_format_options . GetCountValue ( ) . OptionWasSet ( ) )
2010-06-08 16:52:24 +00:00
{
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " specify either the end address (0x% " PRIx64 " ) or the count (--count % " PRIu64 " ), not both. \n " , end_addr , ( uint64_t ) item_count ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
total_byte_size = end_addr - addr ;
item_count = total_byte_size / item_byte_size ;
}
2014-09-29 08:02:24 +00:00
2013-06-04 22:54:16 +00:00
uint32_t max_unforced_size = target - > GetMaximumMemReadSize ( ) ;
if ( total_byte_size > max_unforced_size & & ! m_memory_options . m_force )
2012-04-28 01:27:38 +00:00
{
2013-06-04 22:54:16 +00:00
result . AppendErrorWithFormat ( " Normally, \' memory read \' will not read over % " PRIu32 " bytes of data. \n " , max_unforced_size ) ;
result . AppendErrorWithFormat ( " Please use --force to override this restriction just once. \n " ) ;
result . AppendErrorWithFormat ( " or set target.max-memory-read-size if you will often need a larger limit. \n " ) ;
2012-04-28 01:27:38 +00:00
return false ;
}
2011-04-27 22:04:39 +00:00
DataBufferSP data_sp ;
size_t bytes_read = 0 ;
2012-12-15 02:08:17 +00:00
if ( clang_ast_type . GetOpaqueQualType ( ) )
{
// Make sure we don't display our type as ASCII bytes like the default memory read
if ( m_format_options . GetFormatValue ( ) . OptionWasSet ( ) = = false )
m_format_options . GetFormatValue ( ) . SetCurrentValue ( eFormatDefault ) ;
2013-07-11 22:46:58 +00:00
bytes_read = clang_ast_type . GetByteSize ( ) * m_format_options . GetCountValue ( ) . GetCurrentValue ( ) ;
2012-12-15 02:08:17 +00:00
}
2013-01-21 19:20:50 +00:00
else if ( m_format_options . GetFormatValue ( ) . GetCurrentValue ( ) ! = eFormatCString )
2010-06-08 16:52:24 +00:00
{
2011-04-27 22:04:39 +00:00
data_sp . reset ( new DataBufferHeap ( total_byte_size , ' \0 ' ) ) ;
2013-07-24 18:17:35 +00:00
if ( data_sp - > GetBytes ( ) = = NULL )
{
2014-03-08 17:15:35 +00:00
result . AppendErrorWithFormat ( " can't allocate 0x% " PRIx32 " bytes for the memory read buffer, specify a smaller size to read " , ( uint32_t ) total_byte_size ) ;
2013-07-24 18:17:35 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2012-02-24 01:59:29 +00:00
Address address ( addr , NULL ) ;
2011-09-22 04:58:26 +00:00
bytes_read = target - > ReadMemory ( address , false , data_sp - > GetBytes ( ) , data_sp - > GetByteSize ( ) , error ) ;
2011-04-27 22:04:39 +00:00
if ( bytes_read = = 0 )
{
2012-05-25 17:05:55 +00:00
const char * error_cstr = error . AsCString ( ) ;
if ( error_cstr & & error_cstr [ 0 ] )
{
result . AppendError ( error_cstr ) ;
}
else
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " failed to read memory from 0x% " PRIx64 " . \n " , addr ) ;
2012-05-25 17:05:55 +00:00
}
2011-04-27 22:04:39 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( bytes_read < total_byte_size )
2014-03-03 19:15:20 +00:00
result . AppendWarningWithFormat ( " Not all bytes (% " PRIu64 " /% " PRIu64 " ) were able to be read from 0x% " PRIx64 " . \n " , ( uint64_t ) bytes_read , ( uint64_t ) total_byte_size , addr ) ;
2013-01-21 19:20:50 +00:00
}
else
{
// we treat c-strings as a special case because they do not have a fixed size
if ( m_format_options . GetByteSizeValue ( ) . OptionWasSet ( ) & & ! m_format_options . HasGDBFormat ( ) )
item_byte_size = m_format_options . GetByteSizeValue ( ) . GetCurrentValue ( ) ;
else
item_byte_size = target - > GetMaximumSizeOfStringSummary ( ) ;
if ( ! m_format_options . GetCountValue ( ) . OptionWasSet ( ) )
item_count = 1 ;
data_sp . reset ( new DataBufferHeap ( ( item_byte_size + 1 ) * item_count , ' \0 ' ) ) ; // account for NULLs as necessary
2013-07-24 18:17:35 +00:00
if ( data_sp - > GetBytes ( ) = = NULL )
{
result . AppendErrorWithFormat ( " can't allocate 0x% " PRIx64 " bytes for the memory read buffer, specify a smaller size to read " , ( uint64_t ) ( ( item_byte_size + 1 ) * item_count ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-01-21 19:20:50 +00:00
uint8_t * data_ptr = data_sp - > GetBytes ( ) ;
auto data_addr = addr ;
auto count = item_count ;
item_count = 0 ;
while ( item_count < count )
{
std : : string buffer ;
buffer . resize ( item_byte_size + 1 , 0 ) ;
Error error ;
size_t read = target - > ReadCStringFromMemory ( data_addr , & buffer [ 0 ] , item_byte_size + 1 , error ) ;
if ( error . Fail ( ) )
{
result . AppendErrorWithFormat ( " failed to read memory from 0x% " PRIx64 " . \n " , addr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( item_byte_size = = read )
{
result . AppendWarningWithFormat ( " unable to find a NULL terminated string at 0x% " PRIx64 " .Consider increasing the maximum read length. \n " , data_addr ) ;
break ;
}
read + = 1 ; // account for final NULL byte
memcpy ( data_ptr , & buffer [ 0 ] , read ) ;
data_ptr + = read ;
data_addr + = read ;
bytes_read + = read ;
item_count + + ; // if we break early we know we only read item_count strings
}
data_sp . reset ( new DataBufferHeap ( data_sp - > GetBytes ( ) , bytes_read + 1 ) ) ;
2010-06-08 16:52:24 +00:00
}
2012-12-15 02:08:17 +00:00
m_next_addr = addr + bytes_read ;
m_prev_byte_size = bytes_read ;
m_prev_format_options = m_format_options ;
m_prev_memory_options = m_memory_options ;
m_prev_outfile_options = m_outfile_options ;
m_prev_varobj_options = m_varobj_options ;
m_prev_clang_ast_type = clang_ast_type ;
2010-10-10 20:52:20 +00:00
StreamFile outfile_stream ;
Stream * output_stream = NULL ;
2011-04-27 22:04:39 +00:00
const FileSpec & outfile_spec = m_outfile_options . GetFile ( ) . GetCurrentValue ( ) ;
if ( outfile_spec )
2010-10-10 20:52:20 +00:00
{
char path [ PATH_MAX ] ;
2011-04-27 22:04:39 +00:00
outfile_spec . GetPath ( path , sizeof ( path ) ) ;
uint32_t open_options = File : : eOpenOptionWrite | File : : eOpenOptionCanCreate ;
const bool append = m_outfile_options . GetAppend ( ) . GetCurrentValue ( ) ;
if ( append )
open_options | = File : : eOpenOptionAppend ;
if ( outfile_stream . GetFile ( ) . Open ( path , open_options ) . Success ( ) )
2010-10-10 20:52:20 +00:00
{
2011-04-27 22:04:39 +00:00
if ( m_memory_options . m_output_as_binary )
2010-10-10 20:52:20 +00:00
{
2013-01-25 18:06:21 +00:00
const size_t bytes_written = outfile_stream . Write ( data_sp - > GetBytes ( ) , bytes_read ) ;
2010-10-10 20:52:20 +00:00
if ( bytes_written > 0 )
{
2013-01-25 18:06:21 +00:00
result . GetOutputStream ( ) . Printf ( " %zi bytes %s to '%s' \n " ,
2010-10-10 20:52:20 +00:00
bytes_written ,
2011-04-27 22:04:39 +00:00
append ? " appended " : " written " ,
2010-10-10 20:52:20 +00:00
path ) ;
return true ;
}
else
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " Failed to write % " PRIu64 " bytes to '%s'. \n " , ( uint64_t ) bytes_read , path ) ;
2010-10-10 20:52:20 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else
{
// We are going to write ASCII to the file just point the
// output_stream to our outfile_stream...
output_stream = & outfile_stream ;
}
}
else
{
2011-04-27 22:04:39 +00:00
result . AppendErrorWithFormat ( " Failed to open file '%s' for %s. \n " , path , append ? " append " : " write " ) ;
2010-10-10 20:52:20 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else
{
output_stream = & result . GetOutputStream ( ) ;
}
2011-04-27 22:04:39 +00:00
2013-01-09 19:44:40 +00:00
ExecutionContextScope * exe_scope = m_exe_ctx . GetBestExecutionContextScope ( ) ;
2011-04-27 22:04:39 +00:00
if ( clang_ast_type . GetOpaqueQualType ( ) )
{
for ( uint32_t i = 0 ; i < item_count ; + + i )
{
addr_t item_addr = addr + ( i * item_byte_size ) ;
2012-02-24 01:59:29 +00:00
Address address ( item_addr ) ;
2011-04-27 22:04:39 +00:00
StreamString name_strm ;
2012-11-29 21:49:15 +00:00
name_strm . Printf ( " 0x% " PRIx64 , item_addr ) ;
2011-10-27 17:55:14 +00:00
ValueObjectSP valobj_sp ( ValueObjectMemory : : Create ( exe_scope ,
2011-04-27 22:04:39 +00:00
name_strm . GetString ( ) . c_str ( ) ,
address ,
clang_ast_type ) ) ;
if ( valobj_sp )
{
2012-12-15 02:08:17 +00:00
Format format = m_format_options . GetFormat ( ) ;
2011-04-28 20:55:26 +00:00
if ( format ! = eFormatDefault )
valobj_sp - > SetFormat ( format ) ;
2013-09-30 19:11:51 +00:00
DumpValueObjectOptions options ( m_varobj_options . GetAsDumpOptions ( eLanguageRuntimeDescriptionDisplayVerbosityFull , format ) ) ;
2013-03-26 18:04:53 +00:00
2013-09-30 19:11:51 +00:00
valobj_sp - > Dump ( * output_stream , options ) ;
2011-04-27 22:04:39 +00:00
}
else
{
result . AppendErrorWithFormat ( " failed to create a value object for: (%s) %s \n " ,
view_as_type_cstr ,
name_strm . GetString ( ) . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
return true ;
}
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
DataExtractor data ( data_sp ,
2011-09-22 04:58:26 +00:00
target - > GetArchitecture ( ) . GetByteOrder ( ) ,
2014-09-29 08:02:24 +00:00
target - > GetArchitecture ( ) . GetAddressByteSize ( ) ,
target - > GetArchitecture ( ) . GetDataByteSize ( ) ) ;
2013-05-21 17:39:04 +00:00
Format format = m_format_options . GetFormat ( ) ;
if ( ( ( format = = eFormatChar ) | | ( format = = eFormatCharPrintable ) )
2013-10-29 23:04:29 +00:00
& & ( item_byte_size ! = 1 ) )
2013-05-21 17:39:04 +00:00
{
2013-10-29 23:04:29 +00:00
// if a count was not passed, or it is 1
if ( m_format_options . GetCountValue ( ) . OptionWasSet ( ) = = false | | item_count = = 1 )
{
// this turns requests such as
// memory read -fc -s10 -c1 *charPtrPtr
// which make no sense (what is a char of size 10?)
// into a request for fetching 10 chars of size 1 from the same memory location
format = eFormatCharArray ;
item_count = item_byte_size ;
item_byte_size = 1 ;
}
else
{
// here we passed a count, and it was not 1
// so we have a byte_size and a count
// we could well multiply those, but instead let's just fail
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " reading memory as characters of size % " PRIu64 " is not supported " , ( uint64_t ) item_byte_size ) ;
2013-10-29 23:04:29 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-05-21 17:39:04 +00:00
}
2011-04-27 22:04:39 +00:00
2010-10-10 20:52:20 +00:00
assert ( output_stream ) ;
2013-01-25 18:06:21 +00:00
size_t bytes_dumped = data . Dump ( output_stream ,
0 ,
2013-05-21 17:39:04 +00:00
format ,
2013-01-25 18:06:21 +00:00
item_byte_size ,
item_count ,
2014-09-29 08:02:24 +00:00
num_per_line / target - > GetArchitecture ( ) . GetDataByteSize ( ) ,
2013-01-25 18:06:21 +00:00
addr ,
0 ,
0 ,
exe_scope ) ;
2011-10-28 23:44:55 +00:00
m_next_addr = addr + bytes_dumped ;
2010-10-10 20:52:20 +00:00
output_stream - > EOL ( ) ;
2010-06-08 16:52:24 +00:00
return true ;
}
2011-04-27 22:04:39 +00:00
OptionGroupOptions m_option_group ;
OptionGroupFormat m_format_options ;
OptionGroupReadMemory m_memory_options ;
OptionGroupOutputFile m_outfile_options ;
2011-04-28 20:55:26 +00:00
OptionGroupValueObjectDisplay m_varobj_options ;
2011-10-26 04:32:38 +00:00
lldb : : addr_t m_next_addr ;
lldb : : addr_t m_prev_byte_size ;
OptionGroupFormat m_prev_format_options ;
OptionGroupReadMemory m_prev_memory_options ;
OptionGroupOutputFile m_prev_outfile_options ;
OptionGroupValueObjectDisplay m_prev_varobj_options ;
2012-12-15 02:08:17 +00:00
ClangASTType m_prev_clang_ast_type ;
2010-06-08 16:52:24 +00:00
} ;
2013-11-13 02:18:44 +00:00
OptionDefinition
g_memory_find_option_table [ ] =
{
2014-07-09 16:31:49 +00:00
{ LLDB_OPT_SET_1 , false , " expression " , ' e ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeExpression , " Evaluate an expression to obtain a byte pattern. " } ,
{ LLDB_OPT_SET_2 , false , " string " , ' s ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeName , " Use text to find a byte pattern. " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " count " , ' c ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeCount , " How many times to perform the search. " } ,
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 , false , " dump-offset " , ' o ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeOffset , " When dumping memory for a match, an offset from the match location to start dumping from. " } ,
2013-11-13 02:18:44 +00:00
} ;
//----------------------------------------------------------------------
// Find the specified data in memory
//----------------------------------------------------------------------
class CommandObjectMemoryFind : public CommandObjectParsed
{
public :
class OptionGroupFindMemory : public OptionGroup
{
public :
OptionGroupFindMemory ( ) :
OptionGroup ( ) ,
m_count ( 1 ) ,
2013-11-13 20:08:30 +00:00
m_offset ( 0 )
2013-11-13 02:18:44 +00:00
{
}
virtual
~ OptionGroupFindMemory ( )
{
}
virtual uint32_t
GetNumDefinitions ( )
{
return sizeof ( g_memory_find_option_table ) / sizeof ( OptionDefinition ) ;
}
virtual const OptionDefinition *
GetDefinitions ( )
{
return g_memory_find_option_table ;
}
virtual Error
SetOptionValue ( CommandInterpreter & interpreter ,
uint32_t option_idx ,
const char * option_arg )
{
Error error ;
const int short_option = g_memory_find_option_table [ option_idx ] . short_option ;
switch ( short_option )
{
case ' e ' :
m_expr . SetValueFromCString ( option_arg ) ;
break ;
case ' s ' :
m_string . SetValueFromCString ( option_arg ) ;
break ;
case ' c ' :
if ( m_count . SetValueFromCString ( option_arg ) . Fail ( ) )
error . SetErrorString ( " unrecognized value for count " ) ;
break ;
2013-11-13 20:08:30 +00:00
case ' o ' :
if ( m_offset . SetValueFromCString ( option_arg ) . Fail ( ) )
error . SetErrorString ( " unrecognized value for dump-offset " ) ;
break ;
2013-11-13 02:18:44 +00:00
default :
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " , short_option ) ;
break ;
}
return error ;
}
virtual void
OptionParsingStarting ( CommandInterpreter & interpreter )
{
m_expr . Clear ( ) ;
m_string . Clear ( ) ;
m_count . Clear ( ) ;
}
OptionValueString m_expr ;
OptionValueString m_string ;
OptionValueUInt64 m_count ;
2013-11-13 20:08:30 +00:00
OptionValueUInt64 m_offset ;
2013-11-13 02:18:44 +00:00
} ;
CommandObjectMemoryFind ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" memory find " ,
" Find a value in the memory of the process being debugged. " ,
NULL ,
eFlagRequiresProcess | eFlagProcessMustBeLaunched ) ,
m_option_group ( interpreter ) ,
m_memory_options ( )
{
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData addr_arg ;
CommandArgumentData value_arg ;
// Define the first (and only) variant of this arg.
addr_arg . arg_type = eArgTypeAddress ;
addr_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg1 . push_back ( addr_arg ) ;
// Define the first (and only) variant of this arg.
value_arg . arg_type = eArgTypeValue ;
value_arg . arg_repetition = eArgRepeatPlus ;
// There is only one variant this argument could be; put it into the argument entry.
arg2 . push_back ( value_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
m_option_group . Append ( & m_memory_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_2 ) ;
m_option_group . Finalize ( ) ;
}
virtual
~ CommandObjectMemoryFind ( )
{
}
Options *
GetOptions ( )
{
return & m_option_group ;
}
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
// No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
Process * process = m_exe_ctx . GetProcessPtr ( ) ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc ! = 2 )
{
2013-11-13 02:22:24 +00:00
result . AppendError ( " two addresses needed for memory find " ) ;
2013-11-13 02:18:44 +00:00
return false ;
}
Error error ;
lldb : : addr_t low_addr = Args : : StringToAddress ( & m_exe_ctx , command . GetArgumentAtIndex ( 0 ) , LLDB_INVALID_ADDRESS , & error ) ;
if ( low_addr = = LLDB_INVALID_ADDRESS | | error . Fail ( ) )
{
result . AppendError ( " invalid low address " ) ;
return false ;
}
lldb : : addr_t high_addr = Args : : StringToAddress ( & m_exe_ctx , command . GetArgumentAtIndex ( 1 ) , LLDB_INVALID_ADDRESS , & error ) ;
if ( high_addr = = LLDB_INVALID_ADDRESS | | error . Fail ( ) )
{
2014-09-06 11:29:08 +00:00
result . AppendError ( " invalid high address " ) ;
2013-11-13 02:18:44 +00:00
return false ;
}
if ( high_addr < = low_addr )
{
result . AppendError ( " starting address must be smaller than ending address " ) ;
return false ;
}
lldb : : addr_t found_location = LLDB_INVALID_ADDRESS ;
DataBufferHeap buffer ;
if ( m_memory_options . m_string . OptionWasSet ( ) )
buffer . CopyData ( m_memory_options . m_string . GetStringValue ( ) , strlen ( m_memory_options . m_string . GetStringValue ( ) ) ) ;
else if ( m_memory_options . m_expr . OptionWasSet ( ) )
{
StackFrame * frame = m_exe_ctx . GetFramePtr ( ) ;
ValueObjectSP result_sp ;
if ( process - > GetTarget ( ) . EvaluateExpression ( m_memory_options . m_expr . GetStringValue ( ) , frame , result_sp ) & & result_sp . get ( ) )
{
uint64_t value = result_sp - > GetValueAsUnsigned ( 0 ) ;
switch ( result_sp - > GetClangType ( ) . GetByteSize ( ) )
{
case 1 : {
uint8_t byte = ( uint8_t ) value ;
buffer . CopyData ( & byte , 1 ) ;
}
break ;
case 2 : {
uint16_t word = ( uint16_t ) value ;
buffer . CopyData ( & word , 2 ) ;
}
break ;
case 4 : {
uint32_t lword = ( uint32_t ) value ;
buffer . CopyData ( & lword , 4 ) ;
}
break ;
case 8 : {
buffer . CopyData ( & value , 8 ) ;
}
break ;
case 3 :
case 5 :
case 6 :
case 7 :
result . AppendError ( " unknown type. pass a string instead " ) ;
return false ;
default :
result . AppendError ( " do not know how to deal with larger than 8 byte result types. pass a string instead " ) ;
return false ;
}
}
else
{
result . AppendError ( " expression evaluation failed. pass a string instead? " ) ;
return false ;
}
}
else
{
result . AppendError ( " please pass either a block of text, or an expression to evaluate. " ) ;
return false ;
}
size_t count = m_memory_options . m_count . GetCurrentValue ( ) ;
found_location = low_addr ;
bool ever_found = false ;
while ( count )
{
found_location = Search ( found_location , high_addr , buffer . GetBytes ( ) , buffer . GetByteSize ( ) ) ;
if ( found_location = = LLDB_INVALID_ADDRESS )
{
if ( ! ever_found )
{
result . AppendMessage ( " Your data was not found within the range. \n " ) ;
result . SetStatus ( lldb : : eReturnStatusSuccessFinishNoResult ) ;
}
else
result . AppendMessage ( " No more matches found within the range. \n " ) ;
break ;
}
result . AppendMessageWithFormat ( " Your data was found at location: 0x% " PRIx64 " \n " , found_location ) ;
2013-11-13 20:08:30 +00:00
DataBufferHeap dumpbuffer ( 32 , 0 ) ;
process - > ReadMemory ( found_location + m_memory_options . m_offset . GetCurrentValue ( ) , dumpbuffer . GetBytes ( ) , dumpbuffer . GetByteSize ( ) , error ) ;
if ( ! error . Fail ( ) )
2013-11-13 02:18:44 +00:00
{
2013-11-13 20:08:30 +00:00
DataExtractor data ( dumpbuffer . GetBytes ( ) , dumpbuffer . GetByteSize ( ) , process - > GetByteOrder ( ) , process - > GetAddressByteSize ( ) ) ;
data . Dump ( & result . GetOutputStream ( ) , 0 , lldb : : eFormatBytesWithASCII , 1 , dumpbuffer . GetByteSize ( ) , 16 , found_location + m_memory_options . m_offset . GetCurrentValue ( ) , 0 , 0 ) ;
result . GetOutputStream ( ) . EOL ( ) ;
2013-11-13 02:18:44 +00:00
}
2013-11-13 20:08:30 +00:00
2013-11-13 02:18:44 +00:00
- - count ;
found_location + + ;
ever_found = true ;
}
result . SetStatus ( lldb : : eReturnStatusSuccessFinishResult ) ;
return true ;
}
lldb : : addr_t
Search ( lldb : : addr_t low ,
lldb : : addr_t high ,
uint8_t * buffer ,
size_t buffer_size )
{
Process * process = m_exe_ctx . GetProcessPtr ( ) ;
DataBufferHeap heap ( buffer_size , 0 ) ;
lldb : : addr_t fictional_ptr = low ;
for ( auto ptr = low ;
low < high ;
fictional_ptr + + )
{
Error error ;
if ( ptr = = low | | buffer_size = = 1 )
process - > ReadMemory ( ptr , heap . GetBytes ( ) , buffer_size , error ) ;
else
{
memmove ( heap . GetBytes ( ) , heap . GetBytes ( ) + 1 , buffer_size - 1 ) ;
process - > ReadMemory ( ptr , heap . GetBytes ( ) + buffer_size - 1 , 1 , error ) ;
}
if ( error . Fail ( ) )
return LLDB_INVALID_ADDRESS ;
if ( memcmp ( heap . GetBytes ( ) , buffer , buffer_size ) = = 0 )
return fictional_ptr ;
if ( ptr = = low )
ptr + = buffer_size ;
else
ptr + = 1 ;
}
return LLDB_INVALID_ADDRESS ;
}
OptionGroupOptions m_option_group ;
OptionGroupFindMemory m_memory_options ;
} ;
2011-10-25 06:44:01 +00:00
OptionDefinition
g_memory_write_option_table [ ] =
{
2014-07-09 16:31:49 +00:00
{ LLDB_OPT_SET_1 , true , " infile " , ' i ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeFilename , " Write memory using the contents of a file. " } ,
2014-07-10 14:45:57 +00:00
{ LLDB_OPT_SET_1 , false , " offset " , ' o ' , OptionParser : : eRequiredArgument , NULL , NULL , 0 , eArgTypeOffset , " Start writing bytes from an offset within the input file. " } ,
2011-10-25 06:44:01 +00:00
} ;
2010-06-08 16:52:24 +00:00
//----------------------------------------------------------------------
// Write memory to the inferior process
//----------------------------------------------------------------------
2012-06-08 21:56:10 +00:00
class CommandObjectMemoryWrite : public CommandObjectParsed
2010-06-08 16:52:24 +00:00
{
public :
2011-10-25 06:44:01 +00:00
class OptionGroupWriteMemory : public OptionGroup
2010-06-08 16:52:24 +00:00
{
public :
2011-10-25 06:44:01 +00:00
OptionGroupWriteMemory ( ) :
OptionGroup ( )
2010-06-08 16:52:24 +00:00
{
}
virtual
2011-10-25 06:44:01 +00:00
~ OptionGroupWriteMemory ( )
2010-06-08 16:52:24 +00:00
{
}
2011-10-25 06:44:01 +00:00
virtual uint32_t
GetNumDefinitions ( )
{
return sizeof ( g_memory_write_option_table ) / sizeof ( OptionDefinition ) ;
}
2013-11-13 02:18:44 +00:00
2011-10-25 06:44:01 +00:00
virtual const OptionDefinition *
GetDefinitions ( )
{
return g_memory_write_option_table ;
}
2013-11-13 02:18:44 +00:00
2010-06-08 16:52:24 +00:00
virtual Error
2011-10-25 06:44:01 +00:00
SetOptionValue ( CommandInterpreter & interpreter ,
uint32_t option_idx ,
const char * option_arg )
2010-06-08 16:52:24 +00:00
{
Error error ;
2012-12-04 00:32:51 +00:00
const int short_option = g_memory_write_option_table [ option_idx ] . short_option ;
2013-11-13 02:18:44 +00:00
2010-06-08 16:52:24 +00:00
switch ( short_option )
{
2011-10-25 06:44:01 +00:00
case ' i ' :
m_infile . SetFile ( option_arg , true ) ;
if ( ! m_infile . Exists ( ) )
2010-10-10 20:52:20 +00:00
{
2011-10-25 06:44:01 +00:00
m_infile . Clear ( ) ;
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " input file does not exist: '%s' " , option_arg ) ;
2010-10-10 20:52:20 +00:00
}
2011-10-25 06:44:01 +00:00
break ;
2013-11-13 02:18:44 +00:00
2011-10-25 06:44:01 +00:00
case ' o ' :
{
bool success ;
m_infile_offset = Args : : StringToUInt64 ( option_arg , 0 , 0 , & success ) ;
if ( ! success )
{
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " invalid offset string '%s' " , option_arg ) ;
2011-10-25 06:44:01 +00:00
}
}
break ;
default :
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " , short_option ) ;
2011-10-25 06:44:01 +00:00
break ;
2010-06-08 16:52:24 +00:00
}
return error ;
}
2011-10-25 06:44:01 +00:00
virtual void
OptionParsingStarting ( CommandInterpreter & interpreter )
2010-06-08 16:52:24 +00:00
{
2010-10-10 20:52:20 +00:00
m_infile . Clear ( ) ;
m_infile_offset = 0 ;
2010-06-08 16:52:24 +00:00
}
2010-10-10 20:52:20 +00:00
FileSpec m_infile ;
off_t m_infile_offset ;
2010-06-08 16:52:24 +00:00
} ;
2010-09-18 01:14:36 +00:00
CommandObjectMemoryWrite ( CommandInterpreter & interpreter ) :
2012-06-08 21:56:10 +00:00
CommandObjectParsed ( interpreter ,
" memory write " ,
" Write to the memory of the process being debugged. " ,
NULL ,
2013-01-09 19:44:40 +00:00
eFlagRequiresProcess | eFlagProcessMustBeLaunched ) ,
2011-10-25 06:44:01 +00:00
m_option_group ( interpreter ) ,
m_format_options ( eFormatBytes , 1 , UINT64_MAX ) ,
m_memory_options ( )
2010-06-08 16:52:24 +00:00
{
2010-10-04 22:28:36 +00:00
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData addr_arg ;
CommandArgumentData value_arg ;
// Define the first (and only) variant of this arg.
addr_arg . arg_type = eArgTypeAddress ;
addr_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg1 . push_back ( addr_arg ) ;
// Define the first (and only) variant of this arg.
value_arg . arg_type = eArgTypeValue ;
value_arg . arg_repetition = eArgRepeatPlus ;
// There is only one variant this argument could be; put it into the argument entry.
arg2 . push_back ( value_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
2011-10-25 06:44:01 +00:00
m_option_group . Append ( & m_format_options , OptionGroupFormat : : OPTION_GROUP_FORMAT , LLDB_OPT_SET_1 ) ;
m_option_group . Append ( & m_format_options , OptionGroupFormat : : OPTION_GROUP_SIZE , LLDB_OPT_SET_1 | LLDB_OPT_SET_2 ) ;
m_option_group . Append ( & m_memory_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_2 ) ;
m_option_group . Finalize ( ) ;
2010-06-08 16:52:24 +00:00
}
virtual
~ CommandObjectMemoryWrite ( )
{
}
Options *
GetOptions ( )
{
2011-10-25 06:44:01 +00:00
return & m_option_group ;
2010-06-08 16:52:24 +00:00
}
bool
UIntValueIsValidForSize ( uint64_t uval64 , size_t total_byte_size )
{
if ( total_byte_size > 8 )
return false ;
if ( total_byte_size = = 8 )
return true ;
const uint64_t max = ( ( uint64_t ) 1 < < ( uint64_t ) ( total_byte_size * 8 ) ) - 1 ;
return uval64 < = max ;
}
bool
SIntValueIsValidForSize ( int64_t sval64 , size_t total_byte_size )
{
if ( total_byte_size > 8 )
return false ;
if ( total_byte_size = = 8 )
return true ;
const int64_t max = ( ( int64_t ) 1 < < ( uint64_t ) ( total_byte_size * 8 - 1 ) ) - 1 ;
const int64_t min = ~ ( max ) ;
return min < = sval64 & & sval64 < = max ;
}
2012-06-08 21:56:10 +00:00
protected :
2010-06-08 16:52:24 +00:00
virtual bool
2012-06-08 21:56:10 +00:00
DoExecute ( Args & command , CommandReturnObject & result )
2010-06-08 16:52:24 +00:00
{
2013-01-09 19:44:40 +00:00
// No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
Process * process = m_exe_ctx . GetProcessPtr ( ) ;
2010-06-08 16:52:24 +00:00
const size_t argc = command . GetArgumentCount ( ) ;
2011-10-25 06:44:01 +00:00
if ( m_memory_options . m_infile )
2010-06-08 16:52:24 +00:00
{
2010-10-10 20:52:20 +00:00
if ( argc < 1 )
{
result . AppendErrorWithFormat ( " %s takes a destination address when writing file contents. \n " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else if ( argc < 2 )
{
result . AppendErrorWithFormat ( " %s takes a destination address and at least one value. \n " , m_cmd_name . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
StreamString buffer ( Stream : : eBinary ,
2011-02-15 21:59:32 +00:00
process - > GetTarget ( ) . GetArchitecture ( ) . GetAddressByteSize ( ) ,
process - > GetTarget ( ) . GetArchitecture ( ) . GetByteOrder ( ) ) ;
2010-06-08 16:52:24 +00:00
2011-10-25 06:44:01 +00:00
OptionValueUInt64 & byte_size_value = m_format_options . GetByteSizeValue ( ) ;
size_t item_byte_size = byte_size_value . GetCurrentValue ( ) ;
2010-07-09 20:39:50 +00:00
2012-12-06 22:49:16 +00:00
Error error ;
2013-01-09 19:44:40 +00:00
lldb : : addr_t addr = Args : : StringToAddress ( & m_exe_ctx ,
2012-12-06 22:49:16 +00:00
command . GetArgumentAtIndex ( 0 ) ,
LLDB_INVALID_ADDRESS ,
& error ) ;
2010-06-08 16:52:24 +00:00
if ( addr = = LLDB_INVALID_ADDRESS )
{
2012-12-06 22:49:16 +00:00
result . AppendError ( " invalid address expression \n " ) ;
result . AppendError ( error . AsCString ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-10-10 20:52:20 +00:00
2011-10-25 06:44:01 +00:00
if ( m_memory_options . m_infile )
2010-10-10 20:52:20 +00:00
{
size_t length = SIZE_MAX ;
2011-10-25 06:44:01 +00:00
if ( item_byte_size > 0 )
length = item_byte_size ;
lldb : : DataBufferSP data_sp ( m_memory_options . m_infile . ReadFileContents ( m_memory_options . m_infile_offset , length ) ) ;
2010-10-10 20:52:20 +00:00
if ( data_sp )
{
length = data_sp - > GetByteSize ( ) ;
if ( length > 0 )
{
Error error ;
size_t bytes_written = process - > WriteMemory ( addr , data_sp - > GetBytes ( ) , length , error ) ;
if ( bytes_written = = length )
{
// All bytes written
2012-11-29 21:49:15 +00:00
result . GetOutputStream ( ) . Printf ( " % " PRIu64 " bytes were written to 0x% " PRIx64 " \n " , ( uint64_t ) bytes_written , addr ) ;
2010-10-10 20:52:20 +00:00
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else if ( bytes_written > 0 )
{
// Some byte written
2012-11-29 21:49:15 +00:00
result . GetOutputStream ( ) . Printf ( " % " PRIu64 " bytes of % " PRIu64 " requested were written to 0x% " PRIx64 " \n " , ( uint64_t ) bytes_written , ( uint64_t ) length , addr ) ;
2010-10-10 20:52:20 +00:00
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " Memory write to 0x% " PRIx64 " failed: %s. \n " , addr , error . AsCString ( ) ) ;
2010-10-10 20:52:20 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
}
}
}
else
{
result . AppendErrorWithFormat ( " Unable to read contents of file. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
2011-10-25 06:44:01 +00:00
else if ( item_byte_size = = 0 )
2010-10-10 20:52:20 +00:00
{
2011-10-25 06:44:01 +00:00
if ( m_format_options . GetFormat ( ) = = eFormatPointer )
2010-10-10 20:52:20 +00:00
item_byte_size = buffer . GetAddressByteSize ( ) ;
else
item_byte_size = 1 ;
}
2010-06-08 16:52:24 +00:00
command . Shift ( ) ; // shift off the address argument
uint64_t uval64 ;
int64_t sval64 ;
bool success = false ;
2013-01-25 18:06:21 +00:00
const size_t num_value_args = command . GetArgumentCount ( ) ;
for ( size_t i = 0 ; i < num_value_args ; + + i )
2010-06-08 16:52:24 +00:00
{
const char * value_str = command . GetArgumentAtIndex ( i ) ;
2011-10-25 06:44:01 +00:00
switch ( m_format_options . GetFormat ( ) )
2010-06-08 16:52:24 +00:00
{
2011-06-23 21:22:24 +00:00
case kNumFormats :
2010-06-08 16:52:24 +00:00
case eFormatFloat : // TODO: add support for floats soon
case eFormatCharPrintable :
case eFormatBytesWithASCII :
case eFormatComplex :
case eFormatEnum :
case eFormatUnicode16 :
case eFormatUnicode32 :
case eFormatVectorOfChar :
case eFormatVectorOfSInt8 :
case eFormatVectorOfUInt8 :
case eFormatVectorOfSInt16 :
case eFormatVectorOfUInt16 :
case eFormatVectorOfSInt32 :
case eFormatVectorOfUInt32 :
case eFormatVectorOfSInt64 :
case eFormatVectorOfUInt64 :
case eFormatVectorOfFloat32 :
case eFormatVectorOfFloat64 :
case eFormatVectorOfUInt128 :
2011-03-20 04:57:14 +00:00
case eFormatOSType :
case eFormatComplexInteger :
2011-10-27 17:55:14 +00:00
case eFormatAddressInfo :
case eFormatHexFloat :
case eFormatInstruction :
2012-08-08 17:35:10 +00:00
case eFormatVoid :
2010-06-08 16:52:24 +00:00
result . AppendError ( " unsupported format for writing memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
case eFormatDefault :
case eFormatBytes :
case eFormatHex :
2012-08-09 19:33:34 +00:00
case eFormatHexUppercase :
2010-07-09 20:39:50 +00:00
case eFormatPointer :
2010-06-08 16:52:24 +00:00
// Decode hex bytes
uval64 = Args : : StringToUInt64 ( value_str , UINT64_MAX , 16 , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " '%s' is not a valid hex string value. \n " , value_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) )
{
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " Value 0x% " PRIx64 " is too large to fit in a % " PRIu64 " byte unsigned integer value. \n " , uval64 , ( uint64_t ) item_byte_size ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatBoolean :
uval64 = Args : : StringToBoolean ( value_str , false , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " '%s' is not a valid boolean string value. \n " , value_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatBinary :
uval64 = Args : : StringToUInt64 ( value_str , UINT64_MAX , 2 , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " '%s' is not a valid binary string value. \n " , value_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) )
{
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " Value 0x% " PRIx64 " is too large to fit in a % " PRIu64 " byte unsigned integer value. \n " , uval64 , ( uint64_t ) item_byte_size ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
2011-06-17 23:50:44 +00:00
case eFormatCharArray :
2010-06-08 16:52:24 +00:00
case eFormatChar :
case eFormatCString :
if ( value_str [ 0 ] )
{
size_t len = strlen ( value_str ) ;
// Include the NULL for C strings...
2011-10-25 06:44:01 +00:00
if ( m_format_options . GetFormat ( ) = = eFormatCString )
2010-06-08 16:52:24 +00:00
+ + len ;
Error error ;
if ( process - > WriteMemory ( addr , value_str , len , error ) = = len )
{
addr + = len ;
}
else
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " Memory write to 0x% " PRIx64 " failed: %s. \n " , addr , error . AsCString ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
break ;
case eFormatDecimal :
sval64 = Args : : StringToSInt64 ( value_str , INT64_MAX , 0 , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " '%s' is not a valid signed decimal value. \n " , value_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( ! SIntValueIsValidForSize ( sval64 , item_byte_size ) )
{
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " Value % " PRIi64 " is too large or small to fit in a % " PRIu64 " byte signed integer value. \n " , sval64 , ( uint64_t ) item_byte_size ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( sval64 , item_byte_size ) ;
break ;
case eFormatUnsigned :
uval64 = Args : : StringToUInt64 ( value_str , UINT64_MAX , 0 , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " '%s' is not a valid unsigned decimal string value. \n " , value_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) )
{
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " Value % " PRIu64 " is too large to fit in a % " PRIu64 " byte unsigned integer value. \n " , uval64 , ( uint64_t ) item_byte_size ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatOctal :
uval64 = Args : : StringToUInt64 ( value_str , UINT64_MAX , 8 , & success ) ;
if ( ! success )
{
result . AppendErrorWithFormat ( " '%s' is not a valid octal string value. \n " , value_str ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) )
{
2014-03-03 19:15:20 +00:00
result . AppendErrorWithFormat ( " Value % " PRIo64 " is too large to fit in a % " PRIu64 " byte unsigned integer value. \n " , uval64 , ( uint64_t ) item_byte_size ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
}
}
if ( ! buffer . GetString ( ) . empty ( ) )
{
Error error ;
2010-07-20 22:52:08 +00:00
if ( process - > WriteMemory ( addr , buffer . GetString ( ) . c_str ( ) , buffer . GetString ( ) . size ( ) , error ) = = buffer . GetString ( ) . size ( ) )
2010-06-08 16:52:24 +00:00
return true ;
else
{
2012-11-29 21:49:15 +00:00
result . AppendErrorWithFormat ( " Memory write to 0x% " PRIx64 " failed: %s. \n " , addr , error . AsCString ( ) ) ;
2010-06-08 16:52:24 +00:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
return true ;
}
2011-10-25 06:44:01 +00:00
OptionGroupOptions m_option_group ;
OptionGroupFormat m_format_options ;
OptionGroupWriteMemory m_memory_options ;
2010-06-08 16:52:24 +00:00
} ;
2014-09-04 01:03:18 +00:00
//----------------------------------------------------------------------
// Get malloc/free history of a memory address.
//----------------------------------------------------------------------
class CommandObjectMemoryHistory : public CommandObjectParsed
{
public :
CommandObjectMemoryHistory ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" memory history " ,
" Prints out the recorded stack traces for allocation/deallocation of a memory address. " ,
NULL ,
eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched )
{
CommandArgumentEntry arg1 ;
CommandArgumentData addr_arg ;
// Define the first (and only) variant of this arg.
addr_arg . arg_type = eArgTypeAddress ;
addr_arg . arg_repetition = eArgRepeatPlain ;
// There is only one variant this argument could be; put it into the argument entry.
arg1 . push_back ( addr_arg ) ;
// Push the data for the first argument into the m_arguments vector.
m_arguments . push_back ( arg1 ) ;
}
virtual
~ CommandObjectMemoryHistory ( )
{
}
virtual const char * GetRepeatCommand ( Args & current_command_args , uint32_t index )
{
return m_cmd_name . c_str ( ) ;
}
protected :
virtual bool
DoExecute ( Args & command , CommandReturnObject & result )
{
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc = = 0 | | argc > 1 )
{
result . AppendErrorWithFormat ( " %s takes an address expression " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Error error ;
lldb : : addr_t addr = Args : : StringToAddress ( & m_exe_ctx ,
command . GetArgumentAtIndex ( 0 ) ,
LLDB_INVALID_ADDRESS ,
& error ) ;
if ( addr = = LLDB_INVALID_ADDRESS )
{
result . AppendError ( " invalid address expression " ) ;
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Stream * output_stream = & result . GetOutputStream ( ) ;
const ProcessSP & process_sp = m_exe_ctx . GetProcessSP ( ) ;
const MemoryHistorySP & memory_history = MemoryHistory : : FindPlugin ( process_sp ) ;
if ( ! memory_history . get ( ) )
{
result . AppendError ( " no available memory history provider " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
HistoryThreads thread_list = memory_history - > GetHistoryThreads ( addr ) ;
for ( auto thread : thread_list ) {
thread - > GetStatus ( * output_stream , 0 , UINT32_MAX , 0 ) ;
}
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return true ;
}
} ;
2010-06-08 16:52:24 +00:00
//-------------------------------------------------------------------------
// CommandObjectMemory
//-------------------------------------------------------------------------
2010-06-23 01:19:29 +00:00
CommandObjectMemory : : CommandObjectMemory ( CommandInterpreter & interpreter ) :
2010-09-18 01:14:36 +00:00
CommandObjectMultiword ( interpreter ,
" memory " ,
2010-09-07 22:38:08 +00:00
" A set of commands for operating on memory. " ,
2010-06-08 16:52:24 +00:00
" memory <subcommand> [<subcommand-options>] " )
{
2013-11-13 02:18:44 +00:00
LoadSubCommand ( " find " , CommandObjectSP ( new CommandObjectMemoryFind ( interpreter ) ) ) ;
2010-09-18 01:14:36 +00:00
LoadSubCommand ( " read " , CommandObjectSP ( new CommandObjectMemoryRead ( interpreter ) ) ) ;
LoadSubCommand ( " write " , CommandObjectSP ( new CommandObjectMemoryWrite ( interpreter ) ) ) ;
2014-09-04 01:03:18 +00:00
LoadSubCommand ( " history " , CommandObjectSP ( new CommandObjectMemoryHistory ( interpreter ) ) ) ;
2010-06-08 16:52:24 +00:00
}
CommandObjectMemory : : ~ CommandObjectMemory ( )
{
}