From fe4a4a9e554c42eb44b8267d49ce6d6896713f9e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 8 May 2007 02:04:47 +0000 Subject: [PATCH] "hardware" (haha) watch points (one!) in progs. only catches changes done by progs, and the expression parser is as flaky as anything, but it's better than nothing :) --- include/QF/progs.h | 2 + libs/gamecode/engine/pr_debug.c | 65 ++++++++++++++++++++++++++++++++- libs/gamecode/engine/pr_exec.c | 9 +++++ qw/source/sv_progs.c | 7 ++++ 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 356a97399..02f886696 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1283,6 +1283,7 @@ void *PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size); void PR_Debug_Init (void); void PR_Debug_Init_Cvars (void); int PR_LoadDebug (progs_t *pr); +void PR_Debug_Watch (progs_t *pr, const char *expr); pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno); pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno); pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno); @@ -1452,6 +1453,7 @@ struct progs_s { struct pr_auxfunction_s **auxfunction_map; struct pr_lineno_s *linenos; ddef_t *local_defs; + pr_type_t *watch; //@} /// required globals (for OP_STATE) diff --git a/libs/gamecode/engine/pr_debug.c b/libs/gamecode/engine/pr_debug.c index 35d37829a..fa1378f8d 100644 --- a/libs/gamecode/engine/pr_debug.c +++ b/libs/gamecode/engine/pr_debug.c @@ -41,7 +41,7 @@ static __attribute__ ((used)) const char rcsid[] = # include #endif #include - +#include #include #include "QF/cvar.h" @@ -51,6 +51,7 @@ static __attribute__ ((used)) const char rcsid[] = #include "QF/progs.h" #include "QF/qendian.h" #include "QF/quakefs.h" +#include "QF/script.h" #include "QF/sys.h" #include "QF/va.h" #include "QF/zone.h" @@ -119,6 +120,68 @@ source_path_f (cvar_t *var) source_paths[i] = 0; } +static void +pr_debug_watch_error (script_t *script, const char *msg) +{ + Sys_Printf ("%s\n", msg); +} + +VISIBLE void +PR_Debug_Watch (progs_t *pr, const char *expr) +{ + script_t *ws; + char *e; + + if (!expr) { + Sys_Printf ("watch \n"); + if (pr->watch) { + Sys_Printf (" watching [%d]\n", + (int) (intptr_t) (pr->watch - pr->pr_globals)); + } else { + Sys_Printf (" none active\n"); + } + return; + } + ws = Script_New (); + ws->error = pr_debug_watch_error; + Script_Start (ws, "", expr); + pr->watch = 0; + if (Script_GetToken (ws, 1)) { + if (strequal (ws->token->str, "[")) { + edict_t *ent; + ddef_t *field; + + if (!Script_GetToken (ws, 1)) + goto error; + ent = EDICT_NUM (pr, strtol (ws->token->str, &e, 0)); + if (e == ws->token->str) + goto error; + if (!Script_GetToken (ws, 1) && !strequal (ws->token->str, "]" )) + goto error; + if (!Script_GetToken (ws, 1) && !strequal (ws->token->str, "." )) + goto error; + if (!Script_GetToken (ws, 1)) + goto error; + field = PR_FindField (pr, ws->token->str); + if (!field) + goto error; + if (Script_TokenAvailable (ws, 1)) + Sys_Printf ("ignoring tail\n"); + pr->watch = &ent->v[field->ofs]; + } else { + ddef_t *global = PR_FindGlobal (pr, ws->token->str); + if (!global) + goto error; + pr->watch = PR_GetPointer (pr, global->ofs); + } + } +error: + if (pr->watch) + Sys_Printf ("watchpoint set to [%d]\n", PR_SetPointer (pr, pr->watch)); + else + Sys_Printf ("watchpoint cleared\n"); +} + void PR_Debug_Init (void) { diff --git a/libs/gamecode/engine/pr_exec.c b/libs/gamecode/engine/pr_exec.c index 9e082fb3e..833b95223 100644 --- a/libs/gamecode/engine/pr_exec.c +++ b/libs/gamecode/engine/pr_exec.c @@ -307,6 +307,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) dstatement_t *st; edict_t *ed; pr_type_t *ptr; + pr_type_t old_val, *watch = 0; // make a stack frame exitdepth = pr->pr_depth; @@ -321,6 +322,11 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) } st = pr->pr_statements + pr->pr_xstatement; + if (pr->watch) { + watch = pr->watch; + old_val = *watch; + } + while (1) { pr_type_t *op_a, *op_b, *op_c; @@ -1014,5 +1020,8 @@ op_call: default: PR_RunError (pr, "Bad opcode %i", st->op); } + if (watch && watch->integer_var != old_val.integer_var) + PR_RunError (pr, "watchpoint hit: %d -> %d", old_val.integer_var, + watch->integer_var); } } diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index 8e67ed3fa..336f9511d 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -157,6 +157,12 @@ PR_Profile_f (void) PR_Profile (&sv_pr_state); } +static void +watch_f (void) +{ + PR_Debug_Watch (&sv_pr_state, Cmd_Argc () < 2 ? 0 : Cmd_Args (1)); +} + static int parse_field (progs_t *pr, const char *key, const char *value) { @@ -528,6 +534,7 @@ SV_Progs_Init (void) "Display summary information on the edicts in the game."); Cmd_AddCommand ("profile", PR_Profile_f, "FIXME: Report information about " "QuakeC Stuff (\?\?\?) No Description"); + Cmd_AddCommand ("watch", watch_f, "set watchpoint"); } void