1 /* main.c --- main function for stand-alone RX simulator.
2 
3 Copyright (C) 2005-2024 Free Software Foundation, Inc.
4 Contributed by Red Hat, Inc.
5 
6 This file is part of the GNU simulators.
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20 
21 /* This must come before any other includes.  */
22 #include "defs.h"
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <assert.h>
29 #include <setjmp.h>
30 #include <signal.h>
31 #include <getopt.h>
32 
33 #include "bfd.h"
34 
35 #include "cpu.h"
36 #include "mem.h"
37 #include "misc.h"
38 #include "load.h"
39 #include "trace.h"
40 #include "err.h"
41 
42 static int disassemble = 0;
43 
44 /* This must be higher than any other option index.  */
45 #define OPT_ACT 400
46 
47 #define ACT(E,A) (OPT_ACT + SIM_ERR_##E * SIM_ERRACTION_NUM_ACTIONS + SIM_ERRACTION_##A)
48 
49 static struct option sim_options[] =
50 {
51   { "end-sim-args", 0, NULL, 'E' },
52   { "exit-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,EXIT) },
53   { "warn-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,WARN) },
54   { "ignore-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,IGNORE) },
55   { "exit-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,EXIT) },
56   { "warn-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,WARN) },
57   { "ignore-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,IGNORE) },
58   { "exit-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,EXIT) },
59   { "warn-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,WARN) },
60   { "ignore-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,IGNORE) },
61   { "exit-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,EXIT) },
62   { "warn-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,WARN) },
63   { "ignore-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,IGNORE) },
64   { 0, 0, 0, 0 }
65 };
66 
67 static void
done(int exit_code)68 done (int exit_code)
69 {
70   if (verbose)
71     {
72       stack_heap_stats ();
73       mem_usage_stats ();
74       /* Only use comma separated numbers when being very verbose.
75            Comma separated numbers are hard to parse in awk scripts.  */
76       if (verbose > 1)
77           printf ("insns: %14s\n", comma (rx_cycles));
78       else
79           printf ("insns: %u\n", rx_cycles);
80 
81       pipeline_stats ();
82     }
83   exit (exit_code);
84 }
85 
86 int
main(int argc,char ** argv)87 main (int argc, char **argv)
88 {
89   int o;
90   int save_trace;
91   bfd *prog;
92   int rc;
93 
94   /* By default, we exit when an execution error occurs.  */
95   execution_error_init_standalone ();
96 
97   while ((o = getopt_long (argc, argv, "tvdeEwi", sim_options, NULL)) != -1)
98     {
99       if (o == 'E')
100           /* Stop processing the command line. This is so that any remaining
101              words on the command line that look like arguments will be passed
102              on to the program being simulated.  */
103           break;
104 
105       if (o >= OPT_ACT)
106           {
107             int e, a;
108 
109             o -= OPT_ACT;
110             e = o / SIM_ERRACTION_NUM_ACTIONS;
111             a = o % SIM_ERRACTION_NUM_ACTIONS;
112             execution_error_set_action (e, a);
113           }
114       else switch (o)
115           {
116           case 't':
117             trace++;
118             break;
119           case 'v':
120             verbose++;
121             break;
122           case 'd':
123             disassemble++;
124             break;
125           case 'e':
126             execution_error_init_standalone ();
127             break;
128           case 'w':
129             execution_error_warn_all ();
130             break;
131           case 'i':
132             execution_error_ignore_all ();
133             break;
134           case '?':
135             {
136               int i;
137               fprintf (stderr,
138                          "usage: run [options] program [arguments]\n");
139               fprintf (stderr,
140                          "\t-v\t- increase verbosity.\n"
141                          "\t-t\t- trace.\n"
142                          "\t-d\t- disassemble.\n"
143                          "\t-E\t- stop processing sim args\n"
144                          "\t-e\t- exit on all execution errors.\n"
145                          "\t-w\t- warn (do not exit) on all execution errors.\n"
146                          "\t-i\t- ignore all execution errors.\n");
147               for (i=0; sim_options[i].name; i++)
148                 fprintf (stderr, "\t--%s\n", sim_options[i].name);
149               exit (1);
150             }
151           }
152     }
153 
154   prog = bfd_openr (argv[optind], 0);
155   if (!prog)
156     {
157       fprintf (stderr, "Can't read %s\n", argv[optind]);
158       exit (1);
159     }
160 
161   if (!bfd_check_format (prog, bfd_object))
162     {
163       fprintf (stderr, "%s not a rx program\n", argv[optind]);
164       exit (1);
165     }
166 
167   init_regs ();
168 
169   rx_in_gdb = 0;
170   save_trace = trace;
171   trace = 0;
172   rx_load (prog, NULL);
173   trace = save_trace;
174 
175   sim_disasm_init (prog);
176 
177   enable_counting = verbose;
178 
179   rc = setjmp (decode_jmp_buf);
180 
181   if (rc == 0)
182     {
183       if (!trace && !disassemble)
184           {
185             /* This will longjmp to the above if an exception
186                happens.  */
187             for (;;)
188               decode_opcode ();
189           }
190       else
191           while (1)
192             {
193 
194               if (trace)
195                 printf ("\n");
196 
197               if (disassemble)
198                 {
199                     enable_counting = 0;
200                     sim_disasm_one ();
201                     enable_counting = verbose;
202                 }
203 
204               rc = decode_opcode ();
205 
206               if (trace)
207                 trace_register_changes ();
208             }
209     }
210 
211   if (RX_HIT_BREAK (rc))
212     done (1);
213   else if (RX_EXITED (rc))
214     done (RX_EXIT_STATUS (rc));
215   else if (RX_STOPPED (rc))
216     {
217       if (verbose)
218           printf("Stopped on signal %d\n", RX_STOP_SIG (rc));
219       exit(1);
220     }
221   done (0);
222   exit (0);
223 }
224