X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=sim%2Fcommon%2Fsim-options.c;h=2c19f43646741c8f5e51cee1f103347d61dfd794;hb=2a8a6bf5cefda15f0e9b437c151c695cd0b25537;hp=8e8cb2fa7e2cfb57e86f5c3ec9a6522a2eeb04b1;hpb=f90b720ba1b70759feea3b3a130a6f8b01709d68;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/common/sim-options.c b/sim/common/sim-options.c index 8e8cb2fa7e..2c19f43646 100644 --- a/sim/common/sim-options.c +++ b/sim/common/sim-options.c @@ -1,22 +1,21 @@ /* Simulator option handling. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 2004, 2007, 2008 Free Software Foundation, Inc. Contributed by Cygnus Support. This file is part of GDB, the GNU debugger. 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, or (at your option) -any later version. +the Free Software Foundation; either version 3 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. */ +You should have received a copy of the GNU General Public License +along with this program. If not, see . */ #include "sim-main.h" #ifdef HAVE_STRING_H @@ -31,7 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif #include #include "libiberty.h" -#include "../libiberty/alloca-conf.h" #include "sim-options.h" #include "sim-io.h" #include "sim-assert.h" @@ -43,9 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., This is intended to be called by modules in their `install' handler. */ SIM_RC -sim_add_option_table (sd, table) - SIM_DESC sd; - const OPTION *table; +sim_add_option_table (SIM_DESC sd, sim_cpu *cpu, const OPTION *table) { struct option_list *ol = ((struct option_list *) xmalloc (sizeof (struct option_list))); @@ -53,9 +49,19 @@ sim_add_option_table (sd, table) /* Note: The list is constructed in the reverse order we're called so later calls will override earlier ones (in case that ever happens). This is the intended behaviour. */ - ol->next = STATE_OPTIONS (sd); - ol->options = table; - STATE_OPTIONS (sd) = ol; + + if (cpu) + { + ol->next = CPU_OPTIONS (cpu); + ol->options = table; + CPU_OPTIONS (cpu) = ol; + } + else + { + ol->next = STATE_OPTIONS (sd); + ol->options = table; + STATE_OPTIONS (sd) = ol; + } return SIM_RC_OK; } @@ -83,25 +89,60 @@ static DECLARE_OPTION_HANDLER (standard_option_handler); If you decide to conditionally compile them out as well, delete this comment and add a comment saying that that is the rule. */ -#define OPTION_DEBUG_INSN (OPTION_START + 0) -#define OPTION_DEBUG_FILE (OPTION_START + 1) -#define OPTION_DO_COMMAND (OPTION_START + 2) -#define OPTION_ARCHITECTURE (OPTION_START + 3) -#define OPTION_TARGET (OPTION_START + 4) +typedef enum { + OPTION_DEBUG_INSN = OPTION_START, + OPTION_DEBUG_FILE, + OPTION_DO_COMMAND, + OPTION_ARCHITECTURE, + OPTION_TARGET, + OPTION_ARCHITECTURE_INFO, + OPTION_ENVIRONMENT, + OPTION_ALIGNMENT, + OPTION_VERBOSE, +#if defined (SIM_HAVE_BIENDIAN) + OPTION_ENDIAN, +#endif + OPTION_DEBUG, +#ifdef SIM_HAVE_FLATMEM + OPTION_MEM_SIZE, +#endif + OPTION_HELP, +#ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir. */ + OPTION_H8300H, + OPTION_H8300S, + OPTION_H8300SX, +#endif + OPTION_LOAD_LMA, + OPTION_LOAD_VMA, + OPTION_SYSROOT +} STANDARD_OPTIONS; static const OPTION standard_options[] = { - { {"verbose", no_argument, NULL, 'v'}, + { {"verbose", no_argument, NULL, OPTION_VERBOSE}, 'v', NULL, "Verbose output", standard_option_handler }, #if defined (SIM_HAVE_BIENDIAN) /* ??? && WITH_TARGET_BYTE_ORDER == 0 */ - { {"endian", required_argument, NULL, 'E'}, + { {"endian", required_argument, NULL, OPTION_ENDIAN}, 'E', "big|little", "Set endianness", standard_option_handler }, #endif - { {"debug", no_argument, NULL, 'D'}, +#ifdef SIM_HAVE_ENVIRONMENT + /* This option isn't supported unless all choices are supported in keeping + with the goal of not printing in --help output things the simulator can't + do [as opposed to things that just haven't been configured in]. */ + { {"environment", required_argument, NULL, OPTION_ENVIRONMENT}, + '\0', "user|virtual|operating", "Set running environment", + standard_option_handler }, +#endif + + { {"alignment", required_argument, NULL, OPTION_ALIGNMENT}, + '\0', "strict|nonstrict|forced", "Set memory access alignment", + standard_option_handler }, + + { {"debug", no_argument, NULL, OPTION_DEBUG}, 'D', NULL, "Print debugging messages", standard_option_handler }, { {"debug-insn", no_argument, NULL, OPTION_DEBUG_INSN}, @@ -112,53 +153,80 @@ static const OPTION standard_options[] = standard_option_handler }, #ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir. */ - { {"h8300h", no_argument, NULL, 'h'}, - 'h', NULL, "Indicate the CPU is h8/300h or h8/300s", + { {"h8300h", no_argument, NULL, OPTION_H8300H}, + 'h', NULL, "Indicate the CPU is H8/300H", + standard_option_handler }, + { {"h8300s", no_argument, NULL, OPTION_H8300S}, + 'S', NULL, "Indicate the CPU is H8S", + standard_option_handler }, + { {"h8300sx", no_argument, NULL, OPTION_H8300SX}, + 'x', NULL, "Indicate the CPU is H8SX", standard_option_handler }, #endif #ifdef SIM_HAVE_FLATMEM - { {"mem-size", required_argument, NULL, 'm'}, - 'm', "MEMORY SIZE", "Specify memory size", - standard_option_handler }, + { {"mem-size", required_argument, NULL, OPTION_MEM_SIZE}, + 'm', "[in bytes, Kb (k suffix), Mb (m suffix) or Gb (g suffix)]", + "Specify memory size", standard_option_handler }, #endif { {"do-command", required_argument, NULL, OPTION_DO_COMMAND}, '\0', "COMMAND", ""/*undocumented*/, standard_option_handler }, - { {"help", no_argument, NULL, 'H'}, + { {"help", no_argument, NULL, OPTION_HELP}, 'H', NULL, "Print help information", standard_option_handler }, { {"architecture", required_argument, NULL, OPTION_ARCHITECTURE}, '\0', "MACHINE", "Specify the architecture to use", standard_option_handler }, + { {"architecture-info", no_argument, NULL, OPTION_ARCHITECTURE_INFO}, + '\0', NULL, "List supported architectures", + standard_option_handler }, + { {"info-architecture", no_argument, NULL, OPTION_ARCHITECTURE_INFO}, + '\0', NULL, NULL, + standard_option_handler }, { {"target", required_argument, NULL, OPTION_TARGET}, '\0', "BFDNAME", "Specify the object-code format for the object files", standard_option_handler }, +#ifdef SIM_HANDLES_LMA + { {"load-lma", no_argument, NULL, OPTION_LOAD_LMA}, + '\0', NULL, +#if SIM_HANDLES_LMA + "Use VMA or LMA addresses when loading image (default LMA)", +#else + "Use VMA or LMA addresses when loading image (default VMA)", +#endif + standard_option_handler, "load-{lma,vma}" }, + { {"load-vma", no_argument, NULL, OPTION_LOAD_VMA}, + '\0', NULL, "", standard_option_handler, "" }, +#endif + + { {"sysroot", required_argument, NULL, OPTION_SYSROOT}, + '\0', "SYSROOT", + "Root for system calls with absolute file-names and cwd at start", + standard_option_handler }, + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } }; static SIM_RC -standard_option_handler (sd, opt, arg, is_command) - SIM_DESC sd; - int opt; - char *arg; - int is_command; +standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) { int i,n; - switch (opt) + switch ((STANDARD_OPTIONS) opt) { - case 'v' : + case OPTION_VERBOSE: STATE_VERBOSE_P (sd) = 1; break; #ifdef SIM_HAVE_BIENDIAN - case 'E' : + case OPTION_ENDIAN: if (strcmp (arg, "big") == 0) { if (WITH_TARGET_BYTE_ORDER == LITTLE_ENDIAN) @@ -187,7 +255,79 @@ standard_option_handler (sd, opt, arg, is_command) break; #endif - case 'D' : + case OPTION_ENVIRONMENT: + if (strcmp (arg, "user") == 0) + STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT; + else if (strcmp (arg, "virtual") == 0) + STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; + else if (strcmp (arg, "operating") == 0) + STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT; + else + { + sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg); + return SIM_RC_FAIL; + } + if (WITH_ENVIRONMENT != ALL_ENVIRONMENT + && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd)) + { + char *type; + switch (WITH_ENVIRONMENT) + { + case USER_ENVIRONMENT: type = "user"; break; + case VIRTUAL_ENVIRONMENT: type = "virtual"; break; + case OPERATING_ENVIRONMENT: type = "operating"; break; + } + sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n", + type); + return SIM_RC_FAIL; + } + break; + + case OPTION_ALIGNMENT: + if (strcmp (arg, "strict") == 0) + { + if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT) + { + current_alignment = STRICT_ALIGNMENT; + break; + } + } + else if (strcmp (arg, "nonstrict") == 0) + { + if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT) + { + current_alignment = NONSTRICT_ALIGNMENT; + break; + } + } + else if (strcmp (arg, "forced") == 0) + { + if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT) + { + current_alignment = FORCED_ALIGNMENT; + break; + } + } + else + { + sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg); + return SIM_RC_FAIL; + } + switch (WITH_ALIGNMENT) + { + case STRICT_ALIGNMENT: + sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n"); + break; + case NONSTRICT_ALIGNMENT: + sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n"); + break; + case FORCED_ALIGNMENT: + sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n"); + break; + } + return SIM_RC_FAIL; + + case OPTION_DEBUG: if (! WITH_DEBUG) sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n"); else @@ -226,15 +366,35 @@ standard_option_handler (sd, opt, arg, is_command) break; #ifdef SIM_H8300 /* FIXME: Can be moved to h8300 dir. */ - case 'h' : - set_h8300h (1); + case OPTION_H8300H: + set_h8300h (bfd_mach_h8300h); + break; + case OPTION_H8300S: + set_h8300h (bfd_mach_h8300s); + break; + case OPTION_H8300SX: + set_h8300h (bfd_mach_h8300sx); break; #endif #ifdef SIM_HAVE_FLATMEM - case 'm': + case OPTION_MEM_SIZE: { - unsigned long ul = strtol (arg, NULL, 0); + char * endp; + unsigned long ul = strtol (arg, &endp, 0); + + switch (* endp) + { + case 'k': case 'K': size <<= 10; break; + case 'm': case 'M': size <<= 20; break; + case 'g': case 'G': size <<= 30; break; + case ' ': case '\0': case '\t': break; + default: + if (ul > 0) + sim_io_eprintf (sd, "Ignoring strange character at end of memory size: %c\n", * endp); + break; + } + /* 16384: some minimal amount */ if (! isdigit (arg[0]) || ul < 16384) { @@ -262,18 +422,52 @@ standard_option_handler (sd, opt, arg, is_command) break; } + case OPTION_ARCHITECTURE_INFO: + { + const char **list = bfd_arch_list(); + const char **lp; + if (list == NULL) + abort (); + sim_io_printf (sd, "Possible architectures:"); + for (lp = list; *lp != NULL; lp++) + sim_io_printf (sd, " %s", *lp); + sim_io_printf (sd, "\n"); + free (list); + break; + } + case OPTION_TARGET: { STATE_TARGET (sd) = xstrdup (arg); break; } - case 'H': + case OPTION_LOAD_LMA: + { + STATE_LOAD_AT_LMA_P (sd) = 1; + break; + } + + case OPTION_LOAD_VMA: + { + STATE_LOAD_AT_LMA_P (sd) = 0; + break; + } + + case OPTION_HELP: sim_print_help (sd, is_command); if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) exit (0); /* FIXME: 'twould be nice to do something similar if gdb. */ break; + + case OPTION_SYSROOT: + /* Don't leak memory in the odd event that there's lots of + --sysroot=... options. */ + if (simulator_sysroot[0] != '\0' && arg[0] != '\0') + free (simulator_sysroot); + simulator_sysroot = xstrdup (arg); + break; } return SIM_RC_OK; @@ -285,8 +479,11 @@ SIM_RC standard_install (SIM_DESC sd) { SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); - if (sim_add_option_table (sd, standard_options) != SIM_RC_OK) + if (sim_add_option_table (sd, NULL, standard_options) != SIM_RC_OK) return SIM_RC_FAIL; +#ifdef SIM_HANDLES_LMA + STATE_LOAD_AT_LMA_P (sd) = SIM_HANDLES_LMA; +#endif return SIM_RC_OK; } @@ -332,16 +529,18 @@ sim_parse_args (sd, argv) SIM_DESC sd; char **argv; { - int i, argc, num_opts; + int c, i, argc, num_opts; char *p, *short_options; /* The `val' option struct entry is dynamically assigned for options that only come in the long form. ORIG_VAL is used to get the original value back. */ - unsigned char *orig_val; + int *orig_val; struct option *lp, *long_options; const struct option_list *ol; const OPTION *opt; OPTION_HANDLER **handlers; + sim_cpu **opt_cpu; + SIM_RC result = SIM_RC_OK; /* Count the number of arguments. */ for (argc = 0; argv[argc] != NULL; ++argc) @@ -350,28 +549,34 @@ sim_parse_args (sd, argv) /* Count the number of options. */ num_opts = 0; for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) - for (opt = ol->options; opt->opt.name != NULL; ++opt) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) ++num_opts; + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + for (ol = CPU_OPTIONS (STATE_CPU (sd, i)); ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + ++num_opts; /* Initialize duplicate argument checker. */ (void) dup_arg_p (NULL); /* Build the option table for getopt. */ - long_options = (struct option *) alloca ((num_opts + 1) * sizeof (struct option)); + + long_options = NZALLOC (struct option, num_opts + 1); lp = long_options; - short_options = (char *) alloca (num_opts * 3 + 1); + short_options = NZALLOC (char, num_opts * 3 + 1); p = short_options; -#if 0 /* ??? necessary anymore? */ - /* Set '+' as first char so argument permutation isn't done. This is done - to workaround a problem with invoking getopt_long in run.c.: optind gets - decremented when the program name is reached. */ + handlers = NZALLOC (OPTION_HANDLER *, OPTION_START + num_opts); + orig_val = NZALLOC (int, OPTION_START + num_opts); + opt_cpu = NZALLOC (sim_cpu *, OPTION_START + num_opts); + + /* Set '+' as first char so argument permutation isn't done. This + is done to stop getopt_long returning options that appear after + the target program. Such options should be passed unchanged into + the program image. */ *p++ = '+'; -#endif - handlers = (OPTION_HANDLER **) alloca (256 * sizeof (OPTION_HANDLER *)); - memset (handlers, 0, 256 * sizeof (OPTION_HANDLER *)); - orig_val = (unsigned char *) alloca (256); + for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) - for (opt = ol->options; opt->opt.name != NULL; ++opt) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) { if (dup_arg_p (opt->opt.name)) continue; @@ -382,21 +587,67 @@ sim_parse_args (sd, argv) *p++ = ':'; else if (opt->opt.has_arg == optional_argument) { *p++ = ':'; *p++ = ':'; } + handlers[(unsigned char) opt->shortopt] = opt->handler; + if (opt->opt.val != 0) + orig_val[(unsigned char) opt->shortopt] = opt->opt.val; + else + orig_val[(unsigned char) opt->shortopt] = opt->shortopt; + } + if (opt->opt.name != NULL) + { + *lp = opt->opt; + /* Dynamically assign `val' numbers for long options. */ + lp->val = i++; + handlers[lp->val] = opt->handler; + orig_val[lp->val] = opt->opt.val; + opt_cpu[lp->val] = NULL; + ++lp; } - *lp = opt->opt; - /* Dynamically assign `val' numbers for long options that don't have - a short option equivalent. */ - if (OPTION_LONG_ONLY_P (opt->opt.val)) - lp->val = i++; - handlers[(unsigned char) lp->val] = opt->handler; - orig_val[(unsigned char) lp->val] = opt->opt.val; - ++lp; } + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + sim_cpu *cpu = STATE_CPU (sd, c); + for (ol = CPU_OPTIONS (cpu); ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + { +#if 0 /* Each option is prepended with --- so this greatly cuts down + on the need for dup_arg_p checking. Maybe in the future it'll be + needed so this is just commented out, and not deleted. */ + if (dup_arg_p (opt->opt.name)) + continue; +#endif + /* Don't allow short versions of cpu specific options for now. */ + if (opt->shortopt != 0) + { + sim_io_eprintf (sd, "internal error, short cpu specific option"); + result = SIM_RC_FAIL; + break; + } + if (opt->opt.name != NULL) + { + char *name; + *lp = opt->opt; + /* Prepend --- to the option. */ + asprintf (&name, "%s-%s", CPU_NAME (cpu), lp->name); + lp->name = name; + /* Dynamically assign `val' numbers for long options. */ + lp->val = i++; + handlers[lp->val] = opt->handler; + orig_val[lp->val] = opt->opt.val; + opt_cpu[lp->val] = cpu; + ++lp; + } + } + } + + /* Terminate the short and long option lists. */ *p = 0; lp->name = NULL; /* Ensure getopt is initialized. */ optind = 0; + while (1) { int longind, optc; @@ -409,40 +660,37 @@ sim_parse_args (sd, argv) break; } if (optc == '?') - return SIM_RC_FAIL; + { + result = SIM_RC_FAIL; + break; + } - if ((*handlers[optc]) (sd, orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL) - return SIM_RC_FAIL; + if ((*handlers[optc]) (sd, opt_cpu[optc], orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL) + { + result = SIM_RC_FAIL; + break; + } } - return SIM_RC_OK; + zfree (long_options); + zfree (short_options); + zfree (handlers); + zfree (opt_cpu); + zfree (orig_val); + return result; } -/* Print help messages for the options. */ +/* Utility of sim_print_help to print a list of option tables. */ -void -sim_print_help (sd, is_command) - SIM_DESC sd; - int is_command; +static void +print_help (SIM_DESC sd, sim_cpu *cpu, const struct option_list *ol, int is_command) { - const struct option_list *ol; const OPTION *opt; - if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) - sim_io_printf (sd, "Usage: %s [options] program [program args]\n", - STATE_MY_NAME (sd)); - - /* Initialize duplicate argument checker. */ - (void) dup_arg_p (NULL); - - if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) - sim_io_printf (sd, "Options:\n"); - else - sim_io_printf (sd, "Commands:\n"); - - for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) - for (opt = ol->options; opt->opt.name != NULL; ++opt) + for ( ; ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) { + const int indent = 30; int comma, len; const OPTION *o; @@ -460,6 +708,7 @@ sim_print_help (sd, is_command) comma = 0; len = 2; + /* list any short options (aliases) for the current OPT */ if (!is_command) { o = opt; @@ -486,22 +735,26 @@ sim_print_help (sd, is_command) } ++o; } - while (o->opt.name != NULL && o->doc == NULL); + while (OPTION_VALID_P (o) && o->doc == NULL); } + /* list any long options (aliases) for the current OPT */ o = opt; do { const char *name; + const char *cpu_prefix = cpu ? CPU_NAME (cpu) : NULL; if (o->doc_name != NULL) name = o->doc_name; else name = o->opt.name; if (name != NULL) { - sim_io_printf (sd, "%s%s%s", + sim_io_printf (sd, "%s%s%s%s%s", comma ? ", " : "", is_command ? "" : "--", + cpu ? cpu_prefix : "", + cpu ? "-" : "", name); len += ((comma ? 2 : 0) + (is_command ? 0 : 2) @@ -510,7 +763,7 @@ sim_print_help (sd, is_command) { if (o->opt.has_arg == optional_argument) { - sim_io_printf (sd, " [%s]", o->arg); + sim_io_printf (sd, "[=%s]", o->arg); len += 2 + strlen (o->arg) + 1; } else @@ -523,21 +776,76 @@ sim_print_help (sd, is_command) } ++o; } - while (o->opt.name != NULL && o->doc == NULL); + while (OPTION_VALID_P (o) && o->doc == NULL); - if (len >= 30) + if (len >= indent) { - sim_io_printf (sd, "\n"); - len = 0; + sim_io_printf (sd, "\n%*s", indent, ""); } + else + sim_io_printf (sd, "%*s", indent - len, ""); - for (; len < 30; len++) - sim_io_printf (sd, " "); - - sim_io_printf (sd, "%s\n", opt->doc); + /* print the description, word wrap long lines */ + { + const char *chp = opt->doc; + unsigned doc_width = 80 - indent; + while (strlen (chp) >= doc_width) /* some slack */ + { + const char *end = chp + doc_width - 1; + while (end > chp && !isspace (*end)) + end --; + if (end == chp) + end = chp + doc_width - 1; + /* The cast should be ok - its distances between to + points in a string. */ + sim_io_printf (sd, "%.*s\n%*s", (int) (end - chp), chp, indent, + ""); + chp = end; + while (isspace (*chp) && *chp != '\0') + chp++; + } + sim_io_printf (sd, "%s\n", chp); + } } +} + +/* Print help messages for the options. */ + +void +sim_print_help (sd, is_command) + SIM_DESC sd; + int is_command; +{ + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + sim_io_printf (sd, "Usage: %s [options] program [program args]\n", + STATE_MY_NAME (sd)); + + /* Initialize duplicate argument checker. */ + (void) dup_arg_p (NULL); + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + sim_io_printf (sd, "Options:\n"); + else + sim_io_printf (sd, "Commands:\n"); + + print_help (sd, NULL, STATE_OPTIONS (sd), is_command); sim_io_printf (sd, "\n"); + + /* Print cpu-specific options. */ + { + int i; + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + sim_cpu *cpu = STATE_CPU (sd, i); + if (CPU_OPTIONS (cpu) == NULL) + continue; + sim_io_printf (sd, "CPU %s specific options:\n", CPU_NAME (cpu)); + print_help (sd, cpu, CPU_OPTIONS (cpu), is_command); + sim_io_printf (sd, "\n"); + } + } + sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n", STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command"); sim_io_printf (sd, " may not be applicable\n"); @@ -550,17 +858,74 @@ sim_print_help (sd, is_command) } } +/* Utility of sim_args_command to find the closest match for a command. + Commands that have "-" in them can be specified as separate words. + e.g. sim memory-region 0x800000,0x4000 + or sim memory region 0x800000,0x4000 + If CPU is non-null, use its option table list, otherwise use the main one. + *PARGI is where to start looking in ARGV. It is updated to point past + the found option. */ +static const OPTION * +find_match (SIM_DESC sd, sim_cpu *cpu, char *argv[], int *pargi) +{ + const struct option_list *ol; + const OPTION *opt; + /* most recent option match */ + const OPTION *matching_opt = NULL; + int matching_argi = -1; + + if (cpu) + ol = CPU_OPTIONS (cpu); + else + ol = STATE_OPTIONS (sd); + + /* Skip passed elements specified by *PARGI. */ + argv += *pargi; + + for ( ; ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + { + int argi = 0; + const char *name = opt->opt.name; + if (name == NULL) + continue; + while (argv [argi] != NULL + && strncmp (name, argv [argi], strlen (argv [argi])) == 0) + { + name = &name [strlen (argv[argi])]; + if (name [0] == '-') + { + /* leading match ...-d-e-f - continue search */ + name ++; /* skip `-' */ + argi ++; + continue; + } + else if (name [0] == '\0') + { + /* exact match ... - better than before? */ + if (argi > matching_argi) + { + matching_argi = argi; + matching_opt = opt; + } + break; + } + else + break; + } + } + *pargi = matching_argi; + return matching_opt; +} SIM_RC -sim_args_command (sd, cmd) - SIM_DESC sd; - char *cmd; +sim_args_command (SIM_DESC sd, char *cmd) { /* something to do? */ if (cmd == NULL) - return SIM_RC_OK; /* FIXME - perhaphs help would be better */ + return SIM_RC_OK; /* FIXME - perhaps help would be better */ if (cmd [0] == '-') { @@ -572,50 +937,53 @@ sim_args_command (sd, cmd) } else { - /* user specified form? */ - const struct option_list *ol; - const OPTION *opt; char **argv = buildargv (cmd); - /* most recent option match */ const OPTION *matching_opt = NULL; - int matching_argi = -1; - if (argv [0] != NULL) - for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) - for (opt = ol->options; opt->opt.name != NULL; ++opt) - { - int argi = 0; - const char *name = opt->opt.name; - while (strncmp (name, argv [argi], strlen (argv [argi])) == 0) - { - name = &name [strlen (argv[argi])]; - if (name [0] == '-') - { - /* leading match ...-d-e-f - continue search */ - name ++; /* skip `-' */ - argi ++; - continue; - } - else if (name [0] == '\0') - { - /* exact match ... - better than before? */ - if (argi > matching_argi) - { - matching_argi = argi; - matching_opt = opt; - } - break; - } - else - break; - } - } + int matching_argi; + sim_cpu *cpu; + + if (argv [0] == NULL) + return SIM_RC_OK; /* FIXME - perhaps help would be better */ + + /* First check for a cpu selector. */ + { + char *cpu_name = xstrdup (argv[0]); + char *hyphen = strchr (cpu_name, '-'); + if (hyphen) + *hyphen = 0; + cpu = sim_cpu_lookup (sd, cpu_name); + if (cpu) + { + /* If -, point argv[0] at . */ + if (hyphen) + { + matching_argi = 0; + argv[0] += hyphen - cpu_name + 1; + } + else + matching_argi = 1; + matching_opt = find_match (sd, cpu, argv, &matching_argi); + /* If hyphen found restore argv[0]. */ + if (hyphen) + argv[0] -= hyphen - cpu_name + 1; + } + free (cpu_name); + } + + /* If that failed, try the main table. */ + if (matching_opt == NULL) + { + matching_argi = 0; + matching_opt = find_match (sd, NULL, argv, &matching_argi); + } + if (matching_opt != NULL) { switch (matching_opt->opt.has_arg) { case no_argument: if (argv [matching_argi + 1] == NULL) - matching_opt->handler (sd, matching_opt->opt.val, + matching_opt->handler (sd, cpu, matching_opt->opt.val, NULL, 1/*is_command*/); else sim_io_eprintf (sd, "Command `%s' takes no arguments\n", @@ -623,10 +991,10 @@ sim_args_command (sd, cmd) break; case optional_argument: if (argv [matching_argi + 1] == NULL) - matching_opt->handler (sd, matching_opt->opt.val, + matching_opt->handler (sd, cpu, matching_opt->opt.val, NULL, 1/*is_command*/); else if (argv [matching_argi + 2] == NULL) - matching_opt->handler (sd, matching_opt->opt.val, + matching_opt->handler (sd, cpu, matching_opt->opt.val, argv [matching_argi + 1], 1/*is_command*/); else sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n", @@ -637,14 +1005,17 @@ sim_args_command (sd, cmd) sim_io_eprintf (sd, "Command `%s' requires an argument\n", matching_opt->opt.name); else if (argv [matching_argi + 2] == NULL) - matching_opt->handler (sd, matching_opt->opt.val, + matching_opt->handler (sd, cpu, matching_opt->opt.val, argv [matching_argi + 1], 1/*is_command*/); else sim_io_eprintf (sd, "Command `%s' requires only one argument\n", matching_opt->opt.name); } + freeargv (argv); return SIM_RC_OK; } + + freeargv (argv); } /* didn't find anything that remotly matched */