| /* run front end support for all the simulators. | |
| Copyright (C) 1992, 93-96, 1997 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 2, or (at your option) | |
| any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License along | |
| with this program; if not, write to the Free Software Foundation, Inc., | |
| 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
| /* Steve Chamberlain sac@cygnus.com, | |
| and others at Cygnus. */ | |
| #include "config.h" | |
| #include "tconfig.h" | |
| #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 "callback.h" | |
| #include "remote-sim.h" | |
| #include "ansidecl.h" | |
| static void usage PARAMS ((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 (*ui_loop_hook) PARAMS ((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); | |
| /* FIXME: This is currently being rewritten to have each simulator | |
| do all argv processing. */ | |
| #ifdef SIM_H8300 /* FIXME: quick hack */ | |
| while ((i = getopt (ac, av, "a:c:m:op:s:htv")) != EOF) | |
| #else | |
| while ((i = getopt (ac, av, "a:c:m:op:s:tv")) != EOF) | |
| #endif | |
| 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 SIM_HAVE_ENVIRONMENT | |
| #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. */ | |
| #ifdef SIM_H8300 | |
| case 'h': | |
| set_h8300h (1); | |
| break; | |
| #endif | |
| default: | |
| usage (); | |
| } | |
| ac -= optind; | |
| av += optind; | |
| if (ac <= 0) | |
| usage (); | |
| 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. */ | |
| #ifdef SIM_H8300 /* FIXME: Ugh. grep for SLEEP in compile.c */ | |
| if (sigrc == SIGILL) | |
| abort (); | |
| sigrc = 0; | |
| #else | |
| /* 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; | |
| } | |
| #endif | |
| return sigrc; | |
| } | |
| static void | |
| usage () | |
| { | |
| fprintf (stderr, "Usage: %s [options] program [program args]\n", myname); | |
| fprintf (stderr, "Options:\n"); | |
| fprintf (stderr, "-a args Pass `args' to simulator.\n"); | |
| #ifdef SIM_HAVE_SIMCACHE | |
| fprintf (stderr, "-c size Set simulator cache size to `size'.\n"); | |
| #endif | |
| #ifdef SIM_H8300 | |
| fprintf (stderr, "-h Executable is for h8/300h or h8/300s.\n"); | |
| #endif | |
| fprintf (stderr, "-m size Set memory size of simulator, in bytes.\n"); | |
| #ifdef SIM_HAVE_ENVIRONMENT | |
| fprintf (stderr, "-o Select operating (kernel) environment.\n"); | |
| #endif | |
| #ifdef SIM_HAVE_PROFILE | |
| fprintf (stderr, "-p freq Set profiling frequency.\n"); | |
| fprintf (stderr, "-s size Set profiling size.\n"); | |
| #endif | |
| fprintf (stderr, "-t Perform instruction tracing.\n"); | |
| fprintf (stderr, " Note: Very few simulators support tracing.\n"); | |
| fprintf (stderr, "-v Verbose output.\n"); | |
| fprintf (stderr, "\n"); | |
| fprintf (stderr, "program args Arguments to pass to simulated program.\n"); | |
| fprintf (stderr, " Note: Very few simulators support this.\n"); | |
| exit (1); | |
| } |