xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/sim-options.c (revision 0d3e0572e40d81edb4fdbff937458d47b685c34c)
1 /* Simulator option handling.
2    Copyright (C) 1996-2024 Free Software Foundation, Inc.
3    Contributed by Cygnus Support.
4 
5 This file is part of GDB, the GNU debugger.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 /* This must come before any other includes.  */
21 #include "defs.h"
22 
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "bfd.h"
30 #include "environ.h"
31 #include "hashtab.h"
32 #include "libiberty.h"
33 
34 #include "sim-main.h"
35 #include "sim-options.h"
36 #include "sim-io.h"
37 #include "sim-assert.h"
38 #include "version.h"
39 
40 /* Add a set of options to the simulator.
41    TABLE is an array of OPTIONS terminated by a NULL `opt.name' entry.
42    This is intended to be called by modules in their `install' handler.  */
43 
44 SIM_RC
45 sim_add_option_table (SIM_DESC sd, sim_cpu *cpu, const OPTION *table)
46 {
47   struct option_list *ol = ((struct option_list *)
48 			    xmalloc (sizeof (struct option_list)));
49 
50   /* Note: The list is constructed in the reverse order we're called so
51      later calls will override earlier ones (in case that ever happens).
52      This is the intended behaviour.  */
53 
54   if (cpu)
55     {
56       ol->next = CPU_OPTIONS (cpu);
57       ol->options = table;
58       CPU_OPTIONS (cpu) = ol;
59     }
60   else
61     {
62       ol->next = STATE_OPTIONS (sd);
63       ol->options = table;
64       STATE_OPTIONS (sd) = ol;
65     }
66 
67   return SIM_RC_OK;
68 }
69 
70 /* Standard option table.
71    Modules may specify additional ones.
72    The caller of sim_parse_args may also specify additional options
73    by calling sim_add_option_table first.  */
74 
75 static DECLARE_OPTION_HANDLER (standard_option_handler);
76 
77 /* FIXME: We shouldn't print in --help output options that aren't usable.
78    Some fine tuning will be necessary.  One can either move less general
79    options to another table or use a HAVE_FOO macro to ifdef out unavailable
80    options.  */
81 
82 /* ??? One might want to conditionally compile out the entries that
83    aren't enabled.  There's a distinction, however, between options a
84    simulator can't support and options that haven't been configured in.
85    Certainly options a simulator can't support shouldn't appear in the
86    output of --help.  Whether the same thing applies to options that haven't
87    been configured in or not isn't something I can get worked up over.
88    [Note that conditionally compiling them out might simply involve moving
89    the option to another table.]
90    If you decide to conditionally compile them out as well, delete this
91    comment and add a comment saying that that is the rule.  */
92 
93 typedef enum {
94   OPTION_DEBUG_INSN = OPTION_START,
95   OPTION_DEBUG_FILE,
96   OPTION_DO_COMMAND,
97   OPTION_ARCHITECTURE,
98   OPTION_TARGET,
99   OPTION_TARGET_INFO,
100   OPTION_ARCHITECTURE_INFO,
101   OPTION_ENVIRONMENT,
102   OPTION_ALIGNMENT,
103   OPTION_VERBOSE,
104   OPTION_ENDIAN,
105   OPTION_DEBUG,
106   OPTION_HELP,
107   OPTION_VERSION,
108   OPTION_LOAD_LMA,
109   OPTION_LOAD_VMA,
110   OPTION_SYSROOT,
111   OPTION_ARGV0,
112   OPTION_ENV_SET,
113   OPTION_ENV_UNSET,
114   OPTION_ENV_CLEAR,
115 } STANDARD_OPTIONS;
116 
117 static const OPTION standard_options[] =
118 {
119   { {"verbose", no_argument, NULL, OPTION_VERBOSE},
120       'v', NULL, "Verbose output",
121       standard_option_handler, NULL },
122 
123   { {"endian", required_argument, NULL, OPTION_ENDIAN},
124       'E', "B|big|L|little", "Set endianness",
125       standard_option_handler, NULL },
126 
127   /* This option isn't supported unless all choices are supported in keeping
128      with the goal of not printing in --help output things the simulator can't
129      do [as opposed to things that just haven't been configured in].  */
130   { {"environment", required_argument, NULL, OPTION_ENVIRONMENT},
131       '\0', "user|virtual|operating", "Set running environment",
132       standard_option_handler },
133 
134   { {"alignment", required_argument, NULL, OPTION_ALIGNMENT},
135       '\0', "strict|nonstrict|forced", "Set memory access alignment",
136       standard_option_handler },
137 
138   { {"debug", no_argument, NULL, OPTION_DEBUG},
139       'D', NULL, "Print debugging messages",
140       standard_option_handler },
141   { {"debug-insn", no_argument, NULL, OPTION_DEBUG_INSN},
142       '\0', NULL, "Print instruction debugging messages",
143       standard_option_handler },
144   { {"debug-file", required_argument, NULL, OPTION_DEBUG_FILE},
145       '\0', "FILE NAME", "Specify debugging output file",
146       standard_option_handler },
147 
148   { {"do-command", required_argument, NULL, OPTION_DO_COMMAND},
149       '\0', "COMMAND", ""/*undocumented*/,
150       standard_option_handler },
151 
152   { {"help", no_argument, NULL, OPTION_HELP},
153       'h', NULL, "Print help information",
154       standard_option_handler },
155   { {"version", no_argument, NULL, OPTION_VERSION},
156       '\0', NULL, "Print version information",
157       standard_option_handler },
158 
159   { {"architecture", required_argument, NULL, OPTION_ARCHITECTURE},
160       '\0', "MACHINE", "Specify the architecture to use",
161       standard_option_handler },
162   { {"architecture-info", no_argument, NULL, OPTION_ARCHITECTURE_INFO},
163       '\0', NULL, "List supported architectures",
164       standard_option_handler },
165   { {"info-architecture", no_argument, NULL, OPTION_ARCHITECTURE_INFO},
166       '\0', NULL, NULL,
167       standard_option_handler },
168 
169   { {"target", required_argument, NULL, OPTION_TARGET},
170       '\0', "BFDNAME", "Specify the object-code format for the object files",
171       standard_option_handler },
172   { {"target-info", no_argument, NULL, OPTION_TARGET_INFO},
173       '\0', NULL, "List supported targets", standard_option_handler },
174   { {"info-target", no_argument, NULL, OPTION_TARGET_INFO},
175       '\0', NULL, NULL, standard_option_handler },
176 
177   { {"load-lma", no_argument, NULL, OPTION_LOAD_LMA},
178       '\0', NULL,
179     "Use VMA or LMA addresses when loading image (default LMA)",
180       standard_option_handler, "load-{lma,vma}" },
181   { {"load-vma", no_argument, NULL, OPTION_LOAD_VMA},
182       '\0', NULL, "", standard_option_handler,  "" },
183 
184   { {"sysroot", required_argument, NULL, OPTION_SYSROOT},
185       '\0', "SYSROOT",
186     "Root for system calls with absolute file-names and cwd at start",
187       standard_option_handler, NULL },
188 
189   { {"argv0", required_argument, NULL, OPTION_ARGV0},
190       '\0', "ARGV0", "Set argv[0] to the specified string",
191       standard_option_handler, NULL },
192 
193   { {"env-set", required_argument, NULL, OPTION_ENV_SET},
194       '\0', "VAR=VAL", "Set the variable in the program's environment",
195       standard_option_handler, NULL },
196   { {"env-unset", required_argument, NULL, OPTION_ENV_UNSET},
197       '\0', "VAR", "Unset the variable in the program's environment",
198       standard_option_handler, NULL },
199   { {"env-clear", no_argument, NULL, OPTION_ENV_CLEAR},
200       '\0', NULL, "Clear the program's environment",
201       standard_option_handler, NULL },
202 
203   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
204 };
205 
206 static SIM_RC
207 env_set (SIM_DESC sd, const char *arg)
208 {
209   int i, varlen;
210   char *eq;
211   char **envp;
212 
213   if (STATE_PROG_ENVP (sd) == NULL)
214     STATE_PROG_ENVP (sd) = dupargv (environ);
215 
216   eq = strchr (arg, '=');
217   if (eq == NULL)
218     {
219       sim_io_eprintf (sd, "invalid syntax when setting env var `%s'"
220 		      ": missing value", arg);
221       return SIM_RC_FAIL;
222     }
223   /* Include the = in the comparison below.  */
224   varlen = eq - arg + 1;
225 
226   /* If we can find an existing variable, replace it.  */
227   envp = STATE_PROG_ENVP (sd);
228   for (i = 0; envp[i]; ++i)
229     {
230       if (strncmp (envp[i], arg, varlen) == 0)
231 	{
232 	  free (envp[i]);
233 	  envp[i] = xstrdup (arg);
234 	  break;
235 	}
236     }
237 
238   /* If we didn't find the var, add it.  */
239   if (envp[i] == NULL)
240     {
241       envp = xrealloc (envp, (i + 2) * sizeof (char *));
242       envp[i] = xstrdup (arg);
243       envp[i + 1] = NULL;
244       STATE_PROG_ENVP (sd) = envp;
245   }
246 
247   return SIM_RC_OK;
248 }
249 
250 static SIM_RC
251 standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
252 			 char *arg, int is_command)
253 {
254   int i,n;
255 
256   switch ((STANDARD_OPTIONS) opt)
257     {
258     case OPTION_VERBOSE:
259       STATE_VERBOSE_P (sd) = 1;
260       break;
261 
262     case OPTION_ENDIAN:
263       if (strcmp (arg, "big") == 0 || strcmp (arg, "B") == 0)
264 	{
265 	  if (WITH_TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
266 	    {
267 	      sim_io_eprintf (sd, "Simulator compiled for little endian only.\n");
268 	      return SIM_RC_FAIL;
269 	    }
270 	  /* FIXME:wip: Need to set something in STATE_CONFIG.  */
271 	  current_target_byte_order = BFD_ENDIAN_BIG;
272 	}
273       else if (strcmp (arg, "little") == 0 || strcmp (arg, "L") == 0)
274 	{
275 	  if (WITH_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
276 	    {
277 	      sim_io_eprintf (sd, "Simulator compiled for big endian only.\n");
278 	      return SIM_RC_FAIL;
279 	    }
280 	  /* FIXME:wip: Need to set something in STATE_CONFIG.  */
281 	  current_target_byte_order = BFD_ENDIAN_LITTLE;
282 	}
283       else
284 	{
285 	  sim_io_eprintf (sd, "Invalid endian specification `%s'\n", arg);
286 	  return SIM_RC_FAIL;
287 	}
288       break;
289 
290     case OPTION_ENVIRONMENT:
291       if (strcmp (arg, "user") == 0)
292 	STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT;
293       else if (strcmp (arg, "virtual") == 0)
294 	STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
295       else if (strcmp (arg, "operating") == 0)
296 	STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
297       else
298 	{
299 	  sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg);
300 	  return SIM_RC_FAIL;
301 	}
302       if (WITH_ENVIRONMENT != ALL_ENVIRONMENT
303 	  && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd))
304 	{
305 	  const char *type;
306 	  switch (WITH_ENVIRONMENT)
307 	    {
308 	    case USER_ENVIRONMENT: type = "user"; break;
309 	    case VIRTUAL_ENVIRONMENT: type = "virtual"; break;
310 	    case OPERATING_ENVIRONMENT: type = "operating"; break;
311 	    default: abort ();
312 	    }
313 	  sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n",
314 			  type);
315 	  return SIM_RC_FAIL;
316 	}
317       break;
318 
319     case OPTION_ALIGNMENT:
320       if (strcmp (arg, "strict") == 0)
321 	{
322 	  if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT)
323 	    {
324 	      current_alignment = STRICT_ALIGNMENT;
325 	      break;
326 	    }
327 	}
328       else if (strcmp (arg, "nonstrict") == 0)
329 	{
330 	  if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT)
331 	    {
332 	      current_alignment = NONSTRICT_ALIGNMENT;
333 	      break;
334 	    }
335 	}
336       else if (strcmp (arg, "forced") == 0)
337 	{
338 	  if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT)
339 	    {
340 	      current_alignment = FORCED_ALIGNMENT;
341 	      break;
342 	    }
343 	}
344       else
345 	{
346 	  sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg);
347 	  return SIM_RC_FAIL;
348 	}
349       switch (WITH_ALIGNMENT)
350 	{
351 	case STRICT_ALIGNMENT:
352 	  sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n");
353 	  break;
354 	case NONSTRICT_ALIGNMENT:
355 	  sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n");
356 	  break;
357 	case FORCED_ALIGNMENT:
358 	  sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n");
359 	  break;
360 	default: abort ();
361 	}
362       return SIM_RC_FAIL;
363 
364     case OPTION_DEBUG:
365       if (! WITH_DEBUG)
366 	sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n");
367       else
368 	{
369 	  for (n = 0; n < MAX_NR_PROCESSORS; ++n)
370 	    for (i = 0; i < MAX_DEBUG_VALUES; ++i)
371 	      CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[i] = 1;
372 	}
373       break;
374 
375     case OPTION_DEBUG_INSN :
376       if (! WITH_DEBUG)
377 	sim_io_eprintf (sd, "Debugging not compiled in, `--debug-insn' ignored\n");
378       else
379 	{
380 	  for (n = 0; n < MAX_NR_PROCESSORS; ++n)
381 	    CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[DEBUG_INSN_IDX] = 1;
382 	}
383       break;
384 
385     case OPTION_DEBUG_FILE :
386       if (! WITH_DEBUG)
387 	sim_io_eprintf (sd, "Debugging not compiled in, `--debug-file' ignored\n");
388       else
389 	{
390 	  FILE *f = fopen (arg, "w");
391 
392 	  if (f == NULL)
393 	    {
394 	      sim_io_eprintf (sd, "Unable to open debug output file `%s'\n", arg);
395 	      return SIM_RC_FAIL;
396 	    }
397 	  for (n = 0; n < MAX_NR_PROCESSORS; ++n)
398 	    CPU_DEBUG_FILE (STATE_CPU (sd, n)) = f;
399 	}
400       break;
401 
402     case OPTION_DO_COMMAND:
403       sim_do_command (sd, arg);
404       break;
405 
406     case OPTION_ARCHITECTURE:
407       {
408 	const struct bfd_arch_info *ap = bfd_scan_arch (arg);
409 	if (ap == NULL)
410 	  {
411 	    sim_io_eprintf (sd, "Architecture `%s' unknown\n", arg);
412 	    return SIM_RC_FAIL;
413 	  }
414 	STATE_ARCHITECTURE (sd) = ap;
415 	break;
416       }
417 
418     case OPTION_ARCHITECTURE_INFO:
419       {
420 	const char **list = bfd_arch_list ();
421 	const char **lp;
422 	if (list == NULL)
423 	  abort ();
424 	sim_io_printf (sd, "Possible architectures:");
425 	for (lp = list; *lp != NULL; lp++)
426 	  sim_io_printf (sd, " %s", *lp);
427 	sim_io_printf (sd, "\n");
428 	free (list);
429 	break;
430       }
431 
432     case OPTION_TARGET:
433       {
434 	STATE_TARGET (sd) = xstrdup (arg);
435 	break;
436       }
437 
438     case OPTION_TARGET_INFO:
439       {
440 	const char **list = bfd_target_list ();
441 	const char **lp;
442 	if (list == NULL)
443 	  abort ();
444 	sim_io_printf (sd, "Possible targets:");
445 	for (lp = list; *lp != NULL; lp++)
446 	  sim_io_printf (sd, " %s", *lp);
447 	sim_io_printf (sd, "\n");
448 	free (list);
449 	break;
450       }
451 
452     case OPTION_LOAD_LMA:
453       {
454 	STATE_LOAD_AT_LMA_P (sd) = 1;
455 	break;
456       }
457 
458     case OPTION_LOAD_VMA:
459       {
460 	STATE_LOAD_AT_LMA_P (sd) = 0;
461 	break;
462       }
463 
464     case OPTION_HELP:
465       sim_print_help (sd, is_command);
466       if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
467 	exit (0);
468       /* FIXME: 'twould be nice to do something similar if gdb.  */
469       break;
470 
471     case OPTION_VERSION:
472       sim_print_version (sd, is_command);
473       if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
474 	exit (0);
475       break;
476 
477     case OPTION_SYSROOT:
478       /* Don't leak memory in the odd event that there's lots of
479 	 --sysroot=... options.  We treat "" specially since this
480 	 is the statically initialized value and cannot free it.  */
481       if (simulator_sysroot[0] != '\0')
482 	free (simulator_sysroot);
483       if (arg[0] != '\0')
484 	simulator_sysroot = xstrdup (arg);
485       else
486 	simulator_sysroot = "";
487       break;
488 
489     case OPTION_ARGV0:
490       free (STATE_PROG_ARGV0 (sd));
491       STATE_PROG_ARGV0 (sd) = xstrdup (arg);
492       break;
493 
494     case OPTION_ENV_SET:
495       return env_set (sd, arg);
496 
497     case OPTION_ENV_UNSET:
498       {
499 	int varlen;
500 	char **envp;
501 
502 	if (STATE_PROG_ENVP (sd) == NULL)
503 	  STATE_PROG_ENVP (sd) = dupargv (environ);
504 
505 	varlen = strlen (arg);
506 
507 	/* If we can find an existing variable, replace it.  */
508 	envp = STATE_PROG_ENVP (sd);
509 	for (i = 0; envp[i]; ++i)
510 	  {
511 	    char *env = envp[i];
512 
513 	    if (strncmp (env, arg, varlen) == 0
514 		&& (env[varlen] == '\0' || env[varlen] == '='))
515 	      {
516 		free (envp[i]);
517 		break;
518 	      }
519 	  }
520 
521 	/* If we clear the var, shift the array down.  */
522 	for (; envp[i]; ++i)
523 	  envp[i] = envp[i + 1];
524 
525 	break;
526       }
527 
528     case OPTION_ENV_CLEAR:
529       freeargv (STATE_PROG_ENVP (sd));
530       STATE_PROG_ENVP (sd) = xmalloc (sizeof (char *));
531       STATE_PROG_ENVP (sd)[0] = NULL;
532       break;
533     }
534 
535   return SIM_RC_OK;
536 }
537 
538 /* Add the standard option list to the simulator.  */
539 
540 SIM_RC
541 standard_install (SIM_DESC sd)
542 {
543   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
544   if (sim_add_option_table (sd, NULL, standard_options) != SIM_RC_OK)
545     return SIM_RC_FAIL;
546   STATE_LOAD_AT_LMA_P (sd) = 1;
547   return SIM_RC_OK;
548 }
549 
550 /* Return non-zero if arg is a duplicate argument.
551    If ARG is NULL, initialize.  */
552 
553 static int
554 dup_arg_p (const char *arg)
555 {
556   static htab_t arg_table = NULL;
557   void **slot;
558 
559   if (arg == NULL)
560     {
561       if (arg_table == NULL)
562 	arg_table = htab_create_alloc (10, htab_hash_string,
563 				       htab_eq_string, NULL,
564 				       xcalloc, free);
565       htab_empty (arg_table);
566       return 0;
567     }
568 
569   slot = htab_find_slot (arg_table, arg, INSERT);
570   if (*slot != NULL)
571     return 1;
572   *slot = (void *) arg;
573   return 0;
574 }
575 
576 /* Called by sim_open to parse the arguments.  */
577 
578 SIM_RC
579 sim_parse_args (SIM_DESC sd, char * const *argv)
580 {
581   int c, i, argc, num_opts, save_opterr;
582   char *p, *short_options;
583   /* The `val' option struct entry is dynamically assigned for options that
584      only come in the long form.  ORIG_VAL is used to get the original value
585      back.  */
586   int *orig_val;
587   struct option *lp, *long_options;
588   const struct option_list *ol;
589   const OPTION *opt;
590   OPTION_HANDLER **handlers;
591   sim_cpu **opt_cpu;
592   SIM_RC result = SIM_RC_OK;
593 
594   /* Count the number of arguments.  */
595   argc = countargv (argv);
596 
597   /* Count the number of options.  */
598   num_opts = 0;
599   for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next)
600     for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
601       ++num_opts;
602   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
603     for (ol = CPU_OPTIONS (STATE_CPU (sd, i)); ol != NULL; ol = ol->next)
604       for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
605 	++num_opts;
606 
607   /* Initialize duplicate argument checker.  */
608   (void) dup_arg_p (NULL);
609 
610   /* Build the option table for getopt.  */
611 
612   long_options = NZALLOC (struct option, num_opts + 1);
613   lp = long_options;
614   short_options = NZALLOC (char, num_opts * 3 + 1);
615   p = short_options;
616   handlers = NZALLOC (OPTION_HANDLER *, OPTION_START + num_opts);
617   orig_val = NZALLOC (int, OPTION_START + num_opts);
618   opt_cpu = NZALLOC (sim_cpu *, OPTION_START + num_opts);
619 
620   /* Set '+' as first char so argument permutation isn't done.  This
621      is done to stop getopt_long returning options that appear after
622      the target program.  Such options should be passed unchanged into
623      the program image. */
624   *p++ = '+';
625 
626   for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next)
627     for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
628       {
629 	if (dup_arg_p (opt->opt.name))
630 	  continue;
631 	if (opt->shortopt != 0)
632 	  {
633 	    *p++ = opt->shortopt;
634 	    if (opt->opt.has_arg == required_argument)
635 	      *p++ = ':';
636 	    else if (opt->opt.has_arg == optional_argument)
637 	      { *p++ = ':'; *p++ = ':'; }
638 	    handlers[(unsigned char) opt->shortopt] = opt->handler;
639 	    if (opt->opt.val != 0)
640 	      orig_val[(unsigned char) opt->shortopt] = opt->opt.val;
641 	    else
642 	      orig_val[(unsigned char) opt->shortopt] = opt->shortopt;
643 	  }
644 	if (opt->opt.name != NULL)
645 	  {
646 	    *lp = opt->opt;
647 	    /* Dynamically assign `val' numbers for long options. */
648 	    lp->val = i++;
649 	    handlers[lp->val] = opt->handler;
650 	    orig_val[lp->val] = opt->opt.val;
651 	    opt_cpu[lp->val] = NULL;
652 	    ++lp;
653 	  }
654       }
655 
656   for (c = 0; c < MAX_NR_PROCESSORS; ++c)
657     {
658       sim_cpu *cpu = STATE_CPU (sd, c);
659       for (ol = CPU_OPTIONS (cpu); ol != NULL; ol = ol->next)
660 	for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
661 	  {
662 #if 0 /* Each option is prepended with --<cpuname>- so this greatly cuts down
663 	 on the need for dup_arg_p checking.  Maybe in the future it'll be
664 	 needed so this is just commented out, and not deleted.  */
665 	    if (dup_arg_p (opt->opt.name))
666 	      continue;
667 #endif
668 	    /* Don't allow short versions of cpu specific options for now.  */
669 	    if (opt->shortopt != 0)
670 	      {
671 		sim_io_eprintf (sd, "internal error, short cpu specific option");
672 		result = SIM_RC_FAIL;
673 		break;
674 	      }
675 	    if (opt->opt.name != NULL)
676 	      {
677 		char *name;
678 		*lp = opt->opt;
679 		/* Prepend --<cpuname>- to the option.  */
680 		if (asprintf (&name, "%s-%s", CPU_NAME (cpu), lp->name) < 0)
681 		  {
682 		    sim_io_eprintf (sd, "internal error, out of memory");
683 		    result = SIM_RC_FAIL;
684 		    break;
685 		  }
686 		lp->name = name;
687 		/* Dynamically assign `val' numbers for long options. */
688 		lp->val = i++;
689 		handlers[lp->val] = opt->handler;
690 		orig_val[lp->val] = opt->opt.val;
691 		opt_cpu[lp->val] = cpu;
692 		++lp;
693 	      }
694 	  }
695     }
696 
697   /* Terminate the short and long option lists.  */
698   *p = 0;
699   lp->name = NULL;
700 
701   /* Ensure getopt is initialized.  */
702   optind = 0;
703 
704   /* Do not lot getopt throw errors for us.  But don't mess with the state for
705      any callers higher up by saving/restoring it.  */
706   save_opterr = opterr;
707   opterr = 0;
708 
709   while (1)
710     {
711       int longind, optc;
712 
713       optc = getopt_long (argc, argv, short_options, long_options, &longind);
714       if (optc == -1)
715 	{
716 	  if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
717 	    {
718 	      char **new_argv;
719 
720 	      free (STATE_PROG_FILE (sd));
721 	      STATE_PROG_FILE (sd) = NULL;
722 
723 	      /* Handle any inline variables if -- wasn't used.  */
724 	      if (argv[optind] != NULL && optind > 0
725 		  && strcmp (argv[optind - 1], "--") != 0)
726 		{
727 		  while (1)
728 		    {
729 		      const char *arg = argv[optind];
730 
731 		      if (strchr (arg, '=') == NULL)
732 			break;
733 
734 		      env_set (sd, arg);
735 		      ++optind;
736 		    }
737 		}
738 
739 	      new_argv = dupargv (argv + optind);
740 	      freeargv (STATE_PROG_ARGV (sd));
741 	      STATE_PROG_ARGV (sd) = new_argv;
742 
743 	      /* Skip steps when argc == 0.  */
744 	      if (argv[optind] != NULL)
745 		{
746 		  STATE_PROG_FILE (sd) = xstrdup (argv[optind]);
747 
748 		  if (STATE_PROG_ARGV0 (sd) != NULL)
749 		    {
750 		      free (new_argv[0]);
751 		      new_argv[0] = xstrdup (STATE_PROG_ARGV0 (sd));
752 		    }
753 		}
754 	    }
755 	  break;
756 	}
757       if (optc == '?')
758 	{
759 	  /* If getopt rejects a short option, optopt is set to the bad char.
760 	     If it rejects a long option, we have to look at optind.  In the
761 	     short option case, argv could be multiple short options.  */
762 	  const char *badopt;
763 	  char optbuf[3];
764 
765 	  if (optopt)
766 	    {
767 	      sprintf (optbuf, "-%c", optopt);
768 	      badopt = optbuf;
769 	    }
770 	  else
771 	    badopt = argv[optind - 1];
772 
773 	  sim_io_eprintf (sd,
774 			  "%s: unrecognized option '%s'\n"
775 			  "Use --help for a complete list of options.\n",
776 			  STATE_MY_NAME (sd), badopt);
777 
778 	  result = SIM_RC_FAIL;
779 	  break;
780 	}
781 
782       if ((*handlers[optc]) (sd, opt_cpu[optc], orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL)
783 	{
784 	  result = SIM_RC_FAIL;
785 	  break;
786 	}
787     }
788 
789   opterr = save_opterr;
790 
791   free (long_options);
792   free (short_options);
793   free (handlers);
794   free (opt_cpu);
795   free (orig_val);
796   return result;
797 }
798 
799 /* Utility of sim_print_help to print a list of option tables.  */
800 
801 static void
802 print_help (SIM_DESC sd, sim_cpu *cpu, const struct option_list *ol, int is_command)
803 {
804   const OPTION *opt;
805 
806   for ( ; ol != NULL; ol = ol->next)
807     for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
808       {
809 	const int indent = 30;
810 	int comma, len;
811 	const OPTION *o;
812 
813 	if (dup_arg_p (opt->opt.name))
814 	  continue;
815 
816 	if (opt->doc == NULL)
817 	  continue;
818 
819 	if (opt->doc_name != NULL && opt->doc_name [0] == '\0')
820 	  continue;
821 
822 	sim_io_printf (sd, "  ");
823 
824 	comma = 0;
825 	len = 2;
826 
827 	/* list any short options (aliases) for the current OPT */
828 	if (!is_command)
829 	  {
830 	    o = opt;
831 	    do
832 	      {
833 		if (o->shortopt != '\0')
834 		  {
835 		    sim_io_printf (sd, "%s-%c", comma ? ", " : "", o->shortopt);
836 		    len += (comma ? 2 : 0) + 2;
837 		    if (o->arg != NULL)
838 		      {
839 			if (o->opt.has_arg == optional_argument)
840 			  {
841 			    sim_io_printf (sd, "[%s]", o->arg);
842 			    len += 1 + strlen (o->arg) + 1;
843 			  }
844 			else
845 			  {
846 			    sim_io_printf (sd, " %s", o->arg);
847 			    len += 1 + strlen (o->arg);
848 			  }
849 		      }
850 		    comma = 1;
851 		  }
852 		++o;
853 	      }
854 	    while (OPTION_VALID_P (o) && o->doc == NULL);
855 	  }
856 
857 	/* list any long options (aliases) for the current OPT */
858 	o = opt;
859 	do
860 	  {
861 	    const char *name;
862 	    const char *cpu_prefix = cpu ? CPU_NAME (cpu) : NULL;
863 	    if (o->doc_name != NULL)
864 	      name = o->doc_name;
865 	    else
866 	      name = o->opt.name;
867 	    if (name != NULL)
868 	      {
869 		sim_io_printf (sd, "%s%s%s%s%s",
870 			       comma ? ", " : "",
871 			       is_command ? "" : "--",
872 			       cpu ? cpu_prefix : "",
873 			       cpu ? "-" : "",
874 			       name);
875 		len += ((comma ? 2 : 0)
876 			+ (is_command ? 0 : 2)
877 			+ strlen (name));
878 		if (o->arg != NULL)
879 		  {
880 		    if (o->opt.has_arg == optional_argument)
881 		      {
882 			sim_io_printf (sd, "[=%s]", o->arg);
883 			len += 2 + strlen (o->arg) + 1;
884 		      }
885 		    else
886 		      {
887 			sim_io_printf (sd, " %s", o->arg);
888 			len += 1 + strlen (o->arg);
889 		      }
890 		  }
891 		comma = 1;
892 	      }
893 	    ++o;
894 	  }
895 	while (OPTION_VALID_P (o) && o->doc == NULL);
896 
897 	if (len >= indent)
898 	  {
899 	    sim_io_printf (sd, "\n%*s", indent, "");
900 	  }
901 	else
902 	  sim_io_printf (sd, "%*s", indent - len, "");
903 
904 	/* print the description, word wrap long lines */
905 	{
906 	  const char *chp = opt->doc;
907 	  unsigned doc_width = 80 - indent;
908 	  while (strlen (chp) >= doc_width) /* some slack */
909 	    {
910 	      const char *end = chp + doc_width - 1;
911 	      while (end > chp && !isspace (*end))
912 		end --;
913 	      if (end == chp)
914 		end = chp + doc_width - 1;
915 	      /* The cast should be ok - its distances between to
916                  points in a string.  */
917 	      sim_io_printf (sd, "%.*s\n%*s", (int) (end - chp), chp, indent,
918 			     "");
919 	      chp = end;
920 	      while (isspace (*chp) && *chp != '\0')
921 		chp++;
922 	    }
923 	  sim_io_printf (sd, "%s\n", chp);
924 	}
925       }
926 }
927 
928 /* Print help messages for the options.  */
929 
930 void
931 sim_print_help (SIM_DESC sd, int is_command)
932 {
933   if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
934     sim_io_printf (sd,
935 		   "Usage: %s [options] [VAR=VAL|--] program [program args]\n",
936 		   STATE_MY_NAME (sd));
937 
938   /* Initialize duplicate argument checker.  */
939   (void) dup_arg_p (NULL);
940 
941   if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
942     sim_io_printf (sd, "Options:\n");
943   else
944     sim_io_printf (sd, "Commands:\n");
945 
946   print_help (sd, NULL, STATE_OPTIONS (sd), is_command);
947   sim_io_printf (sd, "\n");
948 
949   /* Print cpu-specific options.  */
950   {
951     int i;
952 
953     for (i = 0; i < MAX_NR_PROCESSORS; ++i)
954       {
955 	sim_cpu *cpu = STATE_CPU (sd, i);
956 	if (CPU_OPTIONS (cpu) == NULL)
957 	  continue;
958 	sim_io_printf (sd, "CPU %s specific options:\n", CPU_NAME (cpu));
959 	print_help (sd, cpu, CPU_OPTIONS (cpu), is_command);
960 	sim_io_printf (sd, "\n");
961       }
962   }
963 
964   sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n",
965 		 STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command");
966   sim_io_printf (sd, "      may not be applicable\n");
967 
968   if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
969     {
970       sim_io_printf (sd, "\n");
971       sim_io_printf (sd,
972 		     "VAR=VAL         Environment variables to set.  "
973 		     "Ignored if -- is used.\n");
974       sim_io_printf (sd, "program args    Arguments to pass to simulated program.\n");
975       sim_io_printf (sd, "                Note: Very few simulators support this.\n");
976     }
977 }
978 
979 /* Print version information.  */
980 
981 void
982 sim_print_version (SIM_DESC sd, int is_command)
983 {
984   sim_io_printf (sd, "GNU simulator %s%s\n", PKGVERSION, version);
985 
986   sim_io_printf (sd, "Copyright (C) 2024 Free Software Foundation, Inc.\n");
987 
988   /* Following the copyright is a brief statement that the program is
989      free software, that users are free to copy and change it on
990      certain conditions, that it is covered by the GNU GPL, and that
991      there is no warranty.  */
992 
993   sim_io_printf (sd, "\
994 License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\
995 \nThis is free software: you are free to change and redistribute it.\n\
996 There is NO WARRANTY, to the extent permitted by law.\n");
997 
998   if (!is_command)
999     return;
1000 
1001   sim_io_printf (sd, "This SIM was configured as:\n");
1002   sim_config_print (sd);
1003 
1004   if (REPORT_BUGS_TO[0])
1005     {
1006       sim_io_printf (sd, "For bug reporting instructions, please see:\n\
1007     %s.\n",
1008 		     REPORT_BUGS_TO);
1009     }
1010   sim_io_printf (sd, "Find the SIM homepage & other documentation resources \
1011 online at:\n    <https://sourceware.org/gdb/wiki/Sim/>.\n");
1012 }
1013 
1014 /* Utility of sim_args_command to find the closest match for a command.
1015    Commands that have "-" in them can be specified as separate words.
1016    e.g. sim memory-region 0x800000,0x4000
1017    or   sim memory region 0x800000,0x4000
1018    If CPU is non-null, use its option table list, otherwise use the main one.
1019    *PARGI is where to start looking in ARGV.  It is updated to point past
1020    the found option.  */
1021 
1022 static const OPTION *
1023 find_match (SIM_DESC sd, sim_cpu *cpu, char *argv[], int *pargi)
1024 {
1025   const struct option_list *ol;
1026   const OPTION *opt;
1027   /* most recent option match */
1028   const OPTION *matching_opt = NULL;
1029   int matching_argi = -1;
1030 
1031   if (cpu)
1032     ol = CPU_OPTIONS (cpu);
1033   else
1034     ol = STATE_OPTIONS (sd);
1035 
1036   /* Skip passed elements specified by *PARGI.  */
1037   argv += *pargi;
1038 
1039   for ( ; ol != NULL; ol = ol->next)
1040     for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
1041       {
1042 	int argi = 0;
1043 	const char *name = opt->opt.name;
1044 	if (name == NULL)
1045 	  continue;
1046 	while (argv [argi] != NULL
1047 	       && strncmp (name, argv [argi], strlen (argv [argi])) == 0)
1048 	  {
1049 	    name = &name [strlen (argv[argi])];
1050 	    if (name [0] == '-')
1051 	      {
1052 		/* leading match ...<a-b-c>-d-e-f - continue search */
1053 		name ++; /* skip `-' */
1054 		argi ++;
1055 		continue;
1056 	      }
1057 	    else if (name [0] == '\0')
1058 	      {
1059 		/* exact match ...<a-b-c-d-e-f> - better than before? */
1060 		if (argi > matching_argi)
1061 		  {
1062 		    matching_argi = argi;
1063 		    matching_opt = opt;
1064 		  }
1065 		break;
1066 	      }
1067 	    else
1068 	      break;
1069 	  }
1070       }
1071 
1072   *pargi = matching_argi;
1073   return matching_opt;
1074 }
1075 
1076 static char **
1077 complete_option_list (char **ret, size_t *cnt, const struct option_list *ol,
1078 		      const char *text, const char *word)
1079 {
1080   const OPTION *opt = NULL;
1081   size_t len = strlen (word);
1082 
1083   for ( ; ol != NULL; ol = ol->next)
1084     for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
1085       {
1086 	const char *name = opt->opt.name;
1087 
1088 	/* A long option to match against?  */
1089 	if (!name)
1090 	  continue;
1091 
1092 	/* Does this option actually match?  */
1093 	if (strncmp (name, word, len))
1094 	  continue;
1095 
1096 	ret = xrealloc (ret, ++*cnt * sizeof (ret[0]));
1097 	ret[*cnt - 2] = xstrdup (name);
1098       }
1099 
1100   return ret;
1101 }
1102 
1103 /* All leading text is stored in @text, while the current word being
1104    completed is stored in @word.  Trailing text of @word is not.  */
1105 
1106 char **
1107 sim_complete_command (SIM_DESC sd, const char *text, const char *word)
1108 {
1109   char **ret = NULL;
1110   size_t cnt = 1;
1111   sim_cpu *cpu;
1112 
1113   /* Only complete first word for now.  */
1114   if (text != word)
1115     return ret;
1116 
1117   cpu = STATE_CPU (sd, 0);
1118   if (cpu)
1119     ret = complete_option_list (ret, &cnt, CPU_OPTIONS (cpu), text, word);
1120   ret = complete_option_list (ret, &cnt, STATE_OPTIONS (sd), text, word);
1121 
1122   if (ret)
1123     ret[cnt - 1] = NULL;
1124   return ret;
1125 }
1126 
1127 SIM_RC
1128 sim_args_command (SIM_DESC sd, const char *cmd)
1129 {
1130   /* something to do? */
1131   if (cmd == NULL)
1132     return SIM_RC_OK; /* FIXME - perhaps help would be better */
1133 
1134   if (cmd [0] == '-')
1135     {
1136       /* user specified -<opt> ... form? */
1137       char **argv = buildargv (cmd);
1138       SIM_RC rc = sim_parse_args (sd, argv);
1139       freeargv (argv);
1140       return rc;
1141     }
1142   else
1143     {
1144       char **argv = buildargv (cmd);
1145       const OPTION *matching_opt = NULL;
1146       int matching_argi;
1147       sim_cpu *cpu;
1148 
1149       if (argv [0] == NULL)
1150 	{
1151 	  freeargv (argv);
1152 	  return SIM_RC_OK; /* FIXME - perhaps help would be better */
1153 	}
1154 
1155       /* First check for a cpu selector.  */
1156       {
1157 	char *cpu_name = xstrdup (argv[0]);
1158 	char *hyphen = strchr (cpu_name, '-');
1159 	if (hyphen)
1160 	  *hyphen = 0;
1161 	cpu = sim_cpu_lookup (sd, cpu_name);
1162 	if (cpu)
1163 	  {
1164 	    /* If <cpuname>-<command>, point argv[0] at <command>.  */
1165 	    if (hyphen)
1166 	      {
1167 		matching_argi = 0;
1168 		argv[0] += hyphen - cpu_name + 1;
1169 	      }
1170 	    else
1171 	      matching_argi = 1;
1172 	    matching_opt = find_match (sd, cpu, argv, &matching_argi);
1173 	    /* If hyphen found restore argv[0].  */
1174 	    if (hyphen)
1175 	      argv[0] -= hyphen - cpu_name + 1;
1176 	  }
1177 	free (cpu_name);
1178       }
1179 
1180       /* If that failed, try the main table.  */
1181       if (matching_opt == NULL)
1182 	{
1183 	  matching_argi = 0;
1184 	  matching_opt = find_match (sd, NULL, argv, &matching_argi);
1185 	}
1186 
1187       if (matching_opt != NULL)
1188 	{
1189 	  switch (matching_opt->opt.has_arg)
1190 	    {
1191 	    case no_argument:
1192 	      if (argv [matching_argi + 1] == NULL)
1193 		matching_opt->handler (sd, cpu, matching_opt->opt.val,
1194 				       NULL, 1/*is_command*/);
1195 	      else
1196 		sim_io_eprintf (sd, "Command `%s' takes no arguments\n",
1197 				matching_opt->opt.name);
1198 	      break;
1199 	    case optional_argument:
1200 	      if (argv [matching_argi + 1] == NULL)
1201 		matching_opt->handler (sd, cpu, matching_opt->opt.val,
1202 				       NULL, 1/*is_command*/);
1203 	      else if (argv [matching_argi + 2] == NULL)
1204 		matching_opt->handler (sd, cpu, matching_opt->opt.val,
1205 				       argv [matching_argi + 1], 1/*is_command*/);
1206 	      else
1207 		sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n",
1208 				matching_opt->opt.name);
1209 	      break;
1210 	    case required_argument:
1211 	      if (argv [matching_argi + 1] == NULL)
1212 		sim_io_eprintf (sd, "Command `%s' requires an argument\n",
1213 				matching_opt->opt.name);
1214 	      else if (argv [matching_argi + 2] == NULL)
1215 		matching_opt->handler (sd, cpu, matching_opt->opt.val,
1216 				       argv [matching_argi + 1], 1/*is_command*/);
1217 	      else
1218 		sim_io_eprintf (sd, "Command `%s' requires only one argument\n",
1219 				matching_opt->opt.name);
1220 	    }
1221 	  freeargv (argv);
1222 	  return SIM_RC_OK;
1223 	}
1224 
1225       freeargv (argv);
1226     }
1227 
1228   /* didn't find anything that remotly matched */
1229   return SIM_RC_FAIL;
1230 }
1231