2013-08-23 13:46:38 -04: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.
//
//===----------------------------------------------------------------------===//
// C Includes
2013-11-06 11:48:53 -05:00
# include <inttypes.h>
2013-08-23 13:46:38 -04:00
// C++ Includes
// Other libraries and framework includes
2015-07-03 12:57:06 -04:00
# include "clang/AST/Decl.h"
2016-07-23 16:50:09 -04:00
2013-08-23 13:46:38 -04:00
// Project includes
2016-07-23 16:50:09 -04:00
# include "CommandObjectMemory.h"
# include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/DataBufferHeap.h"
# include "lldb/Core/DataExtractor.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Core/Module.h"
2016-07-23 16:50:09 -04:00
# include "lldb/Core/Section.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/StreamString.h"
# include "lldb/Core/ValueObjectMemory.h"
2013-11-06 11:48:53 -05:00
# include "lldb/DataFormatters/ValueObjectPrinter.h"
2015-02-08 20:44:09 -05:00
# include "lldb/Host/StringConvert.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/Args.h"
# include "lldb/Interpreter/CommandInterpreter.h"
2016-07-23 16:50:09 -04:00
# include "lldb/Interpreter/CommandReturnObject.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/OptionGroupFormat.h"
# include "lldb/Interpreter/OptionGroupOutputFile.h"
# include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
# include "lldb/Interpreter/OptionValueString.h"
2016-07-23 16:50:09 -04:00
# include "lldb/Interpreter/Options.h"
2015-12-30 06:55:28 -05:00
# include "lldb/Symbol/ClangASTContext.h"
2016-07-23 16:50:09 -04:00
# include "lldb/Symbol/SymbolFile.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Symbol/TypeList.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Target/MemoryHistory.h"
2016-07-23 16:50:09 -04:00
# include "lldb/Target/MemoryRegionInfo.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/Process.h"
# include "lldb/Target/StackFrame.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Target/Thread.h"
2013-08-23 13:46:38 -04:00
2016-07-23 16:50:09 -04:00
# include "lldb/lldb-private.h"
2013-08-23 13:46:38 -04:00
using namespace lldb ;
using namespace lldb_private ;
2017-01-02 14:26:05 -05:00
static OptionDefinition g_read_memory_options [ ] = {
// clang-format off
{ LLDB_OPT_SET_1 , false , " num-per-line " , ' l ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeNumberPerLine , " The number of items per line to display. " } ,
{ LLDB_OPT_SET_2 , false , " binary " , ' b ' , OptionParser : : eNoArgument , nullptr , nullptr , 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 , nullptr , nullptr , 0 , eArgTypeNone , " The name of a type to view memory as. " } ,
{ LLDB_OPT_SET_3 , false , " offset " , ' E ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeCount , " How many elements of the specified type to skip before starting to display data. " } ,
{ LLDB_OPT_SET_1 |
LLDB_OPT_SET_2 |
LLDB_OPT_SET_3 , false , " force " , ' r ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Necessary if reading over target.max-memory-read-size bytes. " } ,
// clang-format on
2013-08-23 13:46:38 -04:00
} ;
2017-01-02 14:26:05 -05:00
class OptionGroupReadMemory : public OptionGroup {
2013-08-23 13:46:38 -04:00
public :
2017-01-02 14:26:05 -05:00
OptionGroupReadMemory ( )
: m_num_per_line ( 1 , 1 ) , m_output_as_binary ( false ) , m_view_as_type ( ) ,
m_offset ( 0 , 0 ) { }
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
~ OptionGroupReadMemory ( ) override = default ;
2016-07-23 16:50:09 -04:00
2017-01-02 14:26:05 -05:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
return llvm : : makeArrayRef ( g_read_memory_options ) ;
}
Error SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_value ,
ExecutionContext * execution_context ) override {
Error error ;
const int short_option = g_read_memory_options [ option_idx ] . short_option ;
switch ( short_option ) {
case ' l ' :
error = m_num_per_line . SetValueFromString ( option_value ) ;
if ( m_num_per_line . GetCurrentValue ( ) = = 0 )
error . SetErrorStringWithFormat (
" invalid value for --num-per-line option '%s' " ,
option_value . str ( ) . c_str ( ) ) ;
break ;
case ' b ' :
m_output_as_binary = true ;
break ;
case ' t ' :
error = m_view_as_type . SetValueFromString ( option_value ) ;
break ;
case ' r ' :
m_force = true ;
break ;
case ' E ' :
error = m_offset . SetValueFromString ( option_value ) ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " ,
short_option ) ;
break ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
return error ;
}
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
m_num_per_line . Clear ( ) ;
m_output_as_binary = false ;
m_view_as_type . Clear ( ) ;
m_force = false ;
m_offset . Clear ( ) ;
}
Error FinalizeSettings ( Target * target , OptionGroupFormat & format_options ) {
Error error ;
OptionValueUInt64 & byte_size_value = format_options . GetByteSizeValue ( ) ;
OptionValueUInt64 & count_value = format_options . GetCountValue ( ) ;
const bool byte_size_option_set = byte_size_value . OptionWasSet ( ) ;
const bool num_per_line_option_set = m_num_per_line . OptionWasSet ( ) ;
const bool count_option_set = format_options . GetCountValue ( ) . OptionWasSet ( ) ;
switch ( format_options . GetFormat ( ) ) {
default :
break ;
case eFormatBoolean :
if ( ! byte_size_option_set )
byte_size_value = 1 ;
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 8 ;
break ;
case eFormatCString :
break ;
case eFormatInstruction :
if ( count_option_set )
byte_size_value = target - > GetArchitecture ( ) . GetMaximumOpcodeByteSize ( ) ;
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 ;
case eFormatPointer :
byte_size_value = target - > GetArchitecture ( ) . GetAddressByteSize ( ) ;
if ( ! num_per_line_option_set )
m_num_per_line = 4 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 8 ;
break ;
case eFormatBinary :
case eFormatFloat :
case eFormatOctal :
case eFormatDecimal :
case eFormatEnum :
case eFormatUnicode16 :
case eFormatUnicode32 :
case eFormatUnsigned :
case eFormatHexFloat :
if ( ! byte_size_option_set )
byte_size_value = 4 ;
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 8 ;
break ;
case eFormatBytes :
case eFormatBytesWithASCII :
if ( byte_size_option_set ) {
if ( byte_size_value > 1 )
error . SetErrorStringWithFormat (
" display format (bytes/bytes with ASCII) conflicts with the "
" specified byte size % " PRIu64 " \n "
" \t consider using a different display format or don't specify "
" the byte size. " ,
byte_size_value . GetCurrentValue ( ) ) ;
} else
byte_size_value = 1 ;
if ( ! num_per_line_option_set )
m_num_per_line = 16 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 32 ;
break ;
case eFormatCharArray :
case eFormatChar :
case eFormatCharPrintable :
if ( ! byte_size_option_set )
byte_size_value = 1 ;
if ( ! num_per_line_option_set )
m_num_per_line = 32 ;
if ( ! count_option_set )
format_options . GetCountValue ( ) = 64 ;
break ;
case eFormatComplex :
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 ;
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 ;
break ;
case eFormatHex :
if ( ! byte_size_option_set )
byte_size_value = 4 ;
if ( ! num_per_line_option_set ) {
switch ( byte_size_value ) {
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 ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
if ( ! count_option_set )
count_value = 8 ;
break ;
case eFormatVectorOfChar :
case eFormatVectorOfSInt8 :
case eFormatVectorOfUInt8 :
case eFormatVectorOfSInt16 :
case eFormatVectorOfUInt16 :
case eFormatVectorOfSInt32 :
case eFormatVectorOfUInt32 :
case eFormatVectorOfSInt64 :
case eFormatVectorOfUInt64 :
case eFormatVectorOfFloat16 :
case eFormatVectorOfFloat32 :
case eFormatVectorOfFloat64 :
case eFormatVectorOfUInt128 :
if ( ! byte_size_option_set )
byte_size_value = 128 ;
if ( ! num_per_line_option_set )
m_num_per_line = 1 ;
if ( ! count_option_set )
count_value = 4 ;
break ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
return error ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
bool AnyOptionWasSet ( ) const {
return m_num_per_line . OptionWasSet ( ) | | m_output_as_binary | |
m_view_as_type . OptionWasSet ( ) | | m_offset . OptionWasSet ( ) ;
}
OptionValueUInt64 m_num_per_line ;
bool m_output_as_binary ;
OptionValueString m_view_as_type ;
bool m_force ;
OptionValueUInt64 m_offset ;
2013-08-23 13:46:38 -04:00
} ;
//----------------------------------------------------------------------
// Read memory from the inferior process
//----------------------------------------------------------------------
2017-01-02 14:26:05 -05:00
class CommandObjectMemoryRead : public CommandObjectParsed {
2013-08-23 13:46:38 -04:00
public :
2017-01-02 14:26:05 -05:00
CommandObjectMemoryRead ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " memory read " ,
" Read from the memory of the current target process. " , nullptr ,
eCommandRequiresTarget | eCommandProcessMustBePaused ) ,
m_option_group ( ) , m_format_options ( eFormatBytesWithASCII , 1 , 8 ) ,
m_memory_options ( ) , m_outfile_options ( ) , 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 ( ) {
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData start_addr_arg ;
CommandArgumentData end_addr_arg ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Define the first (and only) variant of this arg.
start_addr_arg . arg_type = eArgTypeAddressOrExpression ;
start_addr_arg . arg_repetition = eArgRepeatPlain ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// There is only one variant this argument could be; put it into the
// argument entry.
arg1 . push_back ( start_addr_arg ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Define the first (and only) variant of this arg.
end_addr_arg . arg_type = eArgTypeAddressOrExpression ;
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 ) ;
// 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 ,
LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3 ) ;
m_option_group . Append ( & m_format_options ,
OptionGroupFormat : : OPTION_GROUP_GDB_FMT ,
LLDB_OPT_SET_1 | LLDB_OPT_SET_3 ) ;
// 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 ) ;
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 ) ;
m_option_group . Append ( & m_varobj_options , LLDB_OPT_SET_ALL , LLDB_OPT_SET_3 ) ;
m_option_group . Finalize ( ) ;
}
~ CommandObjectMemoryRead ( ) override = default ;
Options * GetOptions ( ) override { return & m_option_group ; }
const char * GetRepeatCommand ( Args & current_command_args ,
uint32_t index ) override {
return m_cmd_name . c_str ( ) ;
}
2013-08-23 13:46:38 -04:00
protected :
2017-01-02 14:26:05 -05:00
bool DoExecute ( Args & command , CommandReturnObject & result ) override {
// No need to check "target" for validity as eCommandRequiresTarget ensures
// it is valid
Target * target = m_exe_ctx . GetTargetPtr ( ) ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( ( argc = = 0 & & m_next_addr = = LLDB_INVALID_ADDRESS ) | | argc > 2 ) {
result . AppendErrorWithFormat ( " %s takes a start address expression with "
" an optional end address expression. \n " ,
m_cmd_name . c_str ( ) ) ;
result . AppendRawWarning ( " Expressions should be quoted if they contain "
" spaces or other special characters. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
CompilerType clang_ast_type ;
Error error ;
const char * view_as_type_cstr =
m_memory_options . m_view_as_type . GetCurrentValue ( ) ;
if ( view_as_type_cstr & & view_as_type_cstr [ 0 ] ) {
// We are viewing memory as a type
SymbolContext sc ;
const bool exact_match = false ;
TypeList type_list ;
uint32_t reference_count = 0 ;
uint32_t pointer_count = 0 ;
size_t idx ;
# define ALL_KEYWORDS \
KEYWORD ( " const " ) \
KEYWORD ( " volatile " ) \
KEYWORD ( " restrict " ) \
KEYWORD ( " struct " ) \
KEYWORD ( " class " ) \
KEYWORD ( " union " )
2013-08-23 13:46:38 -04:00
# define KEYWORD(s) s,
2017-01-02 14:26:05 -05:00
static const char * g_keywords [ ] = { ALL_KEYWORDS } ;
2013-08-23 13:46:38 -04:00
# undef KEYWORD
# define KEYWORD(s) (sizeof(s) - 1),
2017-01-02 14:26:05 -05:00
static const int g_keyword_lengths [ ] = { ALL_KEYWORDS } ;
2013-08-23 13:46:38 -04:00
# undef KEYWORD
2017-01-02 14:26:05 -05:00
2013-08-23 13:46:38 -04:00
# undef ALL_KEYWORDS
2015-12-30 06:55:28 -05:00
2017-01-02 14:26:05 -05:00
static size_t g_num_keywords = sizeof ( g_keywords ) / sizeof ( const char * ) ;
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 ] ;
int keyword_len = g_keyword_lengths [ i ] ;
idx = 0 ;
while ( ( idx = type_str . find ( keyword , idx ) ) ! = std : : string : : npos ) {
if ( type_str [ idx + keyword_len ] = = ' ' | |
type_str [ idx + keyword_len ] = = ' \t ' ) {
type_str . erase ( idx , keyword_len + 1 ) ;
idx = 0 ;
} else {
idx + = keyword_len ;
}
}
}
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 ;
LLVM_FALLTHROUGH ;
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 ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
break ;
2015-12-30 06:55:28 -05:00
2017-01-02 14:26:05 -05:00
default :
done = true ;
break ;
}
}
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
llvm : : DenseSet < lldb_private : : SymbolFile * > searched_symbol_files ;
ConstString lookup_type_name ( type_str . c_str ( ) ) ;
StackFrame * frame = m_exe_ctx . GetFramePtr ( ) ;
if ( frame ) {
sc = frame - > GetSymbolContext ( eSymbolContextModule ) ;
if ( sc . module_sp ) {
sc . module_sp - > FindTypes ( sc , lookup_type_name , exact_match , 1 ,
searched_symbol_files , type_list ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
if ( type_list . GetSize ( ) = = 0 ) {
target - > GetImages ( ) . FindTypes ( sc , lookup_type_name , exact_match , 1 ,
searched_symbol_files , type_list ) ;
}
if ( type_list . GetSize ( ) = = 0 & & lookup_type_name . GetCString ( ) & &
* lookup_type_name . GetCString ( ) = = ' $ ' ) {
if ( ClangPersistentVariables * persistent_vars =
llvm : : dyn_cast_or_null < ClangPersistentVariables > (
target - > GetPersistentExpressionStateForLanguage (
lldb : : eLanguageTypeC ) ) ) {
clang : : TypeDecl * tdecl = llvm : : dyn_cast_or_null < clang : : TypeDecl > (
persistent_vars - > GetPersistentDecl (
ConstString ( lookup_type_name ) ) ) ;
if ( tdecl ) {
clang_ast_type . SetCompilerType (
ClangASTContext : : GetASTContext ( & tdecl - > getASTContext ( ) ) ,
reinterpret_cast < lldb : : opaque_compiler_type_t > (
const_cast < clang : : Type * > ( tdecl - > getTypeForDecl ( ) ) ) ) ;
}
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
if ( ! clang_ast_type . IsValid ( ) ) {
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 ) ) ;
clang_ast_type = type_sp - > GetFullCompilerType ( ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
while ( pointer_count > 0 ) {
CompilerType pointer_type = clang_ast_type . GetPointerType ( ) ;
if ( pointer_type . IsValid ( ) )
clang_ast_type = pointer_type ;
else {
result . AppendError ( " unable make a pointer type \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
- - pointer_count ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
m_format_options . GetByteSizeValue ( ) = clang_ast_type . GetByteSize ( nullptr ) ;
2015-02-06 16:38:51 -05:00
2017-01-02 14:26:05 -05:00
if ( m_format_options . GetByteSizeValue ( ) = = 0 ) {
result . AppendErrorWithFormat (
" unable to get the byte size of the type '%s' \n " ,
view_as_type_cstr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2015-02-06 16:38:51 -05:00
2017-01-02 14:26:05 -05:00
if ( ! m_format_options . GetCountValue ( ) . OptionWasSet ( ) )
m_format_options . GetCountValue ( ) = 1 ;
} else {
error = m_memory_options . FinalizeSettings ( target , m_format_options ) ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Look for invalid combinations of settings
if ( error . Fail ( ) ) {
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05: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 ;
clang_ast_type = m_prev_clang_ast_type ;
if ( ! m_format_options . AnyOptionWasSet ( ) & &
! 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 ;
}
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
size_t item_count = m_format_options . GetCountValue ( ) . GetCurrentValue ( ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05: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 ( ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
const size_t num_per_line =
m_memory_options . m_num_per_line . GetCurrentValue ( ) ;
2015-02-06 16:38:51 -05:00
2017-01-02 14:26:05 -05:00
if ( total_byte_size = = 0 ) {
total_byte_size = item_count * item_byte_size ;
if ( total_byte_size = = 0 )
total_byte_size = 32 ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
if ( argc > 0 )
addr = Args : : StringToAddress ( & m_exe_ctx , command [ 0 ] . ref ,
LLDB_INVALID_ADDRESS , & error ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
if ( addr = = LLDB_INVALID_ADDRESS ) {
result . AppendError ( " invalid start address expression. " ) ;
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( argc = = 2 ) {
lldb : : addr_t end_addr = Args : : StringToAddress (
& m_exe_ctx , command [ 1 ] . ref , LLDB_INVALID_ADDRESS , nullptr ) ;
if ( end_addr = = LLDB_INVALID_ADDRESS ) {
result . AppendError ( " invalid end address expression. " ) ;
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( end_addr < = addr ) {
result . AppendErrorWithFormat (
" end address (0x% " PRIx64
" ) must be greater that the start address (0x% " PRIx64 " ). \n " ,
end_addr , addr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( m_format_options . GetCountValue ( ) . OptionWasSet ( ) ) {
result . AppendErrorWithFormat (
" specify either the end address (0x% " PRIx64
" ) or the count (--count % " PRIu64 " ), not both. \n " ,
end_addr , ( uint64_t ) item_count ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
total_byte_size = end_addr - addr ;
item_count = total_byte_size / item_byte_size ;
}
uint32_t max_unforced_size = target - > GetMaximumMemReadSize ( ) ;
if ( total_byte_size > max_unforced_size & & ! m_memory_options . m_force ) {
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 " ) ;
return false ;
}
DataBufferSP data_sp ;
size_t bytes_read = 0 ;
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 ( ) )
m_format_options . GetFormatValue ( ) . SetCurrentValue ( eFormatDefault ) ;
bytes_read = clang_ast_type . GetByteSize ( nullptr ) *
m_format_options . GetCountValue ( ) . GetCurrentValue ( ) ;
if ( argc > 0 )
addr = addr + ( clang_ast_type . GetByteSize ( nullptr ) *
m_memory_options . m_offset . GetCurrentValue ( ) ) ;
} else if ( m_format_options . GetFormatValue ( ) . GetCurrentValue ( ) ! =
eFormatCString ) {
data_sp . reset ( new DataBufferHeap ( total_byte_size , ' \0 ' ) ) ;
if ( data_sp - > GetBytes ( ) = = nullptr ) {
result . AppendErrorWithFormat (
" can't allocate 0x% " PRIx32
" bytes for the memory read buffer, specify a smaller size to read " ,
( uint32_t ) total_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
Address address ( addr , nullptr ) ;
bytes_read = target - > ReadMemory ( address , false , data_sp - > GetBytes ( ) ,
data_sp - > GetByteSize ( ) , error ) ;
if ( bytes_read = = 0 ) {
const char * error_cstr = error . AsCString ( ) ;
if ( error_cstr & & error_cstr [ 0 ] ) {
result . AppendError ( error_cstr ) ;
} else {
result . AppendErrorWithFormat (
" failed to read memory from 0x% " PRIx64 " . \n " , addr ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( bytes_read < total_byte_size )
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 ) ;
} 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
if ( data_sp - > GetBytes ( ) = = nullptr ) {
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 ;
}
uint8_t * data_ptr = data_sp - > GetBytes ( ) ;
auto data_addr = addr ;
auto count = item_count ;
item_count = 0 ;
bool break_on_no_NULL = false ;
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 ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
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 ) ;
- - read ;
break_on_no_NULL = true ;
} else
+ + read ; // 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
if ( break_on_no_NULL )
break ;
}
data_sp . reset ( new DataBufferHeap ( data_sp - > GetBytes ( ) , bytes_read + 1 ) ) ;
}
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 ;
StreamFile outfile_stream ;
Stream * output_stream = nullptr ;
const FileSpec & outfile_spec =
m_outfile_options . GetFile ( ) . GetCurrentValue ( ) ;
if ( outfile_spec ) {
char path [ PATH_MAX ] ;
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 ( ) ) {
if ( m_memory_options . m_output_as_binary ) {
const size_t bytes_written =
outfile_stream . Write ( data_sp - > GetBytes ( ) , bytes_read ) ;
if ( bytes_written > 0 ) {
result . GetOutputStream ( ) . Printf (
" %zi bytes %s to '%s' \n " , bytes_written ,
append ? " appended " : " written " , path ) ;
2013-08-23 13:46:38 -04:00
return true ;
2017-01-02 14:26:05 -05:00
} else {
result . AppendErrorWithFormat ( " Failed to write % " PRIu64
" bytes to '%s'. \n " ,
( uint64_t ) bytes_read , path ) ;
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 ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
} else {
result . AppendErrorWithFormat ( " Failed to open file '%s' for %s. \n " , path ,
append ? " append " : " write " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
} else {
output_stream = & result . GetOutputStream ( ) ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
ExecutionContextScope * exe_scope = m_exe_ctx . GetBestExecutionContextScope ( ) ;
if ( clang_ast_type . GetOpaqueQualType ( ) ) {
for ( uint32_t i = 0 ; i < item_count ; + + i ) {
addr_t item_addr = addr + ( i * item_byte_size ) ;
Address address ( item_addr ) ;
StreamString name_strm ;
name_strm . Printf ( " 0x% " PRIx64 , item_addr ) ;
ValueObjectSP valobj_sp ( ValueObjectMemory : : Create (
exe_scope , name_strm . GetString ( ) , address , clang_ast_type ) ) ;
if ( valobj_sp ) {
Format format = m_format_options . GetFormat ( ) ;
if ( format ! = eFormatDefault )
valobj_sp - > SetFormat ( format ) ;
DumpValueObjectOptions options ( m_varobj_options . GetAsDumpOptions (
eLanguageRuntimeDescriptionDisplayVerbosityFull , format ) ) ;
valobj_sp - > Dump ( * output_stream , options ) ;
} else {
result . AppendErrorWithFormat (
" failed to create a value object for: (%s) %s \n " ,
view_as_type_cstr , name_strm . GetData ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
}
return true ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
DataExtractor data ( data_sp , target - > GetArchitecture ( ) . GetByteOrder ( ) ,
target - > GetArchitecture ( ) . GetAddressByteSize ( ) ,
target - > GetArchitecture ( ) . GetDataByteSize ( ) ) ;
Format format = m_format_options . GetFormat ( ) ;
if ( ( ( format = = eFormatChar ) | | ( format = = eFormatCharPrintable ) ) & &
( item_byte_size ! = 1 ) ) {
// if a count was not passed, or it is 1
if ( ! m_format_options . GetCountValue ( ) . OptionWasSet ( ) | | 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
result . AppendErrorWithFormat (
" reading memory as characters of size % " PRIu64 " is not supported " ,
( uint64_t ) item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
assert ( output_stream ) ;
size_t bytes_dumped =
data . Dump ( output_stream , 0 , format , item_byte_size , item_count ,
num_per_line / target - > GetArchitecture ( ) . GetDataByteSize ( ) ,
addr , 0 , 0 , exe_scope ) ;
m_next_addr = addr + bytes_dumped ;
output_stream - > EOL ( ) ;
return true ;
}
OptionGroupOptions m_option_group ;
OptionGroupFormat m_format_options ;
OptionGroupReadMemory m_memory_options ;
OptionGroupOutputFile m_outfile_options ;
OptionGroupValueObjectDisplay m_varobj_options ;
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 ;
CompilerType m_prev_clang_ast_type ;
2013-08-23 13:46:38 -04:00
} ;
2017-01-02 14:26:05 -05:00
OptionDefinition g_memory_find_option_table [ ] = {
// clang-format off
{ LLDB_OPT_SET_1 , true , " expression " , ' e ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeExpression , " Evaluate an expression to obtain a byte pattern. " } ,
{ LLDB_OPT_SET_2 , true , " string " , ' s ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeName , " Use text to find a byte pattern. " } ,
{ LLDB_OPT_SET_ALL , false , " count " , ' c ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeCount , " How many times to perform the search. " } ,
{ LLDB_OPT_SET_ALL , false , " dump-offset " , ' o ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeOffset , " When dumping memory for a match, an offset from the match location to start dumping from. " } ,
// clang-format on
2013-12-03 13:51:59 -05:00
} ;
//----------------------------------------------------------------------
// Find the specified data in memory
//----------------------------------------------------------------------
2017-01-02 14:26:05 -05:00
class CommandObjectMemoryFind : public CommandObjectParsed {
2013-12-03 13:51:59 -05:00
public :
2017-01-02 14:26:05 -05:00
class OptionGroupFindMemory : public OptionGroup {
2013-12-03 13:51:59 -05:00
public :
2017-01-02 14:26:05 -05:00
OptionGroupFindMemory ( ) : OptionGroup ( ) , m_count ( 1 ) , m_offset ( 0 ) { }
2016-07-23 16:50:09 -04:00
~ OptionGroupFindMemory ( ) override = default ;
2017-01-02 14:26:05 -05:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
return llvm : : makeArrayRef ( g_memory_find_option_table ) ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
Error SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_value ,
ExecutionContext * execution_context ) override {
Error error ;
const int short_option =
g_memory_find_option_table [ option_idx ] . short_option ;
switch ( short_option ) {
case ' e ' :
m_expr . SetValueFromString ( option_value ) ;
break ;
case ' s ' :
m_string . SetValueFromString ( option_value ) ;
break ;
case ' c ' :
if ( m_count . SetValueFromString ( option_value ) . Fail ( ) )
error . SetErrorString ( " unrecognized value for count " ) ;
break ;
case ' o ' :
if ( m_offset . SetValueFromString ( option_value ) . Fail ( ) )
error . SetErrorString ( " unrecognized value for dump-offset " ) ;
break ;
default :
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " ,
short_option ) ;
break ;
}
return error ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
m_expr . Clear ( ) ;
m_string . Clear ( ) ;
m_count . Clear ( ) ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
OptionValueString m_expr ;
OptionValueString m_string ;
OptionValueUInt64 m_count ;
OptionValueUInt64 m_offset ;
2013-12-03 13:51:59 -05:00
} ;
2016-07-23 16:50:09 -04:00
CommandObjectMemoryFind ( CommandInterpreter & interpreter )
2017-01-02 14:26:05 -05:00
: CommandObjectParsed (
interpreter , " memory find " ,
" Find a value in the memory of the current target process. " ,
nullptr , eCommandRequiresProcess | eCommandProcessMustBeLaunched ) ,
m_option_group ( ) , m_memory_options ( ) {
2013-12-03 13:51:59 -05:00
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData addr_arg ;
CommandArgumentData value_arg ;
2017-01-02 14:26:05 -05:00
2013-12-03 13:51:59 -05:00
// Define the first (and only) variant of this arg.
2015-12-30 06:55:28 -05:00
addr_arg . arg_type = eArgTypeAddressOrExpression ;
2013-12-03 13:51:59 -05:00
addr_arg . arg_repetition = eArgRepeatPlain ;
2017-01-02 14:26:05 -05:00
// There is only one variant this argument could be; put it into the
// argument entry.
arg1 . push_back ( addr_arg ) ;
2013-12-03 13:51:59 -05:00
// Define the first (and only) variant of this arg.
2015-12-30 06:55:28 -05:00
value_arg . arg_type = eArgTypeAddressOrExpression ;
value_arg . arg_repetition = eArgRepeatPlain ;
2017-01-02 14:26:05 -05:00
// There is only one variant this argument could be; put it into the
// argument entry.
arg2 . push_back ( value_arg ) ;
2013-12-03 13:51:59 -05:00
// Push the data for the first argument into the m_arguments vector.
2017-01-02 14:26:05 -05:00
m_arguments . push_back ( arg1 ) ;
m_arguments . push_back ( arg2 ) ;
m_option_group . Append ( & m_memory_options ) ;
2013-12-03 13:51:59 -05:00
m_option_group . Finalize ( ) ;
}
2016-07-23 16:50:09 -04:00
~ CommandObjectMemoryFind ( ) override = default ;
2017-01-02 14:26:05 -05:00
Options * GetOptions ( ) override { return & m_option_group ; }
2013-12-03 13:51:59 -05:00
protected :
2017-01-02 14:26:05 -05:00
class ProcessMemoryIterator {
public :
ProcessMemoryIterator ( ProcessSP process_sp , lldb : : addr_t base )
: m_process_sp ( process_sp ) , m_base_addr ( base ) , m_is_valid ( true ) {
lldbassert ( process_sp . get ( ) ! = nullptr ) ;
}
2013-12-03 13:51:59 -05:00
2017-01-02 14:26:05 -05:00
bool IsValid ( ) { return m_is_valid ; }
2013-12-03 13:51:59 -05:00
2017-01-02 14:26:05 -05:00
uint8_t operator [ ] ( lldb : : addr_t offset ) {
if ( ! IsValid ( ) )
return 0 ;
2013-12-03 13:51:59 -05:00
2017-01-02 14:26:05 -05:00
uint8_t retval = 0 ;
2013-12-03 13:51:59 -05:00
Error error ;
2017-01-02 14:26:05 -05:00
if ( 0 = =
m_process_sp - > ReadMemory ( m_base_addr + offset , & retval , 1 , error ) ) {
m_is_valid = false ;
return 0 ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
return retval ;
}
private :
ProcessSP m_process_sp ;
lldb : : addr_t m_base_addr ;
bool m_is_valid ;
} ;
bool DoExecute ( Args & command , CommandReturnObject & result ) override {
// No need to check "process" for validity as eCommandRequiresProcess
// ensures it is valid
Process * process = m_exe_ctx . GetProcessPtr ( ) ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc ! = 2 ) {
result . AppendError ( " two addresses needed for memory find " ) ;
return false ;
}
Error error ;
lldb : : addr_t low_addr = Args : : StringToAddress ( & m_exe_ctx , command [ 0 ] . ref ,
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 [ 1 ] . ref , LLDB_INVALID_ADDRESS , & error ) ;
if ( high_addr = = LLDB_INVALID_ADDRESS | | error . Fail ( ) ) {
result . AppendError ( " invalid high address " ) ;
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 ( ) ) ;
else if ( m_memory_options . m_expr . OptionWasSet ( ) ) {
StackFrame * frame = m_exe_ctx . GetFramePtr ( ) ;
ValueObjectSP result_sp ;
if ( ( eExpressionCompleted = =
process - > GetTarget ( ) . EvaluateExpression (
m_memory_options . m_expr . GetStringValue ( ) , frame , result_sp ) ) & &
result_sp ) {
uint64_t value = result_sp - > GetValueAsUnsigned ( 0 ) ;
switch ( result_sp - > GetCompilerType ( ) . GetByteSize ( nullptr ) ) {
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 " ) ;
2013-12-03 13:51:59 -05:00
return false ;
2017-01-02 14:26:05 -05:00
default :
result . AppendError (
" result size larger than 8 bytes. pass a string instead " ) ;
2013-12-03 13:51:59 -05:00
return false ;
2017-01-02 14:26:05 -05:00
}
} else {
result . AppendError (
" expression evaluation failed. pass a string instead " ) ;
return false ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
} else {
result . AppendError (
" please pass either a block of text, or an expression to evaluate. " ) ;
return false ;
}
2013-12-03 13:51:59 -05:00
2017-01-02 14:26:05 -05:00
size_t count = m_memory_options . m_count . GetCurrentValue ( ) ;
found_location = low_addr ;
bool ever_found = false ;
while ( count ) {
found_location = FastSearch ( found_location , high_addr , buffer . GetBytes ( ) ,
buffer . GetByteSize ( ) ) ;
if ( found_location = = LLDB_INVALID_ADDRESS ) {
if ( ! ever_found ) {
result . AppendMessage ( " data not found within the range. \n " ) ;
result . SetStatus ( lldb : : eReturnStatusSuccessFinishNoResult ) ;
} else
result . AppendMessage ( " no more matches within the range. \n " ) ;
break ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
result . AppendMessageWithFormat ( " data found at location: 0x% " PRIx64 " \n " ,
found_location ) ;
DataBufferHeap dumpbuffer ( 32 , 0 ) ;
process - > ReadMemory (
found_location + m_memory_options . m_offset . GetCurrentValue ( ) ,
dumpbuffer . GetBytes ( ) , dumpbuffer . GetByteSize ( ) , error ) ;
if ( ! error . Fail ( ) ) {
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 ( ) ;
}
- - count ;
found_location + + ;
ever_found = true ;
}
result . SetStatus ( lldb : : eReturnStatusSuccessFinishResult ) ;
return true ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
lldb : : addr_t FastSearch ( lldb : : addr_t low , lldb : : addr_t high , uint8_t * buffer ,
size_t buffer_size ) {
const size_t region_size = high - low ;
if ( region_size < buffer_size )
return LLDB_INVALID_ADDRESS ;
std : : vector < size_t > bad_char_heuristic ( 256 , buffer_size ) ;
ProcessSP process_sp = m_exe_ctx . GetProcessSP ( ) ;
ProcessMemoryIterator iterator ( process_sp , low ) ;
for ( size_t idx = 0 ; idx < buffer_size - 1 ; idx + + ) {
decltype ( bad_char_heuristic ) : : size_type bcu_idx = buffer [ idx ] ;
bad_char_heuristic [ bcu_idx ] = buffer_size - idx - 1 ;
}
for ( size_t s = 0 ; s < = ( region_size - buffer_size ) ; ) {
int64_t j = buffer_size - 1 ;
while ( j > = 0 & & buffer [ j ] = = iterator [ s + j ] )
j - - ;
if ( j < 0 )
return low + s ;
else
s + = bad_char_heuristic [ iterator [ s + buffer_size - 1 ] ] ;
2013-12-03 13:51:59 -05:00
}
2017-01-02 14:26:05 -05:00
return LLDB_INVALID_ADDRESS ;
}
OptionGroupOptions m_option_group ;
OptionGroupFindMemory m_memory_options ;
2013-12-03 13:51:59 -05:00
} ;
2017-01-02 14:26:05 -05:00
OptionDefinition g_memory_write_option_table [ ] = {
// clang-format off
{ LLDB_OPT_SET_1 , true , " infile " , ' i ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeFilename , " Write memory using the contents of a file. " } ,
{ LLDB_OPT_SET_1 , false , " offset " , ' o ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeOffset , " Start writing bytes from an offset within the input file. " } ,
// clang-format on
2013-08-23 13:46:38 -04:00
} ;
//----------------------------------------------------------------------
// Write memory to the inferior process
//----------------------------------------------------------------------
2017-01-02 14:26:05 -05:00
class CommandObjectMemoryWrite : public CommandObjectParsed {
2013-08-23 13:46:38 -04:00
public :
2017-01-02 14:26:05 -05:00
class OptionGroupWriteMemory : public OptionGroup {
public :
OptionGroupWriteMemory ( ) : OptionGroup ( ) { }
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
~ OptionGroupWriteMemory ( ) override = default ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
llvm : : ArrayRef < OptionDefinition > GetDefinitions ( ) override {
return llvm : : makeArrayRef ( g_memory_write_option_table ) ;
}
Error SetOptionValue ( uint32_t option_idx , llvm : : StringRef option_value ,
ExecutionContext * execution_context ) override {
Error error ;
const int short_option =
g_memory_write_option_table [ option_idx ] . short_option ;
switch ( short_option ) {
case ' i ' :
m_infile . SetFile ( option_value , true ) ;
if ( ! m_infile . Exists ( ) ) {
m_infile . Clear ( ) ;
error . SetErrorStringWithFormat ( " input file does not exist: '%s' " ,
option_value . str ( ) . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
break ;
case ' o ' : {
if ( option_value . getAsInteger ( 0 , m_infile_offset ) ) {
m_infile_offset = 0 ;
error . SetErrorStringWithFormat ( " invalid offset string '%s' " ,
option_value . str ( ) . c_str ( ) ) ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
} break ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
default :
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " ,
short_option ) ;
break ;
}
return error ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
void OptionParsingStarting ( ExecutionContext * execution_context ) override {
m_infile . Clear ( ) ;
m_infile_offset = 0 ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
FileSpec m_infile ;
off_t m_infile_offset ;
} ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
CommandObjectMemoryWrite ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " memory write " ,
" Write to the memory of the current target process. " , nullptr ,
eCommandRequiresProcess | eCommandProcessMustBeLaunched ) ,
m_option_group ( ) , m_format_options ( eFormatBytes , 1 , UINT64_MAX ) ,
m_memory_options ( ) {
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData addr_arg ;
CommandArgumentData value_arg ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Define the first (and only) variant of this arg.
addr_arg . arg_type = eArgTypeAddress ;
addr_arg . arg_repetition = eArgRepeatPlain ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// There is only one variant this argument could be; put it into the
// argument entry.
arg1 . push_back ( addr_arg ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// Define the first (and only) variant of this arg.
value_arg . arg_type = eArgTypeValue ;
value_arg . arg_repetition = eArgRepeatPlus ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
// 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_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 ( ) ;
}
~ CommandObjectMemoryWrite ( ) override = default ;
Options * GetOptions ( ) override { return & m_option_group ; }
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 ;
}
2013-08-23 13:46:38 -04:00
protected :
2017-01-02 14:26:05 -05:00
bool DoExecute ( Args & command , CommandReturnObject & result ) override {
// No need to check "process" for validity as eCommandRequiresProcess
// ensures it is valid
Process * process = m_exe_ctx . GetProcessPtr ( ) ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( m_memory_options . m_infile ) {
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 ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
StreamString buffer (
Stream : : eBinary ,
process - > GetTarget ( ) . GetArchitecture ( ) . GetAddressByteSize ( ) ,
process - > GetTarget ( ) . GetArchitecture ( ) . GetByteOrder ( ) ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
OptionValueUInt64 & byte_size_value = m_format_options . GetByteSizeValue ( ) ;
size_t item_byte_size = byte_size_value . GetCurrentValue ( ) ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
Error error ;
lldb : : addr_t addr = Args : : StringToAddress ( & m_exe_ctx , command [ 0 ] . ref ,
LLDB_INVALID_ADDRESS , & error ) ;
if ( addr = = LLDB_INVALID_ADDRESS ) {
result . AppendError ( " invalid address expression \n " ) ;
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( m_memory_options . m_infile ) {
size_t length = SIZE_MAX ;
if ( item_byte_size > 1 )
length = item_byte_size ;
lldb : : DataBufferSP data_sp ( m_memory_options . m_infile . ReadFileContents (
m_memory_options . m_infile_offset , length ) ) ;
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
result . GetOutputStream ( ) . Printf (
" % " PRIu64 " bytes were written to 0x% " PRIx64 " \n " ,
( uint64_t ) bytes_written , addr ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else if ( bytes_written > 0 ) {
// Some byte written
result . GetOutputStream ( ) . Printf (
" % " PRIu64 " bytes of % " PRIu64
" requested were written to 0x% " PRIx64 " \n " ,
( uint64_t ) bytes_written , ( uint64_t ) length , addr ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendErrorWithFormat ( " Memory write to 0x% " PRIx64
" failed: %s. \n " ,
addr , error . AsCString ( ) ) ;
2013-08-23 13:46:38 -04:00
result . SetStatus ( eReturnStatusFailed ) ;
2017-01-02 14:26:05 -05:00
}
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
} else {
result . AppendErrorWithFormat ( " Unable to read contents of file. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
} else if ( item_byte_size = = 0 ) {
if ( m_format_options . GetFormat ( ) = = eFormatPointer )
item_byte_size = buffer . GetAddressByteSize ( ) ;
else
item_byte_size = 1 ;
}
command . Shift ( ) ; // shift off the address argument
uint64_t uval64 ;
int64_t sval64 ;
bool success = false ;
for ( auto & entry : command ) {
switch ( m_format_options . GetFormat ( ) ) {
case kNumFormats :
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 eFormatVectorOfFloat16 :
case eFormatVectorOfFloat32 :
case eFormatVectorOfFloat64 :
case eFormatVectorOfUInt128 :
case eFormatOSType :
case eFormatComplexInteger :
case eFormatAddressInfo :
case eFormatHexFloat :
case eFormatInstruction :
case eFormatVoid :
result . AppendError ( " unsupported format for writing memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
case eFormatDefault :
case eFormatBytes :
case eFormatHex :
case eFormatHexUppercase :
case eFormatPointer :
// Decode hex bytes
if ( entry . ref . getAsInteger ( 16 , uval64 ) ) {
result . AppendErrorWithFormat (
" '%s' is not a valid hex string value. \n " , entry . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) ) {
result . AppendErrorWithFormat ( " Value 0x% " PRIx64
" is too large to fit in a % " PRIu64
" byte unsigned integer value. \n " ,
uval64 , ( uint64_t ) item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatBoolean :
uval64 = Args : : StringToBoolean ( entry . ref , false , & success ) ;
if ( ! success ) {
result . AppendErrorWithFormat (
" '%s' is not a valid boolean string value. \n " , entry . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatBinary :
if ( entry . ref . getAsInteger ( 2 , uval64 ) ) {
result . AppendErrorWithFormat (
" '%s' is not a valid binary string value. \n " , entry . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) ) {
result . AppendErrorWithFormat ( " Value 0x% " PRIx64
" is too large to fit in a % " PRIu64
" byte unsigned integer value. \n " ,
uval64 , ( uint64_t ) item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatCharArray :
case eFormatChar :
case eFormatCString : {
if ( entry . ref . empty ( ) )
break ;
size_t len = entry . ref . size ( ) ;
// Include the NULL for C strings...
if ( m_format_options . GetFormat ( ) = = eFormatCString )
+ + len ;
Error error ;
if ( process - > WriteMemory ( addr , entry . c_str ( ) , len , error ) = = len ) {
addr + = len ;
} else {
result . AppendErrorWithFormat ( " Memory write to 0x% " PRIx64
" failed: %s. \n " ,
addr , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
break ;
}
case eFormatDecimal :
if ( entry . ref . getAsInteger ( 0 , sval64 ) ) {
result . AppendErrorWithFormat (
" '%s' is not a valid signed decimal value. \n " , entry . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( ! SIntValueIsValidForSize ( sval64 , item_byte_size ) ) {
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 ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( sval64 , item_byte_size ) ;
break ;
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
case eFormatUnsigned :
if ( ! entry . ref . getAsInteger ( 0 , uval64 ) ) {
result . AppendErrorWithFormat (
" '%s' is not a valid unsigned decimal string value. \n " ,
entry . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) ) {
result . AppendErrorWithFormat ( " Value % " PRIu64
" is too large to fit in a % " PRIu64
" byte unsigned integer value. \n " ,
uval64 , ( uint64_t ) item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatOctal :
if ( entry . ref . getAsInteger ( 8 , uval64 ) ) {
result . AppendErrorWithFormat (
" '%s' is not a valid octal string value. \n " , entry . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( ! UIntValueIsValidForSize ( uval64 , item_byte_size ) ) {
result . AppendErrorWithFormat ( " Value % " PRIo64
" is too large to fit in a % " PRIu64
" byte unsigned integer value. \n " ,
uval64 , ( uint64_t ) item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
}
}
if ( ! buffer . GetString ( ) . empty ( ) ) {
Error error ;
if ( process - > WriteMemory ( addr , buffer . GetString ( ) . data ( ) ,
buffer . GetString ( ) . size ( ) ,
error ) = = buffer . GetString ( ) . size ( ) )
2013-08-23 13:46:38 -04:00
return true ;
2017-01-02 14:26:05 -05:00
else {
result . AppendErrorWithFormat ( " Memory write to 0x% " PRIx64
" failed: %s. \n " ,
addr , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2013-08-23 13:46:38 -04:00
}
2017-01-02 14:26:05 -05:00
return true ;
}
2013-08-23 13:46:38 -04:00
2017-01-02 14:26:05 -05:00
OptionGroupOptions m_option_group ;
OptionGroupFormat m_format_options ;
OptionGroupWriteMemory m_memory_options ;
2013-08-23 13:46:38 -04:00
} ;
2015-02-06 16:38:51 -05:00
//----------------------------------------------------------------------
// Get malloc/free history of a memory address.
//----------------------------------------------------------------------
2017-01-02 14:26:05 -05:00
class CommandObjectMemoryHistory : public CommandObjectParsed {
2015-02-06 16:38:51 -05:00
public :
2017-01-02 14:26:05 -05:00
CommandObjectMemoryHistory ( CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " memory history " , " Print recorded stack traces for "
" allocation/deallocation events "
" associated with an address. " ,
nullptr ,
eCommandRequiresTarget | eCommandRequiresProcess |
eCommandProcessMustBePaused | eCommandProcessMustBeLaunched ) {
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 ) ;
}
~ CommandObjectMemoryHistory ( ) override = default ;
const char * GetRepeatCommand ( Args & current_command_args ,
uint32_t index ) override {
return m_cmd_name . c_str ( ) ;
}
protected :
bool DoExecute ( Args & command , CommandReturnObject & result ) override {
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 ;
2015-02-06 16:38:51 -05:00
}
2016-07-23 16:50:09 -04:00
2017-01-02 14:26:05 -05:00
Error error ;
lldb : : addr_t addr = Args : : StringToAddress ( & m_exe_ctx , command [ 0 ] . ref ,
LLDB_INVALID_ADDRESS , & error ) ;
2016-07-23 16:50:09 -04:00
2017-01-02 14:26:05 -05:00
if ( addr = = LLDB_INVALID_ADDRESS ) {
result . AppendError ( " invalid address expression " ) ;
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2015-02-06 16:38:51 -05:00
}
2017-01-02 14:26:05 -05:00
Stream * output_stream = & result . GetOutputStream ( ) ;
const ProcessSP & process_sp = m_exe_ctx . GetProcessSP ( ) ;
const MemoryHistorySP & memory_history =
MemoryHistory : : FindPlugin ( process_sp ) ;
if ( ! memory_history ) {
result . AppendError ( " no available memory history provider " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2015-02-06 16:38:51 -05:00
}
2017-01-02 14:26:05 -05:00
HistoryThreads thread_list = memory_history - > GetHistoryThreads ( addr ) ;
const bool stop_format = false ;
for ( auto thread : thread_list ) {
thread - > GetStatus ( * output_stream , 0 , UINT32_MAX , 0 , stop_format ) ;
}
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return true ;
}
2015-02-06 16:38:51 -05:00
} ;
2016-07-23 16:50:09 -04:00
//-------------------------------------------------------------------------
// CommandObjectMemoryRegion
//-------------------------------------------------------------------------
# pragma mark CommandObjectMemoryRegion
2017-01-02 14:26:05 -05:00
class CommandObjectMemoryRegion : public CommandObjectParsed {
2016-07-23 16:50:09 -04:00
public :
2017-01-02 14:26:05 -05:00
CommandObjectMemoryRegion ( CommandInterpreter & interpreter )
: CommandObjectParsed ( interpreter , " memory region " ,
" Get information on the memory region containing "
" an address in the current target process. " ,
" memory region ADDR " ,
eCommandRequiresProcess | eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched ) ,
m_prev_end_addr ( LLDB_INVALID_ADDRESS ) { }
2016-07-23 16:50:09 -04:00
2017-01-02 14:26:05 -05:00
~ CommandObjectMemoryRegion ( ) override = default ;
2016-07-23 16:50:09 -04:00
protected :
2017-01-02 14:26:05 -05:00
bool DoExecute ( Args & command , CommandReturnObject & result ) override {
ProcessSP process_sp = m_exe_ctx . GetProcessSP ( ) ;
if ( process_sp ) {
Error error ;
lldb : : addr_t load_addr = m_prev_end_addr ;
m_prev_end_addr = LLDB_INVALID_ADDRESS ;
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc > 1 | | ( argc = = 0 & & load_addr = = LLDB_INVALID_ADDRESS ) ) {
result . AppendErrorWithFormat ( " '%s' takes one argument: \n Usage: %s \n " ,
m_cmd_name . c_str ( ) , m_cmd_syntax . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
} else {
auto load_addr_str = command [ 0 ] . ref ;
if ( command . GetArgumentCount ( ) = = 1 ) {
load_addr = Args : : StringToAddress ( & m_exe_ctx , load_addr_str ,
LLDB_INVALID_ADDRESS , & error ) ;
if ( error . Fail ( ) | | load_addr = = LLDB_INVALID_ADDRESS ) {
result . AppendErrorWithFormat (
" invalid address argument \" %s \" : %s \n " , command [ 0 ] . c_str ( ) ,
error . AsCString ( ) ) ;
2016-07-23 16:50:09 -04:00
result . SetStatus ( eReturnStatusFailed ) ;
2017-01-02 14:26:05 -05:00
}
2016-07-23 16:50:09 -04:00
}
2017-01-02 14:26:05 -05:00
lldb_private : : MemoryRegionInfo range_info ;
error = process_sp - > GetMemoryRegionInfo ( load_addr , range_info ) ;
if ( error . Success ( ) ) {
lldb_private : : Address addr ;
ConstString section_name ;
if ( process_sp - > GetTarget ( ) . ResolveLoadAddress ( load_addr , addr ) ) {
SectionSP section_sp ( addr . GetSection ( ) ) ;
if ( section_sp ) {
// Got the top most section, not the deepest section
while ( section_sp - > GetParent ( ) )
section_sp = section_sp - > GetParent ( ) ;
section_name = section_sp - > GetName ( ) ;
}
}
result . AppendMessageWithFormat (
" [0x%16.16 " PRIx64 " -0x%16.16 " PRIx64 " ) %c%c%c%s%s \n " ,
range_info . GetRange ( ) . GetRangeBase ( ) ,
range_info . GetRange ( ) . GetRangeEnd ( ) ,
range_info . GetReadable ( ) ? ' r ' : ' - ' ,
range_info . GetWritable ( ) ? ' w ' : ' - ' ,
range_info . GetExecutable ( ) ? ' x ' : ' - ' , section_name ? " " : " " ,
section_name ? section_name . AsCString ( ) : " " ) ;
m_prev_end_addr = range_info . GetRange ( ) . GetRangeEnd ( ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . SetStatus ( eReturnStatusFailed ) ;
result . AppendErrorWithFormat ( " %s \n " , error . AsCString ( ) ) ;
}
}
} else {
m_prev_end_addr = LLDB_INVALID_ADDRESS ;
result . AppendError ( " invalid process " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2016-07-23 16:50:09 -04:00
}
2017-01-02 14:26:05 -05:00
return result . Succeeded ( ) ;
}
const char * GetRepeatCommand ( Args & current_command_args ,
uint32_t index ) override {
// If we repeat this command, repeat it without any arguments so we can
// show the next memory range
return m_cmd_name . c_str ( ) ;
}
2016-07-23 16:50:09 -04:00
2017-01-02 14:26:05 -05:00
lldb : : addr_t m_prev_end_addr ;
2016-07-23 16:50:09 -04:00
} ;
2013-08-23 13:46:38 -04:00
//-------------------------------------------------------------------------
// CommandObjectMemory
//-------------------------------------------------------------------------
2016-07-23 16:50:09 -04:00
CommandObjectMemory : : CommandObjectMemory ( CommandInterpreter & interpreter )
2017-01-02 14:26:05 -05:00
: CommandObjectMultiword (
interpreter , " memory " ,
" Commands for operating on memory in the current target process. " ,
" memory <subcommand> [<subcommand-options>] " ) {
LoadSubCommand ( " find " ,
CommandObjectSP ( new CommandObjectMemoryFind ( interpreter ) ) ) ;
LoadSubCommand ( " read " ,
CommandObjectSP ( new CommandObjectMemoryRead ( interpreter ) ) ) ;
LoadSubCommand ( " write " ,
CommandObjectSP ( new CommandObjectMemoryWrite ( interpreter ) ) ) ;
LoadSubCommand ( " history " ,
CommandObjectSP ( new CommandObjectMemoryHistory ( interpreter ) ) ) ;
LoadSubCommand ( " region " ,
CommandObjectSP ( new CommandObjectMemoryRegion ( interpreter ) ) ) ;
2013-08-23 13:46:38 -04:00
}
2016-07-23 16:50:09 -04:00
CommandObjectMemory : : ~ CommandObjectMemory ( ) = default ;