[gamecode] Add debug hooks to the VM engine

While there was a breakpoint hook, it was for only breakpoints and more
was needed. Now there's a generic hook that is called for tracing,
breakpoints, watch points, runtime errors and VM errors, with the
"event" type passed as the first parameter and a data pointer in the
second.
This commit is contained in:
Bill Currie 2020-03-24 15:35:42 +09:00
parent 148a351e94
commit 713150b41a
3 changed files with 39 additions and 7 deletions

View file

@ -1690,6 +1690,15 @@ typedef struct {
strref_t *tstr; ///< Linked list of temporary strings.
} prstack_t;
typedef enum {
prd_none,
prd_trace,
prd_breakpoint,
prd_watchpoint,
prd_runerror,
prd_error, // lower level error thann prd_runerror
} prdebug_t;
struct progs_s {
int (*parse_field) (progs_t *pr, const char *key, const char *value);
@ -1831,7 +1840,9 @@ struct progs_s {
/// \name debugging
///@{
struct prdeb_resources_s *pr_debug_resources;
void (*breakpoint_handler) (progs_t *pr);
void (*debug_handler) (prdebug_t event, void *data);
void *debug_data;
const char *error_string;
pr_type_t *watch;
int wp_conditional;
pr_type_t wp_val;

View file

@ -62,6 +62,12 @@ PR_RunError (progs_t * pr, const char *error, ...)
dvsprintf (string, error, argptr);
va_end (argptr);
if (pr->debug_handler) {
pr->error_string = string->str;
pr->debug_handler (prd_runerror, pr->debug_data);
// not expected to return, but if so, behave as if there was no handler
}
Sys_Printf ("%s\n", string->str);
PR_DumpState (pr);
@ -477,12 +483,17 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
op_b = pr->pr_globals + st->b;
op_c = pr->pr_globals + st->c;
if (pr->pr_trace)
PR_PrintStatement (pr, st, 1);
if (pr->pr_trace) {
if (pr->debug_handler) {
pr->debug_handler (prd_trace, pr->debug_data);
} else {
PR_PrintStatement (pr, st, 1);
}
}
if (st->op & OP_BREAK) {
if (pr->breakpoint_handler) {
pr->breakpoint_handler (pr);
if (pr->debug_handler) {
pr->debug_handler (prd_breakpoint, pr->debug_data);
} else {
PR_RunError (pr, "breakpoint hit");
}
@ -1701,8 +1712,12 @@ op_call:
if (watch && watch->integer_var != old_val.integer_var) {
if (!pr->wp_conditional
|| watch->integer_var == pr->wp_val.integer_var) {
PR_RunError (pr, "watchpoint hit: %d -> %d",
old_val.integer_var, watch->integer_var);
if (pr->debug_handler) {
pr->debug_handler (prd_watchpoint, pr->debug_data);
} else {
PR_RunError (pr, "watchpoint hit: %d -> %d",
old_val.integer_var, watch->integer_var);
}
}
old_val.integer_var = watch->integer_var;
}

View file

@ -323,6 +323,7 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size)
def->type_encoding = xdef->type;
}
}
pr->error_string = 0;
pr->pr_trace = 0;
pr->pr_trace_depth = 0;
pr->pr_xfunction = 0;
@ -485,5 +486,10 @@ PR_Error (progs_t *pr, const char *error, ...)
dvsprintf (string, error, argptr);
va_end (argptr);
if (pr->debug_handler) {
pr->error_string = string->str;
pr->debug_handler (prd_error, pr->debug_data);
// not expected to return, but if so, behave as if there was no handler
}
Sys_Error ("%s: %s", pr->progs_name, string->str);
}