1
0
Fork 0
forked from fte/fteqw

Add setwatchpoint builtin, for debugging stuff that would otherwise be hard to monitor.

This commit is contained in:
Shpoike 2024-12-28 15:51:21 +00:00
parent 1ea029f789
commit 0df247d4c1
12 changed files with 97 additions and 21 deletions

View file

@ -127,7 +127,7 @@ static csqcglobals_t csqcg;
playerview_t csqc_nullview; playerview_t csqc_nullview;
static void VARGS CSQC_Abort (char *format, ...); //an error occured. static void VARGS CSQC_Abort (const char *format, ...); //an error occured.
static void cs_set_input_state (usercmd_t *cmd); static void cs_set_input_state (usercmd_t *cmd);
//fixme: we should be using entity numbers, not view numbers. //fixme: we should be using entity numbers, not view numbers.
@ -7055,6 +7055,7 @@ static struct {
{"cprint", PF_cl_cprint, 338}, // #338 void(string s) cprint (EXT_CSQC) {"cprint", PF_cl_cprint, 338}, // #338 void(string s) cprint (EXT_CSQC)
{"print", PF_print, 339}, // #339 void(string s) print (EXT_CSQC) {"print", PF_print, 339}, // #339 void(string s) print (EXT_CSQC)
{"setwatchpoint", PF_setwatchpoint, 0},
//340 //340
{"keynumtostring", PF_cl_keynumtostring, 340}, // #340 string(float keynum) keynumtostring (EXT_CSQC) {"keynumtostring", PF_cl_keynumtostring, 340}, // #340 string(float keynum) keynumtostring (EXT_CSQC)
@ -7522,7 +7523,7 @@ static progparms_t csqcprogparms;
//Any menu builtin error or anything like that will come here. //Any menu builtin error or anything like that will come here.
static void VARGS CSQC_Abort (char *format, ...) //an error occured. static void VARGS CSQC_Abort (const char *format, ...) //an error occured.
{ {
va_list argptr; va_list argptr;
char string[1024]; char string[1024];
@ -8679,7 +8680,7 @@ void CSQC_WatchPoint_f(void)
Con_Printf("csqc not running\n"); Con_Printf("csqc not running\n");
return; return;
} }
if (csqcprogs->SetWatchPoint(csqcprogs, variable)) if (csqcprogs->SetWatchPoint(csqcprogs, variable, variable))
Con_Printf("Watchpoint set\n"); Con_Printf("Watchpoint set\n");
else else
Con_Printf("Watchpoint cleared\n"); Con_Printf("Watchpoint cleared\n");

View file

@ -2631,6 +2631,7 @@ static struct {
{"print_csqc", PF_print, 339}, {"print_csqc", PF_print, 339},
{"setwatchpoint", PF_setwatchpoint, 0},
{"keynumtostring_csqc", PF_cl_keynumtostring, 340}, {"keynumtostring_csqc", PF_cl_keynumtostring, 340},
{"stringtokeynum_csqc", PF_cl_stringtokeynum, 341}, {"stringtokeynum_csqc", PF_cl_stringtokeynum, 341},
{"getkeybind", PF_cl_getkeybind, 342}, {"getkeybind", PF_cl_getkeybind, 342},
@ -3131,7 +3132,7 @@ void *VARGS PR_CB_Malloc(int size); //these functions should be tracked by the l
void VARGS PR_CB_Free(void *mem); void VARGS PR_CB_Free(void *mem);
//Any menu builtin error or anything like that will come here. //Any menu builtin error or anything like that will come here.
void VARGS Menu_Abort (char *format, ...) void VARGS Menu_Abort (const char *format, ...)
{ {
va_list argptr; va_list argptr;
char string[1024]; char string[1024];
@ -3444,7 +3445,7 @@ static void MP_Poke_f(void)
Con_TPrintf ("not supported.\n"); Con_TPrintf ("not supported.\n");
} }
void MP_Breakpoint_f(void) static void MP_Breakpoint_f(void)
{ {
int wasset; int wasset;
int isset; int isset;
@ -3468,17 +3469,41 @@ void MP_Breakpoint_f(void)
Cvar_Set(Cvar_FindVar("pr_debugger"), "1"); Cvar_Set(Cvar_FindVar("pr_debugger"), "1");
} }
static void MP_Watchpoint_f(void)
{
char *variable = Cmd_Argv(1);
if (!*variable)
variable = NULL;
if (!menu_world.progs)
{
Con_Printf("menuqc not running\n");
return;
}
if (menu_world.progs->SetWatchPoint(menu_world.progs, variable, variable))
Con_Printf("Watchpoint set\n");
else
Con_Printf("Watchpoint cleared\n");
}
static void MP_Profile_f(void)
{
if (menu_world.progs && menu_world.progs->DumpProfile)
if (!menu_world.progs->DumpProfile(menu_world.progs, !atof(Cmd_Argv(1))))
Con_Printf("Enabled menuqc Profiling.\n");
}
void MP_RegisterCvarsAndCmds(void) void MP_RegisterCvarsAndCmds(void)
{ {
Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f); Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f);
Cmd_AddCommand("menu_cmd", MP_GameCommand_f); Cmd_AddCommand("menu_cmd", MP_GameCommand_f);
Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f); Cmd_AddCommand("breakpoint_menuqc", MP_Breakpoint_f);
Cmd_AddCommand("watchpoint_menuqc", MP_Watchpoint_f);
#ifdef HAVE_LEGACY #ifdef HAVE_LEGACY
Cmd_AddCommand("loadfont", CL_LoadFont_f); Cmd_AddCommand("loadfont", CL_LoadFont_f);
#endif #endif
Cmd_AddCommand("poke_menuqc", MP_Poke_f); Cmd_AddCommand("poke_menuqc", MP_Poke_f);
Cmd_AddCommand("profile_menuqc", MP_Profile_f);
Cvar_Register(&forceqmenu, MENUPROGSGROUP); Cvar_Register(&forceqmenu, MENUPROGSGROUP);

View file

@ -7103,6 +7103,26 @@ void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
} }
} }
void QCBUILTIN PF_setwatchpoint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *desc = PR_GetStringOfs(prinst, OFS_PARM0);
int type = G_FLOAT(OFS_PARM1);
int qcptr = G_INT(OFS_PARM2);
char variable[64];
if (type == ev_float)
Q_snprintfz(variable,sizeof(variable), "*(float*)%#x", qcptr);
else if (type == ev_string)
Q_snprintfz(variable,sizeof(variable), "*(string*)%#x", qcptr);
else
Q_snprintfz(variable,sizeof(variable), "*(int*)%#x", qcptr);
if (prinst->SetWatchPoint(prinst, desc, variable))
Con_DPrintf("Watchpoint set\n");
else
Con_Printf("Watchpoint failure\n");
}
void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
prinst->debug_trace = DEBUG_TRACE_INTO; prinst->debug_trace = DEBUG_TRACE_INTO;

