text: /* run front end support for all the simulators.
     Copyright (C) 1992-2015 Free Software Foundation, Inc.
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
  
  /* Steve Chamberlain sac@cygnus.com,
     and others at Cygnus.  */
  
  #ifdef HAVE_CONFIG_H
  #include "cconfig.h"
  #include "tconfig.h"
  #endif
  
  #include <signal.h>
  #include <stdio.h>
  #ifdef __STDC__
  #include <stdarg.h>
  #else
  #include <varargs.h>
  #endif
  
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  
  #ifdef HAVE_STRING_H
  #include <string.h>
  #else
  #ifdef HAVE_STRINGS_H
  #include <strings.h>
  #endif
  #endif
  
  #include "libiberty.h"
  #include "bfd.h"
  #include "gdb/callback.h"
  #include "gdb/remote-sim.h"
  #include "ansidecl.h"
  #include "run-sim.h"
  #include "version.h"
  
  static void usage (int help);
  static void print_version (void);
  extern int optind;
  extern char *optarg;
  
  extern host_callback default_callback;
  
  static char *myname;
  
  extern int getopt ();
  
  #ifdef NEED_UI_LOOP_HOOK
  /* Gdb foolery. This is only needed for gdb using a gui.  */
  int (*deprecated_ui_loop_hook) (int signo);
  #endif
  
  static SIM_DESC sd;
  
  static RETSIGTYPE
  cntrl_c (int sig ATTRIBUTE_UNUSED)
  {
    if (! sim_stop (sd))
      {
        fprintf (stderr, "Quit!\n");
        exit (1);
      }
  }
  
  int
  main (ac, av)
       int ac;
       char **av;
  {
    RETSIGTYPE (*prev_sigint) ();
    bfd *abfd;
    int i;
    int verbose = 0;
    int trace = 0;
  #ifdef SIM_HAVE_ENVIRONMENT
    int operating_p = 0;
  #endif
    char *name;
    static char *no_args[4];
    char **sim_argv = &no_args[0];
    char **prog_args;
    enum sim_stop reason;
    int sigrc;
  
    myname = av[0] + strlen (av[0]);
    while (myname > av[0] && myname[-1] != '/')
      --myname;
  
    /* The first element of sim_open's argv is the program name.  */
    no_args[0] = av[0];
  #ifdef SIM_HAVE_BIENDIAN
    no_args[1] = "-E";
    no_args[2] = "set-later";
  #endif
  
    /* FIXME: This is currently being migrated into sim_open.
       Simulators that use functions such as sim_size() still require
       this.  */
    default_callback.init (&default_callback);
    sim_set_callbacks (&default_callback);
  
  #ifdef SIM_TARGET_SWITCHES
    ac = sim_target_parse_command_line (ac, av);
  #endif
  
    for (i = 1; av[i]; ++i)
      {
        if (strcmp (av[i], "--help") == 0)
          {
            usage (1);
          }
        else if (strcmp (av[i], "--version") == 0)
          {
            print_version ();
            return 0;
          }
      }
  
    /* FIXME: This is currently being rewritten to have each simulator
       do all argv processing.  */
  
    while ((i = getopt (ac, av, "a:c:m:op:s:tv")) != EOF)
      switch (i)
        {
        case 'a':
  	/* FIXME: Temporary hack.  */
  	{
  	  int len = strlen (av[0]) + strlen (optarg);
  	  char *argbuf = (char *) alloca (len + 2 + 50);
  	  sprintf (argbuf, "%s %s", av[0], optarg);
  #ifdef SIM_HAVE_BIENDIAN
  	  /* The desired endianness must be passed to sim_open.
  	     The value for "set-later" is set when we know what it is.
  	     -E support isn't yet part of the published interface.  */
  	  strcat (argbuf, " -E set-later");
  #endif
  	  sim_argv = buildargv (argbuf);
  	}
  	break;
  #ifdef SIM_HAVE_SIMCACHE
        case 'c':
  	sim_set_simcache_size (atoi (optarg));
  	break;
  #endif
        case 'm':
  	/* FIXME: Rename to sim_set_mem_size.  */
  	sim_size (atoi (optarg));
  	break;
  #ifdef SIM_HAVE_ENVIRONMENT
        case 'o':
  	/* Operating enironment where any signals are delivered to the
             target.  */
  	operating_p = 1;
  	break;
  #endif
  #ifdef SIM_HAVE_PROFILE
        case 'p':
  	sim_set_profile (atoi (optarg));
  	break;
        case 's':
  	sim_set_profile_size (atoi (optarg));
  	break;
  #endif
        case 't':
  	trace = 1;
  	break;
        case 'v':
  	/* Things that are printed with -v are the kinds of things that
  	   gcc -v prints.  This is not meant to include detailed tracing
  	   or debugging information, just summaries.  */
  	verbose = 1;
  	/* sim_set_verbose (1); */
  	break;
  	/* FIXME: Quick hack, to be replaced by more general facility.  */
        default:
  	usage (0);
        }
  
    ac -= optind;
    av += optind;
    if (ac <= 0)
      usage (0);
  
    name = *av;
    prog_args = av;
  
    if (verbose)
      {
        printf ("%s %s\n", myname, name);
      }
  
    abfd = bfd_openr (name, 0);
    if (!abfd)
      {
        fprintf (stderr, "%s: can't open %s: %s\n",
  	       myname, name, bfd_errmsg (bfd_get_error ()));
        exit (1);
      }
  
    if (!bfd_check_format (abfd, bfd_object))
      {
        fprintf (stderr, "%s: can't load %s: %s\n",
  	       myname, name, bfd_errmsg (bfd_get_error ()));
        exit (1);
      }
  
  #ifdef SIM_HAVE_BIENDIAN
    /* The endianness must be passed to sim_open because one may wish to
       examine/set registers before calling sim_load [which is the other
       place where one can determine endianness].  We previously passed the
       endianness via global `target_byte_order' but that's not a clean
       interface.  */
    for (i = 1; sim_argv[i + 1] != NULL; ++i)
      continue;
    if (bfd_big_endian (abfd))
      sim_argv[i] = "big";
    else
      sim_argv[i] = "little";
  #endif
  
    /* Ensure that any run-time initialisation that needs to be
       performed by the simulator can occur.  */
    sd = sim_open (SIM_OPEN_STANDALONE, &default_callback, abfd, sim_argv);
    if (sd == 0)
      exit (1);
  
    if (sim_load (sd, name, abfd, 0) == SIM_RC_FAIL)
      exit (1);
  
    if (sim_create_inferior (sd, abfd, prog_args, NULL) == SIM_RC_FAIL)
      exit (1);
  
  #ifdef SIM_HAVE_ENVIRONMENT
    /* NOTE: An old simulator supporting the operating environment MUST
       provide sim_set_trace() and not sim_trace(). That way
       sim_stop_reason() can be used to determine any stop reason.  */
    if (trace)
      sim_set_trace ();
    sigrc = 0;
    do
      {
        prev_sigint = signal (SIGINT, cntrl_c);
        sim_resume (sd, 0, sigrc);
        signal (SIGINT, prev_sigint);
        sim_stop_reason (sd, &reason, &sigrc);
      }
    while (operating_p && reason == sim_stopped && sigrc != SIGINT);
  #else
    if (trace)
      {
        int done = 0;
        prev_sigint = signal (SIGINT, cntrl_c);
        while (!done)
  	{
  	  done = sim_trace (sd);
  	}
        signal (SIGINT, prev_sigint);
        sim_stop_reason (sd, &reason, &sigrc);
      }
    else
      {
        prev_sigint = signal (SIGINT, cntrl_c);
        sigrc = 0;
        sim_resume (sd, 0, sigrc);
        signal (SIGINT, prev_sigint);
        sim_stop_reason (sd, &reason, &sigrc);
      }
  #endif
  
    if (verbose)
      sim_info (sd, 0);
    sim_close (sd, 0);
  
    /* If reason is sim_exited, then sigrc holds the exit code which we want
       to return.  If reason is sim_stopped or sim_signalled, then sigrc holds
       the signal that the simulator received; we want to return that to
       indicate failure.  */
  
    /* Why did we stop? */
    switch (reason)
      {
      case sim_signalled:
      case sim_stopped:
        if (sigrc != 0)
  	fprintf (stderr, "program stopped with signal %d.\n", sigrc);
        break;
  
      case sim_exited:
        break;
  
      case sim_running:
      case sim_polling: /* These indicate a serious problem.  */
        abort ();
        break;
  
      }
  
    return sigrc;
  }
  
  static void
  usage (int help)
  {
    FILE *stream = help ? stdout : stderr;
  
    fprintf (stream, "Usage: %s [options] program [program args]\n", myname);
    fprintf (stream, "Options:\n");
    fprintf (stream, "-a args         Pass `args' to simulator.\n");
  #ifdef SIM_HAVE_SIMCACHE
    fprintf (stream, "-c size         Set simulator cache size to `size'.\n");
  #endif
    fprintf (stream, "-m size         Set memory size of simulator, in bytes.\n");
  #ifdef SIM_HAVE_ENVIRONMENT
    fprintf (stream, "-o              Select operating (kernel) environment.\n");
  #endif
  #ifdef SIM_HAVE_PROFILE
    fprintf (stream, "-p freq         Set profiling frequency.\n");
    fprintf (stream, "-s size         Set profiling size.\n");
  #endif
    fprintf (stream, "-t              Perform instruction tracing.\n");
    fprintf (stream, "                Note: Very few simulators support tracing.\n");
    fprintf (stream, "-v              Verbose output.\n");
    fprintf (stream, "\n");
    fprintf (stream, "program args    Arguments to pass to simulated program.\n");
    fprintf (stream, "                Note: Very few simulators support this.\n");
  #ifdef SIM_TARGET_SWITCHES
    fprintf (stream, "\nTarget specific options:\n");
    sim_target_display_usage (help);
  #endif
  
    if (help && REPORT_BUGS_TO[0])
      printf ("Report bugs to %s\n", REPORT_BUGS_TO);
  
    exit (help ? 0 : 1);
  }
  
  static void
  print_version ()
  {
    printf ("GNU simulator %s%s\n", PKGVERSION, version);
  }
  