/* gdb.c --- sim interface to GDB.
Copyright (C) 2005-2023 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 . */
/* This must come before any other includes. */
#include "defs.h"
#include
#include
#include
#include
#include
#include
#include "ansidecl.h"
#include "libiberty.h"
#include "sim/callback.h"
#include "sim/sim.h"
#include "gdb/signals.h"
#include "sim/sim-m32c.h"
#include "cpu.h"
#include "mem.h"
#include "load.h"
#include "syscalls.h"
#ifdef TIMER_A
#include "timer_a.h"
#endif
/* I don't want to wrap up all the minisim's data structures in an
object and pass that around. That'd be a big change, and 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 m32c minisim instance. See libsim.a's global variables."
};
static int is_open;
SIM_DESC
sim_open (SIM_OPEN_KIND kind,
struct host_callback_struct *callback,
struct bfd *abfd, char * const *argv)
{
setbuf (stdout, 0);
if (is_open)
fprintf (stderr, "m32c 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, "m32c minisim: sim_open KIND != SIM_OPEN_DEBUG: %d\n",
kind);
if (abfd)
m32c_set_mach (bfd_get_mach (abfd));
/* We can use ABFD, if non-NULL to select the appropriate
architecture. But we only support the r8c right now. */
set_callbacks (callback);
/* We don't expect any command-line arguments. */
init_mem ();
init_regs ();
is_open = 1;
return &the_minisim;
}
static void
check_desc (SIM_DESC sd)
{
if (sd != &the_minisim)
fprintf (stderr, "m32c 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 ();
is_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 m32c program\n", filename);
return 0;
}
return prog;
}
SIM_RC
sim_load (SIM_DESC sd, const char *prog, struct bfd * abfd, int from_tty)
{
check_desc (sd);
if (!abfd)
abfd = open_objfile (prog);
if (!abfd)
return SIM_RC_FAIL;
m32c_load (abfd);
return SIM_RC_OK;
}
SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd * abfd,
char * const *argv, char * const *env)
{
check_desc (sd);
if (abfd)
m32c_load (abfd);
return SIM_RC_OK;
}
uint64_t
sim_read (SIM_DESC sd, uint64_t mem, void *buf, uint64_t length)
{
check_desc (sd);
if (mem == 0)
return 0;
mem_get_blk ((int) mem, buf, length);
return length;
}
uint64_t
sim_write (SIM_DESC sd, uint64_t mem, const void *buf, uint64_t length)
{
check_desc (sd);
mem_put_blk ((int) mem, buf, length);
return length;
}
/* Read the LENGTH bytes at BUF as an little-endian value. */
static DI
get_le (const unsigned char *buf, int length)
{
DI acc = 0;
while (--length >= 0)
acc = (acc << 8) + buf[length];
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;
}
}
static int
check_regno (enum m32c_sim_reg regno)
{
return 0 <= regno && regno < m32c_sim_reg_num_regs;
}
static size_t
mask_size (int addr_mask)
{
switch (addr_mask)
{
case 0xffff:
return 2;
case 0xfffff:
case 0xffffff:
return 3;
default:
fprintf (stderr,
"m32c minisim: addr_mask_size: unexpected mask 0x%x\n",
addr_mask);
return sizeof (addr_mask);
}
}
static size_t
reg_size (enum m32c_sim_reg regno)
{
switch (regno)
{
case m32c_sim_reg_r0_bank0:
case m32c_sim_reg_r1_bank0:
case m32c_sim_reg_r2_bank0:
case m32c_sim_reg_r3_bank0:
case m32c_sim_reg_r0_bank1:
case m32c_sim_reg_r1_bank1:
case m32c_sim_reg_r2_bank1:
case m32c_sim_reg_r3_bank1:
case m32c_sim_reg_flg:
case m32c_sim_reg_svf:
return 2;
case m32c_sim_reg_a0_bank0:
case m32c_sim_reg_a1_bank0:
case m32c_sim_reg_fb_bank0:
case m32c_sim_reg_sb_bank0:
case m32c_sim_reg_a0_bank1:
case m32c_sim_reg_a1_bank1:
case m32c_sim_reg_fb_bank1:
case m32c_sim_reg_sb_bank1:
case m32c_sim_reg_usp:
case m32c_sim_reg_isp:
return mask_size (addr_mask);
case m32c_sim_reg_pc:
case m32c_sim_reg_intb:
case m32c_sim_reg_svp:
case m32c_sim_reg_vct:
return mask_size (membus_mask);
case m32c_sim_reg_dmd0:
case m32c_sim_reg_dmd1:
return 1;
case m32c_sim_reg_dct0:
case m32c_sim_reg_dct1:
case m32c_sim_reg_drc0:
case m32c_sim_reg_drc1:
return 2;
case m32c_sim_reg_dma0:
case m32c_sim_reg_dma1:
case m32c_sim_reg_dsa0:
case m32c_sim_reg_dsa1:
case m32c_sim_reg_dra0:
case m32c_sim_reg_dra1:
return 3;
default:
fprintf (stderr, "m32c minisim: unrecognized register number: %d\n",
regno);
return -1;
}
}
int
sim_fetch_register (SIM_DESC sd, int regno, void *buf, int length)
{
size_t size;
check_desc (sd);
if (!check_regno (regno))
return 0;
size = reg_size (regno);
if (length == size)
{
DI val;
switch (regno)
{
case m32c_sim_reg_r0_bank0:
val = regs.r[0].r_r0;
break;
case m32c_sim_reg_r1_bank0:
val = regs.r[0].r_r1;
break;
case m32c_sim_reg_r2_bank0:
val = regs.r[0].r_r2;
break;
case m32c_sim_reg_r3_bank0:
val = regs.r[0].r_r3;
break;
case m32c_sim_reg_a0_bank0:
val = regs.r[0].r_a0;
break;
case m32c_sim_reg_a1_bank0:
val = regs.r[0].r_a1;
break;
case m32c_sim_reg_fb_bank0:
val = regs.r[0].r_fb;
break;
case m32c_sim_reg_sb_bank0:
val = regs.r[0].r_sb;
break;
case m32c_sim_reg_r0_bank1:
val = regs.r[1].r_r0;
break;
case m32c_sim_reg_r1_bank1:
val = regs.r[1].r_r1;
break;
case m32c_sim_reg_r2_bank1:
val = regs.r[1].r_r2;
break;
case m32c_sim_reg_r3_bank1:
val = regs.r[1].r_r3;
break;
case m32c_sim_reg_a0_bank1:
val = regs.r[1].r_a0;
break;
case m32c_sim_reg_a1_bank1:
val = regs.r[1].r_a1;
break;
case m32c_sim_reg_fb_bank1:
val = regs.r[1].r_fb;
break;
case m32c_sim_reg_sb_bank1:
val = regs.r[1].r_sb;
break;
case m32c_sim_reg_usp:
val = regs.r_usp;
break;
case m32c_sim_reg_isp:
val = regs.r_isp;
break;
case m32c_sim_reg_pc:
val = regs.r_pc;
break;
case m32c_sim_reg_intb:
val = regs.r_intbl * 65536 + regs.r_intbl;
break;
case m32c_sim_reg_flg:
val = regs.r_flags;
break;
/* These registers aren't implemented by the minisim. */
case m32c_sim_reg_svf:
case m32c_sim_reg_svp:
case m32c_sim_reg_vct:
case m32c_sim_reg_dmd0:
case m32c_sim_reg_dmd1:
case m32c_sim_reg_dct0:
case m32c_sim_reg_dct1:
case m32c_sim_reg_drc0:
case m32c_sim_reg_drc1:
case m32c_sim_reg_dma0:
case m32c_sim_reg_dma1:
case m32c_sim_reg_dsa0:
case m32c_sim_reg_dsa1:
case m32c_sim_reg_dra0:
case m32c_sim_reg_dra1:
return 0;
default:
fprintf (stderr, "m32c minisim: unrecognized register number: %d\n",
regno);
return -1;
}
put_le (buf, length, val);
}
return size;
}
int
sim_store_register (SIM_DESC sd, int regno, const void *buf, int length)
{
size_t size;
check_desc (sd);
if (!check_regno (regno))
return -1;
size = reg_size (regno);
if (length == size)
{
DI val = get_le (buf, length);
switch (regno)
{
case m32c_sim_reg_r0_bank0:
regs.r[0].r_r0 = val & 0xffff;
break;
case m32c_sim_reg_r1_bank0:
regs.r[0].r_r1 = val & 0xffff;
break;
case m32c_sim_reg_r2_bank0:
regs.r[0].r_r2 = val & 0xffff;
break;
case m32c_sim_reg_r3_bank0:
regs.r[0].r_r3 = val & 0xffff;
break;
case m32c_sim_reg_a0_bank0:
regs.r[0].r_a0 = val & addr_mask;
break;
case m32c_sim_reg_a1_bank0:
regs.r[0].r_a1 = val & addr_mask;
break;
case m32c_sim_reg_fb_bank0:
regs.r[0].r_fb = val & addr_mask;
break;
case m32c_sim_reg_sb_bank0:
regs.r[0].r_sb = val & addr_mask;
break;
case m32c_sim_reg_r0_bank1:
regs.r[1].r_r0 = val & 0xffff;
break;
case m32c_sim_reg_r1_bank1:
regs.r[1].r_r1 = val & 0xffff;
break;
case m32c_sim_reg_r2_bank1:
regs.r[1].r_r2 = val & 0xffff;
break;
case m32c_sim_reg_r3_bank1:
regs.r[1].r_r3 = val & 0xffff;
break;
case m32c_sim_reg_a0_bank1:
regs.r[1].r_a0 = val & addr_mask;
break;
case m32c_sim_reg_a1_bank1:
regs.r[1].r_a1 = val & addr_mask;
break;
case m32c_sim_reg_fb_bank1:
regs.r[1].r_fb = val & addr_mask;
break;
case m32c_sim_reg_sb_bank1:
regs.r[1].r_sb = val & addr_mask;
break;
case m32c_sim_reg_usp:
regs.r_usp = val & addr_mask;
break;
case m32c_sim_reg_isp:
regs.r_isp = val & addr_mask;
break;
case m32c_sim_reg_pc:
regs.r_pc = val & membus_mask;
break;
case m32c_sim_reg_intb:
regs.r_intbl = (val & membus_mask) & 0xffff;
regs.r_intbh = (val & membus_mask) >> 16;
break;
case m32c_sim_reg_flg:
regs.r_flags = val & 0xffff;
break;
/* These registers aren't implemented by the minisim. */
case m32c_sim_reg_svf:
case m32c_sim_reg_svp:
case m32c_sim_reg_vct:
case m32c_sim_reg_dmd0:
case m32c_sim_reg_dmd1:
case m32c_sim_reg_dct0:
case m32c_sim_reg_dct1:
case m32c_sim_reg_drc0:
case m32c_sim_reg_drc1:
case m32c_sim_reg_dma0:
case m32c_sim_reg_dma1:
case m32c_sim_reg_dsa0:
case m32c_sim_reg_dsa1:
case m32c_sim_reg_dra0:
case m32c_sim_reg_dra1:
return 0;
default:
fprintf (stderr, "m32c minisim: unrecognized register number: %d\n",
regno);
return 0;
}
}
return size;
}
static volatile int stop;
static enum sim_stop reason;
static int siggnal;
/* Given a signal number used by the M32C bsp (that is, newlib),
return a target signal number used by GDB. */
static int
m32c_signal_to_target (int m32c)
{
switch (m32c)
{
case 4:
return GDB_SIGNAL_ILL;
case 5:
return GDB_SIGNAL_TRAP;
case 10:
return GDB_SIGNAL_BUS;
case 11:
return GDB_SIGNAL_SEGV;
case 24:
return GDB_SIGNAL_XCPU;
case 2:
return GDB_SIGNAL_INT;
case 8:
return GDB_SIGNAL_FPE;
case 6:
return GDB_SIGNAL_ABRT;
}
return 0;
}
/* Take a step return code RC and set up the variables consulted by
sim_stop_reason appropriately. */
static void
handle_step (int rc)
{
if (M32C_STEPPED (rc) || M32C_HIT_BREAK (rc))
{
reason = sim_stopped;
siggnal = GDB_SIGNAL_TRAP;
}
else if (M32C_STOPPED (rc))
{
reason = sim_stopped;
siggnal = m32c_signal_to_target (M32C_STOP_SIG (rc));
}
else
{
assert (M32C_EXITED (rc));
reason = sim_exited;
siggnal = M32C_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 m32c minisim does not implement "
"signal delivery yet.\n" "Resuming with no signal.\n");
}
if (step)
{
handle_step (decode_opcode ());
#ifdef TIMER_A
update_timer_a ();
#endif
}
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 (;;)
{
int rc;
if (stop)
{
stop = 0;
reason = sim_stopped;
siggnal = GDB_SIGNAL_INT;
break;
}
rc = decode_opcode ();
#ifdef TIMER_A
update_timer_a ();
#endif
if (!M32C_STEPPED (rc))
{
handle_step (rc);
break;
}
}
}
m32c_sim_restore_console ();
}
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, const char *cmd)
{
const char *arg;
char **argv = buildargv (cmd);
check_desc (sd);
cmd = arg = "";
if (argv != NULL)
{
if (argv[0] != NULL)
cmd = argv[0];
if (argv[1] != NULL)
arg = argv[1];
}
if (strcmp (cmd, "trace") == 0)
{
if (strcmp (arg, "on") == 0)
trace = 1;
else if (strcmp (arg, "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 (arg, "on") == 0)
verbose = 1;
else if (strcmp (arg, "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");
freeargv (argv);
}
char **
sim_complete_command (SIM_DESC sd, const char *text, const char *word)
{
return NULL;
}
char *
sim_memory_map (SIM_DESC sd)
{
return NULL;
}
void
sim_info (SIM_DESC sd, bool verbose)
{
printf ("The m32c minisim doesn't collect any statistics.\n");
}