summaryrefslogtreecommitdiff
path: root/sim/rx/gdb-if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/rx/gdb-if.c')
-rw-r--r--sim/rx/gdb-if.c841
1 files changed, 841 insertions, 0 deletions
diff --git a/sim/rx/gdb-if.c b/sim/rx/gdb-if.c
new file mode 100644
index 00000000000..a8db2bb13c4
--- /dev/null
+++ b/sim/rx/gdb-if.c
@@ -0,0 +1,841 @@
+/* gdb-if.c -- sim interface to GDB.
+
+Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+Contributed by Red Hat, Inc.
+
+This file is part of the GNU simulators.
+
+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/>. */
+
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "ansidecl.h"
+#include "gdb/callback.h"
+#include "gdb/remote-sim.h"
+#include "gdb/signals.h"
+#include "gdb/sim-rx.h"
+
+#include "cpu.h"
+#include "mem.h"
+#include "load.h"
+#include "syscalls.h"
+#include "err.h"
+
+/* Ideally, we'd wrap up all the minisim's data structures in an
+ object and pass that around. However, neither GDB nor run needs
+ that ability.
+
+ So we just have one instance, that lives in global variables, and
+ each time we open it, we re-initialize it. */
+struct sim_state
+{
+ const char *message;
+};
+
+static struct sim_state the_minisim = {
+ "This is the sole rx minisim instance. See libsim.a's global variables."
+};
+
+static int open;
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind,
+ struct host_callback_struct *callback,
+ struct bfd *abfd, char **argv)
+{
+ if (open)
+ fprintf (stderr, "rx minisim: re-opened sim\n");
+
+ /* The 'run' interface doesn't use this function, so we don't care
+ about KIND; it's always SIM_OPEN_DEBUG. */
+ if (kind != SIM_OPEN_DEBUG)
+ fprintf (stderr, "rx minisim: sim_open KIND != SIM_OPEN_DEBUG: %d\n",
+ kind);
+
+ set_callbacks (callback);
+
+ /* We don't expect any command-line arguments. */
+
+ init_mem ();
+ init_regs ();
+ execution_error_init_debugger ();
+
+ sim_disasm_init (abfd);
+ open = 1;
+ return &the_minisim;
+}
+
+static void
+check_desc (SIM_DESC sd)
+{
+ if (sd != &the_minisim)
+ fprintf (stderr, "rx minisim: desc != &the_minisim\n");
+}
+
+void
+sim_close (SIM_DESC sd, int quitting)
+{
+ check_desc (sd);
+
+ /* Not much to do. At least free up our memory. */
+ init_mem ();
+
+ open = 0;
+}
+
+static bfd *
+open_objfile (const char *filename)
+{
+ bfd *prog = bfd_openr (filename, 0);
+
+ if (!prog)
+ {
+ fprintf (stderr, "Can't read %s\n", filename);
+ return 0;
+ }
+
+ if (!bfd_check_format (prog, bfd_object))
+ {
+ fprintf (stderr, "%s not a rx program\n", filename);
+ return 0;
+ }
+
+ return prog;
+}
+
+static struct swap_list
+{
+ bfd_vma start, end;
+ struct swap_list *next;
+} *swap_list = NULL;
+
+static void
+free_swap_list (void)
+{
+ while (swap_list)
+ {
+ struct swap_list *next = swap_list->next;
+ free (swap_list);
+ swap_list = next;
+ }
+}
+
+/* When running in big endian mode, we must do an additional
+ byte swap of memory areas used to hold instructions. See
+ the comment preceding rx_load in load.c to see why this is
+ so.
+
+ Construct a list of memory areas that must be byte swapped.
+ This list will be consulted when either reading or writing
+ memory. */
+
+static void
+build_swap_list (struct bfd *abfd)
+{
+ asection *s;
+ free_swap_list ();
+
+ /* Nothing to do when in little endian mode. */
+ if (!rx_big_endian)
+ return;
+
+ for (s = abfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) && (s->flags & SEC_CODE))
+ {
+ struct swap_list *sl;
+ bfd_size_type size;
+
+ size = bfd_get_section_size (s);
+ if (size <= 0)
+ continue;
+
+ sl = malloc (sizeof (struct swap_list));
+ assert (sl != NULL);
+ sl->next = swap_list;
+ sl->start = bfd_section_lma (abfd, s);
+ sl->end = sl->start + size;
+ swap_list = sl;
+ }
+ }
+}
+
+static int
+addr_in_swap_list (bfd_vma addr)
+{
+ struct swap_list *s;
+
+ for (s = swap_list; s; s = s->next)
+ {
+ if (s->start <= addr && addr < s->end)
+ return 1;
+ }
+ return 0;
+}
+
+SIM_RC
+sim_load (SIM_DESC sd, char *prog, struct bfd *abfd, int from_tty)
+{
+ check_desc (sd);
+
+ if (!abfd)
+ abfd = open_objfile (prog);
+ if (!abfd)
+ return SIM_RC_FAIL;
+
+ rx_load (abfd);
+ build_swap_list (abfd);
+
+ return SIM_RC_OK;
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env)
+{
+ check_desc (sd);
+
+ if (abfd)
+ {
+ rx_load (abfd);
+ build_swap_list (abfd);
+ }
+
+ return SIM_RC_OK;
+}
+
+int
+sim_read (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length)
+{
+ int i;
+
+ check_desc (sd);
+
+ if (mem == 0)
+ return 0;
+
+ execution_error_clear_last_error ();
+
+ for (i = 0; i < length; i++)
+ {
+ bfd_vma addr = mem + i;
+ int do_swap = addr_in_swap_list (addr);
+ buf[i] = mem_get_qi (addr ^ (do_swap ? 3 : 0));
+
+ if (execution_error_get_last_error () != SIM_ERR_NONE)
+ return i;
+ }
+
+ return length;
+}
+
+int
+sim_write (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length)
+{
+ int i;
+
+ check_desc (sd);
+
+ execution_error_clear_last_error ();
+
+ for (i = 0; i < length; i++)
+ {
+ bfd_vma addr = mem + i;
+ int do_swap = addr_in_swap_list (addr);
+ mem_put_qi (addr ^ (do_swap ? 3 : 0), buf[i]);
+
+ if (execution_error_get_last_error () != SIM_ERR_NONE)
+ return i;
+ }
+
+ return length;
+}
+
+/* Read the LENGTH bytes at BUF as an little-endian value. */
+static DI
+get_le (unsigned char *buf, int length)
+{
+ DI acc = 0;
+ while (--length >= 0)
+ acc = (acc << 8) + buf[length];
+
+ return acc;
+}
+
+/* Read the LENGTH bytes at BUF as a big-endian value. */
+static DI
+get_be (unsigned char *buf, int length)
+{
+ DI acc = 0;
+ while (length-- > 0)
+ acc = (acc << 8) + *buf++;
+
+ return acc;
+}
+
+/* Store VAL as a little-endian value in the LENGTH bytes at BUF. */
+static void
+put_le (unsigned char *buf, int length, DI val)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ buf[i] = val & 0xff;
+ val >>= 8;
+ }
+}
+
+/* Store VAL as a big-endian value in the LENGTH bytes at BUF. */
+static void
+put_be (unsigned char *buf, int length, DI val)
+{
+ int i;
+
+ for (i = length-1; i >= 0; i--)
+ {
+ buf[i] = val & 0xff;
+ val >>= 8;
+ }
+}
+
+
+static int
+check_regno (enum sim_rx_regnum regno)
+{
+ return 0 <= regno && regno < sim_rx_num_regs;
+}
+
+static size_t
+reg_size (enum sim_rx_regnum regno)
+{
+ size_t size;
+
+ switch (regno)
+ {
+ case sim_rx_r0_regnum:
+ size = sizeof (regs.r[0]);
+ break;
+ case sim_rx_r1_regnum:
+ size = sizeof (regs.r[1]);
+ break;
+ case sim_rx_r2_regnum:
+ size = sizeof (regs.r[2]);
+ break;
+ case sim_rx_r3_regnum:
+ size = sizeof (regs.r[3]);
+ break;
+ case sim_rx_r4_regnum:
+ size = sizeof (regs.r[4]);
+ break;
+ case sim_rx_r5_regnum:
+ size = sizeof (regs.r[5]);
+ break;
+ case sim_rx_r6_regnum:
+ size = sizeof (regs.r[6]);
+ break;
+ case sim_rx_r7_regnum:
+ size = sizeof (regs.r[7]);
+ break;
+ case sim_rx_r8_regnum:
+ size = sizeof (regs.r[8]);
+ break;
+ case sim_rx_r9_regnum:
+ size = sizeof (regs.r[9]);
+ break;
+ case sim_rx_r10_regnum:
+ size = sizeof (regs.r[10]);
+ break;
+ case sim_rx_r11_regnum:
+ size = sizeof (regs.r[11]);
+ break;
+ case sim_rx_r12_regnum:
+ size = sizeof (regs.r[12]);
+ break;
+ case sim_rx_r13_regnum:
+ size = sizeof (regs.r[13]);
+ break;
+ case sim_rx_r14_regnum:
+ size = sizeof (regs.r[14]);
+ break;
+ case sim_rx_r15_regnum:
+ size = sizeof (regs.r[15]);
+ break;
+ case sim_rx_isp_regnum:
+ size = sizeof (regs.r_isp);
+ break;
+ case sim_rx_usp_regnum:
+ size = sizeof (regs.r_usp);
+ break;
+ case sim_rx_intb_regnum:
+ size = sizeof (regs.r_intb);
+ break;
+ case sim_rx_pc_regnum:
+ size = sizeof (regs.r_pc);
+ break;
+ case sim_rx_ps_regnum:
+ size = sizeof (regs.r_psw);
+ break;
+ case sim_rx_bpc_regnum:
+ size = sizeof (regs.r_bpc);
+ break;
+ case sim_rx_bpsw_regnum:
+ size = sizeof (regs.r_bpsw);
+ break;
+ case sim_rx_fintv_regnum:
+ size = sizeof (regs.r_fintv);
+ break;
+ case sim_rx_fpsw_regnum:
+ size = sizeof (regs.r_fpsw);
+ break;
+ default:
+ size = 0;
+ break;
+ }
+ return size;
+}
+
+int
+sim_fetch_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
+{
+ size_t size;
+ DI val;
+
+ check_desc (sd);
+
+ if (!check_regno (regno))
+ return 0;
+
+ size = reg_size (regno);
+
+ if (length != size)
+ return 0;
+
+ switch (regno)
+ {
+ case sim_rx_r0_regnum:
+ val = get_reg (0);
+ break;
+ case sim_rx_r1_regnum:
+ val = get_reg (1);
+ break;
+ case sim_rx_r2_regnum:
+ val = get_reg (2);
+ break;
+ case sim_rx_r3_regnum:
+ val = get_reg (3);
+ break;
+ case sim_rx_r4_regnum:
+ val = get_reg (4);
+ break;
+ case sim_rx_r5_regnum:
+ val = get_reg (5);
+ break;
+ case sim_rx_r6_regnum:
+ val = get_reg (6);
+ break;
+ case sim_rx_r7_regnum:
+ val = get_reg (7);
+ break;
+ case sim_rx_r8_regnum:
+ val = get_reg (8);
+ break;
+ case sim_rx_r9_regnum:
+ val = get_reg (9);
+ break;
+ case sim_rx_r10_regnum:
+ val = get_reg (10);
+ break;
+ case sim_rx_r11_regnum:
+ val = get_reg (11);
+ break;
+ case sim_rx_r12_regnum:
+ val = get_reg (12);
+ break;
+ case sim_rx_r13_regnum:
+ val = get_reg (13);
+ break;
+ case sim_rx_r14_regnum:
+ val = get_reg (14);
+ break;
+ case sim_rx_r15_regnum:
+ val = get_reg (15);
+ break;
+ case sim_rx_isp_regnum:
+ val = get_reg (isp);
+ break;
+ case sim_rx_usp_regnum:
+ val = get_reg (usp);
+ break;
+ case sim_rx_intb_regnum:
+ val = get_reg (intb);
+ break;
+ case sim_rx_pc_regnum:
+ val = get_reg (pc);
+ break;
+ case sim_rx_ps_regnum:
+ val = get_reg (psw);
+ break;
+ case sim_rx_bpc_regnum:
+ val = get_reg (bpc);
+ break;
+ case sim_rx_bpsw_regnum:
+ val = get_reg (bpsw);
+ break;
+ case sim_rx_fintv_regnum:
+ val = get_reg (fintv);
+ break;
+ case sim_rx_fpsw_regnum:
+ val = get_reg (fpsw);
+ break;
+ default:
+ fprintf (stderr, "rx minisim: unrecognized register number: %d\n",
+ regno);
+ return -1;
+ }
+
+ if (rx_big_endian)
+ put_be (buf, length, val);
+ else
+ put_le (buf, length, val);
+
+ return size;
+}
+
+int
+sim_store_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
+{
+ size_t size;
+ DI val;
+
+ check_desc (sd);
+
+ if (!check_regno (regno))
+ return 0;
+
+ size = reg_size (regno);
+
+ if (length != size)
+ return 0;
+
+ if (rx_big_endian)
+ val = get_be (buf, length);
+ else
+ val = get_le (buf, length);
+
+ switch (regno)
+ {
+ case sim_rx_r0_regnum:
+ put_reg (0, val);
+ break;
+ case sim_rx_r1_regnum:
+ put_reg (1, val);
+ break;
+ case sim_rx_r2_regnum:
+ put_reg (2, val);
+ break;
+ case sim_rx_r3_regnum:
+ put_reg (3, val);
+ break;
+ case sim_rx_r4_regnum:
+ put_reg (4, val);
+ break;
+ case sim_rx_r5_regnum:
+ put_reg (5, val);
+ break;
+ case sim_rx_r6_regnum:
+ put_reg (6, val);
+ break;
+ case sim_rx_r7_regnum:
+ put_reg (7, val);
+ break;
+ case sim_rx_r8_regnum:
+ put_reg (8, val);
+ break;
+ case sim_rx_r9_regnum:
+ put_reg (9, val);
+ break;
+ case sim_rx_r10_regnum:
+ put_reg (10, val);
+ break;
+ case sim_rx_r11_regnum:
+ put_reg (11, val);
+ break;
+ case sim_rx_r12_regnum:
+ put_reg (12, val);
+ break;
+ case sim_rx_r13_regnum:
+ put_reg (13, val);
+ break;
+ case sim_rx_r14_regnum:
+ put_reg (14, val);
+ break;
+ case sim_rx_r15_regnum:
+ put_reg (15, val);
+ break;
+ case sim_rx_isp_regnum:
+ put_reg (isp, val);
+ break;
+ case sim_rx_usp_regnum:
+ put_reg (usp, val);
+ break;
+ case sim_rx_intb_regnum:
+ put_reg (intb, val);
+ break;
+ case sim_rx_pc_regnum:
+ put_reg (pc, val);
+ break;
+ case sim_rx_ps_regnum:
+ put_reg (psw, val);
+ break;
+ case sim_rx_bpc_regnum:
+ put_reg (bpc, val);
+ break;
+ case sim_rx_bpsw_regnum:
+ put_reg (bpsw, val);
+ break;
+ case sim_rx_fintv_regnum:
+ put_reg (fintv, val);
+ break;
+ case sim_rx_fpsw_regnum:
+ put_reg (fpsw, val);
+ break;
+ default:
+ fprintf (stderr, "rx minisim: unrecognized register number: %d\n",
+ regno);
+ return -1;
+ }
+
+ return size;
+}
+
+void
+sim_info (SIM_DESC sd, int verbose)
+{
+ check_desc (sd);
+
+ printf ("The rx minisim doesn't collect any statistics.\n");
+}
+
+static volatile int stop;
+static enum sim_stop reason;
+int siggnal;
+
+
+/* Given a signal number used by the RX bsp (that is, newlib),
+ return a host signal number. (Oddly, the gdb/sim interface uses
+ host signal numbers...) */
+int
+rx_signal_to_host (int rx)
+{
+ switch (rx)
+ {
+ case 4:
+#ifdef SIGILL
+ return SIGILL;
+#else
+ return SIGSEGV;
+#endif
+
+ case 5:
+ return SIGTRAP;
+
+ case 10:
+#ifdef SIGBUS
+ return SIGBUS;
+#else
+ return SIGSEGV;
+#endif
+
+ case 11:
+ return SIGSEGV;
+
+ case 24:
+#ifdef SIGXCPU
+ return SIGXCPU;
+#else
+ break;
+#endif
+
+ case 2:
+ return SIGINT;
+
+ case 8:
+#ifdef SIGFPE
+ return SIGFPE;
+#else
+ break;
+#endif
+
+ case 6:
+ return SIGABRT;
+ }
+
+ return 0;
+}
+
+
+/* Take a step return code RC and set up the variables consulted by
+ sim_stop_reason appropriately. */
+void
+handle_step (int rc)
+{
+ if (execution_error_get_last_error () != SIM_ERR_NONE)
+ {
+ reason = sim_stopped;
+ siggnal = TARGET_SIGNAL_SEGV;
+ }
+ if (RX_STEPPED (rc) || RX_HIT_BREAK (rc))
+ {
+ reason = sim_stopped;
+ siggnal = TARGET_SIGNAL_TRAP;
+ }
+ else if (RX_STOPPED (rc))
+ {
+ reason = sim_stopped;
+ siggnal = rx_signal_to_host (RX_STOP_SIG (rc));
+ }
+ else
+ {
+ assert (RX_EXITED (rc));
+ reason = sim_exited;
+ siggnal = RX_EXIT_STATUS (rc);
+ }
+}
+
+
+void
+sim_resume (SIM_DESC sd, int step, int sig_to_deliver)
+{
+ check_desc (sd);
+
+ if (sig_to_deliver != 0)
+ {
+ fprintf (stderr,
+ "Warning: the rx minisim does not implement "
+ "signal delivery yet.\n" "Resuming with no signal.\n");
+ }
+
+ execution_error_clear_last_error ();
+
+ if (step)
+ handle_step (decode_opcode ());
+ else
+ {
+ /* We don't clear 'stop' here, because then we would miss
+ interrupts that arrived on the way here. Instead, we clear
+ the flag in sim_stop_reason, after GDB has disabled the
+ interrupt signal handler. */
+ for (;;)
+ {
+ if (stop)
+ {
+ stop = 0;
+ reason = sim_stopped;
+ siggnal = TARGET_SIGNAL_INT;
+ break;
+ }
+
+ int rc = decode_opcode ();
+
+ if (execution_error_get_last_error () != SIM_ERR_NONE)
+ {
+ reason = sim_stopped;
+ siggnal = TARGET_SIGNAL_SEGV;
+ break;
+ }
+
+ if (!RX_STEPPED (rc))
+ {
+ handle_step (rc);
+ break;
+ }
+ }
+ }
+}
+
+int
+sim_stop (SIM_DESC sd)
+{
+ stop = 1;
+
+ return 1;
+}
+
+void
+sim_stop_reason (SIM_DESC sd, enum sim_stop *reason_p, int *sigrc_p)
+{
+ check_desc (sd);
+
+ *reason_p = reason;
+ *sigrc_p = siggnal;
+}
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+ check_desc (sd);
+
+ char *p = cmd;
+
+ /* Skip leading whitespace. */
+ while (isspace (*p))
+ p++;
+
+ /* Find the extent of the command word. */
+ for (p = cmd; *p; p++)
+ if (isspace (*p))
+ break;
+
+ /* Null-terminate the command word, and record the start of any
+ further arguments. */
+ char *args;
+ if (*p)
+ {
+ *p = '\0';
+ args = p + 1;
+ while (isspace (*args))
+ args++;
+ }
+ else
+ args = p;
+
+ if (strcmp (cmd, "trace") == 0)
+ {
+ if (strcmp (args, "on") == 0)
+ trace = 1;
+ else if (strcmp (args, "off") == 0)
+ trace = 0;
+ else
+ printf ("The 'sim trace' command expects 'on' or 'off' "
+ "as an argument.\n");
+ }
+ else if (strcmp (cmd, "verbose") == 0)
+ {
+ if (strcmp (args, "on") == 0)
+ verbose = 1;
+ else if (strcmp (args, "off") == 0)
+ verbose = 0;
+ else
+ printf ("The 'sim verbose' command expects 'on' or 'off'"
+ " as an argument.\n");
+ }
+ else
+ printf ("The 'sim' command expects either 'trace' or 'verbose'"
+ " as a subcommand.\n");
+}