2017-12-03 18:43:03 +00:00
/*
2015-12-29 16:40:33 +00:00
* mon_cmd . cpp - cxmon standard commands
*
* cxmon ( C ) 1997 - 2004 Christian Bauer , Marc Hellwig
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "sysdeps.h"
# include <stdlib.h>
2016-01-31 15:00:57 +00:00
# include <assert.h>
2015-12-29 16:40:33 +00:00
# include "mon.h"
# include "mon_cmd.h"
# include "mon_disass.h"
# ifndef VERSION
# define VERSION "3"
# endif
/*
* range_args = [ expression ] [ [ COMMA ] expression ] END
*
* Read start address to " adr " , end address to " end_adr " .
* " adr " defaults to ' . ' , " end_adr " defaults to ' . ' + def_range
*
* true : OK , false : Error
*/
static bool range_args ( uintptr * adr , uintptr * end_adr , uint32 def_range )
{
* adr = mon_dot_address ;
* end_adr = mon_dot_address + def_range ;
if ( mon_token = = T_END )
return true ;
else {
if ( ! mon_expression ( adr ) )
return false ;
* end_adr = * adr + def_range ;
if ( mon_token = = T_END )
return true ;
else {
if ( mon_token = = T_COMMA ) mon_get_token ( ) ;
if ( ! mon_expression ( end_adr ) )
return false ;
return mon_token = = T_END ;
}
}
}
/*
* byte_string = ( expression | STRING ) { COMMA ( expression | STRING ) } END
*/
static bool byte_string ( uint8 * & str , uintptr & len )
{
uintptr value ;
static const int GRANULARITY = 16 ; // must be a power of 2
str = NULL ;
len = 0 ;
goto start ;
for ( ; ; ) {
if ( mon_token = = T_COMMA ) {
mon_get_token ( ) ;
start :
if ( mon_token = = T_STRING ) {
unsigned n = strlen ( mon_string ) ;
str = ( uint8 * ) realloc ( str , ( len + n - 1 + GRANULARITY ) & ~ ( GRANULARITY - 1 ) ) ;
2016-01-31 15:00:57 +00:00
assert ( str ! = NULL ) ;
2015-12-29 16:40:33 +00:00
memcpy ( str + len , mon_string , n ) ;
len + = n ;
mon_get_token ( ) ;
} else if ( mon_expression ( & value ) ) {
str = ( uint8 * ) realloc ( str , ( len + GRANULARITY ) & ~ ( GRANULARITY - 1 ) ) ;
2016-01-31 15:00:57 +00:00
assert ( str ! = NULL ) ;
2015-12-29 16:40:33 +00:00
str [ len ] = value ;
len + + ;
} else {
if ( str )
free ( str ) ;
return false ;
}
} else if ( mon_token = = T_END ) {
return true ;
} else {
mon_error ( " ',' expected " ) ;
if ( str )
free ( str ) ;
return false ;
}
}
}
/*
* Convert character to printable character
*/
static inline uint8 char2print ( uint8 c )
{
return ( c > = 0x20 & & c < = 0x7e ) ? c : ' . ' ;
}
/*
* Show version
* ver
*/
void version ( void )
{
fprintf ( monout , " cxmon V " VERSION " \n " ) ;
}
/*
* Redirect output
* o [ file ]
*/
void redir_output ( void )
{
// Close old file
if ( monout ! = monerr ) {
fclose ( monout ) ;
monout = monerr ;
return ;
}
// No argument given?
if ( mon_token = = T_END )
return ;
// Otherwise open file
if ( mon_token = = T_STRING ) {
mon_get_token ( ) ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
if ( ! ( monout = fopen ( mon_string , " w " ) ) )
mon_error ( " Unable to open file " ) ;
} else
mon_error ( " ' \" ' around file name expected " ) ;
}
/*
* Compute and display expression
* ? expression
*/
void print_expr ( void )
{
uintptr val ;
if ( ! mon_expression ( & val ) )
return ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
if ( val > 0x7fffffff ) {
fprintf ( monout , " Hex unsigned: $%08x \n "
" Hex signed : -$%08x \n "
" Dec unsigned: %u \n "
" Dec signed : %d \n " , val , - val , val , val ) ;
fprintf ( monout , " Char : '%c%c%c%c' \n " , char2print ( val > > 24 ) , char2print ( val > > 16 ) , char2print ( val > > 8 ) , char2print ( val ) ) ;
} else {
fprintf ( monout , " Hex : $%08x \n "
" Dec : %d \n " , val , val ) ;
fprintf ( monout , " Char: '%c%c%c%c' \n " , char2print ( val > > 24 ) , char2print ( val > > 16 ) , char2print ( val > > 8 ) , char2print ( val ) ) ;
}
}
/*
* Execute shell command
* \ " command "
*/
void shell_command ( void )
{
if ( mon_token ! = T_STRING ) {
mon_error ( " ' \" ' around command expected " ) ;
return ;
}
mon_get_token ( ) ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
system ( mon_string ) ;
}
/*
* Memory dump
* m [ start [ end ] ]
*/
# define MEMDUMP_BPL 16 // Bytes per line
void memory_dump ( void )
{
uintptr adr , end_adr ;
uint8 mem [ MEMDUMP_BPL + 1 ] ;
mem [ MEMDUMP_BPL ] = 0 ;
if ( ! range_args ( & adr , & end_adr , 16 * MEMDUMP_BPL - 1 ) ) // 16 lines unless end address specified
return ;
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
for ( int i = 0 ; i < MEMDUMP_BPL ; i + + , adr + + ) {
if ( i % 4 = = 0 )
fprintf ( monout , " %08x " , mon_read_word ( adr ) ) ;
mem [ i ] = char2print ( mon_read_byte ( adr ) ) ;
}
fprintf ( monout , " '%s' \n " , mem ) ;
}
mon_dot_address = adr ;
}
/*
* ASCII dump
* i [ start [ end ] ]
*/
# define ASCIIDUMP_BPL 64 // Bytes per line
void ascii_dump ( void )
{
uintptr adr , end_adr ;
uint8 str [ ASCIIDUMP_BPL + 1 ] ;
str [ ASCIIDUMP_BPL ] = 0 ;
if ( ! range_args ( & adr , & end_adr , 16 * ASCIIDUMP_BPL - 1 ) ) // 16 lines unless end address specified
return ;
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
for ( int i = 0 ; i < ASCIIDUMP_BPL ; i + + , adr + + )
str [ i ] = char2print ( mon_read_byte ( adr ) ) ;
fprintf ( monout , " '%s' \n " , str ) ;
}
mon_dot_address = adr ;
}
/*
* Binary dump
* b [ start [ end ] ]
*/
void binary_dump ( void )
{
uintptr adr , end_adr ;
uint8 str [ 9 ] ;
str [ 8 ] = 0 ;
if ( ! range_args ( & adr , & end_adr , 7 ) ) // 8 lines unless end address specified
return ;
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
uint8 b = mon_read_byte ( adr ) ;
for ( int m = 0x80 , i = 0 ; i < 8 ; m > > = 1 , i + + )
str [ i ] = ( b & m ) ? ' * ' : ' . ' ;
fprintf ( monout , " '%s' \n " , str ) ;
adr + + ;
}
mon_dot_address = adr ;
}
2017-09-01 14:47:22 +00:00
/*
* Add Break Point
*/
void break_point_add ( void )
{
uintptr address ;
2017-09-04 10:31:36 +00:00
if ( mon_token = = T_END | | ! mon_expression ( & address ) ) {
mon_error ( " Expect break point in hexadecimal. " ) ;
2017-09-01 14:47:22 +00:00
return ;
}
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
2017-09-16 01:35:27 +00:00
mon_add_break_point ( address ) ;
2017-09-01 14:47:22 +00:00
}
2017-09-04 10:31:36 +00:00
bool validate_index ( uintptr * index_ptr , const BREAK_POINT_SET & break_point_set )
2017-09-01 14:47:22 +00:00
{
2017-09-04 10:31:36 +00:00
if ( mon_token = = T_END | | ! mon_expression ( index_ptr ) ) {
mon_error ( " Expect index number of break point in hexadecimal. \n " ) ;
return false ;
2017-09-01 14:47:22 +00:00
}
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
2017-09-04 10:31:36 +00:00
return false ;
2017-09-01 14:47:22 +00:00
}
2017-09-04 10:31:36 +00:00
if ( * index_ptr > break_point_set . size ( ) ) {
2017-09-04 18:21:16 +00:00
mon_error ( " Illegal index number! " ) ;
2017-09-04 10:31:36 +00:00
return false ;
2017-09-01 14:47:22 +00:00
}
2017-09-04 10:31:36 +00:00
return true ;
}
/*
* Remove Break Point
*/
void break_point_remove ( void )
{
uintptr index ;
if ( ! validate_index ( & index , active_break_points ) )
return ;
2017-09-01 14:47:22 +00:00
if ( 0 = = index ) {
active_break_points . clear ( ) ;
printf ( " Removed all break points! \n " ) ;
return ;
}
2017-09-04 10:31:36 +00:00
BREAK_POINT_SET : : iterator it = active_break_points . begin ( ) ;
std : : advance ( it , index - 1 ) ;
2017-09-01 14:47:22 +00:00
// Remove break point
printf ( " Removed break point %4x at address %08lx \n " , index , * it ) ;
active_break_points . erase ( it ) ;
}
/*
* Disable Break Point
*/
void break_point_disable ( void )
{
uintptr index ;
2017-09-04 12:00:45 +00:00
if ( ! validate_index ( & index , active_break_points ) )
2017-09-01 14:47:22 +00:00
return ;
if ( 0 = = index ) {
2017-09-04 10:31:36 +00:00
for ( BREAK_POINT_SET : : iterator it = active_break_points . begin ( ) ; it ! = active_break_points . end ( ) ; it + + )
2017-09-01 14:47:22 +00:00
disabled_break_points . insert ( * it ) ;
active_break_points . clear ( ) ;
printf ( " Disabled all break points! \n " ) ;
return ;
}
2017-09-04 10:31:36 +00:00
BREAK_POINT_SET : : iterator it = active_break_points . begin ( ) ;
std : : advance ( it , index - 1 ) ;
2017-09-01 14:47:22 +00:00
// Add to disable break points
printf ( " Disabled break point %4x at address %08lx \n " , index , * it ) ;
disabled_break_points . insert ( * it ) ;
// Remove break point
active_break_points . erase ( it ) ;
}
/*
* Enable Break Point
*/
void break_point_enable ( void )
{
uintptr index ;
2017-09-04 12:00:45 +00:00
if ( ! validate_index ( & index , disabled_break_points ) )
2017-09-01 14:47:22 +00:00
return ;
if ( 0 = = index ) {
2017-09-04 18:21:16 +00:00
active_break_points . insert ( disabled_break_points . begin ( ) , disabled_break_points . end ( ) ) ;
2017-09-01 14:47:22 +00:00
disabled_break_points . clear ( ) ;
printf ( " Enabled all break points! \n " ) ;
return ;
}
2017-09-04 10:31:36 +00:00
BREAK_POINT_SET : : iterator it = disabled_break_points . begin ( ) ;
std : : advance ( it , index - 1 ) ;
2017-09-01 14:47:22 +00:00
// Add to active break points
printf ( " Disabled break point %4x at address %08lx \n " , index , * it ) ;
active_break_points . insert ( * it ) ;
// Remove break point
disabled_break_points . erase ( it ) ;
}
/*
* List all Active Break Points
*/
void break_point_info ( void )
{
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
BREAK_POINT_SET : : iterator it ;
if ( ! active_break_points . empty ( ) ) {
2017-09-04 10:31:36 +00:00
int pos = 1 ;
2017-09-01 14:47:22 +00:00
printf ( STR_ACTIVE_BREAK_POINTS ) ;
for ( it = active_break_points . begin ( ) ; it ! = active_break_points . end ( ) ; it + + )
printf ( " \t Break point %4x at address %08lx \n " , pos + + , * it ) ;
}
if ( ! disabled_break_points . empty ( ) ) {
putchar ( ' \n ' ) ;
printf ( STR_DISABLED_BREAK_POINTS ) ;
2017-09-04 10:31:36 +00:00
int pos = 1 ;
2017-09-01 14:47:22 +00:00
for ( it = disabled_break_points . begin ( ) ; it ! = disabled_break_points . end ( ) ; it + + )
printf ( " \t Break point %4x at address %08lx \n " , pos + + , * it ) ;
}
}
/*
* Save all Active Break Points to a file
*/
void break_point_save ( void )
{
if ( mon_token = = T_END ) {
mon_error ( " Missing file name " ) ;
return ;
}
if ( mon_token ! = T_STRING ) {
mon_error ( " ' \" ' around file name expected " ) ;
return ;
}
mon_get_token ( ) ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
2017-09-04 18:21:16 +00:00
FILE * file ;
if ( ! ( file = fopen ( mon_string , " w " ) ) ) {
2017-09-01 14:47:22 +00:00
mon_error ( " Unable to create file " ) ;
2017-09-04 18:21:16 +00:00
return ;
}
2017-09-01 14:47:22 +00:00
2017-09-04 18:21:16 +00:00
BREAK_POINT_SET : : iterator it ;
2017-09-01 14:47:22 +00:00
2017-09-04 18:21:16 +00:00
fprintf ( file , STR_ACTIVE_BREAK_POINTS ) ;
for ( it = active_break_points . begin ( ) ; it ! = active_break_points . end ( ) ; it + + )
fprintf ( file , " %x \n " , * it ) ;
2017-09-01 14:47:22 +00:00
2017-09-04 18:21:16 +00:00
fprintf ( file , STR_DISABLED_BREAK_POINTS ) ;
for ( it = disabled_break_points . begin ( ) ; it ! = disabled_break_points . end ( ) ; it + + )
2017-09-04 18:35:50 +00:00
fprintf ( file , " %x \n " , * it ) ;
2017-09-04 18:21:16 +00:00
fclose ( file ) ;
2017-09-01 14:47:22 +00:00
}
/*
* Load Break Point from a file
*/
void break_point_load ( void )
{
if ( mon_token = = T_END ) {
mon_error ( " Missing file name " ) ;
return ;
}
if ( mon_token ! = T_STRING ) {
mon_error ( " ' \" ' around file name expected " ) ;
return ;
}
mon_get_token ( ) ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
2017-09-16 01:35:27 +00:00
// load from file
mon_load_break_point ( mon_string ) ;
2017-09-01 14:47:22 +00:00
}
2015-12-29 16:40:33 +00:00
/*
* Disassemble
* d [ start [ end ] ]
* d65 [ start [ end ] ]
* d68 [ start [ end ] ]
* d80 [ start [ end ] ]
* d86 [ start [ end ] ]
* d8086 [ start [ end ] ]
*/
enum CPUType {
CPU_PPC ,
CPU_6502 ,
CPU_680x0 ,
CPU_Z80 ,
CPU_80x86_32 ,
CPU_80x86_16 ,
CPU_x86_64
} ;
static void disassemble ( CPUType type )
{
uintptr adr , end_adr ;
if ( ! range_args ( & adr , & end_adr , 16 * 4 - 1 ) ) // 16 lines unless end address specified
return ;
switch ( type ) {
case CPU_PPC :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
uint32 w = mon_read_word ( adr ) ;
fprintf ( monout , " %0*lx: %08x \t " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size , w ) ;
disass_ppc ( monout , mon_use_real_mem ? adr : adr % mon_mem_size , w ) ;
adr + = 4 ;
}
break ;
case CPU_6502 :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
uint8 op = mon_read_byte ( adr ) ;
uint8 lo = mon_read_byte ( adr + 1 ) ;
uint8 hi = mon_read_byte ( adr + 2 ) ;
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
adr + = disass_6502 ( monout , mon_use_real_mem ? adr : adr % mon_mem_size , op , lo , hi ) ;
}
break ;
case CPU_680x0 :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
adr + = disass_68k ( monout , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
}
break ;
case CPU_Z80 :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
adr + = disass_z80 ( monout , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
}
break ;
case CPU_x86_64 :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
adr + = disass_x86 ( monout , mon_use_real_mem ? adr : adr % mon_mem_size , 64 ) ;
}
break ;
case CPU_80x86_32 :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
adr + = disass_x86 ( monout , mon_use_real_mem ? adr : adr % mon_mem_size , 32 ) ;
}
break ;
case CPU_80x86_16 :
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
fprintf ( monout , " %0*lx: " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
adr + = disass_x86 ( monout , mon_use_real_mem ? adr : adr % mon_mem_size , 16 ) ;
}
}
mon_dot_address = adr ;
}
void disassemble_ppc ( void )
{
disassemble ( CPU_PPC ) ;
}
void disassemble_6502 ( void )
{
disassemble ( CPU_6502 ) ;
}
void disassemble_680x0 ( void )
{
disassemble ( CPU_680x0 ) ;
}
void disassemble_z80 ( void )
{
disassemble ( CPU_Z80 ) ;
}
void disassemble_80x86_32 ( void )
{
disassemble ( CPU_80x86_32 ) ;
}
void disassemble_80x86_16 ( void )
{
disassemble ( CPU_80x86_16 ) ;
}
void disassemble_x86_64 ( void )
{
disassemble ( CPU_x86_64 ) ;
}
/*
* Modify memory
* : addr bytestring
*/
void modify ( void )
{
uintptr adr , len , src_adr = 0 ;
uint8 * str ;
if ( ! mon_expression ( & adr ) )
return ;
if ( ! byte_string ( str , len ) )
return ;
while ( src_adr < len )
mon_write_byte ( adr + + , str [ src_adr + + ] ) ;
mon_dot_address = adr ;
free ( str ) ;
}
/*
* Fill
* f start end bytestring
*/
void fill ( void )
{
uintptr adr , end_adr , len , src_adr = 0 ;
uint8 * str ;
if ( ! mon_expression ( & adr ) )
return ;
if ( ! mon_expression ( & end_adr ) )
return ;
if ( ! byte_string ( str , len ) )
return ;
while ( adr < = end_adr )
mon_write_byte ( adr + + , str [ src_adr + + % len ] ) ;
free ( str ) ;
}
/*
* Transfer memory
* t start end dest
*/
void transfer ( void )
{
uintptr adr , end_adr , dest ;
int num ;
if ( ! mon_expression ( & adr ) )
return ;
if ( ! mon_expression ( & end_adr ) )
return ;
if ( ! mon_expression ( & dest ) )
return ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
num = end_adr - adr + 1 ;
if ( dest < adr )
for ( int i = 0 ; i < num ; i + + )
mon_write_byte ( dest + + , mon_read_byte ( adr + + ) ) ;
else {
dest + = end_adr - adr ;
for ( int i = 0 ; i < num ; i + + )
mon_write_byte ( dest - - , mon_read_byte ( end_adr - - ) ) ;
}
}
/*
* Compare
* c start end dest
*/
void compare ( void )
{
uintptr adr , end_adr , dest ;
int num = 0 ;
if ( ! mon_expression ( & adr ) )
return ;
if ( ! mon_expression ( & end_adr ) )
return ;
if ( ! mon_expression ( & dest ) )
return ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
while ( adr < = end_adr & & ! mon_aborted ( ) ) {
if ( mon_read_byte ( adr ) ! = mon_read_byte ( dest ) ) {
fprintf ( monout , " %0*lx " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
num + + ;
if ( ! ( num & 7 ) )
fputc ( ' \n ' , monout ) ;
}
adr + + ; dest + + ;
}
if ( num & 7 )
fputc ( ' \n ' , monout ) ;
fprintf ( monout , " %d byte(s) different \n " , num ) ;
}
/*
* Search for byte string
* h start end bytestring
*/
void hunt ( void )
{
uintptr adr , end_adr , len ;
uint8 * str ;
int num = 0 ;
if ( ! mon_expression ( & adr ) )
return ;
if ( ! mon_expression ( & end_adr ) )
return ;
if ( ! byte_string ( str , len ) )
return ;
while ( ( adr + len - 1 ) < = end_adr & & ! mon_aborted ( ) ) {
uint32 i ;
for ( i = 0 ; i < len ; i + + )
if ( mon_read_byte ( adr + i ) ! = str [ i ] )
break ;
if ( i = = len ) {
fprintf ( monout , " %0*lx " , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr : adr % mon_mem_size ) ;
num + + ;
if ( num = = 1 )
mon_dot_address = adr ;
if ( ! ( num & 7 ) )
fputc ( ' \n ' , monout ) ;
}
adr + + ;
}
free ( str ) ;
if ( num & 7 )
fputc ( ' \n ' , monout ) ;
fprintf ( monout , " Found %d occurrences \n " , num ) ;
}
/*
* Load data
* [ start " file "
*/
void load_data ( void )
{
uintptr start_adr ;
FILE * file ;
int fc ;
if ( ! mon_expression ( & start_adr ) )
return ;
if ( mon_token = = T_END ) {
mon_error ( " Missing file name " ) ;
return ;
}
if ( mon_token ! = T_STRING ) {
mon_error ( " ' \" ' around file name expected " ) ;
return ;
}
mon_get_token ( ) ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
if ( ! ( file = fopen ( mon_string , " rb " ) ) )
mon_error ( " Unable to open file " ) ;
else {
uintptr adr = start_adr ;
while ( ( fc = fgetc ( file ) ) ! = EOF )
mon_write_byte ( adr + + , fc ) ;
fclose ( file ) ;
fprintf ( monerr , " %08x bytes read from %0*lx to %0*lx \n " , adr - start_adr , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? start_adr : start_adr % mon_mem_size , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? adr - 1 : ( adr - 1 ) % mon_mem_size ) ;
mon_dot_address = adr ;
}
}
/*
* Save data
* ] start size " file "
*/
void save_data ( void )
{
uintptr start_adr , size ;
FILE * file ;
if ( ! mon_expression ( & start_adr ) )
return ;
if ( ! mon_expression ( & size ) )
return ;
if ( mon_token = = T_END ) {
mon_error ( " Missing file name " ) ;
return ;
}
if ( mon_token ! = T_STRING ) {
mon_error ( " ' \" ' around file name expected " ) ;
return ;
}
mon_get_token ( ) ;
if ( mon_token ! = T_END ) {
mon_error ( " Too many arguments " ) ;
return ;
}
if ( ! ( file = fopen ( mon_string , " wb " ) ) )
mon_error ( " Unable to create file " ) ;
else {
uintptr adr = start_adr , end_adr = start_adr + size - 1 ;
while ( adr < = end_adr )
fputc ( mon_read_byte ( adr + + ) , file ) ;
fclose ( file ) ;
fprintf ( monerr , " %08x bytes written from %0*lx to %0*lx \n " , size , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? start_adr : start_adr % mon_mem_size , int ( 2 * sizeof ( adr ) ) , mon_use_real_mem ? end_adr : end_adr % mon_mem_size ) ;
}
}