Redo watchpoint code so that it target can specify interrupt names.

Replace v850 interrupt code with this common watchpoint code.
Other minor fixes to core.
This commit is contained in:
Andrew Cagney 1997-09-05 08:16:23 +00:00
parent 1b465b54e1
commit 1bba340afe
4 changed files with 371 additions and 215 deletions

View File

@ -1,5 +1,20 @@
Fri Sep 5 08:39:02 1997 Andrew Cagney <cagney@b1.cygnus.com> Fri Sep 5 08:39:02 1997 Andrew Cagney <cagney@b1.cygnus.com>
* sim-core.c (sim_core_attach): Fix checks of modulo/mask.
* sim-watch.c (delete_watchpoint): Delete by ident and type.
(watch_option_handler): Call delete_watchpoint with ident or type.
(sim_watchpoint_install): Create interrupt specific watchpoint
commands on the fly.
(do_watchpoint_create): New function, create a watch point using
type/int-nr info encoded in the option nr.
(do_watchpoint_info): New function. List active watchpoints.
* sim-watch.h: Change data structure to a list.
* sim-memopt.c (memory_option_handler): Require explicit "all"
before deleting all memory regions.
* sim-utils.c (sim_do_commandf): New function, printf version of * sim-utils.c (sim_do_commandf): New function, printf version of
sim_do_command. sim_do_command.

View File

