summaryrefslogtreecommitdiffhomepage
path: root/mixlib/mix_vm_command.c
diff options
context:
space:
mode:
Diffstat (limited to 'mixlib/mix_vm_command.c')
-rw-r--r--mixlib/mix_vm_command.c243
1 files changed, 239 insertions, 4 deletions
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;
+}
+