xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/main.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
14e98e3e1Schristos /* main.c --- main function for stand-alone RX simulator.
24e98e3e1Schristos 
3*1f4e7eb9Schristos Copyright (C) 2005-2024 Free Software Foundation, Inc.
44e98e3e1Schristos Contributed by Red Hat, Inc.
54e98e3e1Schristos 
64e98e3e1Schristos This file is part of the GNU simulators.
74e98e3e1Schristos 
84e98e3e1Schristos This program is free software; you can redistribute it and/or modify
94e98e3e1Schristos it under the terms of the GNU General Public License as published by
104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
114e98e3e1Schristos (at your option) any later version.
124e98e3e1Schristos 
134e98e3e1Schristos This program is distributed in the hope that it will be useful,
144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164e98e3e1Schristos GNU General Public License for more details.
174e98e3e1Schristos 
184e98e3e1Schristos You should have received a copy of the GNU General Public License
194e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
204e98e3e1Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234e98e3e1Schristos 
244e98e3e1Schristos #include <stdio.h>
254e98e3e1Schristos #include <string.h>
264e98e3e1Schristos #include <stdlib.h>
274e98e3e1Schristos #include <unistd.h>
284e98e3e1Schristos #include <assert.h>
294e98e3e1Schristos #include <setjmp.h>
304e98e3e1Schristos #include <signal.h>
314e98e3e1Schristos #include <getopt.h>
324e98e3e1Schristos 
334e98e3e1Schristos #include "bfd.h"
344e98e3e1Schristos 
354e98e3e1Schristos #include "cpu.h"
364e98e3e1Schristos #include "mem.h"
374e98e3e1Schristos #include "misc.h"
384e98e3e1Schristos #include "load.h"
394e98e3e1Schristos #include "trace.h"
404e98e3e1Schristos #include "err.h"
414e98e3e1Schristos 
424e98e3e1Schristos static int disassemble = 0;
434e98e3e1Schristos 
444e98e3e1Schristos /* This must be higher than any other option index.  */
454e98e3e1Schristos #define OPT_ACT 400
464e98e3e1Schristos 
474e98e3e1Schristos #define ACT(E,A) (OPT_ACT + SIM_ERR_##E * SIM_ERRACTION_NUM_ACTIONS + SIM_ERRACTION_##A)
484e98e3e1Schristos 
494e98e3e1Schristos static struct option sim_options[] =
504e98e3e1Schristos {
514e98e3e1Schristos   { "end-sim-args", 0, NULL, 'E' },
524e98e3e1Schristos   { "exit-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,EXIT) },
534e98e3e1Schristos   { "warn-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,WARN) },
544e98e3e1Schristos   { "ignore-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,IGNORE) },
554e98e3e1Schristos   { "exit-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,EXIT) },
564e98e3e1Schristos   { "warn-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,WARN) },
574e98e3e1Schristos   { "ignore-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,IGNORE) },
584e98e3e1Schristos   { "exit-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,EXIT) },
594e98e3e1Schristos   { "warn-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,WARN) },
604e98e3e1Schristos   { "ignore-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,IGNORE) },
614e98e3e1Schristos   { "exit-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,EXIT) },
624e98e3e1Schristos   { "warn-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,WARN) },
634e98e3e1Schristos   { "ignore-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,IGNORE) },
644e98e3e1Schristos   { 0, 0, 0, 0 }
654e98e3e1Schristos };
664e98e3e1Schristos 
674e98e3e1Schristos static void
684e98e3e1Schristos done (int exit_code)
694e98e3e1Schristos {
704e98e3e1Schristos   if (verbose)
714e98e3e1Schristos     {
724e98e3e1Schristos       stack_heap_stats ();
734e98e3e1Schristos       mem_usage_stats ();
744e98e3e1Schristos       /* Only use comma separated numbers when being very verbose.
754e98e3e1Schristos 	 Comma separated numbers are hard to parse in awk scripts.  */
764e98e3e1Schristos       if (verbose > 1)
774e98e3e1Schristos 	printf ("insns: %14s\n", comma (rx_cycles));
784e98e3e1Schristos       else
794e98e3e1Schristos 	printf ("insns: %u\n", rx_cycles);
804e98e3e1Schristos 
814e98e3e1Schristos       pipeline_stats ();
824e98e3e1Schristos     }
834e98e3e1Schristos   exit (exit_code);
844e98e3e1Schristos }
854e98e3e1Schristos 
864e98e3e1Schristos int
874e98e3e1Schristos main (int argc, char **argv)
884e98e3e1Schristos {
894e98e3e1Schristos   int o;
904e98e3e1Schristos   int save_trace;
914e98e3e1Schristos   bfd *prog;
924e98e3e1Schristos   int rc;
934e98e3e1Schristos 
944e98e3e1Schristos   /* By default, we exit when an execution error occurs.  */
954e98e3e1Schristos   execution_error_init_standalone ();
964e98e3e1Schristos 
974e98e3e1Schristos   while ((o = getopt_long (argc, argv, "tvdeEwi", sim_options, NULL)) != -1)
984e98e3e1Schristos     {
994e98e3e1Schristos       if (o == 'E')
1004e98e3e1Schristos 	/* Stop processing the command line. This is so that any remaining
1014e98e3e1Schristos 	   words on the command line that look like arguments will be passed
1024e98e3e1Schristos 	   on to the program being simulated.  */
1034e98e3e1Schristos 	break;
1044e98e3e1Schristos 
1054e98e3e1Schristos       if (o >= OPT_ACT)
1064e98e3e1Schristos 	{
1074e98e3e1Schristos 	  int e, a;
1084e98e3e1Schristos 
1094e98e3e1Schristos 	  o -= OPT_ACT;
1104e98e3e1Schristos 	  e = o / SIM_ERRACTION_NUM_ACTIONS;
1114e98e3e1Schristos 	  a = o % SIM_ERRACTION_NUM_ACTIONS;
1124e98e3e1Schristos 	  execution_error_set_action (e, a);
1134e98e3e1Schristos 	}
1144e98e3e1Schristos       else switch (o)
1154e98e3e1Schristos 	{
1164e98e3e1Schristos 	case 't':
1174e98e3e1Schristos 	  trace++;
1184e98e3e1Schristos 	  break;
1194e98e3e1Schristos 	case 'v':
1204e98e3e1Schristos 	  verbose++;
1214e98e3e1Schristos 	  break;
1224e98e3e1Schristos 	case 'd':
1234e98e3e1Schristos 	  disassemble++;
1244e98e3e1Schristos 	  break;
1254e98e3e1Schristos 	case 'e':
1264e98e3e1Schristos 	  execution_error_init_standalone ();
1274e98e3e1Schristos 	  break;
1284e98e3e1Schristos 	case 'w':
1294e98e3e1Schristos 	  execution_error_warn_all ();
1304e98e3e1Schristos 	  break;
1314e98e3e1Schristos 	case 'i':
1324e98e3e1Schristos 	  execution_error_ignore_all ();
1334e98e3e1Schristos 	  break;
1344e98e3e1Schristos 	case '?':
1354e98e3e1Schristos 	  {
1364e98e3e1Schristos 	    int i;
1374e98e3e1Schristos 	    fprintf (stderr,
1384e98e3e1Schristos 		     "usage: run [options] program [arguments]\n");
1394e98e3e1Schristos 	    fprintf (stderr,
1404e98e3e1Schristos 		     "\t-v\t- increase verbosity.\n"
1414e98e3e1Schristos 		     "\t-t\t- trace.\n"
1424e98e3e1Schristos 		     "\t-d\t- disassemble.\n"
1434e98e3e1Schristos 		     "\t-E\t- stop processing sim args\n"
1444e98e3e1Schristos 		     "\t-e\t- exit on all execution errors.\n"
1454e98e3e1Schristos 		     "\t-w\t- warn (do not exit) on all execution errors.\n"
1464e98e3e1Schristos 		     "\t-i\t- ignore all execution errors.\n");
1474e98e3e1Schristos 	    for (i=0; sim_options[i].name; i++)
1484e98e3e1Schristos 	      fprintf (stderr, "\t--%s\n", sim_options[i].name);
1494e98e3e1Schristos 	    exit (1);
1504e98e3e1Schristos 	  }
1514e98e3e1Schristos 	}
1524e98e3e1Schristos     }
1534e98e3e1Schristos 
1544e98e3e1Schristos   prog = bfd_openr (argv[optind], 0);
1554e98e3e1Schristos   if (!prog)
1564e98e3e1Schristos     {
1574e98e3e1Schristos       fprintf (stderr, "Can't read %s\n", argv[optind]);
1584e98e3e1Schristos       exit (1);
1594e98e3e1Schristos     }
1604e98e3e1Schristos 
1614e98e3e1Schristos   if (!bfd_check_format (prog, bfd_object))
1624e98e3e1Schristos     {
1634e98e3e1Schristos       fprintf (stderr, "%s not a rx program\n", argv[optind]);
1644e98e3e1Schristos       exit (1);
1654e98e3e1Schristos     }
1664e98e3e1Schristos 
1674e98e3e1Schristos   init_regs ();
1684e98e3e1Schristos 
1694e98e3e1Schristos   rx_in_gdb = 0;
1704e98e3e1Schristos   save_trace = trace;
1714e98e3e1Schristos   trace = 0;
172a2e2270fSchristos   rx_load (prog, NULL);
1734e98e3e1Schristos   trace = save_trace;
1744e98e3e1Schristos 
1754e98e3e1Schristos   sim_disasm_init (prog);
1764e98e3e1Schristos 
1774e98e3e1Schristos   enable_counting = verbose;
1784e98e3e1Schristos 
1794e98e3e1Schristos   rc = setjmp (decode_jmp_buf);
1804e98e3e1Schristos 
1814e98e3e1Schristos   if (rc == 0)
1824e98e3e1Schristos     {
1834e98e3e1Schristos       if (!trace && !disassemble)
1844e98e3e1Schristos 	{
1854e98e3e1Schristos 	  /* This will longjmp to the above if an exception
1864e98e3e1Schristos 	     happens.  */
1874e98e3e1Schristos 	  for (;;)
1884e98e3e1Schristos 	    decode_opcode ();
1894e98e3e1Schristos 	}
1904e98e3e1Schristos       else
1914e98e3e1Schristos 	while (1)
1924e98e3e1Schristos 	  {
1934e98e3e1Schristos 
1944e98e3e1Schristos 	    if (trace)
1954e98e3e1Schristos 	      printf ("\n");
1964e98e3e1Schristos 
1974e98e3e1Schristos 	    if (disassemble)
1984e98e3e1Schristos 	      {
1994e98e3e1Schristos 		enable_counting = 0;
2004e98e3e1Schristos 		sim_disasm_one ();
2014e98e3e1Schristos 		enable_counting = verbose;
2024e98e3e1Schristos 	      }
2034e98e3e1Schristos 
2044e98e3e1Schristos 	    rc = decode_opcode ();
2054e98e3e1Schristos 
2064e98e3e1Schristos 	    if (trace)
2074e98e3e1Schristos 	      trace_register_changes ();
2084e98e3e1Schristos 	  }
2094e98e3e1Schristos     }
2104e98e3e1Schristos 
2114e98e3e1Schristos   if (RX_HIT_BREAK (rc))
2124e98e3e1Schristos     done (1);
2134e98e3e1Schristos   else if (RX_EXITED (rc))
2144e98e3e1Schristos     done (RX_EXIT_STATUS (rc));
2154e98e3e1Schristos   else if (RX_STOPPED (rc))
2164e98e3e1Schristos     {
2174e98e3e1Schristos       if (verbose)
2184e98e3e1Schristos 	printf("Stopped on signal %d\n", RX_STOP_SIG (rc));
2194e98e3e1Schristos       exit(1);
2204e98e3e1Schristos     }
2214e98e3e1Schristos   done (0);
2224e98e3e1Schristos   exit (0);
2234e98e3e1Schristos }
224