View file

@ -195,6 +195,7 @@ void QCBUILTIN PF_rotatevectorsbymatrix (pubprogfuncs_t *prinst, struct globalva
void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_setwatchpoint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_traceoff (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_traceoff (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_eprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_eprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View file

@ -57,9 +57,9 @@
//this will fire on the next instruction after the variable got changed. //this will fire on the next instruction after the variable got changed.
prinst.pr_xstatement = s; prinst.pr_xstatement = s;
if (current_progstate->linenums) if (current_progstate->linenums)
externs->Printf("Watch point hit in %s:%u, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), current_progstate->linenums[s-1], prinst.watch_name); externs->Printf("^b^3Watch point hit in %s:%u, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), current_progstate->linenums[s-1], prinst.watch_name);
else else
externs->Printf("Watch point hit in %s, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), prinst.watch_name); externs->Printf("^b^3Watch point hit in %s, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), prinst.watch_name);
switch(prinst.watch_type) switch(prinst.watch_type)
{ {
case ev_float: case ev_float:

View file

@ -715,6 +715,34 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, const char *key, eval_t **result,
struct edictrun_s *ed; struct edictrun_s *ed;
// etype_t ptrtype = ev_void; // etype_t ptrtype = ev_void;
if (!strncmp(key, "*(float*)", 9))
{
fofs = strtoul(key+9, NULL, 0);
if (fofs < 0 || fofs+3 >= prinst.addressableused)
return false;
*result = (eval_t*)(pr_strings + fofs);
*rettype = ev_float;
return true;
}
if (!strncmp(key, "*(int*)", 7))
{
fofs = strtoul(key+7, NULL, 0);
if (fofs < 0 || fofs+3 >= prinst.addressableused)
return false;
*result = (eval_t*)(pr_strings + fofs);
*rettype = ev_integer;
return true;
}
if (!strncmp(key, "*(string*)", 7))
{
fofs = strtoul(key+7, NULL, 0);
if (fofs < 0 || fofs+3 >= prinst.addressableused)
return false;
*result = (eval_t*)(pr_strings + fofs);
*rettype = ev_string;
return true;
}
c = strchr(key, '.'); c = strchr(key, '.');
if (c) *c = '\0'; if (c) *c = '\0';
def = ED_FindLocalOrGlobal(progfuncs, key, &val); def = ED_FindLocalOrGlobal(progfuncs, key, &val);
@ -797,14 +825,14 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, const char *key, eval_t **result,
return true; return true;
} }
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *key) pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *desc, const char *location)
{ {
progfuncs_t *progfuncs = (progfuncs_t *)ppf; progfuncs_t *progfuncs = (progfuncs_t *)ppf;
eval_t *val; eval_t *val;
eval_t fakeval; eval_t fakeval;
etype_t type; etype_t type;
if (!key) if (!location)
{ {
free(prinst.watch_name); free(prinst.watch_name);
prinst.watch_name = NULL; prinst.watch_name = NULL;
@ -812,9 +840,9 @@ pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *key)
prinst.watch_type = ev_void; prinst.watch_type = ev_void;
return false; return false;
} }
if (!LocateDebugTerm(progfuncs, key, &val, &type, &fakeval)) if (!LocateDebugTerm(progfuncs, location, &val, &type, &fakeval))
{ {
externs->Printf("Unable to evaluate watch term \"%s\"\n", key); externs->Printf("Unable to evaluate watch term \"%s\"\n", location);
return false; return false;
} }
if (val == &fakeval) if (val == &fakeval)
@ -829,7 +857,7 @@ pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *key)
} }
free(prinst.watch_name); free(prinst.watch_name);
prinst.watch_name = strdup(key); prinst.watch_name = strdup(desc);
prinst.watch_ptr = val; prinst.watch_ptr = val;
prinst.watch_old = *prinst.watch_ptr; prinst.watch_old = *prinst.watch_ptr;
prinst.watch_type = type &~ DEF_SAVEGLOBAL; prinst.watch_type = type &~ DEF_SAVEGLOBAL;

