diff options
author | DJ Delorie <dj@redhat.com> | 2009-11-24 19:22:45 +0000 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2009-11-24 19:22:45 +0000 |
commit | 4f8d4a386168d6152f3006187c5ecf722eb27d67 (patch) | |
tree | e86bf5972e5f09f8c37230b21c220a65a116e734 /sim/rx/gdb-if.c | |
parent | e4d2e6658e104829003a91249ffe27ae1afb0b34 (diff) | |
download | gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.zip gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.tar.gz gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.tar.bz2 |
[sim]
* rx: New directory.
* configure.ac: Add entry for Renesas RX.
* configure: Regenerate.
[include/gdb]
* sim-rx.h: New.
Diffstat (limited to 'sim/rx/gdb-if.c')
-rw-r--r-- | sim/rx/gdb-if.c | 841 |
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 0000000..a8db2bb --- /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"); +} |