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 ;
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 ;
}
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 ;
} ;
CommandObjectMemoryRead ( ) :
CommandObject ( " memory read " ,
" Read memory from the process being debugged. " ,
" memory read [<cmd-options>] <start-addr> [<end-addr>] " ,
eFlagProcessMustBeLaunched )
{
}
virtual
~ CommandObjectMemoryRead ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
virtual bool
2010-06-23 09:19:29 +08:00
Execute ( CommandInterpreter & interpreter ,
Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2010-06-23 09:19:29 +08:00
Process * process = 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 )
item_byte_size = process - > GetAddressByteSize ( ) ;
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 ) ;
DataExtractor data ( data_sp , process - > GetByteOrder ( ) , process - > GetAddressByteSize ( ) ) ;
Stream & output_stream = result . GetOutputStream ( ) ;
data . Dump ( & output_stream ,
0 ,
m_options . m_format ,
item_byte_size ,
item_count ,
num_per_line ,
addr ,
0 ,
0 ) ;
output_stream . EOL ( ) ;
return true ;
}
protected :
CommandOptions m_options ;
} ;
lldb : : OptionDefinition
CommandObjectMemoryRead : : CommandOptions : : g_option_table [ ] =
{
2010-06-16 02:47:14 +08:00
{ LLDB_OPT_SET_1 , false , " format " , ' f ' , required_argument , NULL , 0 , " <format> " , " The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y). " } ,
{ LLDB_OPT_SET_1 , false , " size " , ' s ' , required_argument , NULL , 0 , " <byte-size> " , " The size in bytes to use when displaying with the selected format. " } ,
{ LLDB_OPT_SET_1 , false , " num-per-line " , ' l ' , required_argument , NULL , 0 , " <N> " , " The number of items per line to display. " } ,
{ LLDB_OPT_SET_1 , false , " count " , ' c ' , required_argument , NULL , 0 , " <N> " , " The number of total items to display. " } ,
2010-06-09 00:52:24 +08:00
{ 0 , false , NULL , 0 , 0 , NULL , 0 , NULL , NULL }
} ;
//----------------------------------------------------------------------
// 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 ;
default :
error . SetErrorStringWithFormat ( " Unrecognized short option '%c' \n " , short_option ) ;
break ;
}
return error ;
}
void
ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
m_format = eFormatBytes ;
m_byte_size = 1 ;
}
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 ;
} ;
CommandObjectMemoryWrite ( ) :
CommandObject ( " memory write " ,
" Write memory to the process being debugged. " ,
" memory write [<cmd-options>] <addr> [value1 value2 ...] " ,
eFlagProcessMustBeLaunched )
{
}
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-06-23 09:19:29 +08:00
Execute ( CommandInterpreter & interpreter ,
Args & command ,
2010-06-09 00:52:24 +08:00
CommandReturnObject & result )
{
2010-06-23 09:19:29 +08:00
Process * process = 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 < 2 )
{
result . AppendErrorWithFormat ( " %s takes an address and at least one value. \n " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
StreamString buffer ( Stream : : eBinary ,
process - > GetAddressByteSize ( ) ,
process - > GetByteOrder ( ) ) ;
2010-07-10 04:39:50 +08:00
size_t item_byte_size = m_options . m_byte_size ;
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
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 ;
}
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 ;
if ( process - > WriteMemory ( addr , buffer . GetString ( ) . data ( ) , buffer . GetString ( ) . size ( ) , error ) = = buffer . GetString ( ) . size ( ) )
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 ;
} ;
lldb : : OptionDefinition
CommandObjectMemoryWrite : : CommandOptions : : g_option_table [ ] =
{
2010-06-16 02:47:14 +08:00
{ LLDB_OPT_SET_1 , false , " format " , ' f ' , required_argument , NULL , 0 , " <format> " , " The format value types that will be decoded and written to memory. " } ,
{ LLDB_OPT_SET_1 , false , " size " , ' s ' , required_argument , NULL , 0 , " <byte-size> " , " The size in bytes of the values to write to memory. " } ,
2010-06-09 00:52:24 +08:00
{ 0 , false , NULL , 0 , 0 , NULL , 0 , NULL , NULL }
} ;
//-------------------------------------------------------------------------
// CommandObjectMemory
//-------------------------------------------------------------------------
2010-06-23 09:19:29 +08:00
CommandObjectMemory : : CommandObjectMemory ( CommandInterpreter & interpreter ) :
2010-06-09 00:52:24 +08:00
CommandObjectMultiword ( " memory " ,
" A set of commands for operating on a memory. " ,
" memory <subcommand> [<subcommand-options>] " )
{
2010-06-23 09:19:29 +08:00
LoadSubCommand ( interpreter , " read " , CommandObjectSP ( new CommandObjectMemoryRead ( ) ) ) ;
LoadSubCommand ( interpreter , " write " , CommandObjectSP ( new CommandObjectMemoryWrite ( ) ) ) ;
2010-06-09 00:52:24 +08:00
}
CommandObjectMemory : : ~ CommandObjectMemory ( )
{
}