Add level script pointer validation
This commit is contained in:
parent
9426824a4c
commit
fcd61d6c0e
|
@ -1091,6 +1091,9 @@ GfxData *DynOS_Lvl_LoadFromBinary(const SysPath &aFilename, const char *aLevelNa
|
|||
void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder);
|
||||
s64 DynOS_Lvl_ParseLevelScriptConstants(const String& _Arg, bool* found);
|
||||
|
||||
void DynOS_Lvl_Validate_Begin();
|
||||
bool DynOS_Lvl_Validate_RequirePointer(u32 value);
|
||||
|
||||
DataNode<BehaviorScript> *DynOS_Bhv_Parse(GfxData *aGfxData, DataNode<BehaviorScript> *aNode, bool aDisplayPercent);
|
||||
GfxData *DynOS_Bhv_LoadFromBinary(const SysPath &aFilename, const char *aBehaviorName);
|
||||
void DynOS_Bhv_GeneratePack(const SysPath &aPackFolder);
|
||||
|
|
|
@ -993,14 +993,27 @@ static DataNode<LevelScript>* DynOS_Lvl_Load(BinFile *aFile, GfxData *aGfxData)
|
|||
aGfxData->mLevelScripts.Add(_Node);
|
||||
}
|
||||
|
||||
DynOS_Lvl_Validate_Begin();
|
||||
|
||||
// Read it
|
||||
for (u32 i = 0; i != _Node->mSize; ++i) {
|
||||
u32 _Value = aFile->Read<u32>();
|
||||
|
||||
bool requirePointer = DynOS_Lvl_Validate_RequirePointer(_Value);
|
||||
|
||||
void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _Value, &_Node->mFlags);
|
||||
if (_Ptr) {
|
||||
if (!requirePointer) {
|
||||
PrintError("Didn't expect a pointer while reading level script: %s, %u", _Node->mName, _Value);
|
||||
}
|
||||
_Node->mData[i] = (uintptr_t) _Ptr;
|
||||
} else {
|
||||
_Node->mData[i] = (uintptr_t) _Value;
|
||||
if (requirePointer) {
|
||||
PrintError("Expected a pointer while reading level script: %s, %u", _Node->mName, _Value);
|
||||
_Node->mData[i] = 0;
|
||||
} else {
|
||||
_Node->mData[i] = (uintptr_t) _Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
#include "dynos.cpp.h"
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
extern "C" {
|
||||
#include "include/level_commands.h"
|
||||
#include "include/model_ids.h"
|
||||
#include "include/behavior_data.h"
|
||||
#include "include/surface_terrains.h"
|
||||
#include "include/seq_ids.h"
|
||||
#include "level_commands.h"
|
||||
#include "src/game/level_update.h"
|
||||
#include "include/dialog_ids.h"
|
||||
#include "levels/scripts.h"
|
||||
#include "levels/menu/header.h"
|
||||
#include "src/game/area.h"
|
||||
}
|
||||
|
||||
#define POINTER 0xD34DB33F
|
||||
|
||||
struct LevelScriptCommand {
|
||||
u8 id;
|
||||
u8 size;
|
||||
u8 ptrIdx[2];
|
||||
};
|
||||
|
||||
static bool sCommandMapFilled = false;
|
||||
static std::map<u8, struct LevelScriptCommand> sCommandMap;
|
||||
|
||||
static u8 sCurCommandId = 0xFF;
|
||||
static u8 sCurCommandOffset = 0xFF;
|
||||
|
||||
#define ADD_COMMAND(_cmd) { \
|
||||
LevelScript _script[] = { _cmd }; \
|
||||
size_t _size = ARRAY_COUNT(_script); \
|
||||
LvlCmd_Add(_script, _size); \
|
||||
}
|
||||
|
||||
static void LvlCmd_Add(LevelScript script[], size_t size) {
|
||||
// make sure size isn't crazy
|
||||
assert(size < 0xFF);
|
||||
|
||||
// find the single pointer index
|
||||
u8 ptrIdx[2] = { 0xFF, 0xFF };
|
||||
for (u8 i = 0; i < size; i++) {
|
||||
if (script[i] != POINTER) { continue; }
|
||||
if (ptrIdx[0] == 0xFF) {
|
||||
ptrIdx[0] = i;
|
||||
} else {
|
||||
assert(ptrIdx[1] == 0xFF);
|
||||
ptrIdx[1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// extract the id and make sure it's unique
|
||||
u8 id = (u8)(script[0] & 0xFF);
|
||||
if (sCommandMap.count(id) != 0) { return; }
|
||||
|
||||
// add the command to the map
|
||||
sCommandMap[id] = {
|
||||
.id = id,
|
||||
.size = (u8)size,
|
||||
.ptrIdx = { ptrIdx[0], ptrIdx[1] },
|
||||
};
|
||||
}
|
||||
|
||||
static void LvlCmd_Init() {
|
||||
ADD_COMMAND(EXECUTE(0, 0, 0, POINTER));
|
||||
ADD_COMMAND(EXIT_AND_EXECUTE(0, 0, 0, POINTER));
|
||||
ADD_COMMAND(EXIT());
|
||||
ADD_COMMAND(SLEEP(0));
|
||||
ADD_COMMAND(SLEEP_BEFORE_EXIT(0));
|
||||
ADD_COMMAND(JUMP(POINTER));
|
||||
ADD_COMMAND(JUMP_LINK(POINTER));
|
||||
ADD_COMMAND(RETURN());
|
||||
ADD_COMMAND(JUMP_LINK_PUSH_ARG(0));
|
||||
ADD_COMMAND(JUMP_N_TIMES());
|
||||
ADD_COMMAND(LOOP_BEGIN());
|
||||
ADD_COMMAND(LOOP_UNTIL(0, 0));
|
||||
ADD_COMMAND(JUMP_IF(0, 0, POINTER));
|
||||
ADD_COMMAND(JUMP_LINK_IF(0, 0, POINTER));
|
||||
ADD_COMMAND(SKIP_IF(0, 0));
|
||||
ADD_COMMAND(SKIP());
|
||||
ADD_COMMAND(SKIP_NOP());
|
||||
ADD_COMMAND(CALL(0, POINTER));
|
||||
ADD_COMMAND(CALL_LOOP(0, POINTER));
|
||||
ADD_COMMAND(SET_REG(0));
|
||||
ADD_COMMAND(PUSH_POOL());
|
||||
ADD_COMMAND(POP_POOL());
|
||||
ADD_COMMAND(FIXED_LOAD(0, 0, 0));
|
||||
ADD_COMMAND(LOAD_RAW(0, 0, 0));
|
||||
ADD_COMMAND(LOAD_MIO0(0, 0, 0));
|
||||
ADD_COMMAND(LOAD_MARIO_HEAD(0));
|
||||
ADD_COMMAND(LOAD_MIO0_TEXTURE(0, 0, 0));
|
||||
ADD_COMMAND(INIT_LEVEL());
|
||||
ADD_COMMAND(CLEAR_LEVEL());
|
||||
ADD_COMMAND(ALLOC_LEVEL_POOL());
|
||||
ADD_COMMAND(FREE_LEVEL_POOL());
|
||||
ADD_COMMAND(AREA(0, POINTER));
|
||||
ADD_COMMAND(END_AREA());
|
||||
ADD_COMMAND(LOAD_MODEL_FROM_DL(0, 0, 0));
|
||||
ADD_COMMAND(LOAD_MODEL_FROM_GEO(0, POINTER));
|
||||
ADD_COMMAND(CMD23(0, 0, 0));
|
||||
ADD_COMMAND(OBJECT_WITH_ACTS(0, 0, 0, 0, 0, 0, 0, 0, POINTER, 0));
|
||||
ADD_COMMAND(OBJECT(0, 0, 0, 0, 0, 0, 0, 0, POINTER));
|
||||
ADD_COMMAND(MARIO(0, 0, POINTER));
|
||||
ADD_COMMAND(WARP_NODE(0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(PAINTING_WARP_NODE(0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(INSTANT_WARP(0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(LOAD_AREA(0));
|
||||
ADD_COMMAND(CMD2A(0));
|
||||
ADD_COMMAND(MARIO_POS(0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(CMD2C());
|
||||
ADD_COMMAND(CMD2D());
|
||||
ADD_COMMAND(TERRAIN(POINTER));
|
||||
ADD_COMMAND(ROOMS(POINTER));
|
||||
ADD_COMMAND(SHOW_DIALOG(0, 0));
|
||||
ADD_COMMAND(TERRAIN_TYPE(0));
|
||||
ADD_COMMAND(NOP());
|
||||
ADD_COMMAND(TRANSITION(0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(BLACKOUT(0));
|
||||
ADD_COMMAND(GAMMA(0));
|
||||
ADD_COMMAND(SET_BACKGROUND_MUSIC(0, 0));
|
||||
ADD_COMMAND(SET_MENU_MUSIC(0));
|
||||
ADD_COMMAND(STOP_MUSIC(0));
|
||||
ADD_COMMAND(MACRO_OBJECTS(POINTER));
|
||||
ADD_COMMAND(CMD3A(0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(WHIRLPOOL(0, 0, 0, 0, 0, 0));
|
||||
ADD_COMMAND(GET_OR_SET(0, 0));
|
||||
ADD_COMMAND(ADV_DEMO());
|
||||
ADD_COMMAND(CLEAR_DEMO_PTR());
|
||||
ADD_COMMAND(OBJECT_WITH_ACTS_EXT(0, 0, 0, 0, 0, 0, 0, 0, POINTER, 0));
|
||||
ADD_COMMAND(OBJECT_WITH_ACTS_EXT2(POINTER, 0, 0, 0, 0, 0, 0, 0, POINTER, 0));
|
||||
ADD_COMMAND(OBJECT_EXT(0, 0, 0, 0, 0, 0, 0, 0, POINTER));
|
||||
ADD_COMMAND(OBJECT_EXT2(POINTER, 0, 0, 0, 0, 0, 0, 0, POINTER));
|
||||
ADD_COMMAND(LOAD_MODEL_FROM_GEO_EXT(0, POINTER));
|
||||
ADD_COMMAND(JUMP_AREA_EXT(0, 0, POINTER));
|
||||
}
|
||||
|
||||
void DynOS_Lvl_Validate_Begin() {
|
||||
// fill our command map if it hasn't been initialized
|
||||
if (!sCommandMapFilled) {
|
||||
LvlCmd_Init();
|
||||
sCommandMapFilled = true;
|
||||
}
|
||||
|
||||
// set current command info to defaults
|
||||
sCurCommandId = 0xFF;
|
||||
sCurCommandOffset = 0xFF;
|
||||
}
|
||||
|
||||
bool DynOS_Lvl_Validate_RequirePointer(u32 value) {
|
||||
// figure out which command we're inside
|
||||
if (sCurCommandId == 0xFF || sCurCommandOffset >= sCommandMap[sCurCommandId].size) {
|
||||
u8 id = (u8)(value & 0xFF);
|
||||
sCurCommandId = id;
|
||||
sCurCommandOffset = 0;
|
||||
}
|
||||
|
||||
// figure out if we expect a pointer
|
||||
bool ret = (
|
||||
sCurCommandOffset == sCommandMap[sCurCommandId].ptrIdx[0]
|
||||
|| sCurCommandOffset == sCommandMap[sCurCommandId].ptrIdx[1]);
|
||||
|
||||
// advance command offset
|
||||
sCurCommandOffset++;
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -312,4 +312,17 @@
|
|||
CMD_W(arg), \
|
||||
CMD_PTR(target)
|
||||
|
||||
// README //
|
||||
// README //
|
||||
// README //
|
||||
|
||||
/* When adding new level script commands,
|
||||
you have to add the commadn to dynos_bin_lvl_validate.cpp's
|
||||
LvlCmd_Init(), and specify which params are pointers */
|
||||
|
||||
// README //
|
||||
// README //
|
||||
// README //
|
||||
|
||||
|
||||
#endif // LEVEL_COMMANDS_H
|
|
@ -1133,7 +1133,11 @@ struct LevelCommand *level_script_execute(struct LevelCommand *cmd) {
|
|||
while (sScriptStatus == SCRIPT_RUNNING) {
|
||||
sCurrentCmd = dynos_swap_cmd(sCurrentCmd);
|
||||
void *dynosCurrCmd = (void *) sCurrentCmd;
|
||||
LevelScriptJumpTable[sCurrentCmd->type]();
|
||||
|
||||
if (sCurrentCmd->type < ARRAY_COUNT(LevelScriptJumpTable)) {
|
||||
LevelScriptJumpTable[sCurrentCmd->type]();
|
||||
}
|
||||
|
||||
void *dynosNextCmd = dynos_update_cmd(dynosCurrCmd);
|
||||
if (dynosNextCmd) sCurrentCmd = dynosNextCmd;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue