14e98e3e1Schristos /* Simulator option handling. 2*0d3e0572Schristos Copyright (C) 1996-2024 Free Software Foundation, Inc. 34e98e3e1Schristos Contributed by Cygnus Support. 44e98e3e1Schristos 54e98e3e1Schristos This file is part of GDB, the GNU debugger. 64e98e3e1Schristos 74e98e3e1Schristos This program is free software; you can redistribute it and/or modify 84e98e3e1Schristos it under the terms of the GNU General Public License as published by 94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 104e98e3e1Schristos (at your option) any later version. 114e98e3e1Schristos 124e98e3e1Schristos This program is distributed in the hope that it will be useful, 134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154e98e3e1Schristos GNU General Public License for more details. 164e98e3e1Schristos 174e98e3e1Schristos You should have received a copy of the GNU General Public License 184e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 194e98e3e1Schristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224b169a6bSchristos 234e98e3e1Schristos #include <ctype.h> 248dffb485Schristos #include <stdio.h> 254b169a6bSchristos #include <stdlib.h> 264b169a6bSchristos #include <string.h> 274b169a6bSchristos #include <unistd.h> 284b169a6bSchristos 294b169a6bSchristos #include "bfd.h" 304b169a6bSchristos #include "environ.h" 314b169a6bSchristos #include "hashtab.h" 324e98e3e1Schristos #include "libiberty.h" 334b169a6bSchristos 344b169a6bSchristos #include "sim-main.h" 354e98e3e1Schristos #include "sim-options.h" 364e98e3e1Schristos #include "sim-io.h" 374e98e3e1Schristos #include "sim-assert.h" 38212397c6Schristos #include "version.h" 394e98e3e1Schristos 404e98e3e1Schristos /* Add a set of options to the simulator. 414e98e3e1Schristos TABLE is an array of OPTIONS terminated by a NULL `opt.name' entry. 424e98e3e1Schristos This is intended to be called by modules in their `install' handler. */ 434e98e3e1Schristos 444e98e3e1Schristos SIM_RC 454e98e3e1Schristos sim_add_option_table (SIM_DESC sd, sim_cpu *cpu, const OPTION *table) 464e98e3e1Schristos { 474e98e3e1Schristos struct option_list *ol = ((struct option_list *) 484e98e3e1Schristos xmalloc (sizeof (struct option_list))); 494e98e3e1Schristos 504e98e3e1Schristos /* Note: The list is constructed in the reverse order we're called so 514e98e3e1Schristos later calls will override earlier ones (in case that ever happens). 524e98e3e1Schristos This is the intended behaviour. */ 534e98e3e1Schristos 544e98e3e1Schristos if (cpu) 554e98e3e1Schristos { 564e98e3e1Schristos ol->next = CPU_OPTIONS (cpu); 574e98e3e1Schristos ol->options = table; 584e98e3e1Schristos CPU_OPTIONS (cpu) = ol; 594e98e3e1Schristos } 604e98e3e1Schristos else 614e98e3e1Schristos { 624e98e3e1Schristos ol->next = STATE_OPTIONS (sd); 634e98e3e1Schristos ol->options = table; 644e98e3e1Schristos STATE_OPTIONS (sd) = ol; 654e98e3e1Schristos } 664e98e3e1Schristos 674e98e3e1Schristos return SIM_RC_OK; 684e98e3e1Schristos } 694e98e3e1Schristos 704e98e3e1Schristos /* Standard option table. 714e98e3e1Schristos Modules may specify additional ones. 724e98e3e1Schristos The caller of sim_parse_args may also specify additional options 734e98e3e1Schristos by calling sim_add_option_table first. */ 744e98e3e1Schristos 754e98e3e1Schristos static DECLARE_OPTION_HANDLER (standard_option_handler); 764e98e3e1Schristos 774e98e3e1Schristos /* FIXME: We shouldn't print in --help output options that aren't usable. 784e98e3e1Schristos Some fine tuning will be necessary. One can either move less general 794e98e3e1Schristos options to another table or use a HAVE_FOO macro to ifdef out unavailable 804e98e3e1Schristos options. */ 814e98e3e1Schristos 824e98e3e1Schristos /* ??? One might want to conditionally compile out the entries that 834e98e3e1Schristos aren't enabled. There's a distinction, however, between options a 844e98e3e1Schristos simulator can't support and options that haven't been configured in. 854e98e3e1Schristos Certainly options a simulator can't support shouldn't appear in the 864e98e3e1Schristos output of --help. Whether the same thing applies to options that haven't 874e98e3e1Schristos been configured in or not isn't something I can get worked up over. 884e98e3e1Schristos [Note that conditionally compiling them out might simply involve moving 894e98e3e1Schristos the option to another table.] 904e98e3e1Schristos If you decide to conditionally compile them out as well, delete this 914e98e3e1Schristos comment and add a comment saying that that is the rule. */ 924e98e3e1Schristos 934e98e3e1Schristos typedef enum { 944e98e3e1Schristos OPTION_DEBUG_INSN = OPTION_START, 954e98e3e1Schristos OPTION_DEBUG_FILE, 964e98e3e1Schristos OPTION_DO_COMMAND, 974e98e3e1Schristos OPTION_ARCHITECTURE, 984e98e3e1Schristos OPTION_TARGET, 994b169a6bSchristos OPTION_TARGET_INFO, 1004e98e3e1Schristos OPTION_ARCHITECTURE_INFO, 1014e98e3e1Schristos OPTION_ENVIRONMENT, 1024e98e3e1Schristos OPTION_ALIGNMENT, 1034e98e3e1Schristos OPTION_VERBOSE, 1044e98e3e1Schristos OPTION_ENDIAN, 1054e98e3e1Schristos OPTION_DEBUG, 1064e98e3e1Schristos OPTION_HELP, 107212397c6Schristos OPTION_VERSION, 1084e98e3e1Schristos OPTION_LOAD_LMA, 1094e98e3e1Schristos OPTION_LOAD_VMA, 1104b169a6bSchristos OPTION_SYSROOT, 1114b169a6bSchristos OPTION_ARGV0, 1124b169a6bSchristos OPTION_ENV_SET, 1134b169a6bSchristos OPTION_ENV_UNSET, 1144b169a6bSchristos OPTION_ENV_CLEAR, 1154e98e3e1Schristos } STANDARD_OPTIONS; 1164e98e3e1Schristos 1174e98e3e1Schristos static const OPTION standard_options[] = 1184e98e3e1Schristos { 1194e98e3e1Schristos { {"verbose", no_argument, NULL, OPTION_VERBOSE}, 1204e98e3e1Schristos 'v', NULL, "Verbose output", 1214e98e3e1Schristos standard_option_handler, NULL }, 1224e98e3e1Schristos 1234e98e3e1Schristos { {"endian", required_argument, NULL, OPTION_ENDIAN}, 1244b169a6bSchristos 'E', "B|big|L|little", "Set endianness", 1254e98e3e1Schristos standard_option_handler, NULL }, 1264e98e3e1Schristos 1274e98e3e1Schristos /* This option isn't supported unless all choices are supported in keeping 1284e98e3e1Schristos with the goal of not printing in --help output things the simulator can't 1294e98e3e1Schristos do [as opposed to things that just haven't been configured in]. */ 1304e98e3e1Schristos { {"environment", required_argument, NULL, OPTION_ENVIRONMENT}, 1314e98e3e1Schristos '\0', "user|virtual|operating", "Set running environment", 1324e98e3e1Schristos standard_option_handler }, 1334e98e3e1Schristos 1344e98e3e1Schristos { {"alignment", required_argument, NULL, OPTION_ALIGNMENT}, 1354e98e3e1Schristos '\0', "strict|nonstrict|forced", "Set memory access alignment", 1364e98e3e1Schristos standard_option_handler }, 1374e98e3e1Schristos 1384e98e3e1Schristos { {"debug", no_argument, NULL, OPTION_DEBUG}, 1394e98e3e1Schristos 'D', NULL, "Print debugging messages", 1404e98e3e1Schristos standard_option_handler }, 1414e98e3e1Schristos { {"debug-insn", no_argument, NULL, OPTION_DEBUG_INSN}, 1424e98e3e1Schristos '\0', NULL, "Print instruction debugging messages", 1434e98e3e1Schristos standard_option_handler }, 1444e98e3e1Schristos { {"debug-file", required_argument, NULL, OPTION_DEBUG_FILE}, 1454e98e3e1Schristos '\0', "FILE NAME", "Specify debugging output file", 1464e98e3e1Schristos standard_option_handler }, 1474e98e3e1Schristos 1484e98e3e1Schristos { {"do-command", required_argument, NULL, OPTION_DO_COMMAND}, 1494e98e3e1Schristos '\0', "COMMAND", ""/*undocumented*/, 1504e98e3e1Schristos standard_option_handler }, 1514e98e3e1Schristos 1524e98e3e1Schristos { {"help", no_argument, NULL, OPTION_HELP}, 1534b169a6bSchristos 'h', NULL, "Print help information", 1544e98e3e1Schristos standard_option_handler }, 155212397c6Schristos { {"version", no_argument, NULL, OPTION_VERSION}, 156212397c6Schristos '\0', NULL, "Print version information", 157212397c6Schristos standard_option_handler }, 1584e98e3e1Schristos 1594e98e3e1Schristos { {"architecture", required_argument, NULL, OPTION_ARCHITECTURE}, 1604e98e3e1Schristos '\0', "MACHINE", "Specify the architecture to use", 1614e98e3e1Schristos standard_option_handler }, 1624e98e3e1Schristos { {"architecture-info", no_argument, NULL, OPTION_ARCHITECTURE_INFO}, 1634e98e3e1Schristos '\0', NULL, "List supported architectures", 1644e98e3e1Schristos standard_option_handler }, 1654e98e3e1Schristos { {"info-architecture", no_argument, NULL, OPTION_ARCHITECTURE_INFO}, 1664e98e3e1Schristos '\0', NULL, NULL, 1674e98e3e1Schristos standard_option_handler }, 1684e98e3e1Schristos 1694e98e3e1Schristos { {"target", required_argument, NULL, OPTION_TARGET}, 1704e98e3e1Schristos '\0', "BFDNAME", "Specify the object-code format for the object files", 1714e98e3e1Schristos standard_option_handler }, 1724b169a6bSchristos { {"target-info", no_argument, NULL, OPTION_TARGET_INFO}, 1734b169a6bSchristos '\0', NULL, "List supported targets", standard_option_handler }, 1744b169a6bSchristos { {"info-target", no_argument, NULL, OPTION_TARGET_INFO}, 1754b169a6bSchristos '\0', NULL, NULL, standard_option_handler }, 1764e98e3e1Schristos 1774e98e3e1Schristos { {"load-lma", no_argument, NULL, OPTION_LOAD_LMA}, 1784e98e3e1Schristos '\0', NULL, 1794e98e3e1Schristos "Use VMA or LMA addresses when loading image (default LMA)", 1804e98e3e1Schristos standard_option_handler, "load-{lma,vma}" }, 1814e98e3e1Schristos { {"load-vma", no_argument, NULL, OPTION_LOAD_VMA}, 1824e98e3e1Schristos '\0', NULL, "", standard_option_handler, "" }, 1834e98e3e1Schristos 1844e98e3e1Schristos { {"sysroot", required_argument, NULL, OPTION_SYSROOT}, 1854e98e3e1Schristos '\0', "SYSROOT", 1864e98e3e1Schristos "Root for system calls with absolute file-names and cwd at start", 1874e98e3e1Schristos standard_option_handler, NULL }, 1884e98e3e1Schristos 1894b169a6bSchristos { {"argv0", required_argument, NULL, OPTION_ARGV0}, 1904b169a6bSchristos '\0', "ARGV0", "Set argv[0] to the specified string", 1914b169a6bSchristos standard_option_handler, NULL }, 1924b169a6bSchristos 1934b169a6bSchristos { {"env-set", required_argument, NULL, OPTION_ENV_SET}, 1944b169a6bSchristos '\0', "VAR=VAL", "Set the variable in the program's environment", 1954b169a6bSchristos standard_option_handler, NULL }, 1964b169a6bSchristos { {"env-unset", required_argument, NULL, OPTION_ENV_UNSET}, 1974b169a6bSchristos '\0', "VAR", "Unset the variable in the program's environment", 1984b169a6bSchristos standard_option_handler, NULL }, 1994b169a6bSchristos { {"env-clear", no_argument, NULL, OPTION_ENV_CLEAR}, 2004b169a6bSchristos '\0', NULL, "Clear the program's environment", 2014b169a6bSchristos standard_option_handler, NULL }, 2024b169a6bSchristos 2034e98e3e1Schristos { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL } 2044e98e3e1Schristos }; 2054e98e3e1Schristos 2064e98e3e1Schristos static SIM_RC 2074b169a6bSchristos env_set (SIM_DESC sd, const char *arg) 2084b169a6bSchristos { 2094b169a6bSchristos int i, varlen; 2104b169a6bSchristos char *eq; 2114b169a6bSchristos char **envp; 2124b169a6bSchristos 2134b169a6bSchristos if (STATE_PROG_ENVP (sd) == NULL) 2144b169a6bSchristos STATE_PROG_ENVP (sd) = dupargv (environ); 2154b169a6bSchristos 2164b169a6bSchristos eq = strchr (arg, '='); 2174b169a6bSchristos if (eq == NULL) 2184b169a6bSchristos { 2194b169a6bSchristos sim_io_eprintf (sd, "invalid syntax when setting env var `%s'" 2204b169a6bSchristos ": missing value", arg); 2214b169a6bSchristos return SIM_RC_FAIL; 2224b169a6bSchristos } 2234b169a6bSchristos /* Include the = in the comparison below. */ 2244b169a6bSchristos varlen = eq - arg + 1; 2254b169a6bSchristos 2264b169a6bSchristos /* If we can find an existing variable, replace it. */ 2274b169a6bSchristos envp = STATE_PROG_ENVP (sd); 2284b169a6bSchristos for (i = 0; envp[i]; ++i) 2294b169a6bSchristos { 2304b169a6bSchristos if (strncmp (envp[i], arg, varlen) == 0) 2314b169a6bSchristos { 2324b169a6bSchristos free (envp[i]); 2334b169a6bSchristos envp[i] = xstrdup (arg); 2344b169a6bSchristos break; 2354b169a6bSchristos } 2364b169a6bSchristos } 2374b169a6bSchristos 2384b169a6bSchristos /* If we didn't find the var, add it. */ 2394b169a6bSchristos if (envp[i] == NULL) 2404b169a6bSchristos { 2414b169a6bSchristos envp = xrealloc (envp, (i + 2) * sizeof (char *)); 2424b169a6bSchristos envp[i] = xstrdup (arg); 2434b169a6bSchristos envp[i + 1] = NULL; 2444b169a6bSchristos STATE_PROG_ENVP (sd) = envp; 2454b169a6bSchristos } 2464b169a6bSchristos 2474b169a6bSchristos return SIM_RC_OK; 2484b169a6bSchristos } 2494b169a6bSchristos 2504b169a6bSchristos static SIM_RC 2514e98e3e1Schristos standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, 2524e98e3e1Schristos char *arg, int is_command) 2534e98e3e1Schristos { 2544e98e3e1Schristos int i,n; 2554e98e3e1Schristos 2564e98e3e1Schristos switch ((STANDARD_OPTIONS) opt) 2574e98e3e1Schristos { 2584e98e3e1Schristos case OPTION_VERBOSE: 2594e98e3e1Schristos STATE_VERBOSE_P (sd) = 1; 2604e98e3e1Schristos break; 2614e98e3e1Schristos 2624e98e3e1Schristos case OPTION_ENDIAN: 2634b169a6bSchristos if (strcmp (arg, "big") == 0 || strcmp (arg, "B") == 0) 2644e98e3e1Schristos { 265ba340e45Schristos if (WITH_TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) 2664e98e3e1Schristos { 2674e98e3e1Schristos sim_io_eprintf (sd, "Simulator compiled for little endian only.\n"); 2684e98e3e1Schristos return SIM_RC_FAIL; 2694e98e3e1Schristos } 2704e98e3e1Schristos /* FIXME:wip: Need to set something in STATE_CONFIG. */ 271ba340e45Schristos current_target_byte_order = BFD_ENDIAN_BIG; 2724e98e3e1Schristos } 2734b169a6bSchristos else if (strcmp (arg, "little") == 0 || strcmp (arg, "L") == 0) 2744e98e3e1Schristos { 275ba340e45Schristos if (WITH_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) 2764e98e3e1Schristos { 2774e98e3e1Schristos sim_io_eprintf (sd, "Simulator compiled for big endian only.\n"); 2784e98e3e1Schristos return SIM_RC_FAIL; 2794e98e3e1Schristos } 2804e98e3e1Schristos /* FIXME:wip: Need to set something in STATE_CONFIG. */ 281ba340e45Schristos current_target_byte_order = BFD_ENDIAN_LITTLE; 2824e98e3e1Schristos } 2834e98e3e1Schristos else 2844e98e3e1Schristos { 2854e98e3e1Schristos sim_io_eprintf (sd, "Invalid endian specification `%s'\n", arg); 2864e98e3e1Schristos return SIM_RC_FAIL; 2874e98e3e1Schristos } 2884e98e3e1Schristos break; 2894e98e3e1Schristos 2904e98e3e1Schristos case OPTION_ENVIRONMENT: 2914e98e3e1Schristos if (strcmp (arg, "user") == 0) 2924e98e3e1Schristos STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT; 2934e98e3e1Schristos else if (strcmp (arg, "virtual") == 0) 2944e98e3e1Schristos STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; 2954e98e3e1Schristos else if (strcmp (arg, "operating") == 0) 2964e98e3e1Schristos STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT; 2974e98e3e1Schristos else 2984e98e3e1Schristos { 2994e98e3e1Schristos sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg); 3004e98e3e1Schristos return SIM_RC_FAIL; 3014e98e3e1Schristos } 3024e98e3e1Schristos if (WITH_ENVIRONMENT != ALL_ENVIRONMENT 3034e98e3e1Schristos && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd)) 3044e98e3e1Schristos { 3054e98e3e1Schristos const char *type; 3064e98e3e1Schristos switch (WITH_ENVIRONMENT) 3074e98e3e1Schristos { 3084e98e3e1Schristos case USER_ENVIRONMENT: type = "user"; break; 3094e98e3e1Schristos case VIRTUAL_ENVIRONMENT: type = "virtual"; break; 3104e98e3e1Schristos case OPERATING_ENVIRONMENT: type = "operating"; break; 3114b169a6bSchristos default: abort (); 3124e98e3e1Schristos } 3134e98e3e1Schristos sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n", 3144e98e3e1Schristos type); 3154e98e3e1Schristos return SIM_RC_FAIL; 3164e98e3e1Schristos } 3174e98e3e1Schristos break; 3184e98e3e1Schristos 3194e98e3e1Schristos case OPTION_ALIGNMENT: 3204e98e3e1Schristos if (strcmp (arg, "strict") == 0) 3214e98e3e1Schristos { 3224e98e3e1Schristos if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT) 3234e98e3e1Schristos { 3244e98e3e1Schristos current_alignment = STRICT_ALIGNMENT; 3254e98e3e1Schristos break; 3264e98e3e1Schristos } 3274e98e3e1Schristos } 3284e98e3e1Schristos else if (strcmp (arg, "nonstrict") == 0) 3294e98e3e1Schristos { 3304e98e3e1Schristos if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT) 3314e98e3e1Schristos { 3324e98e3e1Schristos current_alignment = NONSTRICT_ALIGNMENT; 3334e98e3e1Schristos break; 3344e98e3e1Schristos } 3354e98e3e1Schristos } 3364e98e3e1Schristos else if (strcmp (arg, "forced") == 0) 3374e98e3e1Schristos { 3384e98e3e1Schristos if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT) 3394e98e3e1Schristos { 3404e98e3e1Schristos current_alignment = FORCED_ALIGNMENT; 3414e98e3e1Schristos break; 3424e98e3e1Schristos } 3434e98e3e1Schristos } 3444e98e3e1Schristos else 3454e98e3e1Schristos { 3464e98e3e1Schristos sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg); 3474e98e3e1Schristos return SIM_RC_FAIL; 3484e98e3e1Schristos } 3494e98e3e1Schristos switch (WITH_ALIGNMENT) 3504e98e3e1Schristos { 3514e98e3e1Schristos case STRICT_ALIGNMENT: 3524e98e3e1Schristos sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n"); 3534e98e3e1Schristos break; 3544e98e3e1Schristos case NONSTRICT_ALIGNMENT: 3554e98e3e1Schristos sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n"); 3564e98e3e1Schristos break; 3574e98e3e1Schristos case FORCED_ALIGNMENT: 3584e98e3e1Schristos sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n"); 3594e98e3e1Schristos break; 3604b169a6bSchristos default: abort (); 3614e98e3e1Schristos } 3624e98e3e1Schristos return SIM_RC_FAIL; 3634e98e3e1Schristos 3644e98e3e1Schristos case OPTION_DEBUG: 3654e98e3e1Schristos if (! WITH_DEBUG) 3664e98e3e1Schristos sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n"); 3674e98e3e1Schristos else 3684e98e3e1Schristos { 3694e98e3e1Schristos for (n = 0; n < MAX_NR_PROCESSORS; ++n) 3704e98e3e1Schristos for (i = 0; i < MAX_DEBUG_VALUES; ++i) 3714e98e3e1Schristos CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[i] = 1; 3724e98e3e1Schristos } 3734e98e3e1Schristos break; 3744e98e3e1Schristos 3754e98e3e1Schristos case OPTION_DEBUG_INSN : 3764e98e3e1Schristos if (! WITH_DEBUG) 3774e98e3e1Schristos sim_io_eprintf (sd, "Debugging not compiled in, `--debug-insn' ignored\n"); 3784e98e3e1Schristos else 3794e98e3e1Schristos { 3804e98e3e1Schristos for (n = 0; n < MAX_NR_PROCESSORS; ++n) 3814e98e3e1Schristos CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[DEBUG_INSN_IDX] = 1; 3824e98e3e1Schristos } 3834e98e3e1Schristos break; 3844e98e3e1Schristos 3854e98e3e1Schristos case OPTION_DEBUG_FILE : 3864e98e3e1Schristos if (! WITH_DEBUG) 3874e98e3e1Schristos sim_io_eprintf (sd, "Debugging not compiled in, `--debug-file' ignored\n"); 3884e98e3e1Schristos else 3894e98e3e1Schristos { 3904e98e3e1Schristos FILE *f = fopen (arg, "w"); 3914e98e3e1Schristos 3924e98e3e1Schristos if (f == NULL) 3934e98e3e1Schristos { 3944e98e3e1Schristos sim_io_eprintf (sd, "Unable to open debug output file `%s'\n", arg); 3954e98e3e1Schristos return SIM_RC_FAIL; 3964e98e3e1Schristos } 3974e98e3e1Schristos for (n = 0; n < MAX_NR_PROCESSORS; ++n) 3984e98e3e1Schristos CPU_DEBUG_FILE (STATE_CPU (sd, n)) = f; 3994e98e3e1Schristos } 4004e98e3e1Schristos break; 4014e98e3e1Schristos 4024e98e3e1Schristos case OPTION_DO_COMMAND: 4034e98e3e1Schristos sim_do_command (sd, arg); 4044e98e3e1Schristos break; 4054e98e3e1Schristos 4064e98e3e1Schristos case OPTION_ARCHITECTURE: 4074e98e3e1Schristos { 4084e98e3e1Schristos const struct bfd_arch_info *ap = bfd_scan_arch (arg); 4094e98e3e1Schristos if (ap == NULL) 4104e98e3e1Schristos { 4114e98e3e1Schristos sim_io_eprintf (sd, "Architecture `%s' unknown\n", arg); 4124e98e3e1Schristos return SIM_RC_FAIL; 4134e98e3e1Schristos } 4144e98e3e1Schristos STATE_ARCHITECTURE (sd) = ap; 4154e98e3e1Schristos break; 4164e98e3e1Schristos } 4174e98e3e1Schristos 4184e98e3e1Schristos case OPTION_ARCHITECTURE_INFO: 4194e98e3e1Schristos { 4204e98e3e1Schristos const char **list = bfd_arch_list (); 4214e98e3e1Schristos const char **lp; 4224e98e3e1Schristos if (list == NULL) 4234e98e3e1Schristos abort (); 4244e98e3e1Schristos sim_io_printf (sd, "Possible architectures:"); 4254e98e3e1Schristos for (lp = list; *lp != NULL; lp++) 4264e98e3e1Schristos sim_io_printf (sd, " %s", *lp); 4274e98e3e1Schristos sim_io_printf (sd, "\n"); 4284e98e3e1Schristos free (list); 4294e98e3e1Schristos break; 4304e98e3e1Schristos } 4314e98e3e1Schristos 4324e98e3e1Schristos case OPTION_TARGET: 4334e98e3e1Schristos { 4344e98e3e1Schristos STATE_TARGET (sd) = xstrdup (arg); 4354e98e3e1Schristos break; 4364e98e3e1Schristos } 4374e98e3e1Schristos 4384b169a6bSchristos case OPTION_TARGET_INFO: 4394b169a6bSchristos { 4404b169a6bSchristos const char **list = bfd_target_list (); 4414b169a6bSchristos const char **lp; 4424b169a6bSchristos if (list == NULL) 4434b169a6bSchristos abort (); 4444b169a6bSchristos sim_io_printf (sd, "Possible targets:"); 4454b169a6bSchristos for (lp = list; *lp != NULL; lp++) 4464b169a6bSchristos sim_io_printf (sd, " %s", *lp); 4474b169a6bSchristos sim_io_printf (sd, "\n"); 4484b169a6bSchristos free (list); 4494b169a6bSchristos break; 4504b169a6bSchristos } 4514b169a6bSchristos 4524e98e3e1Schristos case OPTION_LOAD_LMA: 4534e98e3e1Schristos { 4544e98e3e1Schristos STATE_LOAD_AT_LMA_P (sd) = 1; 4554e98e3e1Schristos break; 4564e98e3e1Schristos } 4574e98e3e1Schristos 4584e98e3e1Schristos case OPTION_LOAD_VMA: 4594e98e3e1Schristos { 4604e98e3e1Schristos STATE_LOAD_AT_LMA_P (sd) = 0; 4614e98e3e1Schristos break; 4624e98e3e1Schristos } 4634e98e3e1Schristos 4644e98e3e1Schristos case OPTION_HELP: 4654e98e3e1Schristos sim_print_help (sd, is_command); 4664e98e3e1Schristos if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 4674e98e3e1Schristos exit (0); 4684e98e3e1Schristos /* FIXME: 'twould be nice to do something similar if gdb. */ 4694e98e3e1Schristos break; 4704e98e3e1Schristos 471212397c6Schristos case OPTION_VERSION: 4724b169a6bSchristos sim_print_version (sd, is_command); 473212397c6Schristos if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 474212397c6Schristos exit (0); 475212397c6Schristos break; 476212397c6Schristos 4774e98e3e1Schristos case OPTION_SYSROOT: 4784e98e3e1Schristos /* Don't leak memory in the odd event that there's lots of 479a2e2270fSchristos --sysroot=... options. We treat "" specially since this 480a2e2270fSchristos is the statically initialized value and cannot free it. */ 481a2e2270fSchristos if (simulator_sysroot[0] != '\0') 4824e98e3e1Schristos free (simulator_sysroot); 483a2e2270fSchristos if (arg[0] != '\0') 4844e98e3e1Schristos simulator_sysroot = xstrdup (arg); 485a2e2270fSchristos else 486a2e2270fSchristos simulator_sysroot = ""; 4874e98e3e1Schristos break; 4884b169a6bSchristos 4894b169a6bSchristos case OPTION_ARGV0: 4904b169a6bSchristos free (STATE_PROG_ARGV0 (sd)); 4914b169a6bSchristos STATE_PROG_ARGV0 (sd) = xstrdup (arg); 4924b169a6bSchristos break; 4934b169a6bSchristos 4944b169a6bSchristos case OPTION_ENV_SET: 4954b169a6bSchristos return env_set (sd, arg); 4964b169a6bSchristos 4974b169a6bSchristos case OPTION_ENV_UNSET: 4984b169a6bSchristos { 499*0d3e0572Schristos int varlen; 5004b169a6bSchristos char **envp; 5014b169a6bSchristos 5024b169a6bSchristos if (STATE_PROG_ENVP (sd) == NULL) 5034b169a6bSchristos STATE_PROG_ENVP (sd) = dupargv (environ); 5044b169a6bSchristos 5054b169a6bSchristos varlen = strlen (arg); 5064b169a6bSchristos 5074b169a6bSchristos /* If we can find an existing variable, replace it. */ 5084b169a6bSchristos envp = STATE_PROG_ENVP (sd); 5094b169a6bSchristos for (i = 0; envp[i]; ++i) 5104b169a6bSchristos { 5114b169a6bSchristos char *env = envp[i]; 5124b169a6bSchristos 5134b169a6bSchristos if (strncmp (env, arg, varlen) == 0 5144b169a6bSchristos && (env[varlen] == '\0' || env[varlen] == '=')) 5154b169a6bSchristos { 5164b169a6bSchristos free (envp[i]); 5174b169a6bSchristos break; 5184b169a6bSchristos } 5194b169a6bSchristos } 5204b169a6bSchristos 5214b169a6bSchristos /* If we clear the var, shift the array down. */ 5224b169a6bSchristos for (; envp[i]; ++i) 5234b169a6bSchristos envp[i] = envp[i + 1]; 5244b169a6bSchristos 5254b169a6bSchristos break; 5264b169a6bSchristos } 5274b169a6bSchristos 5284b169a6bSchristos case OPTION_ENV_CLEAR: 5294b169a6bSchristos freeargv (STATE_PROG_ENVP (sd)); 5304b169a6bSchristos STATE_PROG_ENVP (sd) = xmalloc (sizeof (char *)); 5314b169a6bSchristos STATE_PROG_ENVP (sd)[0] = NULL; 5324b169a6bSchristos break; 5334e98e3e1Schristos } 5344e98e3e1Schristos 5354e98e3e1Schristos return SIM_RC_OK; 5364e98e3e1Schristos } 5374e98e3e1Schristos 5384e98e3e1Schristos /* Add the standard option list to the simulator. */ 5394e98e3e1Schristos 5404e98e3e1Schristos SIM_RC 5414e98e3e1Schristos standard_install (SIM_DESC sd) 5424e98e3e1Schristos { 5434e98e3e1Schristos SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 5444e98e3e1Schristos if (sim_add_option_table (sd, NULL, standard_options) != SIM_RC_OK) 5454e98e3e1Schristos return SIM_RC_FAIL; 546ba340e45Schristos STATE_LOAD_AT_LMA_P (sd) = 1; 5474e98e3e1Schristos return SIM_RC_OK; 5484e98e3e1Schristos } 5494e98e3e1Schristos 5504e98e3e1Schristos /* Return non-zero if arg is a duplicate argument. 5514e98e3e1Schristos If ARG is NULL, initialize. */ 5524e98e3e1Schristos 5534e98e3e1Schristos static int 5544e98e3e1Schristos dup_arg_p (const char *arg) 5554e98e3e1Schristos { 5564b169a6bSchristos static htab_t arg_table = NULL; 5574b169a6bSchristos void **slot; 5584e98e3e1Schristos 5594e98e3e1Schristos if (arg == NULL) 5604e98e3e1Schristos { 5614e98e3e1Schristos if (arg_table == NULL) 5624b169a6bSchristos arg_table = htab_create_alloc (10, htab_hash_string, 5634b169a6bSchristos htab_eq_string, NULL, 5644b169a6bSchristos xcalloc, free); 5654b169a6bSchristos htab_empty (arg_table); 5664e98e3e1Schristos return 0; 5674e98e3e1Schristos } 5684e98e3e1Schristos 5694b169a6bSchristos slot = htab_find_slot (arg_table, arg, INSERT); 5704b169a6bSchristos if (*slot != NULL) 5714e98e3e1Schristos return 1; 5724b169a6bSchristos *slot = (void *) arg; 5734e98e3e1Schristos return 0; 5744e98e3e1Schristos } 5754e98e3e1Schristos 5764e98e3e1Schristos /* Called by sim_open to parse the arguments. */ 5774e98e3e1Schristos 5784e98e3e1Schristos SIM_RC 579ba340e45Schristos sim_parse_args (SIM_DESC sd, char * const *argv) 5804e98e3e1Schristos { 581ba340e45Schristos int c, i, argc, num_opts, save_opterr; 5824e98e3e1Schristos char *p, *short_options; 5834e98e3e1Schristos /* The `val' option struct entry is dynamically assigned for options that 5844e98e3e1Schristos only come in the long form. ORIG_VAL is used to get the original value 5854e98e3e1Schristos back. */ 5864e98e3e1Schristos int *orig_val; 5874e98e3e1Schristos struct option *lp, *long_options; 5884e98e3e1Schristos const struct option_list *ol; 5894e98e3e1Schristos const OPTION *opt; 5904e98e3e1Schristos OPTION_HANDLER **handlers; 5914e98e3e1Schristos sim_cpu **opt_cpu; 5924e98e3e1Schristos SIM_RC result = SIM_RC_OK; 5934e98e3e1Schristos 5944e98e3e1Schristos /* Count the number of arguments. */ 595ba340e45Schristos argc = countargv (argv); 5964e98e3e1Schristos 5974e98e3e1Schristos /* Count the number of options. */ 5984e98e3e1Schristos num_opts = 0; 5994e98e3e1Schristos for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) 6004e98e3e1Schristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 6014e98e3e1Schristos ++num_opts; 6024e98e3e1Schristos for (i = 0; i < MAX_NR_PROCESSORS; ++i) 6034e98e3e1Schristos for (ol = CPU_OPTIONS (STATE_CPU (sd, i)); ol != NULL; ol = ol->next) 6044e98e3e1Schristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 6054e98e3e1Schristos ++num_opts; 6064e98e3e1Schristos 6074e98e3e1Schristos /* Initialize duplicate argument checker. */ 6084e98e3e1Schristos (void) dup_arg_p (NULL); 6094e98e3e1Schristos 6104e98e3e1Schristos /* Build the option table for getopt. */ 6114e98e3e1Schristos 6124e98e3e1Schristos long_options = NZALLOC (struct option, num_opts + 1); 6134e98e3e1Schristos lp = long_options; 6144e98e3e1Schristos short_options = NZALLOC (char, num_opts * 3 + 1); 6154e98e3e1Schristos p = short_options; 6164e98e3e1Schristos handlers = NZALLOC (OPTION_HANDLER *, OPTION_START + num_opts); 6174e98e3e1Schristos orig_val = NZALLOC (int, OPTION_START + num_opts); 6184e98e3e1Schristos opt_cpu = NZALLOC (sim_cpu *, OPTION_START + num_opts); 6194e98e3e1Schristos 6204e98e3e1Schristos /* Set '+' as first char so argument permutation isn't done. This 6214e98e3e1Schristos is done to stop getopt_long returning options that appear after 6224e98e3e1Schristos the target program. Such options should be passed unchanged into 6234e98e3e1Schristos the program image. */ 6244e98e3e1Schristos *p++ = '+'; 6254e98e3e1Schristos 6264e98e3e1Schristos for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) 6274e98e3e1Schristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 6284e98e3e1Schristos { 6294e98e3e1Schristos if (dup_arg_p (opt->opt.name)) 6304e98e3e1Schristos continue; 6314e98e3e1Schristos if (opt->shortopt != 0) 6324e98e3e1Schristos { 6334e98e3e1Schristos *p++ = opt->shortopt; 6344e98e3e1Schristos if (opt->opt.has_arg == required_argument) 6354e98e3e1Schristos *p++ = ':'; 6364e98e3e1Schristos else if (opt->opt.has_arg == optional_argument) 6374e98e3e1Schristos { *p++ = ':'; *p++ = ':'; } 6384e98e3e1Schristos handlers[(unsigned char) opt->shortopt] = opt->handler; 6394e98e3e1Schristos if (opt->opt.val != 0) 6404e98e3e1Schristos orig_val[(unsigned char) opt->shortopt] = opt->opt.val; 6414e98e3e1Schristos else 6424e98e3e1Schristos orig_val[(unsigned char) opt->shortopt] = opt->shortopt; 6434e98e3e1Schristos } 6444e98e3e1Schristos if (opt->opt.name != NULL) 6454e98e3e1Schristos { 6464e98e3e1Schristos *lp = opt->opt; 6474e98e3e1Schristos /* Dynamically assign `val' numbers for long options. */ 6484e98e3e1Schristos lp->val = i++; 6494e98e3e1Schristos handlers[lp->val] = opt->handler; 6504e98e3e1Schristos orig_val[lp->val] = opt->opt.val; 6514e98e3e1Schristos opt_cpu[lp->val] = NULL; 6524e98e3e1Schristos ++lp; 6534e98e3e1Schristos } 6544e98e3e1Schristos } 6554e98e3e1Schristos 6564e98e3e1Schristos for (c = 0; c < MAX_NR_PROCESSORS; ++c) 6574e98e3e1Schristos { 6584e98e3e1Schristos sim_cpu *cpu = STATE_CPU (sd, c); 6594e98e3e1Schristos for (ol = CPU_OPTIONS (cpu); ol != NULL; ol = ol->next) 6604e98e3e1Schristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 6614e98e3e1Schristos { 6624e98e3e1Schristos #if 0 /* Each option is prepended with --<cpuname>- so this greatly cuts down 6634e98e3e1Schristos on the need for dup_arg_p checking. Maybe in the future it'll be 6644e98e3e1Schristos needed so this is just commented out, and not deleted. */ 6654e98e3e1Schristos if (dup_arg_p (opt->opt.name)) 6664e98e3e1Schristos continue; 6674e98e3e1Schristos #endif 6684e98e3e1Schristos /* Don't allow short versions of cpu specific options for now. */ 6694e98e3e1Schristos if (opt->shortopt != 0) 6704e98e3e1Schristos { 6714e98e3e1Schristos sim_io_eprintf (sd, "internal error, short cpu specific option"); 6724e98e3e1Schristos result = SIM_RC_FAIL; 6734e98e3e1Schristos break; 6744e98e3e1Schristos } 6754e98e3e1Schristos if (opt->opt.name != NULL) 6764e98e3e1Schristos { 6774e98e3e1Schristos char *name; 6784e98e3e1Schristos *lp = opt->opt; 6794e98e3e1Schristos /* Prepend --<cpuname>- to the option. */ 6804e98e3e1Schristos if (asprintf (&name, "%s-%s", CPU_NAME (cpu), lp->name) < 0) 6814e98e3e1Schristos { 6824e98e3e1Schristos sim_io_eprintf (sd, "internal error, out of memory"); 6834e98e3e1Schristos result = SIM_RC_FAIL; 6844e98e3e1Schristos break; 6854e98e3e1Schristos } 6864e98e3e1Schristos lp->name = name; 6874e98e3e1Schristos /* Dynamically assign `val' numbers for long options. */ 6884e98e3e1Schristos lp->val = i++; 6894e98e3e1Schristos handlers[lp->val] = opt->handler; 6904e98e3e1Schristos orig_val[lp->val] = opt->opt.val; 6914e98e3e1Schristos opt_cpu[lp->val] = cpu; 6924e98e3e1Schristos ++lp; 6934e98e3e1Schristos } 6944e98e3e1Schristos } 6954e98e3e1Schristos } 6964e98e3e1Schristos 6974e98e3e1Schristos /* Terminate the short and long option lists. */ 6984e98e3e1Schristos *p = 0; 6994e98e3e1Schristos lp->name = NULL; 7004e98e3e1Schristos 7014e98e3e1Schristos /* Ensure getopt is initialized. */ 7024e98e3e1Schristos optind = 0; 7034e98e3e1Schristos 704ba340e45Schristos /* Do not lot getopt throw errors for us. But don't mess with the state for 705ba340e45Schristos any callers higher up by saving/restoring it. */ 706ba340e45Schristos save_opterr = opterr; 707ba340e45Schristos opterr = 0; 708ba340e45Schristos 7094e98e3e1Schristos while (1) 7104e98e3e1Schristos { 7114e98e3e1Schristos int longind, optc; 7124e98e3e1Schristos 7134e98e3e1Schristos optc = getopt_long (argc, argv, short_options, long_options, &longind); 7144e98e3e1Schristos if (optc == -1) 7154e98e3e1Schristos { 7164e98e3e1Schristos if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 7174b169a6bSchristos { 7184b169a6bSchristos char **new_argv; 7194b169a6bSchristos 7204b169a6bSchristos free (STATE_PROG_FILE (sd)); 7214b169a6bSchristos STATE_PROG_FILE (sd) = NULL; 7224b169a6bSchristos 7234b169a6bSchristos /* Handle any inline variables if -- wasn't used. */ 7244b169a6bSchristos if (argv[optind] != NULL && optind > 0 7254b169a6bSchristos && strcmp (argv[optind - 1], "--") != 0) 7264b169a6bSchristos { 7274b169a6bSchristos while (1) 7284b169a6bSchristos { 7294b169a6bSchristos const char *arg = argv[optind]; 7304b169a6bSchristos 7314b169a6bSchristos if (strchr (arg, '=') == NULL) 7324b169a6bSchristos break; 7334b169a6bSchristos 7344b169a6bSchristos env_set (sd, arg); 7354b169a6bSchristos ++optind; 7364b169a6bSchristos } 7374b169a6bSchristos } 7384b169a6bSchristos 7394b169a6bSchristos new_argv = dupargv (argv + optind); 7404b169a6bSchristos freeargv (STATE_PROG_ARGV (sd)); 7414b169a6bSchristos STATE_PROG_ARGV (sd) = new_argv; 7424b169a6bSchristos 7434b169a6bSchristos /* Skip steps when argc == 0. */ 7444b169a6bSchristos if (argv[optind] != NULL) 7454b169a6bSchristos { 7464b169a6bSchristos STATE_PROG_FILE (sd) = xstrdup (argv[optind]); 7474b169a6bSchristos 7484b169a6bSchristos if (STATE_PROG_ARGV0 (sd) != NULL) 7494b169a6bSchristos { 7504b169a6bSchristos free (new_argv[0]); 7514b169a6bSchristos new_argv[0] = xstrdup (STATE_PROG_ARGV0 (sd)); 7524b169a6bSchristos } 7534b169a6bSchristos } 7544b169a6bSchristos } 7554e98e3e1Schristos break; 7564e98e3e1Schristos } 7574e98e3e1Schristos if (optc == '?') 7584e98e3e1Schristos { 759ba340e45Schristos /* If getopt rejects a short option, optopt is set to the bad char. 760ba340e45Schristos If it rejects a long option, we have to look at optind. In the 761ba340e45Schristos short option case, argv could be multiple short options. */ 762ba340e45Schristos const char *badopt; 763ba340e45Schristos char optbuf[3]; 764ba340e45Schristos 765ba340e45Schristos if (optopt) 766ba340e45Schristos { 767ba340e45Schristos sprintf (optbuf, "-%c", optopt); 768ba340e45Schristos badopt = optbuf; 769ba340e45Schristos } 770ba340e45Schristos else 771ba340e45Schristos badopt = argv[optind - 1]; 772ba340e45Schristos 773ba340e45Schristos sim_io_eprintf (sd, 774ba340e45Schristos "%s: unrecognized option '%s'\n" 775ba340e45Schristos "Use --help for a complete list of options.\n", 776ba340e45Schristos STATE_MY_NAME (sd), badopt); 777ba340e45Schristos 7784e98e3e1Schristos result = SIM_RC_FAIL; 7794e98e3e1Schristos break; 7804e98e3e1Schristos } 7814e98e3e1Schristos 7824e98e3e1Schristos if ((*handlers[optc]) (sd, opt_cpu[optc], orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL) 7834e98e3e1Schristos { 7844e98e3e1Schristos result = SIM_RC_FAIL; 7854e98e3e1Schristos break; 7864e98e3e1Schristos } 7874e98e3e1Schristos } 7884e98e3e1Schristos 789ba340e45Schristos opterr = save_opterr; 790ba340e45Schristos 7914e98e3e1Schristos free (long_options); 7924e98e3e1Schristos free (short_options); 7934e98e3e1Schristos free (handlers); 7944e98e3e1Schristos free (opt_cpu); 7954e98e3e1Schristos free (orig_val); 7964e98e3e1Schristos return result; 7974e98e3e1Schristos } 7984e98e3e1Schristos 7994e98e3e1Schristos /* Utility of sim_print_help to print a list of option tables. */ 8004e98e3e1Schristos 8014e98e3e1Schristos static void 8024e98e3e1Schristos print_help (SIM_DESC sd, sim_cpu *cpu, const struct option_list *ol, int is_command) 8034e98e3e1Schristos { 8044e98e3e1Schristos const OPTION *opt; 8054e98e3e1Schristos 8064e98e3e1Schristos for ( ; ol != NULL; ol = ol->next) 8074e98e3e1Schristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 8084e98e3e1Schristos { 8094e98e3e1Schristos const int indent = 30; 8104e98e3e1Schristos int comma, len; 8114e98e3e1Schristos const OPTION *o; 8124e98e3e1Schristos 8134e98e3e1Schristos if (dup_arg_p (opt->opt.name)) 8144e98e3e1Schristos continue; 8154e98e3e1Schristos 8164e98e3e1Schristos if (opt->doc == NULL) 8174e98e3e1Schristos continue; 8184e98e3e1Schristos 8194e98e3e1Schristos if (opt->doc_name != NULL && opt->doc_name [0] == '\0') 8204e98e3e1Schristos continue; 8214e98e3e1Schristos 8224e98e3e1Schristos sim_io_printf (sd, " "); 8234e98e3e1Schristos 8244e98e3e1Schristos comma = 0; 8254e98e3e1Schristos len = 2; 8264e98e3e1Schristos 8274e98e3e1Schristos /* list any short options (aliases) for the current OPT */ 8284e98e3e1Schristos if (!is_command) 8294e98e3e1Schristos { 8304e98e3e1Schristos o = opt; 8314e98e3e1Schristos do 8324e98e3e1Schristos { 8334e98e3e1Schristos if (o->shortopt != '\0') 8344e98e3e1Schristos { 8354e98e3e1Schristos sim_io_printf (sd, "%s-%c", comma ? ", " : "", o->shortopt); 8364e98e3e1Schristos len += (comma ? 2 : 0) + 2; 8374e98e3e1Schristos if (o->arg != NULL) 8384e98e3e1Schristos { 8394e98e3e1Schristos if (o->opt.has_arg == optional_argument) 8404e98e3e1Schristos { 8414e98e3e1Schristos sim_io_printf (sd, "[%s]", o->arg); 8424e98e3e1Schristos len += 1 + strlen (o->arg) + 1; 8434e98e3e1Schristos } 8444e98e3e1Schristos else 8454e98e3e1Schristos { 8464e98e3e1Schristos sim_io_printf (sd, " %s", o->arg); 8474e98e3e1Schristos len += 1 + strlen (o->arg); 8484e98e3e1Schristos } 8494e98e3e1Schristos } 8504e98e3e1Schristos comma = 1; 8514e98e3e1Schristos } 8524e98e3e1Schristos ++o; 8534e98e3e1Schristos } 8544e98e3e1Schristos while (OPTION_VALID_P (o) && o->doc == NULL); 8554e98e3e1Schristos } 8564e98e3e1Schristos 8574e98e3e1Schristos /* list any long options (aliases) for the current OPT */ 8584e98e3e1Schristos o = opt; 8594e98e3e1Schristos do 8604e98e3e1Schristos { 8614e98e3e1Schristos const char *name; 8624e98e3e1Schristos const char *cpu_prefix = cpu ? CPU_NAME (cpu) : NULL; 8634e98e3e1Schristos if (o->doc_name != NULL) 8644e98e3e1Schristos name = o->doc_name; 8654e98e3e1Schristos else 8664e98e3e1Schristos name = o->opt.name; 8674e98e3e1Schristos if (name != NULL) 8684e98e3e1Schristos { 8694e98e3e1Schristos sim_io_printf (sd, "%s%s%s%s%s", 8704e98e3e1Schristos comma ? ", " : "", 8714e98e3e1Schristos is_command ? "" : "--", 8724e98e3e1Schristos cpu ? cpu_prefix : "", 8734e98e3e1Schristos cpu ? "-" : "", 8744e98e3e1Schristos name); 8754e98e3e1Schristos len += ((comma ? 2 : 0) 8764e98e3e1Schristos + (is_command ? 0 : 2) 8774e98e3e1Schristos + strlen (name)); 8784e98e3e1Schristos if (o->arg != NULL) 8794e98e3e1Schristos { 8804e98e3e1Schristos if (o->opt.has_arg == optional_argument) 8814e98e3e1Schristos { 8824e98e3e1Schristos sim_io_printf (sd, "[=%s]", o->arg); 8834e98e3e1Schristos len += 2 + strlen (o->arg) + 1; 8844e98e3e1Schristos } 8854e98e3e1Schristos else 8864e98e3e1Schristos { 8874e98e3e1Schristos sim_io_printf (sd, " %s", o->arg); 8884e98e3e1Schristos len += 1 + strlen (o->arg); 8894e98e3e1Schristos } 8904e98e3e1Schristos } 8914e98e3e1Schristos comma = 1; 8924e98e3e1Schristos } 8934e98e3e1Schristos ++o; 8944e98e3e1Schristos } 8954e98e3e1Schristos while (OPTION_VALID_P (o) && o->doc == NULL); 8964e98e3e1Schristos 8974e98e3e1Schristos if (len >= indent) 8984e98e3e1Schristos { 8994e98e3e1Schristos sim_io_printf (sd, "\n%*s", indent, ""); 9004e98e3e1Schristos } 9014e98e3e1Schristos else 9024e98e3e1Schristos sim_io_printf (sd, "%*s", indent - len, ""); 9034e98e3e1Schristos 9044e98e3e1Schristos /* print the description, word wrap long lines */ 9054e98e3e1Schristos { 9064e98e3e1Schristos const char *chp = opt->doc; 9074e98e3e1Schristos unsigned doc_width = 80 - indent; 9084e98e3e1Schristos while (strlen (chp) >= doc_width) /* some slack */ 9094e98e3e1Schristos { 9104e98e3e1Schristos const char *end = chp + doc_width - 1; 9114e98e3e1Schristos while (end > chp && !isspace (*end)) 9124e98e3e1Schristos end --; 9134e98e3e1Schristos if (end == chp) 9144e98e3e1Schristos end = chp + doc_width - 1; 9154e98e3e1Schristos /* The cast should be ok - its distances between to 9164e98e3e1Schristos points in a string. */ 9174e98e3e1Schristos sim_io_printf (sd, "%.*s\n%*s", (int) (end - chp), chp, indent, 9184e98e3e1Schristos ""); 9194e98e3e1Schristos chp = end; 9204e98e3e1Schristos while (isspace (*chp) && *chp != '\0') 9214e98e3e1Schristos chp++; 9224e98e3e1Schristos } 9234e98e3e1Schristos sim_io_printf (sd, "%s\n", chp); 9244e98e3e1Schristos } 9254e98e3e1Schristos } 9264e98e3e1Schristos } 9274e98e3e1Schristos 9284e98e3e1Schristos /* Print help messages for the options. */ 9294e98e3e1Schristos 9304e98e3e1Schristos void 9314e98e3e1Schristos sim_print_help (SIM_DESC sd, int is_command) 9324e98e3e1Schristos { 9334e98e3e1Schristos if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 9344b169a6bSchristos sim_io_printf (sd, 9354b169a6bSchristos "Usage: %s [options] [VAR=VAL|--] program [program args]\n", 9364e98e3e1Schristos STATE_MY_NAME (sd)); 9374e98e3e1Schristos 9384e98e3e1Schristos /* Initialize duplicate argument checker. */ 9394e98e3e1Schristos (void) dup_arg_p (NULL); 9404e98e3e1Schristos 9414e98e3e1Schristos if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 9424e98e3e1Schristos sim_io_printf (sd, "Options:\n"); 9434e98e3e1Schristos else 9444e98e3e1Schristos sim_io_printf (sd, "Commands:\n"); 9454e98e3e1Schristos 9464e98e3e1Schristos print_help (sd, NULL, STATE_OPTIONS (sd), is_command); 9474e98e3e1Schristos sim_io_printf (sd, "\n"); 9484e98e3e1Schristos 9494e98e3e1Schristos /* Print cpu-specific options. */ 9504e98e3e1Schristos { 9514e98e3e1Schristos int i; 9524e98e3e1Schristos 9534e98e3e1Schristos for (i = 0; i < MAX_NR_PROCESSORS; ++i) 9544e98e3e1Schristos { 9554e98e3e1Schristos sim_cpu *cpu = STATE_CPU (sd, i); 9564e98e3e1Schristos if (CPU_OPTIONS (cpu) == NULL) 9574e98e3e1Schristos continue; 9584e98e3e1Schristos sim_io_printf (sd, "CPU %s specific options:\n", CPU_NAME (cpu)); 9594e98e3e1Schristos print_help (sd, cpu, CPU_OPTIONS (cpu), is_command); 9604e98e3e1Schristos sim_io_printf (sd, "\n"); 9614e98e3e1Schristos } 9624e98e3e1Schristos } 9634e98e3e1Schristos 9644e98e3e1Schristos sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n", 9654e98e3e1Schristos STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command"); 9664e98e3e1Schristos sim_io_printf (sd, " may not be applicable\n"); 9674e98e3e1Schristos 9684e98e3e1Schristos if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 9694e98e3e1Schristos { 9704e98e3e1Schristos sim_io_printf (sd, "\n"); 9714b169a6bSchristos sim_io_printf (sd, 9724b169a6bSchristos "VAR=VAL Environment variables to set. " 9734b169a6bSchristos "Ignored if -- is used.\n"); 9744e98e3e1Schristos sim_io_printf (sd, "program args Arguments to pass to simulated program.\n"); 9754e98e3e1Schristos sim_io_printf (sd, " Note: Very few simulators support this.\n"); 9764e98e3e1Schristos } 9774e98e3e1Schristos } 9784e98e3e1Schristos 9794b169a6bSchristos /* Print version information. */ 9804b169a6bSchristos 9814b169a6bSchristos void 9824b169a6bSchristos sim_print_version (SIM_DESC sd, int is_command) 9834b169a6bSchristos { 9844b169a6bSchristos sim_io_printf (sd, "GNU simulator %s%s\n", PKGVERSION, version); 9854b169a6bSchristos 986*0d3e0572Schristos sim_io_printf (sd, "Copyright (C) 2024 Free Software Foundation, Inc.\n"); 9874b169a6bSchristos 9884b169a6bSchristos /* Following the copyright is a brief statement that the program is 9894b169a6bSchristos free software, that users are free to copy and change it on 9904b169a6bSchristos certain conditions, that it is covered by the GNU GPL, and that 9914b169a6bSchristos there is no warranty. */ 9924b169a6bSchristos 9934b169a6bSchristos sim_io_printf (sd, "\ 9944b169a6bSchristos License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\ 9954b169a6bSchristos \nThis is free software: you are free to change and redistribute it.\n\ 9964b169a6bSchristos There is NO WARRANTY, to the extent permitted by law.\n"); 9974b169a6bSchristos 9984b169a6bSchristos if (!is_command) 9994b169a6bSchristos return; 10004b169a6bSchristos 10014b169a6bSchristos sim_io_printf (sd, "This SIM was configured as:\n"); 10024b169a6bSchristos sim_config_print (sd); 10034b169a6bSchristos 10044b169a6bSchristos if (REPORT_BUGS_TO[0]) 10054b169a6bSchristos { 10064b169a6bSchristos sim_io_printf (sd, "For bug reporting instructions, please see:\n\ 10074b169a6bSchristos %s.\n", 10084b169a6bSchristos REPORT_BUGS_TO); 10094b169a6bSchristos } 10104b169a6bSchristos sim_io_printf (sd, "Find the SIM homepage & other documentation resources \ 10114b169a6bSchristos online at:\n <https://sourceware.org/gdb/wiki/Sim/>.\n"); 10124b169a6bSchristos } 10134b169a6bSchristos 10144e98e3e1Schristos /* Utility of sim_args_command to find the closest match for a command. 10154e98e3e1Schristos Commands that have "-" in them can be specified as separate words. 10164e98e3e1Schristos e.g. sim memory-region 0x800000,0x4000 10174e98e3e1Schristos or sim memory region 0x800000,0x4000 10184e98e3e1Schristos If CPU is non-null, use its option table list, otherwise use the main one. 10194e98e3e1Schristos *PARGI is where to start looking in ARGV. It is updated to point past 10204e98e3e1Schristos the found option. */ 10214e98e3e1Schristos 10224e98e3e1Schristos static const OPTION * 10234e98e3e1Schristos find_match (SIM_DESC sd, sim_cpu *cpu, char *argv[], int *pargi) 10244e98e3e1Schristos { 10254e98e3e1Schristos const struct option_list *ol; 10264e98e3e1Schristos const OPTION *opt; 10274e98e3e1Schristos /* most recent option match */ 10284e98e3e1Schristos const OPTION *matching_opt = NULL; 10294e98e3e1Schristos int matching_argi = -1; 10304e98e3e1Schristos 10314e98e3e1Schristos if (cpu) 10324e98e3e1Schristos ol = CPU_OPTIONS (cpu); 10334e98e3e1Schristos else 10344e98e3e1Schristos ol = STATE_OPTIONS (sd); 10354e98e3e1Schristos 10364e98e3e1Schristos /* Skip passed elements specified by *PARGI. */ 10374e98e3e1Schristos argv += *pargi; 10384e98e3e1Schristos 10394e98e3e1Schristos for ( ; ol != NULL; ol = ol->next) 10404e98e3e1Schristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 10414e98e3e1Schristos { 10424e98e3e1Schristos int argi = 0; 10434e98e3e1Schristos const char *name = opt->opt.name; 10444e98e3e1Schristos if (name == NULL) 10454e98e3e1Schristos continue; 10464e98e3e1Schristos while (argv [argi] != NULL 10474e98e3e1Schristos && strncmp (name, argv [argi], strlen (argv [argi])) == 0) 10484e98e3e1Schristos { 10494e98e3e1Schristos name = &name [strlen (argv[argi])]; 10504e98e3e1Schristos if (name [0] == '-') 10514e98e3e1Schristos { 10524e98e3e1Schristos /* leading match ...<a-b-c>-d-e-f - continue search */ 10534e98e3e1Schristos name ++; /* skip `-' */ 10544e98e3e1Schristos argi ++; 10554e98e3e1Schristos continue; 10564e98e3e1Schristos } 10574e98e3e1Schristos else if (name [0] == '\0') 10584e98e3e1Schristos { 10594e98e3e1Schristos /* exact match ...<a-b-c-d-e-f> - better than before? */ 10604e98e3e1Schristos if (argi > matching_argi) 10614e98e3e1Schristos { 10624e98e3e1Schristos matching_argi = argi; 10634e98e3e1Schristos matching_opt = opt; 10644e98e3e1Schristos } 10654e98e3e1Schristos break; 10664e98e3e1Schristos } 10674e98e3e1Schristos else 10684e98e3e1Schristos break; 10694e98e3e1Schristos } 10704e98e3e1Schristos } 10714e98e3e1Schristos 10724e98e3e1Schristos *pargi = matching_argi; 10734e98e3e1Schristos return matching_opt; 10744e98e3e1Schristos } 10754e98e3e1Schristos 1076a2e2270fSchristos static char ** 1077a2e2270fSchristos complete_option_list (char **ret, size_t *cnt, const struct option_list *ol, 107803467a24Schristos const char *text, const char *word) 1079a2e2270fSchristos { 1080a2e2270fSchristos const OPTION *opt = NULL; 1081a2e2270fSchristos size_t len = strlen (word); 1082a2e2270fSchristos 1083a2e2270fSchristos for ( ; ol != NULL; ol = ol->next) 1084a2e2270fSchristos for (opt = ol->options; OPTION_VALID_P (opt); ++opt) 1085a2e2270fSchristos { 1086a2e2270fSchristos const char *name = opt->opt.name; 1087a2e2270fSchristos 1088a2e2270fSchristos /* A long option to match against? */ 1089a2e2270fSchristos if (!name) 1090a2e2270fSchristos continue; 1091a2e2270fSchristos 1092a2e2270fSchristos /* Does this option actually match? */ 1093a2e2270fSchristos if (strncmp (name, word, len)) 1094a2e2270fSchristos continue; 1095a2e2270fSchristos 1096a2e2270fSchristos ret = xrealloc (ret, ++*cnt * sizeof (ret[0])); 1097a2e2270fSchristos ret[*cnt - 2] = xstrdup (name); 1098a2e2270fSchristos } 1099a2e2270fSchristos 1100a2e2270fSchristos return ret; 1101a2e2270fSchristos } 1102a2e2270fSchristos 1103a2e2270fSchristos /* All leading text is stored in @text, while the current word being 1104a2e2270fSchristos completed is stored in @word. Trailing text of @word is not. */ 1105a2e2270fSchristos 1106a2e2270fSchristos char ** 110703467a24Schristos sim_complete_command (SIM_DESC sd, const char *text, const char *word) 1108a2e2270fSchristos { 1109a2e2270fSchristos char **ret = NULL; 1110a2e2270fSchristos size_t cnt = 1; 1111a2e2270fSchristos sim_cpu *cpu; 1112a2e2270fSchristos 1113a2e2270fSchristos /* Only complete first word for now. */ 1114a2e2270fSchristos if (text != word) 1115a2e2270fSchristos return ret; 1116a2e2270fSchristos 1117a2e2270fSchristos cpu = STATE_CPU (sd, 0); 1118a2e2270fSchristos if (cpu) 1119a2e2270fSchristos ret = complete_option_list (ret, &cnt, CPU_OPTIONS (cpu), text, word); 1120a2e2270fSchristos ret = complete_option_list (ret, &cnt, STATE_OPTIONS (sd), text, word); 1121a2e2270fSchristos 1122a2e2270fSchristos if (ret) 1123a2e2270fSchristos ret[cnt - 1] = NULL; 1124a2e2270fSchristos return ret; 1125a2e2270fSchristos } 1126a2e2270fSchristos 11274e98e3e1Schristos SIM_RC 1128837edd6bSchristos sim_args_command (SIM_DESC sd, const char *cmd) 11294e98e3e1Schristos { 11304e98e3e1Schristos /* something to do? */ 11314e98e3e1Schristos if (cmd == NULL) 11324e98e3e1Schristos return SIM_RC_OK; /* FIXME - perhaps help would be better */ 11334e98e3e1Schristos 11344e98e3e1Schristos if (cmd [0] == '-') 11354e98e3e1Schristos { 11364e98e3e1Schristos /* user specified -<opt> ... form? */ 11374e98e3e1Schristos char **argv = buildargv (cmd); 11384e98e3e1Schristos SIM_RC rc = sim_parse_args (sd, argv); 11394e98e3e1Schristos freeargv (argv); 11404e98e3e1Schristos return rc; 11414e98e3e1Schristos } 11424e98e3e1Schristos else 11434e98e3e1Schristos { 11444e98e3e1Schristos char **argv = buildargv (cmd); 11454e98e3e1Schristos const OPTION *matching_opt = NULL; 11464e98e3e1Schristos int matching_argi; 11474e98e3e1Schristos sim_cpu *cpu; 11484e98e3e1Schristos 11494e98e3e1Schristos if (argv [0] == NULL) 1150212397c6Schristos { 1151212397c6Schristos freeargv (argv); 11524e98e3e1Schristos return SIM_RC_OK; /* FIXME - perhaps help would be better */ 1153212397c6Schristos } 11544e98e3e1Schristos 11554e98e3e1Schristos /* First check for a cpu selector. */ 11564e98e3e1Schristos { 11574e98e3e1Schristos char *cpu_name = xstrdup (argv[0]); 11584e98e3e1Schristos char *hyphen = strchr (cpu_name, '-'); 11594e98e3e1Schristos if (hyphen) 11604e98e3e1Schristos *hyphen = 0; 11614e98e3e1Schristos cpu = sim_cpu_lookup (sd, cpu_name); 11624e98e3e1Schristos if (cpu) 11634e98e3e1Schristos { 11644e98e3e1Schristos /* If <cpuname>-<command>, point argv[0] at <command>. */ 11654e98e3e1Schristos if (hyphen) 11664e98e3e1Schristos { 11674e98e3e1Schristos matching_argi = 0; 11684e98e3e1Schristos argv[0] += hyphen - cpu_name + 1; 11694e98e3e1Schristos } 11704e98e3e1Schristos else 11714e98e3e1Schristos matching_argi = 1; 11724e98e3e1Schristos matching_opt = find_match (sd, cpu, argv, &matching_argi); 11734e98e3e1Schristos /* If hyphen found restore argv[0]. */ 11744e98e3e1Schristos if (hyphen) 11754e98e3e1Schristos argv[0] -= hyphen - cpu_name + 1; 11764e98e3e1Schristos } 11774e98e3e1Schristos free (cpu_name); 11784e98e3e1Schristos } 11794e98e3e1Schristos 11804e98e3e1Schristos /* If that failed, try the main table. */ 11814e98e3e1Schristos if (matching_opt == NULL) 11824e98e3e1Schristos { 11834e98e3e1Schristos matching_argi = 0; 11844e98e3e1Schristos matching_opt = find_match (sd, NULL, argv, &matching_argi); 11854e98e3e1Schristos } 11864e98e3e1Schristos 11874e98e3e1Schristos if (matching_opt != NULL) 11884e98e3e1Schristos { 11894e98e3e1Schristos switch (matching_opt->opt.has_arg) 11904e98e3e1Schristos { 11914e98e3e1Schristos case no_argument: 11924e98e3e1Schristos if (argv [matching_argi + 1] == NULL) 11934e98e3e1Schristos matching_opt->handler (sd, cpu, matching_opt->opt.val, 11944e98e3e1Schristos NULL, 1/*is_command*/); 11954e98e3e1Schristos else 11964e98e3e1Schristos sim_io_eprintf (sd, "Command `%s' takes no arguments\n", 11974e98e3e1Schristos matching_opt->opt.name); 11984e98e3e1Schristos break; 11994e98e3e1Schristos case optional_argument: 12004e98e3e1Schristos if (argv [matching_argi + 1] == NULL) 12014e98e3e1Schristos matching_opt->handler (sd, cpu, matching_opt->opt.val, 12024e98e3e1Schristos NULL, 1/*is_command*/); 12034e98e3e1Schristos else if (argv [matching_argi + 2] == NULL) 12044e98e3e1Schristos matching_opt->handler (sd, cpu, matching_opt->opt.val, 12054e98e3e1Schristos argv [matching_argi + 1], 1/*is_command*/); 12064e98e3e1Schristos else 12074e98e3e1Schristos sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n", 12084e98e3e1Schristos matching_opt->opt.name); 12094e98e3e1Schristos break; 12104e98e3e1Schristos case required_argument: 12114e98e3e1Schristos if (argv [matching_argi + 1] == NULL) 12124e98e3e1Schristos sim_io_eprintf (sd, "Command `%s' requires an argument\n", 12134e98e3e1Schristos matching_opt->opt.name); 12144e98e3e1Schristos else if (argv [matching_argi + 2] == NULL) 12154e98e3e1Schristos matching_opt->handler (sd, cpu, matching_opt->opt.val, 12164e98e3e1Schristos argv [matching_argi + 1], 1/*is_command*/); 12174e98e3e1Schristos else 12184e98e3e1Schristos sim_io_eprintf (sd, "Command `%s' requires only one argument\n", 12194e98e3e1Schristos matching_opt->opt.name); 12204e98e3e1Schristos } 12214e98e3e1Schristos freeargv (argv); 12224e98e3e1Schristos return SIM_RC_OK; 12234e98e3e1Schristos } 12244e98e3e1Schristos 12254e98e3e1Schristos freeargv (argv); 12264e98e3e1Schristos } 12274e98e3e1Schristos 12284e98e3e1Schristos /* didn't find anything that remotly matched */ 12294e98e3e1Schristos return SIM_RC_FAIL; 12304e98e3e1Schristos } 1231