View file

@ -328,7 +328,7 @@ typedef struct edictrun_s
int PDECL Comp_Begin(pubprogfuncs_t *progfuncs, int nump, const char **parms); int PDECL Comp_Begin(pubprogfuncs_t *progfuncs, int nump, const char **parms);
int PDECL Comp_Continue(pubprogfuncs_t *progfuncs); int PDECL Comp_Continue(pubprogfuncs_t *progfuncs);
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *progfuncs, const char *key); pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *progfuncs, const char *desc, const char *location);
char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *progfuncs, const char *key); char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *progfuncs, const char *key);
char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, size_t *size, size_t maxsize, int mode); char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, size_t *size, size_t maxsize, int mode);
int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PDECL *memoryreset) (pubprogfuncs_t *progfuncs, void *ctx), void (PDECL *entspawned) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend), pbool(PDECL *extendedterm)(pubprogfuncs_t *progfuncs, void *ctx, const char **extline)); int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PDECL *memoryreset) (pubprogfuncs_t *progfuncs, void *ctx), void (PDECL *entspawned) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend), pbool(PDECL *extendedterm)(pubprogfuncs_t *progfuncs, void *ctx, const char **extline));

View file

@ -213,7 +213,7 @@ struct pubprogfuncs_s
void (PDECL *EntClear) (pubprogfuncs_t *progfuncs, struct edict_s *e); void (PDECL *EntClear) (pubprogfuncs_t *progfuncs, struct edict_s *e);
void (PDECL *FindPrefixGlobals) (pubprogfuncs_t *progfuncs, int prnum, char *prefix, void (PDECL *found) (pubprogfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type, void *ctx), void *ctx); //calls the callback for each named global found void (PDECL *FindPrefixGlobals) (pubprogfuncs_t *progfuncs, int prnum, char *prefix, void (PDECL *found) (pubprogfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type, void *ctx), void *ctx); //calls the callback for each named global found
pbool (PDECL *SetWatchPoint) (pubprogfuncs_t *prinst, const char *key); pbool (PDECL *SetWatchPoint) (pubprogfuncs_t *prinst, const char *desc, const char *location);
void (PDECL *AddSharedVar) (pubprogfuncs_t *progfuncs, int start, int size); void (PDECL *AddSharedVar) (pubprogfuncs_t *progfuncs, int start, int size);
void (PDECL *AddSharedFieldVar) (pubprogfuncs_t *progfuncs, int num, char *relstringtable); void (PDECL *AddSharedFieldVar) (pubprogfuncs_t *progfuncs, int num, char *relstringtable);
@ -246,7 +246,7 @@ typedef struct progexterns_s {
int (VARGS *Printf) (const char *, ...) LIKEPRINTF(1); int (VARGS *Printf) (const char *, ...) LIKEPRINTF(1);
int (VARGS *DPrintf) (const char *, ...) LIKEPRINTF(1); int (VARGS *DPrintf) (const char *, ...) LIKEPRINTF(1);
void (VARGS *Sys_Error) (const char *, ...) LIKEPRINTF(1); void (VARGS *Sys_Error) (const char *, ...) LIKEPRINTF(1);
void (VARGS *Abort) (char *, ...) LIKEPRINTF(1); void (VARGS *Abort) (const char *, ...) LIKEPRINTF(1);
pbool (PDECL *CheckHeaderCrc) (pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename); pbool (PDECL *CheckHeaderCrc) (pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename);
void (PDECL *entspawn) (struct edict_s *ent, int loading); //ent has been spawned, but may not have all the extra variables (that may need to be set) set void (PDECL *entspawn) (struct edict_s *ent, int loading); //ent has been spawned, but may not have all the extra variables (that may need to be set) set

View file

@ -548,7 +548,7 @@ builtin_t builtins[] = {
//Called when the qc library has some sort of serious error. //Called when the qc library has some sort of serious error.
void Sys_Abort(char *s, ...) void Sys_Abort(const char *s, ...)
{ //quake handles this with a longjmp. { //quake handles this with a longjmp.
va_list ap; va_list ap;
va_start(ap, s); va_start(ap, s);
@ -739,6 +739,7 @@ void runtest(const char *progsname, const char **args)
ext.progsversion = PROGSTRUCT_VERSION; ext.progsversion = PROGSTRUCT_VERSION;
ext.ReadFile = Sys_ReadFile; ext.ReadFile = Sys_ReadFile;
ext.FileSize= Sys_FileSize; ext.FileSize= Sys_FileSize;
ext.Sys_Error = Sys_Abort;
ext.Abort = Sys_Abort; ext.Abort = Sys_Abort;
ext.Printf = printf; ext.Printf = printf;
ext.stateop = StateOp; ext.stateop = StateOp;

View file

@ -1483,7 +1483,7 @@ static void PR_WatchPoint_f(void)
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict); pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, svs.clients[i].edict);
} }
} }
if (svprogfuncs->SetWatchPoint(svprogfuncs, variable)) if (svprogfuncs->SetWatchPoint(svprogfuncs, variable, variable))
Con_Printf("Watchpoint set\n"); Con_Printf("Watchpoint set\n");
else else
Con_Printf("Watchpoint cleared\n"); Con_Printf("Watchpoint cleared\n");
@ -11818,7 +11818,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"cprint", PF_Fixme, 0, 0, 0, 338, D("void(string s, ...)", "Print into the center of the screen just as ssqc's centerprint would appear.")},//(EXT_CSQC) {"cprint", PF_Fixme, 0, 0, 0, 338, D("void(string s, ...)", "Print into the center of the screen just as ssqc's centerprint would appear.")},//(EXT_CSQC)
{"print", PF_print, 0, 0, 0, 339, D("void(string s, ...)", "Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar).")},//(EXT_CSQC) {"print", PF_print, 0, 0, 0, 339, D("void(string s, ...)", "Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar).")},//(EXT_CSQC)
{"setwatchpoint", PF_setwatchpoint,0, 0, 0, 0, D("void(string name, float evaltype, void *ptr)", "For debugging. Set a watchpoint to monitor an address for changes. This is equivelent to using the watchpoint_* console command, but done from qc can be used on abitrary addresses.")},
{"keynumtostring", PF_Fixme, 0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (EXT_CSQC) {"keynumtostring", PF_Fixme, 0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (EXT_CSQC)
{"keynumtostring_csqc",PF_Fixme,0, 0, 0, 340, D("DEP string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (found in menuqc) {"keynumtostring_csqc",PF_Fixme,0, 0, 0, 340, D("DEP string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (found in menuqc)

View file

@ -1157,7 +1157,7 @@ void SV_AutoBanSender (int duration, char *reason); //bans net_from
// //
// sv_main.c // sv_main.c
// //
NORETURN void VARGS SV_Error (char *error, ...) LIKEPRINTF(1); NORETURN void VARGS SV_Error (const char *error, ...) LIKEPRINTF(1);
void SV_Shutdown (void); void SV_Shutdown (void);
float SV_Frame (void); float SV_Frame (void);
void SV_ReadPacket(void); void SV_ReadPacket(void);

View file

@ -321,7 +321,7 @@ Sends a datagram to all the clients informing them of the server crash,
then exits then exits
================ ================
*/ */
void VARGS SV_Error (char *error, ...) void VARGS SV_Error (const char *error, ...)
{ {
va_list argptr; va_list argptr;
static char string[1024]; static char string[1024];