mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-25 11:52:40 +01:00
Merge pull request #188 from danhedron/feature/cleanup-script
Script cleanup and remove old tool
This commit is contained in:
commit
2f0b24c6ea
@ -21,7 +21,7 @@ git:
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. -DBUILD_TESTS=1 -DTESTS_NODATA=1 -DBUILD_VIEWER=1 -DBUILD_SCRIPT_TOOL=1 && make
|
||||
- cmake .. -DBUILD_TESTS=1 -DTESTS_NODATA=1 -DBUILD_VIEWER=1 && make
|
||||
- tests/run_tests
|
||||
notifications:
|
||||
email: false
|
||||
|
@ -16,7 +16,6 @@ set(RW_VERBOSE_DEBUG_MESSAGES 1 CACHE BOOL "Print verbose debugging messages")
|
||||
# Optional components
|
||||
option(BUILD_TESTS "Build test suite")
|
||||
option(BUILD_VIEWER "Build GUI data viewer")
|
||||
option(BUILD_SCRIPT_TOOL "Build script decompiler tool")
|
||||
|
||||
# Compile-time Options & Features
|
||||
option(ENABLE_SCRIPT_DEBUG "Enable verbose script execution")
|
||||
@ -115,9 +114,6 @@ add_subdirectory(rwlib)
|
||||
add_subdirectory(rwengine)
|
||||
add_subdirectory(rwgame)
|
||||
|
||||
IF(${BUILD_SCRIPT_TOOL})
|
||||
add_subdirectory(scripttool)
|
||||
ENDIF()
|
||||
IF(${BUILD_VIEWER})
|
||||
add_subdirectory(rwviewer)
|
||||
ENDIF()
|
||||
|
@ -11,14 +11,14 @@ void SCMFile::loadFile(char *data, unsigned int size)
|
||||
|
||||
_target = static_cast<SCMTarget>(_data[jumpOpSize]);
|
||||
globalSectionOffset = jumpOpSize+1u;
|
||||
modelSectionOffset = read<uint32>(jumpParamSize) + jumpOpSize + 1u;
|
||||
missionSectionOffset = read<uint32>(modelSectionOffset-jumpOpSize-1u+jumpParamSize) + jumpOpSize + 1u;
|
||||
codeSectionOffset = read<uint32>(missionSectionOffset-jumpOpSize-1u+jumpParamSize);
|
||||
modelSectionOffset = read<uint32_t>(jumpParamSize) + jumpOpSize + 1u;
|
||||
missionSectionOffset = read<uint32_t>(modelSectionOffset-jumpOpSize-1u+jumpParamSize) + jumpOpSize + 1u;
|
||||
codeSectionOffset = read<uint32_t>(missionSectionOffset-jumpOpSize-1u+jumpParamSize);
|
||||
|
||||
unsigned int model_count = read<uint32>(modelSectionOffset);
|
||||
unsigned int model_count = read<uint32_t>(modelSectionOffset);
|
||||
models.reserve(model_count);
|
||||
|
||||
int i = modelSectionOffset + sizeof(uint32);
|
||||
int i = modelSectionOffset + sizeof(uint32_t);
|
||||
for(unsigned int m = 0; m < model_count; ++m) {
|
||||
char model_name[24];
|
||||
for(size_t c = 0; c < 24; ++c) {
|
||||
@ -28,16 +28,16 @@ void SCMFile::loadFile(char *data, unsigned int size)
|
||||
}
|
||||
|
||||
i = missionSectionOffset;
|
||||
mainSize = read<uint32>(i);
|
||||
i += sizeof(uint32);
|
||||
missionLargestSize = read<uint32>(i);
|
||||
i += sizeof(uint32);
|
||||
unsigned int missionCount = read<uint32>(i);
|
||||
mainSize = read<uint32_t>(i);
|
||||
i += sizeof(uint32_t);
|
||||
missionLargestSize = read<uint32_t>(i);
|
||||
i += sizeof(uint32_t);
|
||||
unsigned int missionCount = read<uint32_t>(i);
|
||||
missionOffsets.reserve(missionCount);
|
||||
i += sizeof(uint32);
|
||||
i += sizeof(uint32_t);
|
||||
|
||||
for(unsigned int m = 0; m < missionCount; ++m) {
|
||||
missionOffsets.push_back(read<uint32>(i));
|
||||
i += sizeof(uint32);
|
||||
missionOffsets.push_back(read<uint32_t>(i));
|
||||
i += sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef _SCMFILE_HPP_
|
||||
#define _SCMFILE_HPP_
|
||||
#ifndef RWENGINE_SCMFILE_HPP
|
||||
#define RWENGINE_SCMFILE_HPP
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <script/ScriptTypes.hpp>
|
||||
@ -11,10 +10,6 @@
|
||||
class SCMFile {
|
||||
public:
|
||||
|
||||
typedef std::uint32_t uint32;
|
||||
typedef std::uint16_t u16;
|
||||
typedef std::uint8_t u8;
|
||||
|
||||
enum SCMTarget {
|
||||
NoTarget = 0,
|
||||
GTAIII = 0xC6,
|
||||
@ -41,17 +36,17 @@ public:
|
||||
return *(T*)(_data+offset);
|
||||
}
|
||||
|
||||
uint32 getMainSize() const { return mainSize; }
|
||||
uint32 getLargestMissionSize() const { return missionLargestSize; }
|
||||
uint32_t getMainSize() const { return mainSize; }
|
||||
uint32_t getLargestMissionSize() const { return missionLargestSize; }
|
||||
|
||||
const std::vector<std::string>& getModels() const { return models; }
|
||||
|
||||
const std::vector<unsigned int>& getMissionOffsets() const { return missionOffsets; }
|
||||
|
||||
std::uint32_t getGlobalSection() const { return globalSectionOffset; }
|
||||
std::uint32_t getModelSection() const { return modelSectionOffset; }
|
||||
std::uint32_t getMissionSection() const { return missionSectionOffset; }
|
||||
std::uint32_t getCodeSection() const { return codeSectionOffset; }
|
||||
uint32_t getGlobalSection() const { return globalSectionOffset; }
|
||||
uint32_t getModelSection() const { return modelSectionOffset; }
|
||||
uint32_t getMissionSection() const { return missionSectionOffset; }
|
||||
uint32_t getCodeSection() const { return codeSectionOffset; }
|
||||
|
||||
unsigned int getGlobalsSize() const { return modelSectionOffset - globalSectionOffset; }
|
||||
|
||||
@ -65,13 +60,13 @@ private:
|
||||
|
||||
std::vector<unsigned int> missionOffsets;
|
||||
|
||||
uint32 mainSize;
|
||||
uint32 missionLargestSize;
|
||||
uint32_t mainSize;
|
||||
uint32_t missionLargestSize;
|
||||
|
||||
uint32 globalSectionOffset;
|
||||
uint32 modelSectionOffset;
|
||||
uint32 missionSectionOffset;
|
||||
uint32 codeSectionOffset;
|
||||
uint32_t globalSectionOffset;
|
||||
uint32_t modelSectionOffset;
|
||||
uint32_t missionSectionOffset;
|
||||
uint32_t codeSectionOffset;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -27,12 +27,6 @@ bool SCMOpcodes::findOpcode(ScriptFunctionID id, ScriptFunctionMeta** out)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptMachine::interuptNext()
|
||||
{
|
||||
interupt = true;
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
{
|
||||
if( t.wakeCounter > 0 ) {
|
||||
@ -40,8 +34,6 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
}
|
||||
if( t.wakeCounter > 0 ) return;
|
||||
|
||||
bool hasDebugging = !! bpHandler;
|
||||
|
||||
while( t.wakeCounter == 0 ) {
|
||||
auto pc = t.programCounter;
|
||||
auto opcode = _file->read<SCMOpcode>(pc);
|
||||
@ -129,29 +121,22 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
|
||||
ScriptArguments sca(¶meters, &t, this);
|
||||
|
||||
if( hasDebugging )
|
||||
{
|
||||
auto activeBreakpoint = findBreakpoint(t, pc);
|
||||
if( activeBreakpoint || interupt )
|
||||
{
|
||||
interupt = false;
|
||||
SCMBreakpoint bp;
|
||||
bp.pc = t.programCounter;
|
||||
bp.thread = &t;
|
||||
bp.vm = this;
|
||||
bp.function = &code;
|
||||
bp.args = &sca;
|
||||
bpHandler(bp);
|
||||
}
|
||||
}
|
||||
|
||||
#if RW_SCRIPT_DEBUG
|
||||
if (strcmp(t.name, "EIGHT") == 0)
|
||||
static auto sDebugThreadName = getenv("OPENRW_DEBUG_THREAD");
|
||||
if (!sDebugThreadName || strncmp(t.name, sDebugThreadName, 8) == 0)
|
||||
{
|
||||
printf("% 8s %04x %04x % 25s", t.name, t.programCounter, opcode, code.signature.c_str());
|
||||
printf("%8s %01x %06x %04x %s", t.name, t.conditionResult, t.programCounter, opcode, code.signature.c_str());
|
||||
for (auto& a : sca.getParameters())
|
||||
{
|
||||
printf(" %08x", a.integerValue());
|
||||
if (a.type == SCMType::TString) {
|
||||
printf(" %1x:'%s'", a.type, a.string);
|
||||
}
|
||||
else if (a.type == SCMType::TFloat16) {
|
||||
printf(" %1x:%f", a.type, a.realValue());
|
||||
}
|
||||
else {
|
||||
printf(" %1x:%d", a.type, a.integerValue());
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@ -205,7 +190,7 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
}
|
||||
|
||||
ScriptMachine::ScriptMachine(GameState* _state, SCMFile *file, SCMOpcodes *ops)
|
||||
: _file(file), _ops(ops), state(_state), interupt(false)
|
||||
: _file(file), _ops(ops), state(_state)
|
||||
{
|
||||
// Copy globals
|
||||
auto size = _file->getGlobalsSize();
|
||||
@ -259,49 +244,3 @@ void ScriptMachine::execute(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
SCMBreakpointInfo* ScriptMachine::findBreakpoint(SCMThread& t, SCMThread::pc_t pc)
|
||||
{
|
||||
for(std::vector<SCMBreakpointInfo>::iterator bp = breakpoints.begin(); bp != breakpoints.end(); ++bp)
|
||||
{
|
||||
if( (bp->breakpointFlags & SCMBreakpointInfo::BP_ProgramCounter) == SCMBreakpointInfo::BP_ProgramCounter )
|
||||
{
|
||||
if( bp->programCounter != pc )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( (bp->breakpointFlags & SCMBreakpointInfo::BP_ThreadName) == SCMBreakpointInfo::BP_ThreadName )
|
||||
{
|
||||
if( std::strcmp(bp->threadName, t.name) != 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return &(*bp);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ScriptMachine::setBreakpointHandler(const ScriptMachine::BreakpointHandler& handler)
|
||||
{
|
||||
bpHandler = handler;
|
||||
}
|
||||
|
||||
void ScriptMachine::addBreakpoint(const SCMBreakpointInfo& bpi)
|
||||
{
|
||||
breakpoints.push_back(bpi);
|
||||
}
|
||||
|
||||
void ScriptMachine::removeBreakpoint(const SCMBreakpointInfo& bpi)
|
||||
{
|
||||
for (size_t i = 0; i < breakpoints.size(); ++i)
|
||||
{
|
||||
if (bpi == breakpoints[i])
|
||||
{
|
||||
breakpoints.erase(breakpoints.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef _SCRIPTMACHINE_HPP_
|
||||
#define _SCRIPTMACHINE_HPP_
|
||||
#ifndef RWENGINE_SCRIPTMACHINE_HPP
|
||||
#define RWENGINE_SCRIPTMACHINE_HPP
|
||||
#include <rw/defines.hpp>
|
||||
#include <script/ScriptTypes.hpp>
|
||||
#include <sstream>
|
||||
@ -72,44 +71,6 @@ struct UnknownType : SCMException
|
||||
}
|
||||
};
|
||||
|
||||
struct UnimplementedOpcode : SCMException
|
||||
{
|
||||
SCMOpcode opcode;
|
||||
SCMParams parameters;
|
||||
|
||||
UnimplementedOpcode(SCMOpcode opcode, SCMParams parameters)
|
||||
: opcode(opcode), parameters(parameters) {}
|
||||
|
||||
std::string what() const {
|
||||
std::stringstream ss;
|
||||
ss << "Unimplemented opcode " <<
|
||||
std::setfill('0') << std::hex << opcode <<
|
||||
" called with parameters:\n";
|
||||
int i = 0;
|
||||
for(const SCMOpcodeParameter& p : parameters) {
|
||||
ss << (i++) << " " << p.type << " ";
|
||||
switch (p.type) {
|
||||
case TInt8:
|
||||
case TInt16:
|
||||
case TInt32:
|
||||
ss << p.integer;
|
||||
break;
|
||||
case TFloat16:
|
||||
ss << p.real;
|
||||
break;
|
||||
case TGlobal:
|
||||
ss << "Global: " << p.globalPtr;
|
||||
break;
|
||||
default:
|
||||
ss << "Unprintable";
|
||||
break;
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
static SCMMicrocodeTable knownOps;
|
||||
|
||||
struct SCMThread
|
||||
@ -137,59 +98,6 @@ struct SCMThread
|
||||
std::array<pc_t, SCM_STACK_DEPTH> calls;
|
||||
};
|
||||
|
||||
#include <cstring>
|
||||
/**
|
||||
* Stores information about where breakpoints should be triggered.
|
||||
*
|
||||
* breakpointFlags stores the state to be checked against.
|
||||
*/
|
||||
struct SCMBreakpointInfo
|
||||
{
|
||||
enum /* Breakpoint Flags */ {
|
||||
BP_ProgramCounter = 1,
|
||||
BP_ThreadName = 2
|
||||
};
|
||||
uint8_t breakpointFlags;
|
||||
SCMThread::pc_t programCounter;
|
||||
char threadName[17];
|
||||
|
||||
bool operator == (const SCMBreakpointInfo& rhs) const
|
||||
{
|
||||
if (breakpointFlags != rhs.breakpointFlags) return false;
|
||||
if ((breakpointFlags & BP_ProgramCounter) != 0)
|
||||
{
|
||||
if (programCounter != rhs.programCounter) return false;
|
||||
}
|
||||
if ((breakpointFlags & BP_ThreadName) != 0)
|
||||
{
|
||||
if (strncmp(threadName, rhs.threadName, 17) != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static SCMBreakpointInfo breakThreadName(char threadName[17])
|
||||
{
|
||||
SCMBreakpointInfo i;
|
||||
i.breakpointFlags = BP_ThreadName;
|
||||
std::strncpy(i.threadName, threadName, 17);
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Information about breakpoints that have been hit
|
||||
*/
|
||||
struct SCMBreakpoint
|
||||
{
|
||||
SCMThread::pc_t pc;
|
||||
SCMThread* thread;
|
||||
ScriptMachine* vm;
|
||||
ScriptFunctionMeta* function;
|
||||
ScriptArguments* args;
|
||||
/** The breakpoint entry that triggered this breakpoint */
|
||||
SCMBreakpointInfo* info;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the actual fetch-execute mechanism for the game script virtual machine.
|
||||
*
|
||||
@ -206,9 +114,6 @@ struct SCMBreakpoint
|
||||
* Within ScriptMachine, each thread's program counter is used to execute an instruction
|
||||
* by consuming the correct number of arguments, allowing the next instruction to be found,
|
||||
* and then dispatching a call to the opcode's function.
|
||||
*
|
||||
* Breakpoints can be set which will call the breakpoint hander, where it is possible
|
||||
* to halt execution by refusing to return until the handler is ready to continue.
|
||||
*/
|
||||
class ScriptMachine
|
||||
{
|
||||
@ -228,32 +133,6 @@ public:
|
||||
std::vector<SCMByte>& getGlobalData() { return globalData; }
|
||||
|
||||
GameState* getState() const { return state; }
|
||||
|
||||
typedef std::function<void (const SCMBreakpoint&)> BreakpointHandler;
|
||||
|
||||
/**
|
||||
* Set the breakpoint handler callback.
|
||||
*
|
||||
* When the VM reaches an instruction marked as a brekapoint
|
||||
* by addBreakpoint, the handler will be called with information
|
||||
* about the state of the VM and the active thread.
|
||||
*/
|
||||
void setBreakpointHandler(const BreakpointHandler& handler);
|
||||
|
||||
/**
|
||||
* Adds a breakpoint
|
||||
*/
|
||||
void addBreakpoint(const SCMBreakpointInfo& bpi);
|
||||
|
||||
/**
|
||||
* Removes a breakpoint.
|
||||
*/
|
||||
void removeBreakpoint(const SCMBreakpointInfo& bpi);
|
||||
|
||||
/**
|
||||
* Interupt VM execution at the start of the next instruction
|
||||
*/
|
||||
void interuptNext();
|
||||
|
||||
/**
|
||||
* @brief executes threads until they are all in waiting state.
|
||||
@ -264,18 +143,12 @@ private:
|
||||
SCMFile* _file;
|
||||
SCMOpcodes* _ops;
|
||||
GameState* state;
|
||||
bool interupt;
|
||||
|
||||
std::list<SCMThread> _activeThreads;
|
||||
|
||||
void executeThread(SCMThread& t, int msPassed);
|
||||
|
||||
SCMBreakpointInfo* findBreakpoint(SCMThread& t, SCMThread::pc_t pc);
|
||||
|
||||
std::vector<SCMByte> globalData;
|
||||
|
||||
BreakpointHandler bpHandler;
|
||||
std::vector<SCMBreakpointInfo> breakpoints;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef _SCRIPTTYPES_HPP_
|
||||
#define _SCRIPTTYPES_HPP_
|
||||
#ifndef RWENGINE_SCRIPTTYPES_HPP
|
||||
#define RWENGINE_SCRIPTTYPES_HPP
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -255,26 +255,6 @@ void RWGame::startScript(const std::string& name)
|
||||
|
||||
script = new ScriptMachine(state, f, opcodes);
|
||||
|
||||
// Set up breakpoint handler
|
||||
script->setBreakpointHandler(
|
||||
[&](const SCMBreakpoint& bp)
|
||||
{
|
||||
log.info("Script", "Breakpoint hit!");
|
||||
std::stringstream ss;
|
||||
ss << " " << bp.function->description << ".";
|
||||
ss << " Args:";
|
||||
for(size_t a = 0; a < bp.args->getParameters().size(); a++)
|
||||
{
|
||||
auto& arg = bp.args->getParameters()[a];
|
||||
ss << " " << arg.integerValue();
|
||||
if( a != bp.args->getParameters().size()-1 )
|
||||
{
|
||||
ss << ",";
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Script", ss.str());
|
||||
});
|
||||
state->script = script;
|
||||
}
|
||||
else {
|
||||
|
@ -1,10 +0,0 @@
|
||||
SET(SCRIPTTOOL scripttool)
|
||||
add_executable(${SCRIPTTOOL} main.cpp)
|
||||
|
||||
target_link_libraries(${SCRIPTTOOL}
|
||||
rwengine
|
||||
${OPENGL_LIBRARIES}
|
||||
${BULLET_LIBRARIES}
|
||||
${SDL2_LIBRARY})
|
||||
|
||||
install(TARGETS ${SCRIPTTOOL} RUNTIME DESTINATION "${BIN_DIR}")
|
@ -1,3 +0,0 @@
|
||||
# Scripttool
|
||||
|
||||
Decompiles SCM files into their instructions using the same call tables as the game itself.
|
@ -1,168 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <script/SCMFile.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
#include <script/ScriptDisassembly.hpp>
|
||||
#include <script/modules/VMModule.hpp>
|
||||
#include <script/modules/GameModule.hpp>
|
||||
#include <script/modules/ObjectModule.hpp>
|
||||
|
||||
#define FIELD_DESC_WIDTH 30
|
||||
#define FIELD_PARAM_WIDTH 8
|
||||
|
||||
void printUsage();
|
||||
|
||||
void dumpModels(SCMFile* file)
|
||||
{
|
||||
std::cout << "model count: " << std::dec << file->getModels().size() << std::endl;
|
||||
int i = 0;
|
||||
for( auto& m : file->getModels() ) {
|
||||
std::cout << std::dec << (i++) << ": " << m << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpCodeSizes(SCMFile* file)
|
||||
{
|
||||
std::cout << "main size: " << std::hex <<
|
||||
file->getMainSize() << std::endl;
|
||||
|
||||
std::cout << "largest mission size: " << std::hex <<
|
||||
file->getLargestMissionSize() << std::endl;
|
||||
|
||||
std::cout << "mission count: " << std::dec <<
|
||||
file->getMissionOffsets().size() << std::endl;
|
||||
|
||||
int i = 0;
|
||||
for(auto& m : file->getMissionOffsets()) {
|
||||
std::cout << std::dec << (i++) << ": " << std::hex << m << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void dumpOpcodes(SCMFile* scm, SCMOpcodes* codes, unsigned int offset, unsigned int size)
|
||||
{
|
||||
std::cout << "Offs Opcd " << std::setw(FIELD_DESC_WIDTH) << std::left
|
||||
<< "Description" << "Parameters" << std::endl;
|
||||
|
||||
ScriptDisassembly disassembly(codes, scm);
|
||||
|
||||
try
|
||||
{
|
||||
disassembly.disassemble(offset);
|
||||
}
|
||||
catch( IllegalInstruction& ex )
|
||||
{
|
||||
std::cerr << "Error during disassembly: \n"
|
||||
<< ex.what() << std::endl;
|
||||
}
|
||||
|
||||
for( auto& inst : disassembly.getInstructions() )
|
||||
{
|
||||
ScriptFunctionMeta* code;
|
||||
if(! codes->findOpcode(inst.second.opcode, &code) )
|
||||
{
|
||||
std::cerr << "Invalid opcode in disassembly (" << inst.second.opcode << ")" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << std::hex << std::setfill('0') << std::right <<
|
||||
std::setw(4) << inst.first << ":" <<
|
||||
std::setw(4) << inst.second.opcode << " " <<
|
||||
std::setw(FIELD_DESC_WIDTH) << std::setfill(' ') <<
|
||||
std::left << code->signature << std::right << "(";
|
||||
|
||||
for( SCMOpcodeParameter& param : inst.second.parameters )
|
||||
{
|
||||
switch( param.type )
|
||||
{
|
||||
case TInt8:
|
||||
std::cout << " i8: " << param.integer;
|
||||
break;
|
||||
case TInt16:
|
||||
std::cout << " i16: " << param.integer;
|
||||
break;
|
||||
case TInt32:
|
||||
std::cout << " i32: " << param.integer;
|
||||
break;
|
||||
case TFloat16:
|
||||
std::cout << " f16: " << param.real;
|
||||
break;
|
||||
case TString:
|
||||
std::cout << " str: " << param.string;
|
||||
break;
|
||||
case TGlobal:
|
||||
std::cout << " g: " << param.globalPtr;
|
||||
break;
|
||||
case TLocal:
|
||||
std::cout << " l: " << param.globalPtr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << " )\n";
|
||||
}
|
||||
}
|
||||
|
||||
void disassemble(const std::string& scmname)
|
||||
{
|
||||
std::ifstream scmfile(scmname.c_str(), std::ios_base::binary);
|
||||
|
||||
if( !scmfile.is_open() ) {
|
||||
std::cerr << "Failed to open " << scmname << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
scmfile.seekg(0, std::ios_base::end);
|
||||
int size = scmfile.tellg();
|
||||
scmfile.seekg(0);
|
||||
|
||||
SCMByte* byff = new SCMByte[size];
|
||||
scmfile.read(byff, size);
|
||||
SCMFile scm;
|
||||
scm.loadFile(byff, size);
|
||||
delete byff;
|
||||
|
||||
try {
|
||||
std::cout << "section globals: " << std::hex <<
|
||||
scm.getGlobalSection() << std::endl;
|
||||
std::cout << "section models: " << std::hex <<
|
||||
scm.getModelSection() << std::endl;
|
||||
std::cout << "section sizes: " << std::hex <<
|
||||
scm.getMissionSection() << std::endl;
|
||||
std::cout << "section main: " << std::hex <<
|
||||
scm.getCodeSection() << std::endl;
|
||||
|
||||
dumpModels(&scm);
|
||||
|
||||
dumpCodeSizes(&scm);
|
||||
|
||||
SCMOpcodes* opcodes = new SCMOpcodes;
|
||||
opcodes->modules.push_back(new VMModule);
|
||||
opcodes->modules.push_back(new GameModule);
|
||||
opcodes->modules.push_back(new ObjectModule);
|
||||
|
||||
dumpOpcodes(&scm, opcodes, scm.getCodeSection(), size);
|
||||
}
|
||||
catch (SCMException& ex) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if( argc < 2 ) {
|
||||
std::cerr << "Missing argument" << std::endl;
|
||||
printUsage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
disassemble(std::string(argv[1]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void printUsage() {
|
||||
std::cout << "Usage:" << std::endl;
|
||||
std::cout << " scripttool scmfile" << std::endl;
|
||||
}
|
Loading…
Reference in New Issue
Block a user