X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=prvm_edict.c;h=41f8b2a10f1dfb41d4385e61d7bc5c11a2b82c9d;hb=6b19a6786e080a7f70717b28951bd1d3b07d3fb0;hp=5168b597566c225c2dd54cfd56d46022be2c31a4;hpb=6fec031c43332c784db51efa5a98061a230ecc9b;p=xonotic%2Fdarkplaces.git diff --git a/prvm_edict.c b/prvm_edict.c index 5168b597..41f8b2a1 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -39,6 +39,7 @@ cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"}; cvar_t prvm_leaktest_ignore_classnames = {0, "prvm_leaktest_ignore_classnames", "", "classnames of entities to NOT leak check because they are found by find(world, classname, ...) but are actually spawned by QC code (NOT map entities)"}; cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"}; +cvar_t prvm_breakpointdump = {0, "prvm_breakpointdump", "0", "write a savegame on breakpoint to breakpoint-server.dmp"}; cvar_t prvm_reuseedicts_startuptime = {0, "prvm_reuseedicts_startuptime", "2", "allows immediate re-use of freed entity slots during start of new level (value in seconds)"}; cvar_t prvm_reuseedicts_neverinsameframe = {0, "prvm_reuseedicts_neverinsameframe", "1", "never allows re-use of freed entity slots during same frame"}; @@ -73,13 +74,13 @@ static void PRVM_MEM_Alloc(prvm_prog_t *prog) // alloc edict fields prog->entityfieldsarea = prog->entityfields * prog->max_edicts; - prog->edictsfields = (vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(vec_t)); + prog->edictsfields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(prvm_vec_t)); // set edict pointers for(i = 0; i < prog->max_edicts; i++) { prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size); - prog->edicts[i].fields.vp = prog->edictsfields + i * prog->entityfields; + prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields; } } @@ -101,14 +102,14 @@ void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog) prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts); prog->entityfieldsarea = prog->entityfields * prog->max_edicts; - prog->edictsfields = (vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(vec_t)); + prog->edictsfields = (prvm_vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(prvm_vec_t)); prog->edictprivate = (void *)Mem_Realloc(prog->progs_mempool, (void *)prog->edictprivate, prog->max_edicts * prog->edictprivate_size); //set e and v pointers for(i = 0; i < prog->max_edicts; i++) { prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size); - prog->edicts[i].fields.vp = prog->edictsfields + i * prog->entityfields; + prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields; } prog->end_increase_edicts(prog); @@ -190,7 +191,7 @@ Sets everything to NULL */ void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e) { - memset(e->fields.vp, 0, prog->entityfields * 4); + memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); e->priv.required->free = false; // AK: Let the init_edict function determine if something needs to be initialized @@ -442,11 +443,11 @@ static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val break; case ev_float: // LordHavoc: changed from %5.1f to %10.4f - dpsnprintf (line, linelength, "%10.4f", val->_float); + dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float); break; case ev_vector: // LordHavoc: changed from %5.1f to %10.4f - dpsnprintf (line, linelength, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]); + dpsnprintf (line, linelength, "'" VECTOR_LOSSLESS_FORMAT "'", val->vector[0], val->vector[1], val->vector[2]); break; case ev_pointer: dpsnprintf (line, linelength, "pointer"); @@ -512,7 +513,7 @@ char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, c line[i] = '\0'; break; case ev_entity: - dpsnprintf (line, linelength, "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict))); + dpsnprintf (line, linelength, "%i", val->edict); break; case ev_function: f = prog->functions + val->function; @@ -526,10 +527,10 @@ char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, c dpsnprintf (line, linelength, "void"); break; case ev_float: - dpsnprintf (line, linelength, "%.9g", val->_float); + dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float); break; case ev_vector: - dpsnprintf (line, linelength, "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); + dpsnprintf (line, linelength, VECTOR_LOSSLESS_FORMAT, val->vector[0], val->vector[1], val->vector[2]); break; default: dpsnprintf (line, linelength, "bad type %i", type); @@ -552,16 +553,16 @@ char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t lineleng char *s; //size_t i; ddef_t *def; - void *val; + prvm_eval_t *val; char valuebuf[MAX_INPUTLINE]; - val = (void *)&prog->globals.generic[ofs]; + val = (prvm_eval_t *)&prog->globals.fp[ofs]; def = PRVM_ED_GlobalAtOfs(prog, ofs); if (!def) dpsnprintf (line, linelength, "GLOBAL%i", ofs); else { - s = PRVM_ValueString (prog, (etype_t)def->type, (prvm_eval_t *)val, valuebuf, sizeof(valuebuf)); + s = PRVM_ValueString (prog, (etype_t)def->type, val, valuebuf, sizeof(valuebuf)); dpsnprintf (line, linelength, "%s (=%s)", PRVM_GetString(prog, def->s_name), s); } @@ -606,7 +607,7 @@ void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fie { size_t l; ddef_t *d; - int *v; + prvm_eval_t *val; int i, j; const char *name; int type; @@ -634,13 +635,13 @@ void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fie // Didn't match; skip continue; - v = (int *)(ed->fields.vp + d->ofs); + val = (prvm_eval_t *)(ed->fields.fp + d->ofs); // if the value is still all 0, skip the field type = d->type & ~DEF_SAVEGLOBAL; for (j=0 ; jivector[j]) break; if (j == prvm_type_size[type]) continue; @@ -657,7 +658,7 @@ void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fie strlcat(tempstring, " ", sizeof(tempstring)); strlcat(tempstring, " ", sizeof(tempstring)); - name = PRVM_ValueString(prog, (etype_t)d->type, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf)); + name = PRVM_ValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)); if (strlen(name) > sizeof(tempstring2)-4) { memcpy (tempstring2, name, sizeof(tempstring2)-4); @@ -688,7 +689,7 @@ extern cvar_t developer_entityparsing; void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed) { ddef_t *d; - int *v; + prvm_eval_t *val; int i, j; const char *name; int type; @@ -715,19 +716,19 @@ void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed) if(strlen(name) > 1 && name[strlen(name)-2] == '_') continue; // skip _x, _y, _z vars, and ALSO other _? vars as some mods expect them to be never saved (TODO: a gameplayfix for using the "more precise" condition above?) - v = (int *)(ed->fields.vp + d->ofs); + val = (prvm_eval_t *)(ed->fields.fp + d->ofs); // if the value is still all 0, skip the field type = d->type & ~DEF_SAVEGLOBAL; for (j=0 ; jivector[j]) break; if (j == prvm_type_size[type]) continue; FS_Printf(f,"\"%s\" ",name); prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_Write, ent=%d, name=%s", i, name); - FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf))); + FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf))); prog->statestring = NULL; } @@ -875,7 +876,7 @@ void PRVM_ED_WriteGlobals (prvm_prog_t *prog, qfile_t *f) prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_WriteGlobals, name=%s", name); FS_Printf(f,"\"%s\" ", name); - FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs], valuebuf, sizeof(valuebuf))); + FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.fp[def->ofs], valuebuf, sizeof(valuebuf))); prog->statestring = NULL; } FS_Print(f,"}\n"); @@ -946,9 +947,9 @@ qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, c mfunction_t *func; if (ent) - val = (prvm_eval_t *)(ent->fields.vp + key->ofs); + val = (prvm_eval_t *)(ent->fields.fp + key->ofs); else - val = (prvm_eval_t *)(prog->globals.generic + key->ofs); + val = (prvm_eval_t *)(prog->globals.fp + key->ofs); switch (key->type & ~DEF_SAVEGLOBAL) { case ev_string: @@ -1002,7 +1003,7 @@ qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, c PRVM_MEM_IncreaseEdicts(prog); // if IncreaseEdicts was called the base pointer needs to be updated if (ent) - val = (prvm_eval_t *)(ent->fields.vp + key->ofs); + val = (prvm_eval_t *)(ent->fields.fp + key->ofs); val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i)); break; @@ -1129,7 +1130,7 @@ static void PRVM_ED_EdictGet_f(void) goto fail; } - v = (prvm_eval_t *)(ed->fields.vp + key->ofs); + v = (prvm_eval_t *)(ed->fields.fp + key->ofs); s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf)); if(Cmd_Argc() == 5) { @@ -1172,7 +1173,7 @@ static void PRVM_ED_GlobalGet_f(void) goto fail; } - v = (prvm_eval_t *) &prog->globals.generic[key->ofs]; + v = (prvm_eval_t *) &prog->globals.fp[key->ofs]; s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf)); if(Cmd_Argc() == 4) { @@ -1370,7 +1371,7 @@ void PRVM_ED_LoadFromFile (prvm_prog_t *prog, const char *data) // clear it if (ent != prog->edicts) // hack - memset (ent->fields.vp, 0, prog->entityfields * 4); + memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); data = PRVM_ED_ParseEdict (prog, data, ent); parsed++; @@ -1606,7 +1607,7 @@ static void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize) *out++ = '\\'; *out++ = '0' + ((*in & 0700) >> 6); *out++ = '0' + ((*in & 0070) >> 3); - *out++ = '0' + ((*in & 0007)); + *out++ = '0' + (*in & 0007) ; outsize -= 4; } } @@ -1814,12 +1815,18 @@ static void PRVM_PO_Destroy(po_t *po) void PRVM_LeakTest(prvm_prog_t *prog); void PRVM_Prog_Reset(prvm_prog_t *prog) { - PRVM_LeakTest(prog); - prog->reset_cmd(prog); - Mem_FreePool(&prog->progs_mempool); - if(prog->po) - PRVM_PO_Destroy((po_t *) prog->po); + if (prog->loaded) + { + PRVM_LeakTest(prog); + prog->reset_cmd(prog); + Mem_FreePool(&prog->progs_mempool); + if(prog->po) + PRVM_PO_Destroy((po_t *) prog->po); + } memset(prog,0,sizeof(prvm_prog_t)); + prog->break_statement = -1; + prog->watch_global = -1; + prog->watch_edict = -1; } /* @@ -1875,14 +1882,15 @@ static void PRVM_LoadLNO( prvm_prog_t *prog, const char *progname ) { PRVM_LoadProgs =============== */ -void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global) +static void PRVM_UpdateBreakpoints(prvm_prog_t *prog); +void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global) { int i; dprograms_t *dprograms; dstatement_t *instatements; ddef_t *infielddefs; ddef_t *inglobaldefs; - float *inglobals; + int *inglobals; dfunction_t *infunctions; char *instrings; fs_offset_t filesize; @@ -1891,12 +1899,28 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun int a; int b; int c; + union + { + unsigned int i; + float f; + } + u; + unsigned int d; char vabuf[1024]; if (prog->loaded) prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name ); - dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize); + Host_LockSession(); // all progs can use the session cvar + Crypto_LoadKeys(); // all progs might use the keys at init time + + if (data) + { + dprograms = (dprograms_t *) data; + filesize = size; + } + else + dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize); if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t)) prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name); // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file @@ -1927,7 +1951,7 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun prog->progs_numfunctions = LittleLong(dprograms->numfunctions); instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings)); prog->progs_numstrings = LittleLong(dprograms->numstrings); - inglobals = (float *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals)); + inglobals = (int *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals)); prog->progs_numglobals = LittleLong(dprograms->numglobals); prog->progs_entityfields = LittleLong(dprograms->entityfields); @@ -1939,7 +1963,7 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun prog->numglobals = prog->progs_numglobals; prog->entityfields = prog->progs_entityfields; - if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings >= (int)filesize) + if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings > (int)filesize) prog->error_cmd("%s: %s strings go past end of file", prog->name, filename); prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings); memcpy(prog->strings, instrings, prog->progs_numstrings); @@ -1954,7 +1978,10 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun // we need to expand the globaldefs and fielddefs to include engine defs prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t)); - prog->globals.generic = (float *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace) * sizeof(float)); + prog->globals.fp = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace + 2) * sizeof(prvm_vec_t)); + // + 2 is because of an otherwise occurring overrun in RETURN instruction + // when trying to return the last or second-last global + // (RETURN always returns a vector, there is no RETURN_F instruction) prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t)); // we need to convert the statements to our memory format prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t)); @@ -2029,8 +2056,26 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun #define remapfield(index) (index) // copy globals + // FIXME: LordHavoc: this uses a crude way to identify integer constants, rather than checking for matching globaldefs and checking their type for (i = 0;i < prog->progs_numglobals;i++) - ((int *)prog->globals.generic)[remapglobal(i)] = LittleLong(((int *)inglobals)[i]); + { + u.i = LittleLong(inglobals[i]); + // most globals are 0, we only need to deal with the ones that are not + if (u.i) + { + d = u.i & 0xFF800000; + if ((d == 0xFF800000) || (d == 0)) + { + // Looks like an integer (expand to int64) + prog->globals.ip[remapglobal(i)] = u.i; + } + else + { + // Looks like a float (expand to double) + prog->globals.fp[remapglobal(i)] = u.f; + } + } + } // LordHavoc: TODO: support 32bit progs statement formats // copy, remap globals in statements, bounds check @@ -2182,7 +2227,8 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun } // we're done with the file now - Mem_Free(dprograms); + if(!data) + Mem_Free(dprograms); dprograms = NULL; // check required functions @@ -2360,6 +2406,8 @@ fail: prog->loaded = TRUE; + PRVM_UpdateBreakpoints(prog); + // set flags & ddef_ts in prog prog->flag = 0; @@ -2382,7 +2430,7 @@ static void PRVM_Fields_f (void) const char *name; prvm_edict_t *ed; ddef_t *d; - int *v; + prvm_eval_t *val; // TODO /* @@ -2414,11 +2462,11 @@ static void PRVM_Fields_f (void) name = PRVM_GetString(prog, d->s_name); if (name[strlen(name)-2] == '_') continue; // skip _x, _y, _z vars - v = (int *)(ed->fields.vp + d->ofs); + val = (prvm_eval_t *)(ed->fields.fp + d->ofs); // if the value is still all 0, skip the field for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++) { - if (v[j]) + if (val->ivector[j]) { counts[i]++; break; @@ -2585,6 +2633,194 @@ static void PRVM_GlobalSet_f(void) PRVM_ED_ParseEpair( prog, NULL, global, Cmd_Argv(3), true ); } +/* +====================== +Break- and Watchpoints +====================== +*/ +typedef struct +{ + char break_statement[256]; + char watch_global[256]; + int watch_edict; + char watch_field[256]; +} +debug_data_t; +static debug_data_t debug_data[PRVM_PROG_MAX]; + +void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text) +{ + char vabuf[1024]; + Con_Printf("PRVM_Breakpoint: %s\n", text); + PRVM_PrintState(prog, stack_index); + if (prvm_breakpointdump.integer) + Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name)); +} + +static void PRVM_UpdateBreakpoints(prvm_prog_t *prog) +{ + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + if (!prog->loaded) + return; + if (debug->break_statement[0]) + { + if (debug->break_statement[0] >= '0' && debug->break_statement[0] <= '9') + { + prog->break_statement = atoi(debug->break_statement); + prog->break_stack_index = 0; + } + else + { + mfunction_t *func; + func = PRVM_ED_FindFunction (prog, debug->break_statement); + if (!func) + { + Con_Printf("%s progs: no function or statement named %s to break on!\n", prog->name, debug->break_statement); + prog->break_statement = -1; + } + else + { + prog->break_statement = func->first_statement; + prog->break_stack_index = 1; + } + } + if (prog->break_statement >= -1) + Con_Printf("%s progs: breakpoint is at statement %d\n", prog->name, prog->break_statement); + } + else + prog->break_statement = -1; + + if (debug->watch_global[0]) + { + ddef_t *global = PRVM_ED_FindGlobal( prog, debug->watch_global ); + if( !global ) + { + Con_Printf( "%s progs: no global named '%s' to watch!\n", prog->name, debug->watch_global ); + prog->watch_global = -1; + } + else + { + prog->watch_global = global->ofs; + prog->watch_global_value = PRVM_GLOBALFIELDFLOAT(prog->watch_global); + } + if (prog->watch_global >= -1) + Con_Printf("%s progs: global watchpoint is at global index %d\n", prog->name, prog->watch_global); + } + else + prog->watch_global = -1; + + if (debug->watch_field[0]) + { + ddef_t *field = PRVM_ED_FindField( prog, debug->watch_field ); + if( !field ) + { + Con_Printf( "%s progs: no field named '%s' to watch!\n", prog->name, debug->watch_field ); + prog->watch_edict = -1; + } + else + { + prog->watch_edict = debug->watch_edict; + prog->watch_field = field->ofs; + if (prog->watch_edict < prog->num_edicts) + prog->watch_edictfield_value = PRVM_EDICTFIELDFLOAT(PRVM_EDICT_NUM(prog->watch_edict), prog->watch_field); + else + prog->watch_edictfield_value = 0; + } + if (prog->watch_edict >= -1) + Con_Printf("%s progs: edict field watchpoint is at edict %d field index %d\n", prog->name, prog->watch_edict, prog->watch_field); + } + else + prog->watch_edict = -1; +} + +static void PRVM_Breakpoint_f(void) +{ + prvm_prog_t *prog; + + if( Cmd_Argc() == 2 ) { + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->break_statement[0] = 0; + } + PRVM_UpdateBreakpoints(prog); + return; + } + if( Cmd_Argc() != 3 ) { + Con_Printf( "prvm_breakpoint \n" ); + return; + } + + if (!(prog = PRVM_ProgFromString(Cmd_Argv(1)))) + return; + + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + strlcpy(debug->break_statement, Cmd_Argv(2), sizeof(debug->break_statement)); + } + PRVM_UpdateBreakpoints(prog); +} + +static void PRVM_GlobalWatchpoint_f(void) +{ + prvm_prog_t *prog; + + if( Cmd_Argc() == 2 ) { + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->watch_global[0] = 0; + } + PRVM_UpdateBreakpoints(prog); + return; + } + if( Cmd_Argc() != 3 ) { + Con_Printf( "prvm_globalwatchpoint \n" ); + return; + } + + if (!(prog = PRVM_ProgFromString(Cmd_Argv(1)))) + return; + + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + strlcpy(debug->watch_global, Cmd_Argv(2), sizeof(debug->watch_global)); + } + PRVM_UpdateBreakpoints(prog); +} + +static void PRVM_EdictWatchpoint_f(void) +{ + prvm_prog_t *prog; + + if( Cmd_Argc() == 2 ) { + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->watch_field[0] = 0; + } + PRVM_UpdateBreakpoints(prog); + return; + } + if( Cmd_Argc() != 4 ) { + Con_Printf( "prvm_edictwatchpoint \n" ); + return; + } + + if (!(prog = PRVM_ProgFromString(Cmd_Argv(1)))) + return; + + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->watch_edict = atoi(Cmd_Argv(2)); + strlcpy(debug->watch_field, Cmd_Argv(3), sizeof(debug->watch_field)); + } + PRVM_UpdateBreakpoints(prog); +} + /* =============== PRVM_Init @@ -2610,6 +2846,10 @@ void PRVM_Init (void) Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument"); Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument"); + Cmd_AddCommand ("prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint"); + Cmd_AddCommand ("prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); + Cmd_AddCommand ("prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); + Cvar_RegisterVariable (&prvm_language); Cvar_RegisterVariable (&prvm_traceqc); Cvar_RegisterVariable (&prvm_statementprofiling); @@ -2618,6 +2858,7 @@ void PRVM_Init (void) Cvar_RegisterVariable (&prvm_leaktest); Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames); Cvar_RegisterVariable (&prvm_errordump); + Cvar_RegisterVariable (&prvm_breakpointdump); Cvar_RegisterVariable (&prvm_reuseedicts_startuptime); Cvar_RegisterVariable (&prvm_reuseedicts_neverinsameframe); @@ -2634,10 +2875,7 @@ PRVM_InitProg */ void PRVM_Prog_Init(prvm_prog_t *prog) { - if (prog->loaded) - PRVM_Prog_Reset(prog); - - memset(prog, 0, sizeof(prvm_prog_t)); + PRVM_Prog_Reset(prog); prog->leaktest_active = prvm_leaktest.integer != 0; } @@ -2723,9 +2961,7 @@ int PRVM_SetEngineString(prvm_prog_t *prog, const char *s) // if it's in the tempstrings area, use a reserved range // (otherwise we'd get millions of useless string offsets cluttering the database) if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize) -#if 1 return prog->stringssize + (s - (char *)prog->tempstringsbuf.data); -#endif // see if it's a known string address for (i = 0;i < prog->numknownstrings;i++) if (prog->knownstrings[i] == s) @@ -2973,13 +3209,16 @@ static qboolean PRVM_IsEdictReferenced(prvm_prog_t *prog, prvm_edict_t *edict, i if(!*targetname) // "" targetname = NULL; - for (i = 0;i < prog->numglobaldefs;i++) + if(mark == 0) { - ddef_t *d = &prog->globaldefs[i]; - if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity) - continue; - if(edictnum == PRVM_GLOBALFIELDEDICT(d->ofs)) - return true; + for (i = 0;i < prog->numglobaldefs;i++) + { + ddef_t *d = &prog->globaldefs[i]; + if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity) + continue; + if(edictnum == PRVM_GLOBALFIELDEDICT(d->ofs)) + return true; + } } for(j = 0; j < prog->num_edicts; ++j) @@ -3082,6 +3321,8 @@ void PRVM_LeakTest(prvm_prog_t *prog) Con_Print("\n"); leaked = true; } + + ed->priv.required->mark = 0; // clear marks again when done } for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)