2010-06-09 00:52:24 +08: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.
//
//===----------------------------------------------------------------------===//
# include "CommandObjectMemory.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
# include "lldb/Core/DataBufferHeap.h"
# include "lldb/Core/DataExtractor.h"
2010-06-23 09:19:29 +08:00
# include "lldb/Core/Debugger.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/StreamString.h"
2010-06-23 09:19:29 +08:00
# include "lldb/Interpreter/Args.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandReturnObject.h"
2010-06-23 09:19:29 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/Options.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Target/Process.h"
using namespace lldb ;
using namespace lldb_private ;
//----------------------------------------------------------------------
// Read memory from the inferior process
//----------------------------------------------------------------------
class CommandObjectMemoryRead : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
CommandOptions ( ) :
Options ( )
{
ResetOptionValues ( ) ;
}
virtual
~ CommandOptions ( )
{
}
virtual Error
SetOptionValue ( int option_idx , const char * option_arg )
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' f ' :
error = Args : : StringToFormat ( option_arg , m_format ) ;
switch ( m_format )
{
default :
break ;
case eFormatBoolean :
if ( m_byte_size = = 0 )
m_byte_size = 1 ;
if ( m_num_per_line = = 0 )
m_num_per_line = 1 ;
break ;
case eFormatCString :
if ( m_num_per_line = = 0 )
m_num_per_line = 1 ;
break ;
case eFormatPointer :
break ;
case eFormatBinary :
case eFormatFloat :
case eFormatOctal :
case eFormatDecimal :
case eFormatEnum :
case eFormatUnicode16 :
case eFormatUnicode32 :
case eFormatUnsigned :
if ( m_byte_size = = 0 )
m_byte_size = 4 ;
if ( m_num_per_line = = 0 )
m_num_per_line = 1 ;
break ;
case eFormatBytes :
case eFormatBytesWithASCII :
case eFormatChar :
case eFormatCharPrintable :
if ( m_byte_size = = 0 )
m_byte_size = 1 ;
break ;
case eFormatComplex :
if ( m_byte_size = = 0 )
m_byte_size = 8 ;
break ;
case eFormatHex :
if ( m_byte_size = = 0 )
m_byte_size = 4 ;
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 :
break ;
}
break ;
case ' l ' :
m_num_per_line = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( m_num_per_line = = 0 )
error . SetErrorStringWithFormat ( " Invalid value for --num-per-line option '%s'. Must be positive integer value. \n " , option_arg ) ;
break ;
case ' c ' :
m_count = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( m_count = = 0 )
error . SetErrorStringWithFormat ( " Invalid value for --count option '%s'. Must be positive integer value. \n " , option_arg ) ;
break ;
case ' s ' :
m_byte_size = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( m_byte_size = = 0 )
error . SetErrorStringWithFormat ( " Invalid value for --size option '%s'. Must be positive integer value. \n " , option_arg ) ;
break ;
2010-10-11 04:52:20 +08:00
case ' o ' :
2010-10-21 04:54:39 +08:00
m_outfile_filespec . SetFile ( option_arg , true ) ;
2010-10-11 04:52:20 +08:00
break ;
case ' b ' :
m_output_as_binary = true ;
break ;
case ' a ' :
m_append_to_outfile = true ;
break ;
2010-06-09 00:52:24 +08:00
default :
error . SetErrorStringWithFormat ( " Unrecognized short option '%c'. \n " , short_option ) ;
break ;
}
return error ;
}
void
ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
m_format = eFormatBytesWithASCII ;
m_byte_size = 0 ;
m_count = 0 ;
m_num_per_line = 0 ;
2010-10-11 04:52:20 +08:00
m_outfile_filespec . Clear ( ) ;
m_append_to_outfile = false ;
m_output_as_binary = false ;
2010-06-09 00:52:24 +08:00
}
const lldb : : OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static lldb : : OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
lldb : : Format m_format ;
uint32_t m_byte_size ;
uint32_t m_count ;
uint32_t m_num_per_line ;
2010-10-11 04:52:20 +08:00
FileSpec m_outfile_filespec ;
bool m_append_to_outfile ;
bool m_output_as_binary ;
2010-06-09 00:52:24 +08:00
} ;
2010-09-18 09:14:36 +08:00
CommandObjectMemoryRead ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" memory read " ,
2010-09-09 05:06:11 +08:00
" Read from the memory of the process being debugged. " ,
2010-10-05 06:28:36 +08:00
NULL ,
2010-06-09 00:52:24 +08:00
eFlagProcessMustBeLaunched )
{
2010-10-05 06:28:36 +08:00
CommandArgumentEntry arg1 ;
CommandArgumentEntry arg2 ;
CommandArgumentData start_addr_arg ;
CommandArgumentData end_addr_arg ;
// Define the first (and only) variant of this arg.
start_addr_arg . arg_type = eArgTypeStartAddress ;
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.
end_addr_arg . arg_type = eArgTypeEndAddress ;
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 ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandObjectMemoryRead ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2010-09-18 09:14:36 +08:00
Process * process = m_interpreter . GetDebugger ( ) . GetExecutionContext ( ) . process ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " need a process to read memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc = = 0 | | argc > 2 )
{
result . AppendErrorWithFormat ( " %s takes 1 or two args. \n " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
size_t item_byte_size = m_options . m_byte_size ;
if ( item_byte_size = = 0 )
{
if ( m_options . m_format = = eFormatPointer )
2011-02-16 05:59:32 +08:00
item_byte_size = process - > GetTarget ( ) . GetArchitecture ( ) . GetAddressByteSize ( ) ;
2010-06-09 00:52:24 +08:00
else
item_byte_size = 1 ;
}
size_t item_count = m_options . m_count ;
size_t num_per_line = m_options . m_num_per_line ;
if ( num_per_line = = 0 )
{
num_per_line = ( 16 / item_byte_size ) ;
if ( num_per_line = = 0 )
num_per_line = 1 ;
}
size_t total_byte_size = m_options . m_count * item_byte_size ;
if ( total_byte_size = = 0 )
total_byte_size = 32 ;
lldb : : addr_t addr = Args : : StringToUInt64 ( command . GetArgumentAtIndex ( 0 ) , LLDB_INVALID_ADDRESS , 0 ) ;
if ( addr = = LLDB_INVALID_ADDRESS )
{
result . AppendErrorWithFormat ( " invalid start address string '%s'. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( argc = = 2 )
{
lldb : : addr_t end_addr = Args : : StringToUInt64 ( command . GetArgumentAtIndex ( 1 ) , LLDB_INVALID_ADDRESS , 0 ) ;
if ( end_addr = = LLDB_INVALID_ADDRESS )
{
result . AppendErrorWithFormat ( " Invalid end address string '%s'. \n " , command . GetArgumentAtIndex ( 1 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( end_addr < = addr )
{
result . AppendErrorWithFormat ( " End address (0x%llx) must be greater that the start address (0x%llx). \n " , end_addr , addr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
else if ( item_count ! = 0 )
{
result . AppendErrorWithFormat ( " Specify either the end address (0x%llx) or the count (--count %u), not both. \n " , end_addr , item_count ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
total_byte_size = end_addr - addr ;
item_count = total_byte_size / item_byte_size ;
}
else
{
if ( item_count = = 0 )
item_count = 32 ;
}
DataBufferSP data_sp ( new DataBufferHeap ( total_byte_size , ' \0 ' ) ) ;
Error error ;
size_t bytes_read = process - > ReadMemory ( addr , data_sp - > GetBytes ( ) , data_sp - > GetByteSize ( ) , error ) ;
if ( bytes_read = = 0 )
{
result . AppendWarningWithFormat ( " Read from 0x%llx failed. \n " , addr ) ;
result . AppendError ( error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( bytes_read < total_byte_size )
result . AppendWarningWithFormat ( " Not all bytes (%u/%u) were able to be read from 0x%llx. \n " , bytes_read , total_byte_size , addr ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
2011-02-16 05:59:32 +08:00
DataExtractor data ( data_sp ,
process - > GetTarget ( ) . GetArchitecture ( ) . GetByteOrder ( ) ,
process - > GetTarget ( ) . GetArchitecture ( ) . GetAddressByteSize ( ) ) ;
2010-06-09 00:52:24 +08:00
2010-10-11 04:52:20 +08:00
StreamFile outfile_stream ;
Stream * output_stream = NULL ;
if ( m_options . m_outfile_filespec )
{
char path [ PATH_MAX ] ;
m_options . m_outfile_filespec . GetPath ( path , sizeof ( path ) ) ;
char mode [ 16 ] = { ' w ' , ' \0 ' } ;
if ( m_options . m_append_to_outfile )
mode [ 0 ] = ' a ' ;
2011-02-09 09:08:52 +08:00
if ( outfile_stream . GetFile ( ) . Open ( path , File : : eOpenOptionWrite | File : : eOpenOptionCanCreate ) . Success ( ) )
2010-10-11 04:52:20 +08:00
{
if ( m_options . m_output_as_binary )
{
int bytes_written = outfile_stream . Write ( data_sp - > GetBytes ( ) , bytes_read ) ;
if ( bytes_written > 0 )
{
result . GetOutputStream ( ) . Printf ( " %i bytes %s to '%s' \n " ,
bytes_written ,
m_options . m_append_to_outfile ? " appended " : " written " ,
path ) ;
return true ;
}
else
{
result . AppendErrorWithFormat ( " Failed to write %zu bytes to '%s'. \n " , 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 ;
}
}
else
{
result . AppendErrorWithFormat ( " Failed to open file '%s' with a mode of '%s'. \n " , path , mode ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
else
{
output_stream = & result . GetOutputStream ( ) ;
}
assert ( output_stream ) ;
data . Dump ( output_stream ,
0 ,
m_options . m_format ,
item_byte_size ,
item_count ,
num_per_line ,
addr ,
0 ,
0 ) ;
output_stream - > EOL ( ) ;
2010-06-09 00:52:24 +08:00
return true ;
}
protected :
CommandOptions m_options ;
} ;
2010-10-11 04:52:20 +08:00
# define SET1 LLDB_OPT_SET_1
# define SET2 LLDB_OPT_SET_2
2010-06-09 00:52:24 +08:00
lldb : : OptionDefinition
CommandObjectMemoryRead : : CommandOptions : : g_option_table [ ] =
{
2010-10-11 04:52:20 +08:00
{ SET1 , false , " format " , ' f ' , required_argument , NULL , 0 , eArgTypeFormat , " The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y). " } ,
{ SET1 , false , " size " , ' s ' , required_argument , NULL , 0 , eArgTypeByteSize , " The size in bytes to use when displaying with the selected format. " } ,
{ SET1 , false , " num-per-line " , ' l ' , required_argument , NULL , 0 , eArgTypeNumberPerLine , " The number of items per line to display. " } ,
{ SET1 , false , " count " , ' c ' , required_argument , NULL , 0 , eArgTypeCount , " The number of total items to display. " } ,
{ SET1 | SET2 , false , " outfile " , ' o ' , required_argument , NULL , 0 , eArgTypeFilename , " Dump memory read results into a file. " } ,
{ SET1 | SET2 , false , " append " , ' a ' , no_argument , NULL , 0 , eArgTypeNone , " Append memory read results to 'outfile'. " } ,
{ SET2 , false , " binary " , ' b ' , no_argument , 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. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-06-09 00:52:24 +08:00
} ;
2010-10-11 04:52:20 +08:00
# undef SET1
# undef SET2
2010-06-09 00:52:24 +08:00
//----------------------------------------------------------------------
// Write memory to the inferior process
//----------------------------------------------------------------------
class CommandObjectMemoryWrite : public CommandObject
{
public :
class CommandOptions : public Options
{
public :
CommandOptions ( ) :
Options ( )
{
ResetOptionValues ( ) ;
}
virtual
~ CommandOptions ( )
{
}
virtual Error
SetOptionValue ( int option_idx , const char * option_arg )
{
Error error ;
char short_option = ( char ) m_getopt_table [ option_idx ] . val ;
switch ( short_option )
{
case ' f ' :
error = Args : : StringToFormat ( option_arg , m_format ) ;
break ;
case ' s ' :
m_byte_size = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( m_byte_size = = 0 )
error . SetErrorStringWithFormat ( " Invalid value for --size option '%s'. Must be positive integer value. \n " , option_arg ) ;
break ;
2010-10-11 04:52:20 +08:00
case ' i ' :
2010-10-21 04:54:39 +08:00
m_infile . SetFile ( option_arg , true ) ;
2010-10-11 04:52:20 +08:00
if ( ! m_infile . Exists ( ) )
{
m_infile . Clear ( ) ;
error . SetErrorStringWithFormat ( " Input file does not exist: '%s' \n " , option_arg ) ;
}
break ;
case ' o ' :
{
bool success ;
m_infile_offset = Args : : StringToUInt64 ( option_arg , 0 , 0 , & success ) ;
if ( ! success )
{
error . SetErrorStringWithFormat ( " Invalid offset string '%s' \n " , option_arg ) ;
}
}
break ;
2010-06-09 00:52:24 +08:00
default :
error . SetErrorStringWithFormat ( " Unrecognized short option '%c' \n " , short_option ) ;
break ;
}
return error ;
}
void
ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
m_format = eFormatBytes ;
m_byte_size = 1 ;
2010-10-11 04:52:20 +08:00
m_infile . Clear ( ) ;
m_infile_offset = 0 ;
2010-06-09 00:52:24 +08:00
}
const lldb : : OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
// Options table: Required for subclasses of Options.
static lldb : : OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
lldb : : Format m_format ;
uint32_t m_byte_size ;
2010-10-11 04:52:20 +08:00
FileSpec m_infile ;
off_t m_infile_offset ;
2010-06-09 00:52:24 +08:00
} ;
2010-09-18 09:14:36 +08:00
CommandObjectMemoryWrite ( CommandInterpreter & interpreter ) :
CommandObject ( interpreter ,
" memory write " ,
2010-09-09 05:06:11 +08:00
" Write to the memory of the process being debugged. " ,
2010-10-05 06:28:36 +08:00
//"memory write [<cmd-options>] <addr> [value1 value2 ...]",
NULL ,
2010-06-09 00:52:24 +08:00
eFlagProcessMustBeLaunched )
{
2010-10-05 06:28:36 +08: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 ) ;
2010-06-09 00:52:24 +08:00
}
virtual
~ CommandObjectMemoryWrite ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
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 ;
}
virtual bool
2010-09-18 09:14:36 +08:00
Execute ( Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2010-09-18 09:14:36 +08:00
Process * process = m_interpreter . GetDebugger ( ) . GetExecutionContext ( ) . process ;
2010-06-09 00:52:24 +08:00
if ( process = = NULL )
{
result . AppendError ( " need a process to read memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const size_t argc = command . GetArgumentCount ( ) ;
2010-10-11 04:52:20 +08:00
if ( m_options . m_infile )
2010-06-09 00:52:24 +08:00
{
2010-10-11 04:52:20 +08: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-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
StreamString buffer ( Stream : : eBinary ,
2011-02-16 05:59:32 +08:00
process - > GetTarget ( ) . GetArchitecture ( ) . GetAddressByteSize ( ) ,
process - > GetTarget ( ) . GetArchitecture ( ) . GetByteOrder ( ) ) ;
2010-06-09 00:52:24 +08:00
2010-07-10 04:39:50 +08:00
size_t item_byte_size = m_options . m_byte_size ;
2010-06-09 00:52:24 +08:00
lldb : : addr_t addr = Args : : StringToUInt64 ( command . GetArgumentAtIndex ( 0 ) , LLDB_INVALID_ADDRESS , 0 ) ;
if ( addr = = LLDB_INVALID_ADDRESS )
{
result . AppendErrorWithFormat ( " Invalid address string '%s'. \n " , command . GetArgumentAtIndex ( 0 ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-10-11 04:52:20 +08:00
if ( m_options . m_infile )
{
size_t length = SIZE_MAX ;
if ( m_options . m_byte_size > 0 )
length = m_options . m_byte_size ;
lldb : : DataBufferSP data_sp ( m_options . m_infile . ReadFileContents ( m_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 ( " %zu bytes were written to 0x%llx \n " , bytes_written , addr ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else if ( bytes_written > 0 )
{
// Some byte written
result . GetOutputStream ( ) . Printf ( " %zu bytes of %zu requested were written to 0x%llx \n " , bytes_written , length , addr ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Memory write to 0x%llx failed: %s. \n " , addr , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
}
else
{
result . AppendErrorWithFormat ( " Unable to read contents of file. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
return result . Succeeded ( ) ;
}
else if ( m_options . m_byte_size = = 0 )
{
if ( m_options . m_format = = eFormatPointer )
item_byte_size = buffer . GetAddressByteSize ( ) ;
else
item_byte_size = 1 ;
}
2010-06-09 00:52:24 +08:00
command . Shift ( ) ; // shift off the address argument
uint64_t uval64 ;
int64_t sval64 ;
bool success = false ;
const uint32_t num_value_args = command . GetArgumentCount ( ) ;
uint32_t i ;
for ( i = 0 ; i < num_value_args ; + + i )
{
const char * value_str = command . GetArgumentAtIndex ( i ) ;
switch ( m_options . m_format )
{
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 :
result . AppendError ( " unsupported format for writing memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
case eFormatDefault :
case eFormatBytes :
case eFormatHex :
2010-07-10 04:39:50 +08:00
case eFormatPointer :
2010-06-09 00:52:24 +08: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 ) )
{
result . AppendErrorWithFormat ( " Value 0x%llx is too large to fit in a %u byte unsigned integer value. \n " , uval64 , item_byte_size ) ;
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 ) )
{
result . AppendErrorWithFormat ( " Value 0x%llx is too large to fit in a %u byte unsigned integer value. \n " , uval64 , item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
case eFormatChar :
case eFormatCString :
if ( value_str [ 0 ] )
{
size_t len = strlen ( value_str ) ;
// Include the NULL for C strings...
if ( m_options . m_format = = eFormatCString )
+ + len ;
Error error ;
if ( process - > WriteMemory ( addr , value_str , len , error ) = = len )
{
addr + = len ;
}
else
{
result . AppendErrorWithFormat ( " Memory write to 0x%llx failed: %s. \n " , addr , error . AsCString ( ) ) ;
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 ) )
{
result . AppendErrorWithFormat ( " Value %lli is too large or small to fit in a %u byte signed integer value. \n " , sval64 , item_byte_size ) ;
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 ) )
{
result . AppendErrorWithFormat ( " Value %llu is too large to fit in a %u byte unsigned integer value. \n " , uval64 , item_byte_size ) ;
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 ) )
{
result . AppendErrorWithFormat ( " Value %llo is too large to fit in a %u byte unsigned integer value. \n " , uval64 , item_byte_size ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
buffer . PutMaxHex64 ( uval64 , item_byte_size ) ;
break ;
}
}
if ( ! buffer . GetString ( ) . empty ( ) )
{
Error error ;
2010-07-21 06:52:08 +08:00
if ( process - > WriteMemory ( addr , buffer . GetString ( ) . c_str ( ) , buffer . GetString ( ) . size ( ) , error ) = = buffer . GetString ( ) . size ( ) )
2010-06-09 00:52:24 +08:00
return true ;
else
{
result . AppendErrorWithFormat ( " Memory write to 0x%llx failed: %s. \n " , addr , error . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
return true ;
}
protected :
CommandOptions m_options ;
} ;
2010-10-11 04:52:20 +08:00
# define SET1 LLDB_OPT_SET_1
# define SET2 LLDB_OPT_SET_2
2010-06-09 00:52:24 +08:00
lldb : : OptionDefinition
CommandObjectMemoryWrite : : CommandOptions : : g_option_table [ ] =
{
2010-10-11 04:52:20 +08:00
{ SET1 , false , " format " , ' f ' , required_argument , NULL , 0 , eArgTypeFormat , " The format value types that will be decoded and written to memory. " } ,
{ SET1 | SET2 , false , " size " , ' s ' , required_argument , NULL , 0 , eArgTypeByteSize , " The size in bytes of the values to write to memory. " } ,
{ SET2 , true , " infile " , ' i ' , required_argument , NULL , 0 , eArgTypeFilename , " Write memory using the contents of a file. " } ,
{ SET2 , false , " offset " , ' o ' , required_argument , NULL , 0 , eArgTypeOffset , " Start writng bytes from an offset within the input file. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , eArgTypeNone , NULL }
2010-06-09 00:52:24 +08:00
} ;
2010-10-11 04:52:20 +08:00
# undef SET1
# undef SET2
2010-06-09 00:52:24 +08:00
//-------------------------------------------------------------------------
// CommandObjectMemory
//-------------------------------------------------------------------------
2010-06-23 09:19:29 +08:00
CommandObjectMemory : : CommandObjectMemory ( CommandInterpreter & interpreter ) :
2010-09-18 09:14:36 +08:00
CommandObjectMultiword ( interpreter ,
" memory " ,
2010-09-08 06:38:08 +08:00
" A set of commands for operating on memory. " ,
2010-06-09 00:52:24 +08:00
" memory <subcommand> [<subcommand-options>] " )
{
2010-09-18 09:14:36 +08:00
LoadSubCommand ( " read " , CommandObjectSP ( new CommandObjectMemoryRead ( interpreter ) ) ) ;
LoadSubCommand ( " write " , CommandObjectSP ( new CommandObjectMemoryWrite ( interpreter ) ) ) ;
2010-06-09 00:52:24 +08:00
}
CommandObjectMemory : : ~ CommandObjectMemory ( )
{
}