From 46a24b411ef2bee4eb2a08da15d38a61b484f471 Mon Sep 17 00:00:00 2001 From: cloudwalk Date: Fri, 14 Aug 2020 14:46:07 +0000 Subject: [PATCH] prvm: Initial experimental implementation of support for 32-bit progs offsets This implementation is may be incomplete and also includes some fixes to some opcodes. This shouldn't break anything in its current state. Thanks to Spoike for the patch. He also left a few comments on some compatibility issues DP ought to fix, which can be found by grepping "spike FIXME". git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12901 d7cf8633-e32d-0410-b094-e92efae38249 --- pr_comp.h | 68 +++++++++--- progsvm.h | 14 +-- prvm_cmds.c | 9 +- prvm_edict.c | 272 ++++++++++++++++++++++++++++++++++----------- prvm_exec.c | 206 ++++++++++++++++++++++++++++++++-- prvm_execprogram.h | 9 +- sv_ccmds.c | 2 +- 7 files changed, 471 insertions(+), 109 deletions(-) diff --git a/pr_comp.h b/pr_comp.h index 19b8f15a..20801b84 100644 --- a/pr_comp.h +++ b/pr_comp.h @@ -205,21 +205,35 @@ typedef enum opcode_e opcode_t; -typedef struct statement_s +typedef struct statement16_s { unsigned short op; signed short a,b,c; } -dstatement_t; +dstatement16_t; +typedef struct statement32_s +{ + unsigned int op; + signed int a,b,c; +} +dstatement32_t; -typedef struct ddef_s +typedef struct ddef16_s { unsigned short type; // if DEF_SAVEGLOBGAL bit is set // the variable needs to be saved in savegames unsigned short ofs; int s_name; } -ddef_t; +ddef16_t; +typedef struct ddef32_s +{ + unsigned int type; // if DEF_SAVEGLOBGAL bit is set + // the variable needs to be saved in savegames + unsigned int ofs; + int s_name; +} +ddef32_t, mdef_t; #define DEF_SAVEGLOBAL (1<<15) #define MAX_PARMS 8 @@ -281,27 +295,47 @@ typedef struct dprograms_s int version; int crc; // check of header file - int ofs_statements; - int numstatements; // statement 0 is an error + unsigned int ofs_statements; + unsigned int numstatements; // statement 0 is an error - int ofs_globaldefs; - int numglobaldefs; + unsigned int ofs_globaldefs; + unsigned int numglobaldefs; - int ofs_fielddefs; - int numfielddefs; + unsigned int ofs_fielddefs; + unsigned int numfielddefs; - int ofs_functions; - int numfunctions; // function 0 is an empty + unsigned int ofs_functions; + unsigned int numfunctions; // function 0 is an empty - int ofs_strings; - int numstrings; // first string is a null string + unsigned int ofs_strings; + unsigned int numstrings; // first string is a null string - int ofs_globals; - int numglobals; + unsigned int ofs_globals; + unsigned int numglobals; - int entityfields; + unsigned int entityfields; } dprograms_t; +typedef struct dprograms_v7_s +{ //extended header written by fteqcc. + dprograms_t v6; //for easier casting. + + //debug / version 7 extensions + unsigned int ofsfiles; //ignored. deprecated, should be 0. source files can instead be embedded by simply treating the .dat as a zip. + unsigned int ofslinenums; //ignored. alternative to external .lno files. + unsigned int ofsbodylessfuncs; //unsupported. function names imported from other modules. must be 0. + unsigned int numbodylessfuncs; //unsupported. must be 0. + + unsigned int ofs_types; //unsupported+deprecated. rich type info. must be 0. + unsigned int numtypes; //unsupported+deprecated. rich type info. must be 0. + unsigned int blockscompressed; //unsupported. per-block compression. must be 0. + + int secondaryversion; //if not known then its kkqwsv's v7, qfcc's v7, or uhexen2's v7, or something. abandon all hope when not recognised. +#define PROG_SECONDARYVERSION16 ((('1'<<0)|('F'<<8)|('T'<<16)|('E'<<24))^(('P'<<0)|('R'<<8)|('O'<<16)|('G'<<24))) //regular 16bit statements. +#define PROG_SECONDARYVERSION32 ((('1'<<0)|('F'<<8)|('T'<<16)|('E'<<24))^(('3'<<0)|('2'<<8)|('B'<<16)|(' '<<24))) //statements+globaldefs+fielddefs extended to 32bit. +} +dprograms_v7_t; + #endif diff --git a/progsvm.h b/progsvm.h index 738101bb..6c185b63 100644 --- a/progsvm.h +++ b/progsvm.h @@ -525,8 +525,8 @@ typedef struct prvm_prog_s int functions_covered; char *strings; int stringssize; - ddef_t *fielddefs; - ddef_t *globaldefs; + mdef_t *fielddefs; + mdef_t *globaldefs; mstatement_t *statements; int entityfields; // number of vec_t fields in progs (some variables are 3) int entityfieldsarea; // LadyHavoc: equal to max_edicts * entityfields (for bounds checking) @@ -709,7 +709,7 @@ typedef struct prvm_prog_s //============================================================================ - ddef_t *self; // if self != 0 then there is a global self + mdef_t *self; // if self != 0 then there is a global self //============================================================================ // function pointers @@ -813,8 +813,8 @@ void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize); const char *PRVM_AllocationOrigin(prvm_prog_t *prog); void PRVM_GarbageCollection(prvm_prog_t *prog); -ddef_t *PRVM_ED_FindField(prvm_prog_t *prog, const char *name); -ddef_t *PRVM_ED_FindGlobal(prvm_prog_t *prog, const char *name); +mdef_t *PRVM_ED_FindField(prvm_prog_t *prog, const char *name); +mdef_t *PRVM_ED_FindGlobal(prvm_prog_t *prog, const char *name); prvm_eval_t *PRVM_ED_FindGlobalEval(prvm_prog_t *prog, const char *name); mfunction_t *PRVM_ED_FindFunction(prvm_prog_t *prog, const char *name); @@ -891,8 +891,8 @@ int PRVM_SetTempString(prvm_prog_t *prog, const char *s); int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer); void PRVM_FreeString(prvm_prog_t *prog, int num); -ddef_t *PRVM_ED_FieldAtOfs(prvm_prog_t *prog, int ofs); -qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash); +mdef_t *PRVM_ED_FieldAtOfs(prvm_prog_t *prog, unsigned int ofs); +qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, mdef_t *key, const char *s, qboolean parsebackslash); char *PRVM_UglyValueString(prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength); char *PRVM_GlobalString(prvm_prog_t *prog, int ofs, char *line, size_t linelength); char *PRVM_GlobalStringNoContents(prvm_prog_t *prog, int ofs, char *line, size_t linelength); diff --git a/prvm_cmds.c b/prvm_cmds.c index 5216d3f7..46c5864a 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -2044,7 +2044,7 @@ Return name of the specified field as a string, or empty if the field is invalid */ void VM_entityfieldname(prvm_prog_t *prog) { - ddef_t *d; + mdef_t *d; int i = (int)PRVM_G_FLOAT(OFS_PARM0); if (i < 0 || i >= prog->numfielddefs) @@ -2068,7 +2068,7 @@ float(float fieldnum) entityfieldtype */ void VM_entityfieldtype(prvm_prog_t *prog) { - ddef_t *d; + mdef_t *d; int i = (int)PRVM_G_FLOAT(OFS_PARM0); if (i < 0 || i >= prog->numfielddefs) @@ -2093,7 +2093,7 @@ string(float fieldnum, entity ent) getentityfieldstring void VM_getentityfieldstring(prvm_prog_t *prog) { // put the data into a string - ddef_t *d; + mdef_t *d; int type, j; prvm_eval_t *val; prvm_edict_t * ent; @@ -2143,7 +2143,7 @@ float(float fieldnum, entity ent, string s) putentityfieldstring */ void VM_putentityfieldstring(prvm_prog_t *prog) { - ddef_t *d; + mdef_t *d; prvm_edict_t * ent; int i = (int)PRVM_G_FLOAT(OFS_PARM0); @@ -6827,6 +6827,7 @@ nolength: o += u8_strpad(o, end - o, buf, (flags & PRINTF_LEFT) != 0, width, precision); } break; + //spike FIXME -- 'S' for quoted tokenize-safe-or-print escaping of strings so stuff can safely survive console commands. case 's': if(flags & PRINTF_ALTERNATE) { diff --git a/prvm_edict.c b/prvm_edict.c index 92004b0a..8b3a645e 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -127,7 +127,7 @@ void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog) int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *field) { - ddef_t *d; + mdef_t *d; d = PRVM_ED_FindField(prog, field); if (!d) return -1; @@ -136,7 +136,7 @@ int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *field) int PRVM_ED_FindGlobalOffset(prvm_prog_t *prog, const char *global) { - ddef_t *d; + mdef_t *d; d = PRVM_ED_FindGlobal(prog, global); if (!d) return -1; @@ -324,9 +324,9 @@ void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed) PRVM_ED_GlobalAtOfs ============ */ -static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs) +static mdef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, unsigned int ofs) { - ddef_t *def; + mdef_t *def; int i; for (i = 0;i < prog->numglobaldefs;i++) @@ -343,9 +343,9 @@ static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs) PRVM_ED_FieldAtOfs ============ */ -ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs) +mdef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, unsigned int ofs) { - ddef_t *def; + mdef_t *def; int i; for (i = 0;i < prog->numfielddefs;i++) @@ -362,9 +362,9 @@ ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs) PRVM_ED_FindField ============ */ -ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name) +mdef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name) { - ddef_t *def; + mdef_t *def; int i; for (i = 0;i < prog->numfielddefs;i++) @@ -381,9 +381,9 @@ ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name) PRVM_ED_FindGlobal ============ */ -ddef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name) +mdef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name) { - ddef_t *def; + mdef_t *def; int i; for (i = 0;i < prog->numglobaldefs;i++) @@ -402,7 +402,7 @@ PRVM_ED_FindGlobalEval */ prvm_eval_t *PRVM_ED_FindGlobalEval(prvm_prog_t *prog, const char *name) { - ddef_t *def = PRVM_ED_FindGlobal(prog, name); + mdef_t *def = PRVM_ED_FindGlobal(prog, name); return def ? (prvm_eval_t *) &prog->globals.fp[def->ofs] : NULL; } @@ -435,7 +435,7 @@ Returns a string describing *data in a type specific manner */ static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength) { - ddef_t *def; + mdef_t *def; mfunction_t *f; int n; @@ -503,7 +503,7 @@ char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, c { int i; const char *s; - ddef_t *def; + mdef_t *def; mfunction_t *f; type = (etype_t)((int)type & ~DEF_SAVEGLOBAL); @@ -592,7 +592,7 @@ char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t lineleng { char *s; //size_t i; - ddef_t *def; + mdef_t *def; prvm_eval_t *val; char valuebuf[MAX_INPUTLINE]; @@ -617,7 +617,7 @@ char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t lineleng char *PRVM_GlobalStringNoContents (prvm_prog_t *prog, int ofs, char *line, size_t linelength) { //size_t i; - ddef_t *def; + mdef_t *def; def = PRVM_ED_GlobalAtOfs(prog, ofs); if (!def) @@ -646,7 +646,7 @@ For debugging void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname) { size_t l; - ddef_t *d; + mdef_t *d; prvm_eval_t *val; int i, j; const char *name; @@ -727,7 +727,7 @@ For savegames */ void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed) { - ddef_t *d; + mdef_t *d; prvm_eval_t *val; int i, j; const char *name; @@ -889,7 +889,7 @@ PRVM_ED_WriteGlobals */ void PRVM_ED_WriteGlobals (prvm_prog_t *prog, qfile_t *f) { - ddef_t *def; + mdef_t *def; int i; const char *name; int type; @@ -929,7 +929,7 @@ PRVM_ED_ParseGlobals void PRVM_ED_ParseGlobals (prvm_prog_t *prog, const char *data) { char keyname[MAX_INPUTLINE]; - ddef_t *key; + mdef_t *key; while (1) { @@ -977,11 +977,11 @@ Can parse either fields or globals returns false if error ============= */ -qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash) +qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, mdef_t *key, const char *s, qboolean parsebackslash) { int i, l; char *new_p; - ddef_t *def; + mdef_t *def; prvm_eval_t *val; mfunction_t *func; @@ -1147,7 +1147,7 @@ static void PRVM_ED_EdictGet_f(cmd_state_t *cmd) { prvm_prog_t *prog; prvm_edict_t *ed; - ddef_t *key; + mdef_t *key; const char *s; prvm_eval_t *v; char valuebuf[MAX_INPUTLINE]; @@ -1190,7 +1190,7 @@ fail: static void PRVM_ED_GlobalGet_f(cmd_state_t *cmd) { prvm_prog_t *prog; - ddef_t *key; + mdef_t *key; const char *s; prvm_eval_t *v; char valuebuf[MAX_INPUTLINE]; @@ -1239,7 +1239,7 @@ static void PRVM_ED_EdictSet_f(cmd_state_t *cmd) { prvm_prog_t *prog; prvm_edict_t *ed; - ddef_t *key; + mdef_t *key; if(Cmd_Argc(cmd) != 5) { @@ -1269,7 +1269,7 @@ Used for initial level load and for savegames. */ const char *PRVM_ED_ParseEdict (prvm_prog_t *prog, const char *data, prvm_edict_t *ent) { - ddef_t *key; + mdef_t *key; qboolean anglehack; qboolean init; char keyname[256]; @@ -1729,7 +1729,7 @@ static void PRVM_PO_ParseString(char *out, const char *in, size_t outsize) case '\\': if(outsize > 0) { *out++ = '\\'; --outsize; } break; case '"': if(outsize > 0) { *out++ = '"'; --outsize; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - if(outsize > 0) + if(outsize > 0) *out = *in - '0'; ++in; if(*in >= '0' && *in <= '7') @@ -1873,7 +1873,7 @@ static po_t *PRVM_PO_Load(const char *filename, const char *filename2, mempool_t memset(&thisstr, 0, sizeof(thisstr)); } } - + Mem_Free((char *) buf); } @@ -1994,9 +1994,14 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da { int i; dprograms_t *dprograms; - dstatement_t *instatements; - ddef_t *infielddefs; - ddef_t *inglobaldefs; + + dstatement16_t *instatements16; + dstatement32_t *instatements32; + ddef16_t *infielddefs16; + ddef32_t *infielddefs32; + ddef16_t *inglobaldefs16; + ddef32_t *inglobaldefs32; + int *inglobals; dfunction_t *infunctions; char *instrings; @@ -2016,6 +2021,7 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da char vabuf[1024]; char vabuf2[1024]; cvar_t *cvar; + int structtype = 0; if (prog->loaded) prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name ); @@ -2046,13 +2052,29 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da // byte swap the header prog->progs_version = LittleLong(dprograms->version); prog->progs_crc = LittleLong(dprograms->crc); - if (prog->progs_version != PROG_VERSION) + if (prog->progs_version == 7) + { + dprograms_v7_t *v7 = (dprograms_v7_t*)dprograms; + structtype = LittleLong(v7->secondaryversion); + if (structtype == PROG_SECONDARYVERSION16 || + structtype == PROG_SECONDARYVERSION32) + ;//supported + else + prog->error_cmd("%s: %s targets unknown engine", prog->name, filename); + + if (v7->numbodylessfuncs != 0 || v7->numtypes != 0 || v7->blockscompressed != 0) + prog->error_cmd("%s: %s uses unsupported features.", prog->name, filename); + } + else if (prog->progs_version != PROG_VERSION) prog->error_cmd("%s: %s has wrong version number (%i should be %i)", prog->name, filename, prog->progs_version, PROG_VERSION); - instatements = (dstatement_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements)); + instatements16 = (dstatement16_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements)); + instatements32 = (dstatement32_t *)instatements16; prog->progs_numstatements = LittleLong(dprograms->numstatements); - inglobaldefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs)); + inglobaldefs16 = (ddef16_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs)); + inglobaldefs32 = (ddef32_t *)inglobaldefs16; prog->progs_numglobaldefs = LittleLong(dprograms->numglobaldefs); - infielddefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs)); + infielddefs16 = (ddef16_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs)); + infielddefs32 = (ddef32_t *)infielddefs16; prog->progs_numfielddefs = LittleLong(dprograms->numfielddefs); infunctions = (dfunction_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_functions)); prog->progs_numfunctions = LittleLong(dprograms->numfunctions); @@ -2084,12 +2106,12 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64); // 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->globaldefs = (mdef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(mdef_t)); 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)); + prog->fielddefs = (mdef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(mdef_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)); // allocate space for profiling statement usage @@ -2113,12 +2135,26 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da } // copy the globaldefs to the new globaldefs list - for (i=0 ; inumglobaldefs ; i++) + switch(structtype) { - prog->globaldefs[i].type = LittleShort(inglobaldefs[i].type); - prog->globaldefs[i].ofs = LittleShort(inglobaldefs[i].ofs); - prog->globaldefs[i].s_name = LittleLong(inglobaldefs[i].s_name); - // TODO bounds check ofs, s_name + case PROG_SECONDARYVERSION32: + for (i=0 ; inumglobaldefs ; i++) + { + prog->globaldefs[i].type = LittleLong(inglobaldefs32[i].type); + prog->globaldefs[i].ofs = LittleLong(inglobaldefs32[i].ofs); + prog->globaldefs[i].s_name = LittleLong(inglobaldefs32[i].s_name); + // TODO bounds check ofs, s_name + } + break; + default: + for (i=0 ; inumglobaldefs ; i++) + { + prog->globaldefs[i].type = (unsigned short)LittleShort(inglobaldefs16[i].type); + prog->globaldefs[i].ofs = (unsigned short)LittleShort(inglobaldefs16[i].ofs); + prog->globaldefs[i].s_name = LittleLong(inglobaldefs16[i].s_name); + // TODO bounds check ofs, s_name + } + break; } // append the required globals @@ -2135,14 +2171,30 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da } // copy the progs fields to the new fields list - for (i = 0;i < prog->numfielddefs;i++) + switch(structtype) { - prog->fielddefs[i].type = LittleShort(infielddefs[i].type); - if (prog->fielddefs[i].type & DEF_SAVEGLOBAL) - prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name); - prog->fielddefs[i].ofs = LittleShort(infielddefs[i].ofs); - prog->fielddefs[i].s_name = LittleLong(infielddefs[i].s_name); - // TODO bounds check ofs, s_name + case PROG_SECONDARYVERSION32: + for (i = 0;i < prog->numfielddefs;i++) + { + prog->fielddefs[i].type = LittleLong(infielddefs32[i].type); + if (prog->fielddefs[i].type & DEF_SAVEGLOBAL) + prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name); + prog->fielddefs[i].ofs = LittleLong(infielddefs32[i].ofs); + prog->fielddefs[i].s_name = LittleLong(infielddefs32[i].s_name); + // TODO bounds check ofs, s_name + } + break; + default: + for (i = 0;i < prog->numfielddefs;i++) + { + prog->fielddefs[i].type = (unsigned short)LittleShort(infielddefs16[i].type); + if (prog->fielddefs[i].type & DEF_SAVEGLOBAL) + prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name); + prog->fielddefs[i].ofs = (unsigned short)LittleShort(infielddefs16[i].ofs); + prog->fielddefs[i].s_name = LittleLong(infielddefs16[i].s_name); + // TODO bounds check ofs, s_name + } + break; } // append the required fields @@ -2185,14 +2237,24 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da } } - // LadyHavoc: TODO: support 32bit progs statement formats // copy, remap globals in statements, bounds check for (i = 0;i < prog->progs_numstatements;i++) { - op = (opcode_t)LittleShort(instatements[i].op); - a = (unsigned short)LittleShort(instatements[i].a); - b = (unsigned short)LittleShort(instatements[i].b); - c = (unsigned short)LittleShort(instatements[i].c); + switch(structtype) + { + case PROG_SECONDARYVERSION32: + op = (opcode_t)LittleLong(instatements32[i].op); + a = (unsigned int)LittleLong(instatements32[i].a); + b = (unsigned int)LittleLong(instatements32[i].b); + c = (unsigned int)LittleLong(instatements32[i].c); + break; + default: + op = (opcode_t)LittleShort(instatements16[i].op); + a = (unsigned short)LittleShort(instatements16[i].a); + b = (unsigned short)LittleShort(instatements16[i].b); + c = (unsigned short)LittleShort(instatements16[i].c); + break; + } switch (op) { case OP_IF: @@ -2218,7 +2280,82 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da break; default: Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, prog->name); + + //make sure its something well defined. + prog->statements[i].op = OP_BOUNDCHECK; + prog->statements[i].operand[0] = 0; + prog->statements[i].operand[1] = + prog->statements[i].operand[2] = op; + prog->statements[i].jumpabsolute = -1; break; + case OP_STORE_I: + case OP_ADD_I: + case OP_ADD_FI: + case OP_ADD_IF: + case OP_SUB_I: + case OP_SUB_FI: + case OP_SUB_IF: + case OP_CONV_IF: + case OP_CONV_FI: + case OP_LOAD_I: + case OP_STOREP_I: + case OP_BITAND_I: + case OP_BITOR_I: + case OP_MUL_I: + case OP_DIV_I: + case OP_EQ_I: + case OP_NE_I: + case OP_NOT_I: + case OP_DIV_VF: + case OP_STORE_P: + case OP_LE_I: + case OP_GE_I: + case OP_LT_I: + case OP_GT_I: + case OP_LE_IF: + case OP_GE_IF: + case OP_LT_IF: + case OP_GT_IF: + case OP_LE_FI: + case OP_GE_FI: + case OP_LT_FI: + case OP_GT_FI: + case OP_EQ_IF: + case OP_EQ_FI: + case OP_MUL_IF: + case OP_MUL_FI: + case OP_MUL_VI: + case OP_DIV_IF: + case OP_DIV_FI: + case OP_BITAND_IF: + case OP_BITOR_IF: + case OP_BITAND_FI: + case OP_BITOR_FI: + case OP_AND_I: + case OP_OR_I: + case OP_AND_IF: + case OP_OR_IF: + case OP_AND_FI: + case OP_OR_FI: + case OP_NE_IF: + case OP_NE_FI: + case OP_GSTOREP_I: + case OP_GSTOREP_F: + case OP_GSTOREP_ENT: + case OP_GSTOREP_FLD: + case OP_GSTOREP_S: + case OP_GSTOREP_FNC: + case OP_GSTOREP_V: +// case OP_GADDRESS: + case OP_GLOAD_I: + case OP_GLOAD_F: + case OP_GLOAD_FLD: + case OP_GLOAD_ENT: + case OP_GLOAD_S: + case OP_GLOAD_FNC: + case OP_BOUNDCHECK: + case OP_GLOAD_V: + // global global global case OP_ADD_F: case OP_ADD_V: @@ -2282,6 +2419,9 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da case OP_STOREP_FLD: case OP_STOREP_S: case OP_STOREP_FNC: + if (c) //Spike -- DP is alergic to pointers in QC. Try to avoid too many nasty surprises. + Con_DPrintf("PRVM_LoadProgs: storep-with-offset is not permitted in %s\n", prog->name); + //fallthrough case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: @@ -2317,6 +2457,8 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da case OP_RETURN: if ( a >= prog->progs_numglobals) prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name); + if (b || c) //Spike -- added this check just as a diagnostic... + Con_DPrintf("PRVM_LoadProgs: unxpected offset on call opcode in %s. Hexen2 format is not supported\n", prog->name); prog->statements[i].op = op; prog->statements[i].operand[0] = remapglobal(a); prog->statements[i].operand[1] = -1; @@ -2550,7 +2692,7 @@ fail: PRVM_UpdateBreakpoints(prog); - // set flags & ddef_ts in prog + // set flags & mdef_ts in prog prog->flag = 0; @@ -2577,7 +2719,7 @@ static void PRVM_Fields_f(cmd_state_t *cmd) char tempstring[MAX_INPUTLINE], tempstring2[260]; const char *name; prvm_edict_t *ed; - ddef_t *d; + mdef_t *d; prvm_eval_t *val; // TODO @@ -2740,7 +2882,7 @@ PRVM_Global static void PRVM_Global_f(cmd_state_t *cmd) { prvm_prog_t *prog; - ddef_t *global; + mdef_t *global; char valuebuf[MAX_INPUTLINE]; if( Cmd_Argc(cmd) != 3 ) { Con_Printf( "prvm_global \n" ); @@ -2765,7 +2907,7 @@ PRVM_GlobalSet static void PRVM_GlobalSet_f(cmd_state_t *cmd) { prvm_prog_t *prog; - ddef_t *global; + mdef_t *global; if( Cmd_Argc(cmd) != 4 ) { Con_Printf( "prvm_globalset \n" ); return; @@ -2856,7 +2998,7 @@ static void PRVM_UpdateBreakpoints(prvm_prog_t *prog) if (debug->watch_global[0]) { - ddef_t *global = PRVM_ED_FindGlobal( prog, debug->watch_global ); + mdef_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 ); @@ -2877,7 +3019,7 @@ static void PRVM_UpdateBreakpoints(prvm_prog_t *prog) if (debug->watch_field[0]) { - ddef_t *field = PRVM_ED_FindField( prog, debug->watch_field ); + mdef_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 ); @@ -3292,7 +3434,7 @@ static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string) for (i = 0;i < prog->numglobaldefs;i++) { - ddef_t *d = &prog->globaldefs[i]; + mdef_t *d = &prog->globaldefs[i]; if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string) continue; if(string == PRVM_GLOBALFIELDSTRING(d->ofs)) @@ -3306,7 +3448,7 @@ static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string) continue; for (i=0; inumfielddefs; ++i) { - ddef_t *d = &prog->fielddefs[i]; + mdef_t *d = &prog->fielddefs[i]; if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string) continue; if(string == PRVM_EDICTFIELDSTRING(ed, d->ofs)) @@ -3398,7 +3540,7 @@ static qboolean PRVM_IsEdictReferenced(prvm_prog_t *prog, prvm_edict_t *edict, i } for (i=0; inumfielddefs; ++i) { - ddef_t *d = &prog->fielddefs[i]; + mdef_t *d = &prog->fielddefs[i]; if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity) continue; if(edictnum == PRVM_EDICTFIELDEDICT(ed, d->ofs)) @@ -3426,7 +3568,7 @@ static void PRVM_MarkReferencedEdicts(prvm_prog_t *prog) } for (i = 0;i < prog->numglobaldefs;i++) { - ddef_t *d = &prog->globaldefs[i]; + mdef_t *d = &prog->globaldefs[i]; prvm_edict_t *ed; if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity) continue; @@ -3556,7 +3698,7 @@ void PRVM_GarbageCollection(prvm_prog_t *prog) case PRVM_GC_GLOBALS_MARK: for (; gc->globals_mark_progress < prog->numglobaldefs && (limit--) > 0; gc->globals_mark_progress++) { - ddef_t *d = &prog->globaldefs[gc->globals_mark_progress]; + mdef_t *d = &prog->globaldefs[gc->globals_mark_progress]; switch (d->type) { case ev_string: @@ -3586,7 +3728,7 @@ void PRVM_GarbageCollection(prvm_prog_t *prog) case PRVM_GC_FIELDS_MARK: for (; gc->fields_mark_progress < prog->numfielddefs && limit > 0;) { - ddef_t *d = &prog->fielddefs[gc->fields_mark_progress]; + mdef_t *d = &prog->fielddefs[gc->fields_mark_progress]; switch (d->type) { case ev_string: diff --git a/prvm_exec.c b/prvm_exec.c index 452f2803..dc86140c 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "progsvm.h" -const char *prvm_opnames[] = +static const char *prvm_opnames[] = { "^5DONE", @@ -107,7 +107,186 @@ const char *prvm_opnames[] = "^2OR", "BITAND", -"BITOR" +"BITOR", + + + + +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, + +"STORE_I", + +NULL, +NULL, + +"ADD_I", +"ADD_FI", +"ADD_IF", + +"SUB_I", +"SUB_FI", +"SUB_IF", +"CONV_IF", +"CONV_FI", + +NULL, +NULL, + +"LOAD_I", +"STOREP_I", + +NULL, +NULL, + +"BITAND_I", +"BITOR_I", + +"MUL_I", +"DIV_I", +"EQ_I", +"NE_I", + +NULL, +NULL, + +"NOT_I", + +"DIV_VF", + +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, + +"STORE_P", + +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, + +"LE_I", +"GE_I", +"LT_I", +"GT_I", + +"LE_IF", +"GE_IF", +"LT_IF", +"GT_IF", + +"LE_FI", +"GE_FI", +"LT_FI", +"GT_FI", + +"EQ_IF", +"EQ_FI", + +NULL, +NULL, +NULL, +NULL, + +"MUL_IF", +"MUL_FI", +"MUL_VI", + +NULL, + +"DIV_IF", +"DIV_FI", +"BITAND_IF", +"BITOR_IF", +"BITAND_FI", +"BITOR_FI", +"AND_I", +"OR_I", +"AND_IF", +"OR_IF", +"AND_FI", +"OR_FI", +"NE_IF", +"NE_FI", + +"GSTOREP_I", +"GSTOREP_F", +"GSTOREP_ENT", +"GSTOREP_FLD", +"GSTOREP_S", +"GSTOREP_FNC", +"GSTOREP_V", +"GADDRESS", +"GLOAD_I", +"GLOAD_F", +"GLOAD_FLD", +"GLOAD_ENT", +"GLOAD_S", +"GLOAD_FNC", +"BOUNDCHECK", +NULL, +NULL, +NULL, +NULL, +"GLOAD_V", }; @@ -127,6 +306,7 @@ static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s) size_t i; int opnum = (int)(s - prog->statements); char valuebuf[MAX_INPUTLINE]; + const char *opname; Con_Printf("s%i: ", opnum); if( prog->statement_linenums ) @@ -140,16 +320,18 @@ static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s) if (prvm_statementprofiling.integer) Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]); - if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0])) - { - Con_Printf("%s ", prvm_opnames[s->op]); - i = strlen(prvm_opnames[s->op]); - // don't count a preceding color tag when padding the name - if (prvm_opnames[s->op][0] == STRING_COLOR_TAG) - i -= 2; - for ( ; i<10 ; i++) - Con_Print(" "); - } + if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0]) && prvm_opnames[s->op]) + opname = prvm_opnames[s->op]; + else + opname = valuebuf, dpsnprintf(valuebuf, sizeof(valuebuf), "OPCODE_%u", (unsigned)s->op); + Con_Printf("%s ", opname); + i = strlen(opname); + // don't count a preceding color tag when padding the name + if (opname[0] == STRING_COLOR_TAG) + i -= 2; + for ( ; i<10 ; i++) + Con_Print(" "); + if (s->operand[0] >= 0) Con_Printf( "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf))); if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf))); if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[2], valuebuf, sizeof(valuebuf))); diff --git a/prvm_execprogram.h b/prvm_execprogram.h index ea366821..e0cc872a 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -632,6 +632,8 @@ int i; //================== HANDLE_OPCODE(OP_IFNOT): + //spike FIXME -- dp redefined IFNOT[_I] as IFNOT_F, which breaks if(0x80000000) + //spike FIXME -- you should add separate IFNOT_I/IFNOT_F opcodes and remap IFNOT_I to ITNOT_F in v6 progs for compat. if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int)) // TODO add an "int-if", and change this one to OPA->_float // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero) @@ -651,6 +653,7 @@ int i; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_IF): + //spike FIXME -- dp redefined IF[_I] as IF_F if(FLOAT_IS_TRUE_FOR_INT(OPA->_int)) // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero) @@ -989,7 +992,7 @@ int i; prog->globals.ip[OPB->_int] = OPA->_int; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_GSTOREP_V): - if (OPB->_int < 0 || OPB->_int + 2 >= prog->numglobaldefs) + if (OPB->_int < 0 || OPB->_int + 2 >= prog->numglobals) { PRE_ERROR(); prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name); @@ -1041,10 +1044,10 @@ int i; DISPATCH_OPCODE(); HANDLE_OPCODE(OP_BOUNDCHECK): - if (OPA->_int < 0 || OPA->_int >= OPB->_int) + if ((unsigned int)OPA->_int < (unsigned int)st->operand[2] || (unsigned int)OPA->_int >= (unsigned int)st->operand[1]) { PRE_ERROR(); - prog->error_cmd("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", prog->name, OPB->_int, OPC->_int); + prog->error_cmd("Progs boundcheck failed in %s, value is < %d or >= %d", prog->name, OPC->_int, OPB->_int); goto cleanup; } DISPATCH_OPCODE(); diff --git a/sv_ccmds.c b/sv_ccmds.c index 5ff2f3ce..54718de3 100644 --- a/sv_ccmds.c +++ b/sv_ccmds.c @@ -1487,7 +1487,7 @@ static void SV_Ent_Create_f(cmd_state_t *cmd) { prvm_prog_t *prog = SVVM_prog; prvm_edict_t *ed; - ddef_t *key; + mdef_t *key; int i; qboolean haveorigin; -- 2.39.2