summaryrefslogtreecommitdiff
path: root/utils/mcpu-run.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mcpu-run.c')
-rw-r--r--utils/mcpu-run.c870
1 files changed, 870 insertions, 0 deletions
diff --git a/utils/mcpu-run.c b/utils/mcpu-run.c
new file mode 100644
index 0000000..d79e034
--- /dev/null
+++ b/utils/mcpu-run.c
@@ -0,0 +1,870 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libmcpu.h>
+#include <libmpuio.h>
+#include "mcpu-exec.h"
+#include "mcpu-dependency.h"
+
+#include "mcpu-run-options.h"
+
+static const char *
+memory_name( memory_kind memory )
+{
+ switch( memory )
+ {
+ case MEMORY_DATA: return( "DATA" );
+ case MEMORY_CONTROL: return( "CONTROL" );
+ case MEMORY_HEAP: return( "HEAP" );
+ case MEMORY_INPUT: return( "INPUT" );
+ case MEMORY_OUTPUT: return( "OUTPUT" );
+ case MEMORY_TRACE: return( "TRACE" );
+ default: return( "UNKNOWN" );
+ }
+
+} /* End of memory_name() */
+
+
+static __mpu_UNIT_t *
+memory_ptr( memory_kind memory )
+{
+ switch( memory )
+ {
+ case MEMORY_DATA: return( __cpu_data_ptr() );
+ case MEMORY_CONTROL: return( __cpu_control_ptr() );
+ case MEMORY_HEAP: return( __cpu_heap_ptr() );
+ case MEMORY_INPUT: return( __cpu_input_ptr() );
+ case MEMORY_OUTPUT: return( __cpu_output_ptr() );
+ case MEMORY_TRACE: return( __cpu_trace_ptr() );
+ default: return( (__mpu_UNIT_t *)0 );
+ }
+
+} /* End of memory_ptr() */
+
+
+static __mpu_uint64_t
+memory_size( memory_kind memory )
+{
+ switch( memory )
+ {
+ case MEMORY_DATA: return( __cpu_data_size() );
+ case MEMORY_CONTROL: return( __cpu_control_size() );
+ case MEMORY_HEAP: return( __cpu_heap_size() );
+ case MEMORY_INPUT: return( __cpu_input_size() );
+ case MEMORY_OUTPUT: return( __cpu_output_size() );
+ case MEMORY_TRACE: return( __cpu_trace_size() );
+ default: return( 0 );
+ }
+
+} /* End of memory_size() */
+
+
+
+static int
+make_integer_format( __mpu_char16_t *format, size_t size,
+ unsigned int bits, int newline )
+{
+ char ascii[64];
+ int len, i;
+
+ len = snprintf( ascii, sizeof( ascii ), newline ? "%%Z%ud\n" : "%%Z%ud", bits );
+ if( len < 0 || (size_t)len >= sizeof( ascii ) || (size_t)len + 1U > size )
+ return( -1 );
+
+ for( i = 0; i <= len; ++i )
+ format[i] = (__mpu_char16_t)(unsigned char)ascii[i];
+
+ return( 0 );
+
+} /* End of make_integer_format() */
+
+
+static __mpu_UNIT_t *
+memory_object_ptr( const print_spec *spec, __mpu_uint64_t bytes,
+ const char *object_name )
+{
+ __mpu_UNIT_t *p;
+ __mpu_uint64_t size;
+
+ p = memory_ptr( spec->memory );
+ size = memory_size( spec->memory );
+
+ if( !p || spec->address > size || bytes > size - spec->address )
+ {
+ fprintf( stderr, "mcpu-run: %s %s object is outside %s memory\n",
+ object_name, memory_name( spec->memory ),
+ memory_name( spec->memory ) );
+ return( (__mpu_UNIT_t *)0 );
+ }
+
+ return( p + (size_t)spec->address );
+
+} /* End of memory_object_ptr() */
+
+
+static int
+print_integer_value( const print_spec *spec, int newline )
+{
+ __mpu_char16_t format[64];
+ __mpu_UNIT_t *value;
+ __mpu_uint64_t bytes;
+
+ if( make_integer_format( format, sizeof( format ) / sizeof( format[0] ),
+ spec->bits, newline ) )
+ return( -1 );
+
+ bytes = spec->bits / 8U;
+ if( spec->kind == PRINT_INTEGER_REGISTER )
+ value = __cpu_reg_ptr( spec->bits, (__mpu_uint32_t)spec->address );
+ else if( spec->kind == PRINT_INTEGER_MEMORY )
+ value = memory_object_ptr( spec, bytes, "integer" );
+ else
+ return( -1 );
+
+ if( !value ) return( -1 );
+ if( fflush( stdout ) ) return( -1 );
+
+ if( mpu_dprintf( STDOUT_FILENO, format, (mpu_int *)value ) < 0 )
+ {
+ fprintf( stderr, "mcpu-run: LibMPUIO integer output failed\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+
+} /* End of print_integer_value() */
+
+
+static int
+print_integer( const print_spec *spec )
+{
+ return( print_integer_value( spec, 1 ) );
+
+} /* End of print_integer() */
+
+
+static int
+make_real_format( __mpu_char16_t *format, size_t size,
+ unsigned int bits, unsigned int digits, int newline )
+{
+ char ascii[96];
+ int len, i;
+
+ len = snprintf( ascii, sizeof( ascii ), newline ? "%%.%uZ%uR\n" : "%%.%uZ%uR",
+ digits, bits );
+ if( len < 0 || (size_t)len >= sizeof( ascii ) || (size_t)len + 1U > size )
+ return( -1 );
+
+ for( i = 0; i <= len; ++i )
+ format[i] = (__mpu_char16_t)(unsigned char)ascii[i];
+
+ return( 0 );
+
+} /* End of make_real_format() */
+
+
+static int
+print_real_value( const print_spec *spec, unsigned int digits, int newline )
+{
+ __mpu_char16_t format[96];
+ __mpu_UNIT_t *value;
+ __mpu_uint64_t bytes;
+
+ if( make_real_format( format, sizeof( format ) / sizeof( format[0] ),
+ spec->bits, digits, newline ) )
+ return( -1 );
+
+ bytes = spec->bits / 8U;
+ if( spec->kind == PRINT_REAL_REGISTER )
+ value = __cpu_reg_ptr( spec->bits, (__mpu_uint32_t)spec->address );
+ else if( spec->kind == PRINT_REAL_MEMORY )
+ value = memory_object_ptr( spec, bytes, "real" );
+ else
+ return( -1 );
+
+ if( !value ) return( -1 );
+ if( fflush( stdout ) ) return( -1 );
+
+ if( mpu_dprintf( STDOUT_FILENO, format, (mpu_real *)value ) < 0 )
+ {
+ fprintf( stderr, "mcpu-run: LibMPUIO real output failed\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+
+} /* End of print_real_value() */
+
+
+static int
+print_real( const print_spec *spec, unsigned int digits )
+{
+ return( print_real_value( spec, digits, 1 ) );
+
+} /* End of print_real() */
+
+static int
+raw_memory_range( const print_spec *spec, const cpu_exec_loaded *loaded,
+ __mpu_UNIT_t **ptr, __mpu_uint64_t *count )
+{
+ __mpu_uint64_t begin, end, size;
+ __mpu_UNIT_t *p;
+
+ if( spec->memory == MEMORY_DATA )
+ {
+ if( !loaded->has_data_section )
+ {
+ fprintf( stderr, "mcpu-run: executable has no .data section\n" );
+ return( -1 );
+ }
+
+ begin = loaded->data_section_begin;
+ if( loaded->data_section_size > UINT64_MAX - begin ) return( -1 );
+ end = begin + loaded->data_section_size;
+
+ if( spec->address < begin || spec->address >= end )
+ {
+ fprintf( stderr, "mcpu-run: raw DATA address is outside .data\n" );
+ return( -1 );
+ }
+
+ p = __cpu_data_ptr();
+ }
+ else
+ {
+ begin = 0;
+ size = memory_size( spec->memory );
+ p = memory_ptr( spec->memory );
+ end = size;
+
+ if( !p || spec->address >= end )
+ {
+ fprintf( stderr, "mcpu-run: raw %s address is outside %s memory\n",
+ memory_name( spec->memory ), memory_name( spec->memory ) );
+ return( -1 );
+ }
+ }
+
+ *count = spec->count;
+ if( *count > end - spec->address ) *count = end - spec->address;
+
+ *ptr = p + (size_t)spec->address;
+
+ return( 0 );
+
+} /* End of raw_memory_range() */
+
+
+static int
+print_raw_memory( const print_spec *spec, const cpu_exec_loaded *loaded )
+{
+ __mpu_UNIT_t *p;
+ __mpu_uint64_t count, off;
+
+ if( spec->kind != PRINT_RAW_MEMORY ) return( -1 );
+ if( raw_memory_range( spec, loaded, &p, &count ) ) return( -1 );
+
+ printf( "%s memory dump: (%llu bytes):\n",
+ memory_name( spec->memory ), (unsigned long long)count );
+
+ for( off = 0; off < count; off += 16 )
+ {
+ unsigned int j;
+ unsigned int row = (unsigned int)((count - off) > 16 ? 16 : (count - off));
+
+ printf( " %04llx : ", (unsigned long long)off );
+ for( j = 0; j < 16; ++j )
+ {
+ if( j < row )
+ printf( "%02x ", (unsigned int)p[(size_t)off + j] );
+ else
+ printf( " " );
+ }
+ printf( " | " );
+ for( j = 0; j < row; ++j )
+ {
+ unsigned int c = (unsigned int)p[(size_t)off + j];
+ putchar( c >= 0x20U && c <= 0x7eU ? (int)c : '.' );
+ }
+ putchar( '\n' );
+ }
+
+ return( ferror( stdout ) ? -1 : 0 );
+
+} /* End of print_raw_memory() */
+
+
+static int
+write_stdout( const char *s, size_t n )
+{
+ while( n )
+ {
+ ssize_t rc = write( STDOUT_FILENO, s, n );
+
+ if( rc < 0 )
+ {
+ if( errno == EINTR ) continue;
+ return( -1 );
+ }
+ if( !rc ) return( -1 );
+
+ s += (size_t)rc;
+ n -= (size_t)rc;
+ }
+
+ return( 0 );
+
+} /* End of write_stdout() */
+
+
+static __mpu_char16_t *
+ascii_to_ucs2( const char *s )
+{
+ __mpu_char16_t *p;
+ size_t i, n;
+
+ if( !s ) return( (__mpu_char16_t *)0 );
+
+ n = strlen( s );
+ if( n > (SIZE_MAX / sizeof( *p )) - 1U ) return( (__mpu_char16_t *)0 );
+
+ p = (__mpu_char16_t *)malloc( (n + 1U) * sizeof( *p ) );
+ if( !p ) return( (__mpu_char16_t *)0 );
+
+ for( i = 0; i < n; ++i )
+ {
+ unsigned char c = (unsigned char)s[i];
+
+ if( c >= 0x80U )
+ {
+ free( p );
+ return( (__mpu_char16_t *)0 );
+ }
+ p[i] = (__mpu_char16_t)c;
+ }
+ p[n] = 0;
+
+ return( p );
+
+} /* End of ascii_to_ucs2() */
+
+
+static int
+scan_action_value( const char *value, unsigned int bits,
+ int real_object, __mpu_UNIT_t *dst )
+{
+ __mpu_char16_t *text = (__mpu_char16_t *)0;
+ __mpu_char16_t *format = (__mpu_char16_t *)0;
+ __mpu_uint32_t psw;
+ char ascii[64];
+ size_t n;
+ int len, consumed = -1, rc;
+
+ n = strlen( value );
+ len = snprintf( ascii, sizeof( ascii ), real_object ? "%%Z%uR%%n" : "%%Z%ui%%n",
+ bits );
+ if( len < 0 || (size_t)len >= sizeof( ascii ) ) return( -1 );
+
+ text = ascii_to_ucs2( value );
+ format = ascii_to_ucs2( ascii );
+ if( !text || !format ) goto fail;
+
+ psw = __cpu_get_psw();
+ if( real_object )
+ rc = mpu_sscanf( text, format, (mpu_real *)dst, &consumed );
+ else
+ rc = mpu_sscanf( text, format, (mpu_int *)dst, &consumed );
+ __cpu_set_psw( psw );
+
+ free( format );
+ free( text );
+
+ if( rc != 1 || consumed < 0 || (size_t)consumed != n ) return( -1 );
+
+ return( 0 );
+
+fail:
+ free( format );
+ free( text );
+ return( -1 );
+
+} /* End of scan_action_value() */
+
+
+static void
+make_action_print_spec( const stage_action *action, const action_item *item,
+ print_spec *spec )
+{
+ memset( spec, 0, sizeof( *spec ) );
+ spec->memory = action->memory;
+ spec->bits = item->bits;
+ spec->address = item->address;
+
+ if( action->kind == ACTION_PRINT_INTEGER_REGISTER ||
+ action->kind == ACTION_SET_INTEGER_REGISTER )
+ spec->kind = PRINT_INTEGER_REGISTER;
+ else if( action->kind == ACTION_PRINT_REAL_REGISTER ||
+ action->kind == ACTION_SET_REAL_REGISTER )
+ spec->kind = PRINT_REAL_REGISTER;
+ else if( action->kind == ACTION_PRINT_INTEGER_MEMORY ||
+ action->kind == ACTION_SET_INTEGER_MEMORY )
+ spec->kind = PRINT_INTEGER_MEMORY;
+ else if( action->kind == ACTION_PRINT_REAL_MEMORY ||
+ action->kind == ACTION_SET_REAL_MEMORY )
+ spec->kind = PRINT_REAL_MEMORY;
+
+} /* End of make_action_print_spec() */
+
+
+static __mpu_UNIT_t *
+action_object_ptr( const stage_action *action, const action_item *item,
+ const char *object_name )
+{
+ print_spec spec;
+
+ make_action_print_spec( action, item, &spec );
+ if( spec.kind == PRINT_INTEGER_REGISTER || spec.kind == PRINT_REAL_REGISTER )
+ return( __cpu_reg_ptr( spec.bits, (__mpu_uint32_t)spec.address ) );
+
+ return( memory_object_ptr( &spec, spec.bits / 8U, object_name ) );
+
+} /* End of action_object_ptr() */
+
+
+static int
+execute_print_action( const stage_action *action, unsigned int digits )
+{
+ print_spec spec;
+ size_t i;
+
+ /* Validate the whole action before producing any output. */
+ for( i = 0; i < action->count; ++i )
+ {
+ if( !action_object_ptr( action, &action->item[i],
+ (action->kind == ACTION_PRINT_REAL_REGISTER ||
+ action->kind == ACTION_PRINT_REAL_MEMORY) ?
+ "real" : "integer" ) )
+ return( -1 );
+ }
+
+ for( i = 0; i < action->count; ++i )
+ {
+ make_action_print_spec( action, &action->item[i], &spec );
+
+ if( i && write_stdout( " ", 1U ) ) return( -1 );
+
+ if( spec.kind == PRINT_INTEGER_REGISTER || spec.kind == PRINT_INTEGER_MEMORY )
+ {
+ if( print_integer_value( &spec, 0 ) ) return( -1 );
+ }
+ else
+ {
+ if( print_real_value( &spec, digits, 0 ) ) return( -1 );
+ }
+ }
+
+ if( write_stdout( "\n", 1U ) ) return( -1 );
+
+ return( 0 );
+
+} /* End of execute_print_action() */
+
+
+typedef struct __set_value
+{
+ __mpu_UNIT_t *dst;
+ __mpu_UNIT_t *value;
+ size_t bytes;
+} set_value;
+
+
+static int
+execute_set_action( const stage_action *action )
+{
+ set_value *value;
+ size_t i, j;
+ int real_object;
+
+ value = (set_value *)calloc( action->count, sizeof( *value ) );
+ if( !value ) return( -1 );
+
+ real_object = (action->kind == ACTION_SET_REAL_REGISTER ||
+ action->kind == ACTION_SET_REAL_MEMORY);
+
+ /* Parse and validate every assignment before changing guest state. */
+ for( i = 0; i < action->count; ++i )
+ {
+ value[i].bytes = action->item[i].bits / 8U;
+ value[i].dst = action_object_ptr( action, &action->item[i],
+ real_object ? "real" : "integer" );
+ if( !value[i].dst ) goto fail;
+
+ value[i].value = (__mpu_UNIT_t *)calloc( value[i].bytes, 1U );
+ if( !value[i].value ) goto fail;
+
+ if( scan_action_value( action->item[i].value, action->item[i].bits,
+ real_object, value[i].value ) )
+ {
+ fprintf( stderr, "mcpu-run: cannot parse stage value '%s' as %s%u\n",
+ action->item[i].value, real_object ? "real" : "int",
+ action->item[i].bits );
+ goto fail;
+ }
+ }
+
+ for( i = 0; i < action->count; ++i )
+ memcpy( value[i].dst, value[i].value, value[i].bytes );
+
+ for( i = 0; i < action->count; ++i ) free( value[i].value );
+ free( value );
+
+ return( 0 );
+
+fail:
+ for( j = 0; j < action->count; ++j ) free( value[j].value );
+ free( value );
+ return( -1 );
+
+} /* End of execute_set_action() */
+
+
+static int
+execute_stage_action( const stage_action *action, unsigned int digits,
+ const cpu_exec_loaded *loaded )
+{
+ switch( action->kind )
+ {
+ case ACTION_PRINT_INTEGER_REGISTER:
+ case ACTION_PRINT_REAL_REGISTER:
+ case ACTION_PRINT_INTEGER_MEMORY:
+ case ACTION_PRINT_REAL_MEMORY:
+ return( execute_print_action( action, digits ) );
+
+ case ACTION_SET_INTEGER_REGISTER:
+ case ACTION_SET_REAL_REGISTER:
+ case ACTION_SET_INTEGER_MEMORY:
+ case ACTION_SET_REAL_MEMORY:
+ return( execute_set_action( action ) );
+
+ case ACTION_PRINT_RAW_MEMORY:
+ if( print_raw_memory( &action->raw, loaded ) ) return( -1 );
+ if( fflush( stdout ) ) return( -1 );
+ return( 0 );
+
+ default:
+ return( -1 );
+ }
+
+} /* End of execute_stage_action() */
+
+
+static int
+execute_stage_action_list( const stage_action_list *list, unsigned int digits,
+ const cpu_exec_loaded *loaded )
+{
+ size_t i;
+
+ for( i = 0; i < list->count; ++i )
+ if( execute_stage_action( &list->action[i], digits, loaded ) )
+ return( -1 );
+
+ return( 0 );
+
+} /* End of execute_stage_action_list() */
+
+
+static int
+execution_fault( int rc )
+{
+ fprintf( stderr, "mcpu-run: execution fault %d at PC=0x%016llx, PSW=0x%08x\n",
+ rc, (unsigned long long)__cpu_pc, (unsigned int)__cpu_get_psw());
+ return( 1 );
+}
+
+
+static int
+mcpu_run_execute( const mcpu_run_options *options )
+{
+ unsigned long long completed = 0;
+ cpu_exec_loaded loaded;
+ char err[512];
+ char *resolved_preload = NULL;
+ char *resolved_modules = NULL;
+ size_t preload_count = 0;
+ int rc;
+ int host_status = 0;
+
+ if( options == NULL )
+ return( 1 );
+
+ if( mcpu_run_resolve_preload(options, &resolved_preload,
+ err, sizeof(err)) != 0 )
+ {
+ fprintf( stderr, "%s: preload resolution error: %s\n",
+ options->common.progname, err );
+ return( 1 );
+ }
+
+ if( mcpu_dependency_build_load_list(&options->common, options->exe,
+ resolved_preload, &resolved_modules,
+ &preload_count, err, sizeof(err)) != 0 )
+ {
+ fprintf( stderr, "%s: dependency resolution error: %s\n",
+ options->common.progname, err );
+ free( resolved_preload );
+ return( 1 );
+ }
+
+ __cpu_init();
+
+ /* Guest argv begins with the executable spelling supplied to mcpu-run. */
+ if( cpu_exec_load_resolved(options->exe, resolved_modules,
+ preload_count,
+ options->program_argc, options->program_argv,
+ &loaded, err, sizeof(err)) )
+ {
+ fprintf( stderr, "%s: load error: %s\n",
+ options->common.progname, err );
+ __cpu_free_context();
+ free( resolved_modules );
+ free( resolved_preload );
+ return( 1 );
+ }
+
+ if( execute_stage_action_list(&options->before_run,
+ options->digits, &loaded) )
+ {
+ fprintf( stderr, "%s: --before-run action failed\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+
+ if( loaded.has_init )
+ {
+ __cpu_pc = loaded.init_entry;
+ rc = __cpu_run();
+ if( rc < 0 )
+ {
+ host_status = execution_fault( rc );
+ goto done;
+ }
+ if( rc == CPU_EXEC_EXIT )
+ goto graceful_exit;
+ if( __cpu_get_stop_reason() == CPU_STOP_HALT )
+ goto stopped;
+ if( rc != CPU_EXEC_END )
+ {
+ fprintf( stderr, "%s: INIT did not terminate with END\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+ if( __cpu_sp != loaded.startup_base || __cpu_fp != loaded.stack_size )
+ {
+ fprintf( stderr, "%s: INIT did not restore top-level STACK state\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+ __cpu_pc = loaded.life_entry;
+ }
+
+ if( execute_stage_action_list(&options->after_init,
+ options->digits, &loaded) )
+ {
+ fprintf( stderr, "%s: --after-init action failed\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+
+ if( options->init_only )
+ goto stopped;
+
+ for( ; ; )
+ {
+ rc = __cpu_run();
+ if( rc < 0 )
+ {
+ host_status = execution_fault( rc );
+ goto done;
+ }
+ if( rc == CPU_EXEC_EXIT )
+ goto graceful_exit;
+ if( __cpu_get_stop_reason() == CPU_STOP_HALT )
+ goto stopped;
+ if( rc != CPU_EXEC_END )
+ {
+ fprintf( stderr, "%s: LIFE phase stopped unexpectedly (%d)\n",
+ options->common.progname, rc );
+ host_status = 1;
+ goto done;
+ }
+ ++completed;
+ if( execute_stage_action_list(&options->on_step,
+ options->digits, &loaded) )
+ {
+ fprintf( stderr,
+ "%s: --on-step action failed after LIFE step %llu\n",
+ options->common.progname, completed );
+ host_status = 1;
+ goto done;
+ }
+ if( !options->steps_set || completed >= options->steps )
+ goto stopped;
+ /* Resume from the PC already advanced past END. */
+ }
+
+graceful_exit:
+ host_status = (int)__cpu_get_exit_status();
+ if( loaded.has_fini )
+ {
+ if( __cpu_sp != loaded.startup_base || __cpu_fp != loaded.stack_size )
+ {
+ fprintf( stderr,
+ "%s: LIFE did not restore top-level STACK state before FINI\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+ __cpu_pc = loaded.fini_entry;
+ rc = __cpu_run();
+ if( rc < 0 )
+ {
+ host_status = execution_fault( rc );
+ goto done;
+ }
+ if( rc != CPU_EXEC_END )
+ {
+ fprintf( stderr, "%s: FINI must terminate with END\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+ if( __cpu_sp != loaded.startup_base || __cpu_fp != loaded.stack_size )
+ {
+ fprintf( stderr, "%s: FINI did not restore top-level STACK state\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+ }
+
+stopped:
+ if( execute_stage_action_list(&options->after_run,
+ options->digits, &loaded) )
+ {
+ fprintf( stderr, "%s: --after-run action failed\n",
+ options->common.progname );
+ host_status = 1;
+ goto done;
+ }
+
+ if( options->output.kind == PRINT_INTEGER_REGISTER ||
+ options->output.kind == PRINT_INTEGER_MEMORY )
+ {
+ if( print_integer(&options->output) )
+ {
+ host_status = 1;
+ goto done;
+ }
+ }
+ else if( options->output.kind == PRINT_REAL_REGISTER ||
+ options->output.kind == PRINT_REAL_MEMORY )
+ {
+ if( print_real(&options->output, options->digits) )
+ {
+ host_status = 1;
+ goto done;
+ }
+ }
+ else if( options->output.kind == PRINT_RAW_MEMORY )
+ {
+ if( print_raw_memory(&options->output, &loaded) )
+ {
+ host_status = 1;
+ goto done;
+ }
+ }
+
+done:
+ __cpu_free_context();
+ free( resolved_modules );
+ free( resolved_preload );
+ if( host_status < 0 || host_status > 255 )
+ return( 1 );
+ return( host_status );
+
+} /* End of mcpu_run_execute() */
+
+
+int
+main( int argc, char **argv )
+{
+ mcpu_run_options options;
+ int rc = 2;
+
+ mcpu_run_options_init( &options, argv[0] );
+
+ if( mcpu_run_handle_options(&options, argc, argv) != 0 )
+ goto done;
+
+ if( options.common.help )
+ {
+ mcpu_run_usage( &options );
+ rc = 0;
+ goto done;
+ }
+
+ if( options.common.version_action != MCPU_VERSION_NONE )
+ {
+ if( mcpu_version_print(options.common.progname,
+ options.common.version_action) != 0 )
+ {
+ rc = 1;
+ goto done;
+ }
+ rc = 0;
+ goto done;
+ }
+
+ if( mcpu_tool_options_prepare(&options.common, argv[0]) != 0 )
+ {
+ rc = 1;
+ goto done;
+ }
+
+ if( mcpu_tool_has_information_action(&options.common) )
+ {
+ if( options.common.dump_config &&
+ mcpu_tool_dump_config(&options.common, stdout) != 0 )
+ {
+ rc = 1;
+ goto done;
+ }
+ if( options.common.print_search_dirs &&
+ mcpu_tool_print_search_dirs(&options.common, stdout) != 0 )
+ {
+ rc = 1;
+ goto done;
+ }
+ rc = 0;
+ goto done;
+ }
+
+ rc = mcpu_run_execute( &options );
+
+done:
+ mcpu_run_options_free( &options );
+ return( rc );
+
+} /* End of main() */