summaryrefslogtreecommitdiffhomepage
path: root/mixlib
diff options
context:
space:
mode:
Diffstat (limited to 'mixlib')
-rw-r--r--mixlib/mix_vm.c50
-rw-r--r--mixlib/mix_vm.h12
-rw-r--r--mixlib/xmix_vm.h3
-rw-r--r--mixlib/xmix_vm_handlers.c45
-rw-r--r--mixlib/xmix_vm_handlers.h1
5 files changed, 91 insertions, 20 deletions
diff --git a/mixlib/mix_vm.c b/mixlib/mix_vm.c
index d714bba..94eae1e 100644
--- a/mixlib/mix_vm.c
+++ b/mixlib/mix_vm.c
@@ -81,8 +81,8 @@ vm_reset_reload_ (mix_vm_t *vm, gboolean is_reload)
if (vm->address_list)
{
- g_slist_free (vm->address_list);
- vm->address_list = NULL;
+ g_queue_free (vm->address_list);
+ vm->address_list = g_queue_new ();
}
}
@@ -99,7 +99,8 @@ mix_vm_new (void)
vm->symbol_table = NULL;
vm->src_file = NULL;
vm->pred_list = mix_predicate_list_new (vm);
- vm->address_list = NULL;
+ vm->max_backtrace_amount = MIX_MAX_TRACE_AMOUNT;
+ vm->address_list = g_queue_new ();
vm->last_error = MIX_VM_ERROR_NONE;
for (i = 0; i < BD_NO_; ++i)
@@ -126,7 +127,7 @@ mix_vm_delete (mix_vm_t * vm)
if (vm->symbol_table != NULL) mix_symbol_table_delete (vm->symbol_table);
if (vm->src_file != NULL) mix_src_file_delete (vm->src_file);
if (vm->pred_list != NULL) mix_predicate_list_delete (vm->pred_list);
- if (vm->address_list != NULL) g_slist_free (vm->address_list);
+ if (vm->address_list != NULL) g_queue_free (vm->address_list);
for (i = 0; i < BD_NO_; ++i)
mix_device_delete (vm->devices[i]);
mix_vm_clock_delete (vm->clock);
@@ -452,9 +453,14 @@ mix_vm_run (mix_vm_t *vm)
while ( !is_halted_ (vm) )
{
mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins);
- vm->address_list =
- g_slist_prepend (vm->address_list,
- GINT_TO_POINTER ((gint)get_loc_ (vm)));
+ if ( vm->max_backtrace_amount != 0 ) {
+ g_queue_push_head (vm->address_list,
+ GINT_TO_POINTER ((gint)get_loc_ (vm)));
+ if ( vm->max_backtrace_amount > 0 &&
+ g_queue_get_length (vm->address_list) > vm->max_backtrace_amount ) {
+ g_queue_pop_tail (vm->address_list);
+ }
+ }
if ( !(*ins_handlers_[ins.opcode]) (vm,&ins) )
return set_status_ (vm, MIX_VM_ERROR);
else
@@ -476,9 +482,14 @@ mix_vm_exec_next (mix_vm_t *vm)
g_return_val_if_fail (vm != NULL, MIX_VM_ERROR);
if (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE);
if (is_halted_ (vm)) return set_status_ (vm, MIX_VM_HALT);
- vm->address_list =
- g_slist_prepend (vm->address_list,
- GINT_TO_POINTER ((gint)get_loc_ (vm)));
+ if ( vm->max_backtrace_amount != 0 ) {
+ g_queue_push_head (vm->address_list,
+ GINT_TO_POINTER ((gint)get_loc_ (vm)));
+ if ( vm->max_backtrace_amount > 0 &&
+ g_queue_get_length (vm->address_list) > vm->max_backtrace_amount ) {
+ g_queue_pop_tail (vm->address_list);
+ }
+ }
mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins);
if (!(*ins_handlers_[ins.opcode]) (vm, &ins))
return set_status_ (vm, MIX_VM_ERROR);
@@ -698,9 +709,24 @@ mix_vm_get_uptime (const mix_vm_t *vm)
}
/* Get the list of addresses for executed instructions */
-const GSList *
+GQueue *
mix_vm_get_backtrace (const mix_vm_t *vm)
{
g_return_val_if_fail (vm != NULL, NULL);
- return get_address_list_ (vm);
+ return vm->address_list;
+}
+
+gint
+mix_vm_get_max_trace (const mix_vm_t *vm)
+{
+ g_return_val_if_fail (vm != NULL, -2);
+ return vm->max_backtrace_amount;
+}
+
+void
+mix_vm_set_max_trace (mix_vm_t *vm, gint val)
+{
+ g_return_if_fail (vm != NULL);
+ g_return_if_fail (val >= -1);
+ vm->max_backtrace_amount = val;
}
diff --git a/mixlib/mix_vm.h b/mixlib/mix_vm.h
index 0f4e690..4b07164 100644
--- a/mixlib/mix_vm.h
+++ b/mixlib/mix_vm.h
@@ -34,6 +34,9 @@
/* Comparison flag */
typedef enum { mix_LESS, mix_EQ, mix_GREAT } mix_cmpflag_t;
+/* Maximum number of addresses for backtraces: -1 = unlimited, 0 = off */
+enum { MIX_MAX_TRACE_AMOUNT = 500 };
+
/* Number of memory cells in the virtual machine */
enum { MIX_VM_CELL_NO = 4000 };
@@ -247,9 +250,16 @@ extern mix_time_t
mix_vm_get_uptime (const mix_vm_t *vm);
/* Get the list of addresses for executed instructions */
-extern const GSList *
+extern GQueue *
mix_vm_get_backtrace (const mix_vm_t *vm);
+/* Get the maximum number of instructions we will trace */
+gint
+mix_vm_get_max_trace (const mix_vm_t *vm);
+
+/* Set the maximum number of instructions we will trace */
+void
+mix_vm_set_max_trace (mix_vm_t *vm, gint val);
#endif /* MIX_VM_H */
diff --git a/mixlib/xmix_vm.h b/mixlib/xmix_vm.h
index 0d6605f..34dedd7 100644
--- a/mixlib/xmix_vm.h
+++ b/mixlib/xmix_vm.h
@@ -50,6 +50,7 @@ struct mix_vm_t
mix_vm_status_t status;
mix_vm_error_t last_error;
mix_device_t * devices[BD_NO_];
+ gint max_backtrace_amount; /* the limit of backtraces */
mix_address_t start_addr; /* start address of loaded file */
GTree *line_table; /* source line no -> address */
GTree *address_table; /* adress -> source line no */
@@ -59,7 +60,7 @@ struct mix_vm_t
mix_src_file_t *src_file; /* source of last loaded code file */
mix_device_factory_t factory; /* the factory for new devices */
mix_predicate_list_t *pred_list; /* predicates for conditional bps */
- GSList *address_list; /* list of executed addresses */
+ GQueue *address_list; /* list of executed addresses */
};
/* Macros for accessing/modifying the above structure.
diff --git a/mixlib/xmix_vm_handlers.c b/mixlib/xmix_vm_handlers.c
index c964116..f356607 100644
--- a/mixlib/xmix_vm_handlers.c
+++ b/mixlib/xmix_vm_handlers.c
@@ -86,6 +86,8 @@ mix_vm_command_info_t commands_[] = {
"strace on|off"},
{ "pbt", cmd_pbt_, N_("Print backtrace of executed instructions"),
"pbt [INS_NO] (e.g pbt 5)"},
+ { "sbt", cmd_sbt_, N_("Set limit on backtrace of executed instructions"),
+ "sbt [LIMIT] (e.g sbt 100)"},
{ "stime", cmd_stime_, N_("Turn on/off timing statistics"),
"stime on|off"},
{ "ptime", cmd_ptime_, N_("Print current time statistics"), "ptime"},
@@ -1306,6 +1308,7 @@ gboolean
cmd_pbt_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
{
enum {SIZE = 256};
+ static const gchar *NULLSTR = "(null)";
static gchar BUFFER[SIZE];
gint no = atoi (arg);
gint k = 0, address;
@@ -1314,29 +1317,59 @@ cmd_pbt_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
char *name =
file ? g_path_get_basename (mix_src_file_get_path (file)) : NULL;
- const GSList *add = mix_vm_get_backtrace (dis->vm);
- while (add && (no == 0 || k < no))
+ GQueue *add = mix_vm_get_backtrace (dis->vm);
+ while (g_queue_get_length (add) > k && (no == 0 || k < no))
{
BUFFER[0] = '\0';
- address = GPOINTER_TO_INT (add->data);
+ address = GPOINTER_TO_INT (g_queue_peek_nth (add, k));
line = mix_vm_get_address_lineno (dis->vm, address);
if (line && file)
{
int j = 0;
g_snprintf (BUFFER, SIZE, "%s", mix_src_file_get_line (file, line));
- while (!isspace (BUFFER[j])) j++;
+ while ( (j < SIZE - 1) && (BUFFER[j] != '\n') && (BUFFER[j] != '\r')
+ && (BUFFER[j] != '\f') && (BUFFER[j] != '\0') ) j++;
BUFFER[j] = '\0';
}
- if (strlen (BUFFER) == 0) g_snprintf (BUFFER, SIZE, "%d", address);
+ if ( (strlen (BUFFER) == 0) || !(strcmp(NULLSTR,BUFFER)) )
+ g_snprintf (BUFFER, SIZE, "%d", address);
fprintf (dis->out, "#%d\t%s\tin %s%s:%d\n", k, BUFFER, name,
MIX_SRC_DEFEXT, line);
++k;
- add = add->next;
}
return TRUE;
}
gboolean
+cmd_sbt_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
+{
+ gint no = atoi (arg);
+ GQueue *add = mix_vm_get_backtrace (dis->vm);
+
+ if ( strlen(arg) == 0 ) {
+ log_message_ (dis, "Backtrace limit is %d instructions",
+ mix_vm_get_max_trace(dis->vm));
+ } else {
+ if ( no >= -1 ) {
+ log_message_ (dis, "Backtrace limit changed from %d to %d instructions",
+ mix_vm_get_max_trace(dis->vm), no);
+ mix_vm_set_max_trace (dis->vm, no);
+
+ /* We might have shrunk the queue and need to resize it */
+ if ( no >= 0 ) {
+ while ( g_queue_get_length (add) > no ) {
+ g_queue_pop_tail(add);
+ }
+ }
+
+ } else {
+ log_error_ (dis, "Error: %d is not a valid number of instructions.", no);
+ }
+ }
+ return TRUE;
+}
+
+gboolean
cmd_slog_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg)
{
static const gchar *ON = "on";
diff --git a/mixlib/xmix_vm_handlers.h b/mixlib/xmix_vm_handlers.h
index decdd24..be276d4 100644
--- a/mixlib/xmix_vm_handlers.h
+++ b/mixlib/xmix_vm_handlers.h
@@ -71,6 +71,7 @@ DEC_FUN (cbpm_);
DEC_FUN (cbpc_);
DEC_FUN (cbpo_);
DEC_FUN (pbt_);
+DEC_FUN (sbt_);
DEC_FUN (slog_);
DEC_FUN (pprog_);
DEC_FUN (psrc_);