diff options
Diffstat (limited to 'utils/mcpu-run-options.c')
| -rw-r--r-- | utils/mcpu-run-options.c | 1169 |
1 files changed, 1169 insertions, 0 deletions
diff --git a/utils/mcpu-run-options.c b/utils/mcpu-run-options.c new file mode 100644 index 0000000..f3cb881 --- /dev/null +++ b/utils/mcpu-run-options.c @@ -0,0 +1,1169 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libmcpu.h> +#include <libmpuio.h> + +#include "mcpu-run-options.h" + +void +mcpu_run_usage( const mcpu_run_options *options ) +{ + const char *name = options ? options->common.progname : "mcpu-run"; + + fprintf( stderr, + "usage: %s [runtime-options] -- executable [program-args...]\n" + " %s [runtime-options] executable [program-args...] (compatibility)\n\n" + "Execute a LibMCPU MELF ET_EXEC image. STACK and HEAP sizes are part of\n" + "the executable ABI and cannot be overridden by mcpu-run.\n\n" + "MCPU system options:\n" + " --no-config - do not read mcpu-ld.conf files\n" + " --sys-root=PATH - use PATH as MCPU root and do not read config files\n" + " --dump-config - print effective MCPU configuration and exit\n" + " --print-search-dirs - print effective library search directories and exit\n" + "\nLibrary options (must precede executable or explicit --):\n" + " --library-path=DIR[:DIR...] - add explicit library search directories\n" + " --ldpreload=<a.so:b.so> - preload ABI-v2/ABI-v3 shared objects; names use search path\n" + "\nEnvironment:\n" + " MCPU_LD_PRELOAD=a.so:b.so - preload shared objects before command-line --ldpreload\n" + "\nRuntime options (must precede executable or explicit --):\n" + " --int-reg=r<bits>@<addr> - print a signed integer register after stop\n" + " --real-reg=r<bits>@<addr> - print a real register after stop\n" + " --int-data=<bits>@<addr> - print a signed integer object from DATA memory\n" + " --real-data=<bits>@<addr> - print a real object from DATA memory\n" + " --raw-data=<bytes>@<addr> - dump bytes from .data, clipped at .data end\n" + " --int-control=<bits>@<addr> - print a signed integer object from CONTROL memory\n" + " --real-control=<bits>@<addr> - print a real object from CONTROL memory\n" + " --raw-control=<bytes>@<addr> - dump bytes from .control, clipped at .control end\n" + " --int-heap=<bits>@<addr> - print a signed integer object from HEAP memory\n" + " --real-heap=<bits>@<addr> - print a real object from HEAP memory\n" + " --raw-heap=<bytes>@<addr> - dump bytes from HEAP, clipped at HEAP end\n" + " --int-input=<bits>@<addr> - print a signed integer object from INPUT memory\n" + " --real-input=<bits>@<addr> - print a real object from INPUT memory\n" + " --raw-input=<bytes>@<addr> - dump bytes from .input, clipped at .input end\n" + " --int-output=<bits>@<addr> - print a signed integer object from OUTPUT memory\n" + " --real-output=<bits>@<addr> - print a real object from OUTPUT memory\n" + " --raw-output=<bytes>@<addr> - dump bytes from .output, clipped at .output end\n" + " --int-trace=<bits>@<addr> - print a signed integer object from TRACE memory\n" + " --real-trace=<bits>@<addr> - print a real object from TRACE memory\n" + " --raw-trace=<bytes>@<addr> - dump bytes from .trace, clipped at .trace end\n" + " --before-run=<action> - execute host action before first guest instruction\n" + " --after-init=<action> - execute host action after INIT (or empty INIT stage)\n" + " --on-step=<action> - execute host action after every LIFE END boundary\n" + " --after-run=<action> - execute host action after final execution stop\n" + " --digits=<n> - mantissa digits for real output (default: 80)\n" + " --init-only - execute INIT through END, then stop\n" + " --steps=<n> - stop after n LIFE END boundaries\n" + " (default: stop at first LIFE END)\n" + " -h, --help - show this help\n" + " --version - show program version\n" + " --dump-version - show version number only\n" + "\nBare preload names from MCPU_LD_PRELOAD and --ldpreload are searched in\n" + "--library-path order and then in the effective MCPU system library path.\n" + "Names containing '/' are explicit pathnames and bypass name lookup.\n" + "Environment preloads are ordered before command-line preloads; because the\n" + "rightmost equal-strength preload wins, command-line preloads override the\n" + "environment. Empty preload/path-list elements are errors.\n\n" + "Stage actions:\n" + " print-int-regs:r<bits>@<addr>[,...]\n" + " print-real-regs:r<bits>@<addr>[,...]\n" + " set-int-regs:r<bits>@<addr>=<value>[,...]\n" + " set-real-regs:r<bits>@<addr>=<value>[,...]\n" + " print-int-<memory>:<bits>@<addr>[,...]\n" + " print-real-<memory>:<bits>@<addr>[,...]\n" + " set-int-<memory>:<bits>@<addr>=<value>[,...]\n" + " set-real-<memory>:<bits>@<addr>=<value>[,...]\n" + " print-raw-<memory>:<bytes>@<addr>\n\n" + "<memory> is data, control, heap, input, output or trace. Scalar print\n" + "actions print their comma-separated objects on one line separated by spaces.\n" + "Raw actions contain exactly one dump; repeat the stage option for more dumps.\n" + "There are no set-raw-* actions. Values for set-int-* and set-real-* are\n" + "parsed by LibMPUIO mpu_sscanf(). Repeated stage options execute in command-\n" + "line order. Step-number filters are not implemented.\n\n" + "For --raw-* and print-raw-* <bytes>, K/KiB, M/MiB and G/GiB suffixes are\n" + "accepted. K, M and G use binary multipliers (1024, 1024^2 and 1024^3).\n" + "Use -- to unambiguously separate mcpu-run options from executable/argv.\n", + name, name ); + +} /* End of mcpu_run_usage() */ + + +static int +valid_int_bits( unsigned int bits ) +{ + return( bits >= CPU_REGISTER_MIN_BITS && + bits <= CPU_REGISTER_MAX_BITS && + (bits & (bits - 1U)) == 0U ); + +} /* End of valid_int_bits() */ + + +static int +valid_real_bits( unsigned int bits ) +{ + return( bits >= 32U && + bits <= CPU_REGISTER_MAX_BITS && + bits <= (unsigned int)MPU_REAL_IO_LIMIT && + (bits & (bits - 1U)) == 0U ); + +} /* End of valid_real_bits() */ + + +static int +parse_u64( const char *s, __mpu_uint64_t *v ) +{ + char *e; + unsigned long long x; + + errno = 0; + x = strtoull( s, &e, 0 ); + if( errno || e == s || *e ) return( -1 ); + + *v = (__mpu_uint64_t)x; + + return( 0 ); + +} /* End of parse_u64() */ + + +static int +parse_size( const char *s, __mpu_uint64_t *v ) +{ + unsigned long long x; + __mpu_uint64_t m = 1; + char *e; + + if( !s || !*s || *s == '-' ) return( -1 ); + + errno = 0; + x = strtoull( s, &e, 0 ); + if( errno || e == s ) return( -1 ); + + if( *e == '\0' ) + m = 1; + else if( !strcmp( e, "K" ) || !strcmp( e, "KiB" ) ) + m = __mpu_UINT64_C( 1024 ); + else if( !strcmp( e, "M" ) || !strcmp( e, "MiB" ) ) + m = __mpu_UINT64_C( 1024 ) * __mpu_UINT64_C( 1024 ); + else if( !strcmp( e, "G" ) || !strcmp( e, "GiB" ) ) + m = __mpu_UINT64_C( 1024 ) * __mpu_UINT64_C( 1024 ) * __mpu_UINT64_C( 1024 ); + else + return( -1 ); + + if( (__mpu_uint64_t)x != x || (__mpu_uint64_t)x > UINT64_MAX / m ) + return( -1 ); + + *v = (__mpu_uint64_t)x * m; + + return( 0 ); + +} /* End of parse_size() */ + + + +static int +parse_integer_register( const char *s, print_spec *spec ) +{ + const char *at; + char width[32], *end; + size_t n; + unsigned long bits; + __mpu_uint64_t address; + + if( !s || (s[0] != 'r' && s[0] != 'R') ) return( -1 ); + + at = strchr( s + 1, '@' ); + if( !at ) return( -1 ); + + n = (size_t)(at - (s + 1)); + if( !n || n >= sizeof( width ) ) return( -1 ); + + memcpy( width, s + 1, n ); + width[n] = 0; + + errno = 0; + bits = strtoul( width, &end, 10 ); + if( errno || end == width || *end || bits > (unsigned long)~0U || + !valid_int_bits( (unsigned)bits ) ) + return( -1 ); + + if( parse_u64( at + 1, &address ) || + address > CPU_REGISTER_ADDRESS_MAX || + !__cpu_reg_valid( (unsigned)bits, (__mpu_uint32_t)address ) ) + return( -1 ); + + spec->kind = PRINT_INTEGER_REGISTER; + spec->memory = MEMORY_NONE; + spec->bits = (unsigned)bits; + spec->address = address; + + return( 0 ); + +} /* End of parse_integer_register() */ + + +static int +parse_real_register( const char *s, print_spec *spec ) +{ + const char *at; + char width[32], *end; + size_t n; + unsigned long bits; + __mpu_uint64_t address; + + if( !s || (s[0] != 'r' && s[0] != 'R') ) return( -1 ); + + at = strchr( s + 1, '@' ); + if( !at ) return( -1 ); + + n = (size_t)(at - (s + 1)); + if( !n || n >= sizeof( width ) ) return( -1 ); + + memcpy( width, s + 1, n ); + width[n] = 0; + + errno = 0; + bits = strtoul( width, &end, 10 ); + if( errno || end == width || *end || bits > (unsigned long)~0U || + !valid_real_bits( (unsigned)bits ) ) + return( -1 ); + + if( parse_u64( at + 1, &address ) || + address > CPU_REGISTER_ADDRESS_MAX || + !__cpu_reg_valid( (unsigned)bits, (__mpu_uint32_t)address ) ) + return( -1 ); + + spec->kind = PRINT_REAL_REGISTER; + spec->memory = MEMORY_NONE; + spec->bits = (unsigned)bits; + spec->address = address; + + return( 0 ); + +} /* End of parse_real_register() */ + + +static int +parse_memory_object( const char *s, print_spec *spec, + int real_object, memory_kind memory ) +{ + const char *at; + char width[32], *end; + size_t n; + unsigned long bits; + __mpu_uint64_t address; + + if( !s ) return( -1 ); + if( real_object && (*s == 'r' || *s == 'R') ) ++s; + + at = strchr( s, '@' ); + if( !at ) return( -1 ); + + n = (size_t)(at - s); + if( !n || n >= sizeof( width ) ) return( -1 ); + + memcpy( width, s, n ); + width[n] = 0; + + errno = 0; + bits = strtoul( width, &end, 10 ); + if( errno || end == width || *end || bits > (unsigned long)~0U ) + return( -1 ); + + if( real_object ? !valid_real_bits( (unsigned)bits ) : + !valid_int_bits( (unsigned)bits ) ) + return( -1 ); + + if( parse_u64( at + 1, &address ) ) return( -1 ); + + spec->kind = real_object ? PRINT_REAL_MEMORY : PRINT_INTEGER_MEMORY; + spec->memory = memory; + spec->bits = (unsigned)bits; + spec->address = address; + + return( 0 ); + +} /* End of parse_memory_object() */ + + +static int +parse_raw_memory( const char *s, print_spec *spec, memory_kind memory ) +{ + const char *at; + char countbuf[32]; + size_t n; + __mpu_uint64_t count, address; + + if( !s ) return( -1 ); + + at = strchr( s, '@' ); + if( !at ) return( -1 ); + + n = (size_t)(at - s); + if( !n || n >= sizeof( countbuf ) ) return( -1 ); + + memcpy( countbuf, s, n ); + countbuf[n] = 0; + + if( parse_size( countbuf, &count ) || !count || + parse_u64( at + 1, &address ) ) + return( -1 ); + + spec->kind = PRINT_RAW_MEMORY; + spec->memory = memory; + spec->address = address; + spec->count = count; + + return( 0 ); + +} /* End of parse_raw_memory() */ + + +static void +free_stage_action( stage_action *action ) +{ + size_t i; + + if( !action ) return; + + for( i = 0; i < action->count; ++i ) + free( action->item[i].value ); + free( action->item ); + memset( action, 0, sizeof( *action ) ); + +} /* End of free_stage_action() */ + + +static void +free_stage_action_list( stage_action_list *list ) +{ + size_t i; + + if( !list ) return; + + for( i = 0; i < list->count; ++i ) + free_stage_action( &list->action[i] ); + free( list->action ); + memset( list, 0, sizeof( *list ) ); + +} /* End of free_stage_action_list() */ + + +static int +append_stage_action( stage_action_list *list, stage_action *action ) +{ + stage_action *a; + size_t capacity; + + if( list->count == list->capacity ) + { + capacity = list->capacity ? list->capacity * 2U : 4U; + if( capacity < list->capacity || capacity > SIZE_MAX / sizeof( *a ) ) + return( -1 ); + + a = (stage_action *)realloc( list->action, capacity * sizeof( *a ) ); + if( !a ) return( -1 ); + + list->action = a; + list->capacity = capacity; + } + + list->action[list->count++] = *action; + memset( action, 0, sizeof( *action ) ); + + return( 0 ); + +} /* End of append_stage_action() */ + + +static int +append_action_item( stage_action *action, const action_item *item ) +{ + action_item *p; + + if( action->count == SIZE_MAX / sizeof( *p ) ) return( -1 ); + + p = (action_item *)realloc( action->item, + (action->count + 1U) * sizeof( *p ) ); + if( !p ) return( -1 ); + + action->item = p; + action->item[action->count++] = *item; + + return( 0 ); + +} /* End of append_action_item() */ + + +static char * +dup_range( const char *s, size_t n ) +{ + char *p; + + p = (char *)malloc( n + 1U ); + if( !p ) return( (char *)0 ); + + memcpy( p, s, n ); + p[n] = 0; + + return( p ); + +} /* End of dup_range() */ + + +static int +parse_action_object( const char *text, size_t length, + int is_register, int real_object, int set_object, + memory_kind memory, action_item *item ) +{ + print_spec spec; + char *copy, *eq; + const char *value = (const char *)0; + + memset( item, 0, sizeof( *item ) ); + memset( &spec, 0, sizeof( spec ) ); + + copy = dup_range( text, length ); + if( !copy ) return( -1 ); + + eq = strchr( copy, '=' ); + if( set_object ) + { + if( !eq || eq == copy || !eq[1] || strchr( eq + 1, '=' ) ) + goto fail; + *eq = 0; + value = eq + 1; + } + else if( eq ) + goto fail; + + if( is_register ) + { + if( real_object ? parse_real_register( copy, &spec ) : + parse_integer_register( copy, &spec ) ) + goto fail; + } + else + { + if( parse_memory_object( copy, &spec, real_object, memory ) ) + goto fail; + } + + item->bits = spec.bits; + item->address = spec.address; + if( set_object ) + { + item->value = dup_range( value, strlen( value ) ); + if( !item->value ) goto fail; + } + + free( copy ); + return( 0 ); + +fail: + free( item->value ); + memset( item, 0, sizeof( *item ) ); + free( copy ); + return( -1 ); + +} /* End of parse_action_object() */ + + +typedef struct __action_prefix +{ + const char *name; + action_kind kind; + memory_kind memory; + int is_register; + int real_object; + int set_object; + int raw_object; +} action_prefix; + + +static int +parse_stage_action( const char *text, stage_action *action ) +{ + static const action_prefix prefix[] = + { + { "print-int-regs:", ACTION_PRINT_INTEGER_REGISTER, MEMORY_NONE, 1, 0, 0, 0 }, + { "print-real-regs:", ACTION_PRINT_REAL_REGISTER, MEMORY_NONE, 1, 1, 0, 0 }, + { "set-int-regs:", ACTION_SET_INTEGER_REGISTER, MEMORY_NONE, 1, 0, 1, 0 }, + { "set-real-regs:", ACTION_SET_REAL_REGISTER, MEMORY_NONE, 1, 1, 1, 0 }, + + { "print-int-data:", ACTION_PRINT_INTEGER_MEMORY, MEMORY_DATA, 0, 0, 0, 0 }, + { "print-real-data:", ACTION_PRINT_REAL_MEMORY, MEMORY_DATA, 0, 1, 0, 0 }, + { "set-int-data:", ACTION_SET_INTEGER_MEMORY, MEMORY_DATA, 0, 0, 1, 0 }, + { "set-real-data:", ACTION_SET_REAL_MEMORY, MEMORY_DATA, 0, 1, 1, 0 }, + { "print-raw-data:", ACTION_PRINT_RAW_MEMORY, MEMORY_DATA, 0, 0, 0, 1 }, + + { "print-int-control:", ACTION_PRINT_INTEGER_MEMORY, MEMORY_CONTROL, 0, 0, 0, 0 }, + { "print-real-control:", ACTION_PRINT_REAL_MEMORY, MEMORY_CONTROL, 0, 1, 0, 0 }, + { "set-int-control:", ACTION_SET_INTEGER_MEMORY, MEMORY_CONTROL, 0, 0, 1, 0 }, + { "set-real-control:", ACTION_SET_REAL_MEMORY, MEMORY_CONTROL, 0, 1, 1, 0 }, + { "print-raw-control:", ACTION_PRINT_RAW_MEMORY, MEMORY_CONTROL, 0, 0, 0, 1 }, + + { "print-int-heap:", ACTION_PRINT_INTEGER_MEMORY, MEMORY_HEAP, 0, 0, 0, 0 }, + { "print-real-heap:", ACTION_PRINT_REAL_MEMORY, MEMORY_HEAP, 0, 1, 0, 0 }, + { "set-int-heap:", ACTION_SET_INTEGER_MEMORY, MEMORY_HEAP, 0, 0, 1, 0 }, + { "set-real-heap:", ACTION_SET_REAL_MEMORY, MEMORY_HEAP, 0, 1, 1, 0 }, + { "print-raw-heap:", ACTION_PRINT_RAW_MEMORY, MEMORY_HEAP, 0, 0, 0, 1 }, + + { "print-int-input:", ACTION_PRINT_INTEGER_MEMORY, MEMORY_INPUT, 0, 0, 0, 0 }, + { "print-real-input:", ACTION_PRINT_REAL_MEMORY, MEMORY_INPUT, 0, 1, 0, 0 }, + { "set-int-input:", ACTION_SET_INTEGER_MEMORY, MEMORY_INPUT, 0, 0, 1, 0 }, + { "set-real-input:", ACTION_SET_REAL_MEMORY, MEMORY_INPUT, 0, 1, 1, 0 }, + { "print-raw-input:", ACTION_PRINT_RAW_MEMORY, MEMORY_INPUT, 0, 0, 0, 1 }, + + { "print-int-output:", ACTION_PRINT_INTEGER_MEMORY, MEMORY_OUTPUT, 0, 0, 0, 0 }, + { "print-real-output:", ACTION_PRINT_REAL_MEMORY, MEMORY_OUTPUT, 0, 1, 0, 0 }, + { "set-int-output:", ACTION_SET_INTEGER_MEMORY, MEMORY_OUTPUT, 0, 0, 1, 0 }, + { "set-real-output:", ACTION_SET_REAL_MEMORY, MEMORY_OUTPUT, 0, 1, 1, 0 }, + { "print-raw-output:", ACTION_PRINT_RAW_MEMORY, MEMORY_OUTPUT, 0, 0, 0, 1 }, + + { "print-int-trace:", ACTION_PRINT_INTEGER_MEMORY, MEMORY_TRACE, 0, 0, 0, 0 }, + { "print-real-trace:", ACTION_PRINT_REAL_MEMORY, MEMORY_TRACE, 0, 1, 0, 0 }, + { "set-int-trace:", ACTION_SET_INTEGER_MEMORY, MEMORY_TRACE, 0, 0, 1, 0 }, + { "set-real-trace:", ACTION_SET_REAL_MEMORY, MEMORY_TRACE, 0, 1, 1, 0 }, + { "print-raw-trace:", ACTION_PRINT_RAW_MEMORY, MEMORY_TRACE, 0, 0, 0, 1 } + }; + const action_prefix *ap = (const action_prefix *)0; + const char *payload, *p, *comma; + action_item item; + size_t i, n; + + if( !text || !*text ) return( -1 ); + memset( action, 0, sizeof( *action ) ); + + for( i = 0; i < sizeof( prefix ) / sizeof( prefix[0] ); ++i ) + { + n = strlen( prefix[i].name ); + if( !strncmp( text, prefix[i].name, n ) ) + { + ap = &prefix[i]; + payload = text + n; + break; + } + } + + if( !ap || !*payload ) return( -1 ); + + action->kind = ap->kind; + action->memory = ap->memory; + + if( ap->raw_object ) + { + if( strchr( payload, ',' ) || parse_raw_memory( payload, &action->raw, ap->memory ) ) + goto fail; + return( 0 ); + } + + p = payload; + while( *p ) + { + comma = strchr( p, ',' ); + n = comma ? (size_t)(comma - p) : strlen( p ); + if( !n || parse_action_object( p, n, ap->is_register, ap->real_object, + ap->set_object, ap->memory, &item ) ) + goto fail; + + if( append_action_item( action, &item ) ) + { + free( item.value ); + goto fail; + } + + if( !comma ) break; + p = comma + 1; + if( !*p ) goto fail; + } + + return( action->count ? 0 : -1 ); + +fail: + free_stage_action( action ); + return( -1 ); + +} /* End of parse_stage_action() */ + + +static int +parse_stage_option( const char *text, stage_action_list *list ) +{ + stage_action action; + + memset( &action, 0, sizeof( action ) ); + if( parse_stage_action( text, &action ) ) return( -1 ); + + if( append_stage_action( list, &action ) ) + { + free_stage_action( &action ); + return( -1 ); + } + + return( 0 ); + +} /* End of parse_stage_option() */ + + + +void +mcpu_run_options_init( mcpu_run_options *options, const char *progname ) +{ + const char *env_preload; + + if( options == NULL ) + return; + + memset( options, 0, sizeof(*options) ); + mcpu_tool_options_init( &options->common, progname ); + options->digits = 80U; + + env_preload = getenv( "MCPU_LD_PRELOAD" ); + if( env_preload != NULL && *env_preload != 0 ) + options->env_ldpreload = env_preload; + +} /* End of mcpu_run_options_init() */ + + +void +mcpu_run_options_free( mcpu_run_options *options ) +{ + if( options == NULL ) + return; + + free_stage_action_list( &options->before_run ); + free_stage_action_list( &options->after_init ); + free_stage_action_list( &options->on_step ); + free_stage_action_list( &options->after_run ); + mcpu_tool_options_free( &options->common ); + +} /* End of mcpu_run_options_free() */ + + +static int +append_resolved_preload( char **list, size_t *length, const char *path ) +{ + size_t path_length; + size_t extra; + char *p; + + if( list == NULL || length == NULL || path == NULL ) + { + errno = EINVAL; + return( -1 ); + } + + path_length = strlen( path ); + extra = path_length + (*length != 0 ? 1U : 0U); + if( *length > SIZE_MAX - extra - 1U ) + { + errno = EOVERFLOW; + return( -1 ); + } + + p = (char *)realloc( *list, *length + extra + 1U ); + if( p == NULL ) + return( -1 ); + + *list = p; + if( *length != 0 ) + p[(*length)++] = ':'; + memcpy( p + *length, path, path_length ); + *length += path_length; + p[*length] = 0; + return( 0 ); + +} /* End of append_resolved_preload() */ + + +static int +resolve_preload_list( const mcpu_run_options *options, const char *list, + const char *source, char **result, + size_t *result_length, char *err, size_t errsz ) +{ + const char *begin; + + if( list == NULL || *list == 0 ) + return( 0 ); + + begin = list; + for( ;; ) + { + const char *colon = strchr( begin, ':' ); + size_t length = colon ? (size_t)(colon - begin) : strlen(begin); + char *name; + char *path = NULL; + + if( length == 0 ) + { + snprintf( err, errsz, "empty name in %s list", source ); + return( -1 ); + } + + name = (char *)malloc( length + 1U ); + if( name == NULL ) + { + snprintf( err, errsz, "out of memory" ); + return( -1 ); + } + + memcpy( name, begin, length ); + name[length] = 0; + if( mcpu_tool_resolve_library(&options->common, name, &path) != 0 ) + { + if( errno == ENOENT && strchr(name, '/') == NULL ) + snprintf( err, errsz, "%s: cannot find MCPU library '%s'", + source, name ); + else + snprintf( err, errsz, "%s: cannot resolve MCPU library '%s': %s", + source, name, strerror(errno) ); + free( name ); + return( -1 ); + } + free( name ); + + if( append_resolved_preload(result, result_length, path) != 0 ) + { + snprintf( err, errsz, "cannot build effective preload list: %s", + strerror(errno) ); + free( path ); + return( -1 ); + } + free( path ); + + if( colon == NULL ) + break; + begin = colon + 1; + } + + return( 0 ); + +} /* End of resolve_preload_list() */ + + +int +mcpu_run_resolve_preload( const mcpu_run_options *options, + char **resolved, char *err, size_t errsz ) +{ + char *result = NULL; + size_t result_length = 0; + + if( options == NULL || resolved == NULL || err == NULL || errsz == 0 ) + { + errno = EINVAL; + return( -1 ); + } + + *resolved = NULL; + + if( resolve_preload_list(options, options->env_ldpreload, + "MCPU_LD_PRELOAD", &result, &result_length, + err, errsz) != 0 ) + goto fail; + + if( resolve_preload_list(options, options->ldpreload, + "--ldpreload", &result, &result_length, + err, errsz) != 0 ) + goto fail; + + *resolved = result; + return( 0 ); + +fail: + free( result ); + return( -1 ); + +} /* End of mcpu_run_resolve_preload() */ + + +int +mcpu_run_handle_options( mcpu_run_options *options, int argc, char **argv ) +{ + int i; + int exearg = 0; + + if( options == NULL || argv == NULL ) + { + errno = EINVAL; + return( -1 ); + } + + for( i = 1; i < argc; ++i ) + { + const char *arg = argv[i]; + int common; + + if( options->exe != NULL ) + break; + + if( !strcmp( arg, "--" ) ) + { + if( i + 1 >= argc ) + { + fprintf( stderr, "%s: -- must be followed by an executable\n", + options->common.progname ); + return( -1 ); + } + exearg = ++i; + options->exe = argv[exearg]; + break; + } + else if( !strcmp( arg, "-h" ) || !strcmp( arg, "--help" ) ) + { + options->common.help = 1; + return( 0 ); + } + + common = mcpu_tool_parse_common_option( &options->common, + argc, argv, &i ); + if( common < 0 ) + return( -1 ); + if( common > 0 ) + { + if( options->common.version_action != MCPU_VERSION_NONE ) + return( 0 ); + continue; + } + + if( !strncmp( arg, "--int-reg=", 10 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_integer_register(arg + 10, &options->output) ) + { + fprintf( stderr, "%s: bad --int-reg operand: %s\n", + options->common.progname, arg + 10 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-reg=", 11 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_real_register(arg + 11, &options->output) ) + { + fprintf( stderr, "%s: bad --real-reg operand: %s\n", + options->common.progname, arg + 11 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--int-data=", 11 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 11, &options->output, 0, MEMORY_DATA) ) + { + fprintf( stderr, "%s: bad --int-data operand: %s\n", + options->common.progname, arg + 11 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-data=", 12 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 12, &options->output, 1, MEMORY_DATA) ) + { + fprintf( stderr, "%s: bad --real-data operand: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--raw-data=", 11 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_raw_memory(arg + 11, &options->output, MEMORY_DATA) ) + { + fprintf( stderr, "%s: bad --raw-data operand: %s\n", + options->common.progname, arg + 11 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--int-control=", 14 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 14, &options->output, 0, MEMORY_CONTROL) ) + { + fprintf( stderr, "%s: bad --int-control operand: %s\n", + options->common.progname, arg + 14 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-control=", 15 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 15, &options->output, 1, MEMORY_CONTROL) ) + { + fprintf( stderr, "%s: bad --real-control operand: %s\n", + options->common.progname, arg + 15 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--raw-control=", 14 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_raw_memory(arg + 14, &options->output, MEMORY_CONTROL) ) + { + fprintf( stderr, "%s: bad --raw-control operand: %s\n", + options->common.progname, arg + 14 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--int-heap=", 11 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 11, &options->output, 0, MEMORY_HEAP) ) + { + fprintf( stderr, "%s: bad --int-heap operand: %s\n", + options->common.progname, arg + 11 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-heap=", 12 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 12, &options->output, 1, MEMORY_HEAP) ) + { + fprintf( stderr, "%s: bad --real-heap operand: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--raw-heap=", 11 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_raw_memory(arg + 11, &options->output, MEMORY_HEAP) ) + { + fprintf( stderr, "%s: bad --raw-heap operand: %s\n", + options->common.progname, arg + 11 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--int-input=", 12 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 12, &options->output, 0, MEMORY_INPUT) ) + { + fprintf( stderr, "%s: bad --int-input operand: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-input=", 13 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 13, &options->output, 1, MEMORY_INPUT) ) + { + fprintf( stderr, "%s: bad --real-input operand: %s\n", + options->common.progname, arg + 13 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--raw-input=", 12 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_raw_memory(arg + 12, &options->output, MEMORY_INPUT) ) + { + fprintf( stderr, "%s: bad --raw-input operand: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--int-output=", 13 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 13, &options->output, 0, MEMORY_OUTPUT) ) + { + fprintf( stderr, "%s: bad --int-output operand: %s\n", + options->common.progname, arg + 13 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-output=", 14 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 14, &options->output, 1, MEMORY_OUTPUT) ) + { + fprintf( stderr, "%s: bad --real-output operand: %s\n", + options->common.progname, arg + 14 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--raw-output=", 13 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_raw_memory(arg + 13, &options->output, MEMORY_OUTPUT) ) + { + fprintf( stderr, "%s: bad --raw-output operand: %s\n", + options->common.progname, arg + 13 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--int-trace=", 12 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 12, &options->output, 0, MEMORY_TRACE) ) + { + fprintf( stderr, "%s: bad --int-trace operand: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--real-trace=", 13 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_memory_object(arg + 13, &options->output, 1, MEMORY_TRACE) ) + { + fprintf( stderr, "%s: bad --real-trace operand: %s\n", + options->common.progname, arg + 13 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--raw-trace=", 12 ) ) + { + if( options->output.kind != PRINT_NONE || + parse_raw_memory(arg + 12, &options->output, MEMORY_TRACE) ) + { + fprintf( stderr, "%s: bad --raw-trace operand: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--before-run=", 13 ) ) + { + if( parse_stage_option(arg + 13, &options->before_run) ) + { + fprintf( stderr, "%s: bad --before-run action: %s\n", + options->common.progname, arg + 13 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--after-init=", 13 ) ) + { + if( parse_stage_option(arg + 13, &options->after_init) ) + { + fprintf( stderr, "%s: bad --after-init action: %s\n", + options->common.progname, arg + 13 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--on-step=", 10 ) ) + { + if( parse_stage_option(arg + 10, &options->on_step) ) + { + fprintf( stderr, "%s: bad --on-step action: %s\n", + options->common.progname, arg + 10 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--after-run=", 12 ) ) + { + if( parse_stage_option(arg + 12, &options->after_run) ) + { + fprintf( stderr, "%s: bad --after-run action: %s\n", + options->common.progname, arg + 12 ); + return( -1 ); + } + } + else if( !strncmp( arg, "--library-path=", 15 ) ) + { + if( !arg[15] || + mcpu_tool_add_library_path(&options->common, arg + 15) != 0 ) + { + fprintf( stderr, "%s: bad --library-path: %s\n", + options->common.progname, arg + 15 ); + return( -1 ); + } + } + else if( !strcmp( arg, "--library-path" ) ) + { + if( ++i >= argc || argv[i][0] == 0 || + mcpu_tool_add_library_path(&options->common, argv[i]) != 0 ) + { + fprintf( stderr, "%s: argument missing or invalid after --library-path\n", + options->common.progname ); + return( -1 ); + } + } + else if( !strncmp( arg, "--ldpreload=", 12 ) ) + { + if( options->ldpreload != NULL || !arg[12] ) + { + fprintf( stderr, + "%s: --ldpreload must be supplied once with a non-empty ':' list\n", + options->common.progname ); + return( -1 ); + } + options->ldpreload = arg + 12; + } + else if( !strncmp( arg, "--steps=", 8 ) ) + { + if( parse_u64(arg + 8, &options->steps) || !options->steps ) + { + fprintf( stderr, "%s: --steps must be positive\n", + options->common.progname ); + return( -1 ); + } + options->steps_set = 1; + } + else if( !strcmp( arg, "--init-only" ) ) + options->init_only = 1; + else if( !strncmp( arg, "--digits=", 9 ) ) + { + char *end; + unsigned long n; + + errno = 0; + n = strtoul( arg + 9, &end, 10 ); + if( errno || end == arg + 9 || *end || !n || n > 1000000UL ) + { + fprintf( stderr, "%s: bad --digits value\n", + options->common.progname ); + return( -1 ); + } + options->digits = (unsigned)n; + } + else if( !strncmp( arg, "--stack-size", 12 ) || + !strncmp( arg, "--heap-size", 11 ) || + !strncmp( arg, "--heap-limit", 12 ) ) + { + fprintf( stderr, + "%s: STACK/HEAP sizing is part of the MELF executable ABI; " + "runtime size options were removed\n", + options->common.progname ); + return( -1 ); + } + else if( arg[0] == '-' ) + { + fprintf( stderr, "%s: unknown option: %s\n", + options->common.progname, arg ); + mcpu_run_usage( options ); + return( -1 ); + } + else + { + options->exe = arg; + exearg = i; + break; + } + } + + if( options->common.help || + mcpu_tool_has_information_action(&options->common) ) + return( 0 ); + + if( options->exe == NULL ) + { + mcpu_run_usage( options ); + return( -1 ); + } + + options->program_argc = argc - exearg; + options->program_argv = argv + exearg; + return( 0 ); + +} /* End of mcpu_run_handle_options() */ |