@ -297,8 +297,12 @@ sim_core_attach (SIM_DESC sd,
if (mask < 7) /* 8 is minimum modulo */ if (mask < 7) /* 8 is minimum modulo */
mask = 0; mask = 0;
while (mask > 1) /* no zero bits */ while (mask > 1) /* no zero bits */
if ((mask & 1) == 0) {
mask = 0; if ((mask & 1) == 0)
mask = 0;
else
mask >>= 1;
}
if (mask == 0) if (mask == 0)
{ {
#if (WITH_DEVICES) #if (WITH_DEVICES)
@ -308,7 +312,7 @@ sim_core_attach (SIM_DESC sd,
#endif #endif
} }
} }
else if (WITH_MODULO_MEMORY && modulo != 0) else if (!WITH_MODULO_MEMORY && modulo != 0)
{ {
#if (WITH_DEVICES) #if (WITH_DEVICES)
device_error (client, "sim_core_attach - internal error - modulo memory disabled"); device_error (client, "sim_core_attach - internal error - modulo memory disabled");

View File

@ -1,4 +1,4 @@
/* Mips simulator watchpoint support. /* Generic simulator watchpoint support.
Copyright (C) 1997 Free Software Foundation, Inc. Copyright (C) 1997 Free Software Foundation, Inc.
Contributed by Cygnus Support. Contributed by Cygnus Support.
@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sim-assert.h" #include "sim-assert.h"
#include <ctype.h>
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>
#else #else
@ -37,76 +39,175 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <signal.h> #include <signal.h>
static DECLARE_OPTION_HANDLER (watch_option_handler);
enum { enum {
OPTION_WATCH_DELETE = OPTION_START, OPTION_WATCH_DELETE = OPTION_START,
OPTION_WATCH_PC, OPTION_WATCH_INFO,
OPTION_WATCH_CLOCK, OPTION_WATCH_CLOCK,
OPTION_WATCH_CYCLES, OPTION_WATCH_CYCLES,
OPTION_WATCH_PC,
OPTION_ACTION_PC, OPTION_WATCH_OP,
OPTION_ACTION_CLOCK,
OPTION_ACTION_CYCLES,
}; };
static void /* Break an option number into its op/int-nr */
delete_watchpoint (SIM_DESC sd, watchpoint_type type) static watchpoint_type
option_to_type (SIM_DESC sd,
int option)
{ {
sim_watch_point *point = &STATE_WATCHPOINTS (sd)->points[type]; sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
if (point->event != NULL) watchpoint_type type = ((option - OPTION_WATCH_OP)
sim_events_deschedule (sd, point->event); / (watch->nr_interrupts + 1));
point->action = invalid_watchpoint_action; SIM_ASSERT (type >= 0 && type < nr_watchpoint_types);
point->event = NULL; return type;
} }
static int
option_to_interrupt_nr (SIM_DESC sd,
int option)
{
sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
int interrupt_nr = ((option - OPTION_WATCH_OP)
% (watch->nr_interrupts + 1));
return interrupt_nr;
}
static int
type_to_option (SIM_DESC sd,
watchpoint_type type,
int interrupt_nr)
{
sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
return ((type * (watch->nr_interrupts + 1))
+ interrupt_nr
+ OPTION_WATCH_OP);
}
/* Delete one or more watchpoints. Fail if no watchpoints were found */
static SIM_RC
do_watchpoint_delete (SIM_DESC sd,
int ident,
watchpoint_type type)
{
sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
sim_watch_point **entry = &watch->points;
SIM_RC status = SIM_RC_FAIL;
while ((*entry) != NULL)
{
if ((*entry)->ident == ident
|| (*entry)->type == type)
{
sim_watch_point *dead = (*entry);
(*entry) = (*entry)->next;
sim_events_deschedule (sd, dead->event);
zfree (dead);
status = SIM_RC_OK;
}
else
entry = &(*entry)->next;
}
return status;
}
static char *
watchpoint_type_to_str (SIM_DESC sd,
watchpoint_type type)
{
switch (type)
{
case pc_watchpoint:
return "pc";
case clock_watchpoint:
return "clock";
case cycles_watchpoint:
return "cycles";
case invalid_watchpoint:
case nr_watchpoint_types:
return "(invalid-type)";
}
return NULL;
}
static char *
interrupt_nr_to_str (SIM_DESC sd,
int interrupt_nr)
{
sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
if (interrupt_nr < 0)
return "(invalid-interrupt)";
else if (interrupt_nr >= watch->nr_interrupts)
return "breakpoint";
else
return watch->interrupt_names[interrupt_nr];
}
static void
do_watchpoint_info (SIM_DESC sd)
{
sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
sim_watch_point *point;
sim_io_printf (sd, "Watchpoints:\n");
for (point = watch->points; point != NULL; point = point->next)
{
sim_io_printf (sd, "%3d: watch %s %s ",
point->ident,
watchpoint_type_to_str (sd, point->type),
interrupt_nr_to_str (sd, point->interrupt_nr));
if (point->is_periodic)
sim_io_printf (sd, "+");
if (!point->is_within)
sim_io_printf (sd, "!");
sim_io_printf (sd, "0x%lx", point->arg0);
if (point->arg1 != point->arg0)
sim_io_printf (sd, ",0x%lx", point->arg1);
sim_io_printf (sd, "\n");
}
}
static sim_event_handler handle_watchpoint; static sim_event_handler handle_watchpoint;
static SIM_RC static SIM_RC
schedule_watchpoint (SIM_DESC sd, schedule_watchpoint (SIM_DESC sd,
watchpoint_type type, sim_watch_point *point)
unsigned long arg,
int is_within,
int is_command)
{ {
sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
sim_watch_point *point = &watch->points[type]; switch (point->type)
if (point->event != NULL) {
sim_events_deschedule (sd, point->event); case pc_watchpoint:
point->arg = arg; point->event = sim_events_watch_sim (sd,
point->is_within = is_within; watch->pc,
if (point->action == invalid_watchpoint_action) watch->sizeof_pc,
point->action = break_watchpoint_action; 0/* host-endian */,
if (is_command) point->is_within,
switch (type) point->arg0, point->arg1,
{ /* PC in arg0..arg1 */
case pc_watchpoint: handle_watchpoint,
point->event = sim_events_watch_sim (sd, watch->pc, watch->sizeof_pc, point);
0/* host-endian */, return SIM_RC_OK;
point->is_within, case clock_watchpoint:
point->arg, point->arg, /* PC == arg? */ point->event = sim_events_watch_clock (sd,
point->arg0, /* ms time */
handle_watchpoint, handle_watchpoint,
point); point);
return SIM_RC_OK; return SIM_RC_OK;
case clock_watchpoint: case cycles_watchpoint:
point->event = sim_events_watch_clock (sd, point->event = sim_events_schedule (sd,
point->arg, /* ms time */ point->arg0, /* time */
handle_watchpoint, handle_watchpoint,
point); point);
return SIM_RC_OK; return SIM_RC_OK;
case cycles_watchpoint: default:
point->event = sim_events_schedule (sd, point->arg, /* time */ sim_engine_abort (sd, NULL, NULL_CIA,
handle_watchpoint, "handle_watchpoint - internal error - bad switch");
point); return SIM_RC_FAIL;
return SIM_RC_OK; }
default:
sim_engine_abort (sd, NULL, NULL_CIA,
"handle_watchpoint - internal error - bad switch");
return SIM_RC_FAIL;
}
return SIM_RC_OK; return SIM_RC_OK;
} }
@ -115,195 +216,223 @@ static void
handle_watchpoint (SIM_DESC sd, void *data) handle_watchpoint (SIM_DESC sd, void *data)
{ {
sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
sim_watch_point *point = data; sim_watch_point *point = (sim_watch_point *) data;
watchpoint_type type = point - watch->points; int interrupt_nr = point->interrupt_nr;
switch (point->action) if (point->is_periodic)
{ /* reschedule this event before processing it */
schedule_watchpoint (sd, point);
case break_watchpoint_action: else
point->event = NULL; /* gone */ do_watchpoint_delete (sd, point->ident, invalid_watchpoint);
sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIGINT);
break; if (point->interrupt_nr == watch->nr_interrupts)
sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIGINT);
case n_interrupt_watchpoint_action: else
/* First reschedule this event */ watch->interrupt_handler (sd, &interrupt_nr);
schedule_watchpoint (sd, type, point->arg, point->is_within, 1/*is-command*/);
/* FALL-THROUGH */
case interrupt_watchpoint_action:
watch->interrupt_handler (sd, NULL);
break;
default:
sim_engine_abort (sd, NULL, NULL_CIA,
"handle_watchpoint - internal error - bad switch");
}
} }
static SIM_RC static SIM_RC
action_watchpoint (SIM_DESC sd, watchpoint_type type, const char *arg) do_watchpoint_create (SIM_DESC sd,
watchpoint_type type,
int opt,
char *arg)
{ {
sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
sim_watch_point *point = &watch->points[type]; sim_watch_point **point;
if (strcmp (arg, "break") == 0)
/* create the watchpoint */
point = &watch->points;
while ((*point) != NULL)
point = &(*point)->next;
(*point) = ZALLOC (sim_watch_point);
/* fill in the details */
(*point)->ident = ++(watch->last_point_nr);
(*point)->type = option_to_type (sd, opt);
(*point)->interrupt_nr = option_to_interrupt_nr (sd, opt);
/* prefixes to arg - +== periodic, !==not or outside */
(*point)->is_within = 1;
while (1)
{ {
point->action = break_watchpoint_action; if (arg[0] == '+')
} (*point)->is_periodic = 1;
else if (strcmp (arg, "int") == 0) else if (arg[0] == '!')
{ (*point)->is_within = 0;
if (watch->interrupt_handler == NULL) else
{ break;
sim_io_eprintf (sd, "This simulator does not support int watchpoints\n"); arg++;
return SIM_RC_FAIL;
}
point->action = interrupt_watchpoint_action;
}
else if (strcmp (arg, "+int") == 0)
{
if (watch->interrupt_handler == NULL)
{
sim_io_eprintf (sd, "This simulator does not support int watchpoints\n");
return SIM_RC_FAIL;
}
point->action = n_interrupt_watchpoint_action;
} }
(*point)->arg0 = strtoul (arg, &arg, 0);
if (arg[0] == ',')
(*point)->arg0 = strtoul (arg, NULL, 0);
else else
{ (*point)->arg1 = (*point)->arg0;
sim_io_eprintf (sd, "Interrupts other than `int' currently unsuported\n");
return SIM_RC_FAIL; /* schedule it */
} schedule_watchpoint (sd, (*point));
return SIM_RC_OK; return SIM_RC_OK;
} }
static const OPTION watch_options[] =
{
{ {"watch-delete", required_argument, NULL, OPTION_WATCH_DELETE },
'\0', "all|pc|cycles|clock", "Delete a watchpoint",
watch_option_handler },
{ {"delete-watch", required_argument, NULL, OPTION_WATCH_DELETE },
'\0', "all|pc|cycles|clock", NULL,
watch_option_handler },
{ {"watch-pc", required_argument, NULL, OPTION_WATCH_PC },
'\0', "[!] VALUE", "Watch the PC (break)",
watch_option_handler },
{ {"watch-clock", required_argument, NULL, OPTION_WATCH_CLOCK },
'\0', "TIME-IN-MS", "Watch the clock (break)",
watch_option_handler },
{ {"watch-cycles", required_argument, NULL, OPTION_WATCH_CYCLES },
'\0', "CYCLES", "Watch the cycles (break)",
watch_option_handler },
{ {"action-pc", required_argument, NULL, OPTION_ACTION_PC },
'\0', "break|int|+int", "Action taken by PC watchpoint",
watch_option_handler },
{ {"action-clock", required_argument, NULL, OPTION_ACTION_CLOCK },
'\0', "break|int|+int", "Action taken by CLOCK watchpoint",
watch_option_handler },
{ {"action-cycles", required_argument, NULL, OPTION_ACTION_CYCLES },
'\0', "break|int|+int", "Action taken by CYCLES watchpoint",
watch_option_handler },
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
};
static SIM_RC static SIM_RC
watch_option_handler (sd, opt, arg, is_command) watchpoint_option_handler (sd, opt, arg, is_command)
SIM_DESC sd; SIM_DESC sd;
int opt; int opt;
char *arg; char *arg;
int is_command; int is_command;
{ {
switch (opt) if (opt >= OPTION_WATCH_OP)
{ return do_watchpoint_create (sd, clock_watchpoint, opt, arg);
else
case OPTION_WATCH_DELETE: switch (opt)
if (strcmp (arg, "all") == 0 {
|| strcmp (arg, "pc") == 0)
case OPTION_WATCH_DELETE:
if (isdigit ((int) arg[0]))
{
int ident = strtol (arg, NULL, 0);
if (do_watchpoint_delete (sd, ident, invalid_watchpoint)
!= SIM_RC_OK)
{
sim_io_eprintf (sd, "Watchpoint %d not found\n", ident);
return SIM_RC_FAIL;
}
return SIM_RC_OK;
}
else if (strcasecmp (arg, "all") == 0)
{
watchpoint_type type;
for (type = invalid_watchpoint + 1;
type < nr_watchpoint_types;
type++)
{
do_watchpoint_delete (sd, 0, type);
}
return SIM_RC_OK;
}
else if (strcasecmp (arg, "pc") == 0)
{
if (do_watchpoint_delete (sd, 0, pc_watchpoint)
!= SIM_RC_OK)
{
sim_io_eprintf (sd, "No PC watchpoints found\n");
return SIM_RC_FAIL;
}
return SIM_RC_OK;
}
else if (strcasecmp (arg, "clock") == 0)
{
if (do_watchpoint_delete (sd, 0, clock_watchpoint) != SIM_RC_OK)
{
sim_io_eprintf (sd, "No CLOCK watchpoints found\n");
return SIM_RC_FAIL;
}
return SIM_RC_OK;
}
else if (strcasecmp (arg, "cycles") == 0)
{
if (do_watchpoint_delete (sd, 0, cycles_watchpoint) != SIM_RC_OK)
{
sim_io_eprintf (sd, "No CYCLES watchpoints found\n");
return SIM_RC_FAIL;
}
return SIM_RC_OK;
}
sim_io_eprintf (sd, "Unknown watchpoint type `%s'\n", arg);
return SIM_RC_FAIL;
case OPTION_WATCH_INFO:
{ {
delete_watchpoint (sd, pc_watchpoint); do_watchpoint_info (sd);
return SIM_RC_OK; return SIM_RC_OK;
} }
if (strcmp (arg, "all") == 0
|| strcmp (arg, "clock") == 0) default:
{ sim_io_eprintf (sd, "Unknown watch option %d\n", opt);
delete_watchpoint (sd, clock_watchpoint); return SIM_RC_FAIL;
return SIM_RC_OK;
} }
if (strcmp (arg, "all") == 0
|| strcmp (arg, "cycles") == 0)
{
delete_watchpoint (sd, cycles_watchpoint);
return SIM_RC_OK;
}
sim_io_eprintf (sd, "Unknown watchpoint type `%s'\n", arg);
return SIM_RC_FAIL;
case OPTION_WATCH_PC:
if (STATE_WATCHPOINTS (sd)->pc == NULL)
{
sim_io_eprintf (sd, "PC watchpoints are not supported for this simulator\n");
return SIM_RC_FAIL;
}
if (arg[0] == '!')
return schedule_watchpoint (sd, pc_watchpoint, strtoul (arg + 1, NULL, 0),
0 /* !is_within */, is_command);
else
return schedule_watchpoint (sd, pc_watchpoint, strtoul (arg, NULL, 0),
1 /* is_within */, is_command);
case OPTION_WATCH_CLOCK:
return schedule_watchpoint (sd, clock_watchpoint, strtoul (arg, NULL, 0), 0, is_command);
case OPTION_WATCH_CYCLES:
return schedule_watchpoint (sd, cycles_watchpoint, strtoul (arg, NULL, 0), 0, is_command);
case OPTION_ACTION_PC:
return action_watchpoint (sd, pc_watchpoint, arg);
case OPTION_ACTION_CLOCK:
return action_watchpoint (sd, clock_watchpoint, arg);
case OPTION_ACTION_CYCLES:
return action_watchpoint (sd, cycles_watchpoint, arg);
default:
sim_io_eprintf (sd, "Unknown watch option %d\n", opt);
return SIM_RC_FAIL;
}
} }
static SIM_RC static SIM_RC
sim_watchpoint_init (SIM_DESC sd) sim_watchpoint_init (SIM_DESC sd)
{ {
/* schedule any watchpoints enabled by command line options */
sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
watchpoint_type type; sim_watch_point *point;
for (type = 0; type < nr_watchpoint_types; type++) /* NOTE: Do not need to de-schedule any previous watchpoints as
sim-events has already done this */
/* schedule any watchpoints enabled by command line options */
for (point = watch->points; point != NULL; point = point->next)
{ {
if (watch->points[type].action != invalid_watchpoint_action) schedule_watchpoint (sd, point);
schedule_watchpoint (sd, type,
watch->points[type].arg,
watch->points[type].is_within,
1 /*is-command*/);
} }
return SIM_RC_OK; return SIM_RC_OK;
} }
static const OPTION watchpoint_options[] =
{
{ {"watch-delete", required_argument, NULL, OPTION_WATCH_DELETE },
'\0', "IDENT|all|pc|cycles|clock", "Delete a watchpoint",
watchpoint_option_handler },
{ {"watch-info", no_argument, NULL, OPTION_WATCH_INFO },
'\0', NULL, "List scheduled watchpoints",
watchpoint_option_handler },
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
};
static const OPTION template_int_option = {
{ NULL, required_argument, NULL, 0 },
'\0', "VALUE", "Create the specified watchpoint",
watchpoint_option_handler,
};
static char *default_interrupt_names[] = { "int", 0, };
SIM_RC SIM_RC
sim_watchpoint_install (SIM_DESC sd) sim_watchpoint_install (SIM_DESC sd)
{ {
sim_watchpoints *watch = STATE_WATCHPOINTS (sd);
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
sim_add_option_table (sd, watch_options); /* the basic command set */
sim_module_add_init_fn (sd, sim_watchpoint_init); sim_module_add_init_fn (sd, sim_watchpoint_init);
sim_add_option_table (sd, watchpoint_options);
/* fill in some details */
if (watch->interrupt_names == NULL)
watch->interrupt_names = default_interrupt_names;
watch->nr_interrupts = 0;
while (watch->interrupt_names[watch->nr_interrupts] != NULL)
watch->nr_interrupts++;
/* generate more advansed commands */
{
OPTION *int_options = NZALLOC (OPTION, 1 + (watch->nr_interrupts + 1) * nr_watchpoint_types);
int interrupt_nr;
for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++)
{
watchpoint_type type;
for (type = 0; type < nr_watchpoint_types; type++)
{
int nr = interrupt_nr * nr_watchpoint_types + type;
OPTION *option = &int_options[nr];
char *name;
*option = template_int_option;
asprintf (&name, "watch-%s-%s",
watchpoint_type_to_str (sd, type),
interrupt_nr_to_str (sd, interrupt_nr));
option->opt.name = name;
option->opt.val = type_to_option (sd, type, interrupt_nr);
}
}
sim_add_option_table (sd, int_options);
}
return SIM_RC_OK; return SIM_RC_OK;
} }

