From a566628d7992b62819f9cfff13baea83f4b1ab2e Mon Sep 17 00:00:00 2001 From: Jose Antonio Ortega Ruiz Date: Sat, 21 Jul 2001 21:14:05 +0000 Subject: mem and register conditional breakpoints --- mixlib/mix_vm_command.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++- mixlib/mix_vm_command.h | 8 ++ mixutils/mixvm_command.c | 6 +- samples/.cvsignore | 1 + samples/cbp.mixal | 13 +++ 5 files changed, 264 insertions(+), 7 deletions(-) create mode 100644 samples/cbp.mixal diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c index 9344618..0dc56c5 100644 --- a/mixlib/mix_vm_command.c +++ b/mixlib/mix_vm_command.c @@ -31,6 +31,7 @@ #include "mix_vm.h" #include "mix_vm_dump.h" #include "mix_eval.h" +#include "mix_predicate.h" #include "mix_vm_command.h" #ifdef HAVE_LIBHISTORY @@ -54,6 +55,8 @@ typedef struct gpointer data; } global_hook_; +#define PRNO_ MIX_PRED_MEM + struct mix_vm_cmd_dispatcher_t { mix_vm_t *vm; /* the virtual machine */ @@ -75,6 +78,8 @@ struct mix_vm_cmd_dispatcher_t global_hook_ global_pre; /* global pre-command hook */ global_hook_ global_post; /* global post-command hook */ mix_config_t *config; /* externally provided configuration */ + mix_predicate_t *preds[PRNO_]; /* predicates for conditional breakpoints */ + GHashTable *mem_preds; /* predicates for memory conditional bps */ }; /* command handlers */ @@ -113,6 +118,15 @@ DEC_FUN (sedit_); DEC_FUN (pasm_); DEC_FUN (sasm_); DEC_FUN (devdir_); +DEC_FUN (sbpr_); +DEC_FUN (sbpm_); +DEC_FUN (sbpc_); +DEC_FUN (sbpo_); +DEC_FUN (cbpr_); +DEC_FUN (cbpm_); +DEC_FUN (cbpc_); +DEC_FUN (cbpo_); + /* internal command info struct */ typedef struct { @@ -162,6 +176,22 @@ command_ commands_[] = { "sbpa ADDRESS"}, { "cbpa", cmd_cbpa_, N_("Clear break point at given address"), "cbpa ADDRESS"}, + { "sbpr", cmd_sbpr_, N_("Set conditional breakpoint on register change"), + "sbpr A | X | J | I[1-6]"}, + { "cbpr", cmd_cbpr_, N_("Clear conditional breakpoint on register change"), + "sbpr A | X | J | I[1-6]"}, + { "sbpm", cmd_sbpm_, N_("Set conditional breakpoint on mem cell change"), + "sbpm ADDRESS"}, + { "cbpm", cmd_cbpm_, N_("Clear conditional breakpoint on mem cell change"), + "cbpm ADDRESS"}, + { "sbpc", cmd_sbpc_, + N_("Set conditional breakpoint on comparison flag change"), "sbpc"}, + { "cbpc", cmd_cbpc_, + N_("Clear conditional breakpoint on comparison flag change"), "cbpc"}, + { "sbpo", cmd_sbpo_, + N_("Set conditional breakpoint on overflow toggled"), "sbpo"}, + { "cbpo", cmd_cbpo_, + N_("Set conditional breakpoint on overflow toggled"), "cbpo"}, { "cabp", cmd_cabp_, N_("Clear all breakpoints"), "cabp"}, { "weval", cmd_weval_, N_("Evaluate a given W-expression"), "weval WEXPR"}, { "w2d", cmd_w2d_, N_("Convert a MIX word to its decimal value"), @@ -251,6 +281,11 @@ mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ } result->config = NULL; + for (k = 0; k < PRNO_; ++k) + result->preds[k] = mix_predicate_new (k); + + result->mem_preds = g_hash_table_new (NULL, NULL); + return result; } @@ -296,10 +331,19 @@ mix_vm_cmd_dispatcher_new_with_config (FILE *out, FILE *err, /* delete (does not close the fds in the constructor) */ +static gboolean +del_pred_ (gpointer key, gpointer val, gpointer data) +{ + if (val) mix_predicate_delete ((mix_predicate_t *)val); + return TRUE; +} + void mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) { const gchar *hfile = NULL; + gint k; + g_return_if_fail (dis != NULL); mix_eval_delete (dis->eval); mix_dump_context_delete (dis->dump); @@ -311,6 +355,8 @@ mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) (dis->config))) write_history ((char *)hfile); #endif + for (k = 0; k < PRNO_; ++k) mix_predicate_delete (dis->preds[k]); + g_hash_table_foreach_remove (dis->mem_preds, del_pred_, NULL); g_free (dis); } @@ -734,10 +780,23 @@ cmd_run_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) if (line != 0) fprintf (dis->out, _("... stopped: breakpoint at line %ld (address %d)\n"), - line, mix_vm_get_prog_count (dis->vm)); + line, mix_vm_get_prog_count (dis->vm)); else fprintf (dis->out, _("... stopped: breakpoint at address %d\n"), - mix_vm_get_prog_count (dis->vm)); + mix_vm_get_prog_count (dis->vm)); + } + break; + case MIX_VM_COND_BREAK: + { + gulong line = mix_vm_get_break_lineno (dis->vm); + if (line != 0) + fprintf (dis->out, _("... stopped: %s (line %ld, address %d)\n"), + mix_vm_get_last_breakpoint_message (dis->vm), + line, mix_vm_get_prog_count (dis->vm)); + else + fprintf (dis->out, _("... stopped: %s (address %d)\n"), + mix_vm_get_last_breakpoint_message (dis->vm), + mix_vm_get_prog_count (dis->vm)); } break; case MIX_VM_ERROR: @@ -861,7 +920,7 @@ cmd_preg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) int i = arg[1] - '1'; if ( i < 0 || i > 5 ) { - fprintf (dis->err, _("Invalid I index: %d"), i); + fprintf (dis->err, _("Invalid I index: %d\n"), i); return FALSE; } mix_dump_context_add_opt (dis->dump, opt[i]); @@ -1454,5 +1513,181 @@ cmd_devdir_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) return TRUE; } - + +static const gint INVALID_REG_ = -2; + +static mix_predicate_type_t +get_reg_pred_ (const gchar *arg) +{ + mix_predicate_type_t pred = INVALID_REG_; + + switch (*arg) + { + case 'A': + pred = MIX_PRED_REG_A; + break; + case 'X': + pred = MIX_PRED_REG_X; + break; + case 'J': + pred = MIX_PRED_REG_J; + break; + case 'I': + { + if ( strlen (arg) == 2 ) + { + int i = arg[1] - '1'; + if ( i > 0 && i < 7 ) + pred = MIX_PRED_REG_I1 - 1 + i; + } + } + break; + default: + break; + } + return pred; +} + +static gboolean +cmd_sbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_predicate_type_t pred = get_reg_pred_ (arg); + if (pred != INVALID_REG_) + { + mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[pred]); + fprintf (dis->out, _("Conditional breakpoint on r%s change set\n"), arg); + return TRUE; + } + else + { + fprintf (dis->err, "Invalid argument %s\n", arg); + return FALSE; + } +} + +static gboolean +cmd_cbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_predicate_type_t pred = get_reg_pred_ (arg); + if (pred != INVALID_REG_) + { + mix_vm_clear_conditional_breakpoint (dis->vm, dis->preds[pred]); + fprintf (dis->out, + _("Conditional breakpoint on r%s change removed\n"), + arg); + return TRUE; + } + else + { + fprintf (dis->err, _("Invalid argument %s\n"), arg); + return FALSE; + } +} + +static gboolean +cmd_sbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gint add = atoi (arg); + gpointer key, value; + if (add < 0 || add > MIX_VM_CELL_NO) + { + fprintf (dis->out, _("Invalid memory address: %s\n"), arg); + return FALSE; + } + if (!g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add), + &key, &value)) + { + mix_predicate_t *new_pred = mix_predicate_new (MIX_PRED_MEM); + mix_predicate_set_mem_address (new_pred, add); + g_hash_table_insert (dis->mem_preds, + GINT_TO_POINTER (add), (gpointer)new_pred); + mix_vm_set_conditional_breakpoint (dis->vm, new_pred); + } + fprintf (dis->out, _("Conditional breakpoint on mem cell no. %d set\n"), add); + return TRUE; +} + +static gboolean +cmd_cbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gint add = atoi (arg); + gpointer key, value; + if (add < 0 || add > MIX_VM_CELL_NO) + { + fprintf (dis->out, _("Invalid memory address: %s\n"), arg); + return FALSE; + } + if (g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add), + &key, &value)) + { + g_hash_table_remove (dis->mem_preds, key); + mix_vm_clear_conditional_breakpoint (dis->vm, (mix_predicate_t *)value); + mix_predicate_delete ((mix_predicate_t *)value); + fprintf (dis->out, + _("Conditional breakpoint on mem cell no. %d removed\n"), add); + } + else + { + fprintf (dis->out, _("No conditional breakpoint set at address %d\n"), + add); + } + return TRUE; +} + +static gboolean +cmd_sbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_OVER]); + fprintf (dis->out, + _("Conditional breakpoint on overflow toggled set.\n")); + } + return TRUE; +} + +static gboolean +cmd_cbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + mix_vm_clear_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_OVER]); + fprintf (dis->out, + _("Conditional breakpoint on overflow toggled removed.\n")); + } + return TRUE; +} + +static gboolean +cmd_sbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_CMP]); + fprintf (dis->out, + _("Conditional breakpoint on comparison flag changed set.\n")); + } + return TRUE; +} + +static gboolean +cmd_cbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + mix_vm_clear_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_CMP]); + fprintf (dis->out, + _("Conditional breakpoint on comparison flag changed removed.\n")); + } + return TRUE; +} + diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h index 45e2c8c..6c60264 100644 --- a/mixlib/mix_vm_command.h +++ b/mixlib/mix_vm_command.h @@ -63,6 +63,14 @@ typedef enum { MIX_CMD_CBP, /* clear breakpoint at lineno */ MIX_CMD_SBPA, /* set breakpoint at address */ MIX_CMD_CBPA, /* clear breakpoint at address */ + MIX_CMD_SBPR, /* set breakpoint on register changed */ + MIX_CMD_CBPR, /* clear breakpoint on register changed */ + MIX_CMD_SBPM, /* set breakpoint on mem cell changed */ + MIX_CMD_CBPM, /* clear breakpoint on mem cell changed */ + MIX_CMD_SBPC, /* set breakpoint on comp flag changed */ + MIX_CMD_CBPC, /* clear breakpoint on comp flag changed */ + MIX_CMD_SBPO, /* set breakpoint on overflow toggled */ + MIX_CMD_CBPO, /* clear breakpoint on overflow toggled */ MIX_CMD_CABP, /* clear all breakpoints */ MIX_CMD_WEVAL, /* evaluate a w-expression */ MIX_CMD_W2D, /* print word in decimal notation */ diff --git a/mixutils/mixvm_command.c b/mixutils/mixvm_command.c index b8bef53..d13e5ac 100644 --- a/mixutils/mixvm_command.c +++ b/mixutils/mixvm_command.c @@ -76,7 +76,7 @@ static const char *mix_commands_[ALL_COMMANDS_NO_] = {NULL}; #ifdef HAVE_LIBREADLINE /* readline functions */ static char * -mixvm_cmd_generator_ (char *text, int state); +mixvm_cmd_generator_ (const char *text, int state); /* Attempt to complete on the contents of TEXT. START and END bound the @@ -95,7 +95,7 @@ mixvm_cmd_completion_ (char *text, int start, int end) to complete. Otherwise it is the name of a file in the current directory. */ if (start == 0) - matches = completion_matches (text, mixvm_cmd_generator_); + matches = rl_completion_matches (text, mixvm_cmd_generator_); return (matches); } @@ -104,7 +104,7 @@ mixvm_cmd_completion_ (char *text, int start, int end) to start from scratch; without any state (i.e. STATE == 0), then we start at the top of the list. */ static char * -mixvm_cmd_generator_ (char *text, int state) +mixvm_cmd_generator_ (const char *text, int state) { static int list_index, len; const char *name; diff --git a/samples/.cvsignore b/samples/.cvsignore index 18ddd94..bebe302 100644 --- a/samples/.cvsignore +++ b/samples/.cvsignore @@ -1,6 +1,7 @@ Makefile Makefile.in cardwr.dev +cbp.mix disk0.dev disk1.dev disk2.dev diff --git a/samples/cbp.mixal b/samples/cbp.mixal new file mode 100644 index 0000000..b436c8c --- /dev/null +++ b/samples/cbp.mixal @@ -0,0 +1,13 @@ +* testing conditional breakpoints + ORIG 2000 +START ENTA 100 + STA 1000 + ENTX 200 + STX 1001 + CMPA 1001 * cmp flag changed + CMPX 1000 * cmp flag changed + DIV 1002 * over toggle + END START + + + -- cgit v1.2.3