View File

@ -23,25 +23,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define SIM_WATCH_H #define SIM_WATCH_H
typedef enum { typedef enum {
invalid_watchpoint = -1,
pc_watchpoint, pc_watchpoint,
clock_watchpoint, clock_watchpoint,
cycles_watchpoint, cycles_watchpoint,
nr_watchpoint_types, nr_watchpoint_types,
} watchpoint_type; } watchpoint_type;
typedef enum { typedef struct _sim_watch_point sim_watch_point;
invalid_watchpoint_action, struct _sim_watch_point {
n_interrupt_watchpoint_action, int ident;
interrupt_watchpoint_action, watchpoint_type type;
break_watchpoint_action, int interrupt_nr; /* == nr_interrupts -> breakpoint */
} watchpoint_action; int is_periodic;
typedef struct _sim_watch_point {
watchpoint_action action;
int is_within; int is_within;
long arg; unsigned long arg0;
unsigned long arg1;
sim_event *event; sim_event *event;
} sim_watch_point; sim_watch_point *next;
};
typedef struct _sim_watchpoints { typedef struct _sim_watchpoints {
@ -55,10 +55,18 @@ typedef struct _sim_watchpoints {
/* Pointer to the handler for interrupt watchpoints */ /* Pointer to the handler for interrupt watchpoints */
/* FIXME: can this be done better? */ /* FIXME: can this be done better? */
/* NOTE, interrupt is passed in as the target of the pointer! */
sim_event_handler *interrupt_handler; sim_event_handler *interrupt_handler;
/* suported watchpoints */ /* Pointer to a null terminated list of interrupt names */
sim_watch_point points[nr_watchpoint_types]; /* FIXME: can this be done better? Look at the PPC's interrupt
mechanism and table for a rough idea of where it will go next */
int nr_interrupts;
char **interrupt_names;
/* active watchpoints */
int last_point_nr;
sim_watch_point *points;
} sim_watchpoints; } sim_watchpoints;