Files
BlitzNext/Runtime/bbruntime_dll.cpp
T
Michael Fabian 'Xaymar' Dirks 2196cb8419 runtime: Formatting
2019-01-18 17:04:17 +01:00

337 lines
6.8 KiB
C++

#pragma warning(disable : 4786)
#include "bbruntime_dll.hpp"
#include "../debugger/debugger.hpp"
using namespace std;
#include <eh.h>
#include <float.h>
#include <map>
#include "bbruntime.hpp"
class DummyDebugger : public Debugger {
public:
virtual void debugRun() {}
virtual void debugStop() {} // bbruntime_panic(0); }
virtual void debugStmt(int srcpos, const char* file) {}
virtual void debugEnter(void* frame, void* env, const char* func) {}
virtual void debugLeave() {}
virtual void debugLog(const char* msg) {}
virtual void debugMsg(const char* e, bool serious)
{
if (serious)
MessageBox(0, e, "Error!", MB_OK | MB_TOPMOST | MB_SETFOREGROUND);
}
virtual void debugSys(void* msg) {}
};
static HINSTANCE hinst;
static map<const char*, void*> syms;
map<const char*, void*>::iterator sym_it;
static gxRuntime* gx_runtime;
static void rtSym(const char* sym, void* pc)
{
syms[sym] = pc;
}
static void _cdecl seTranslator(unsigned int u, EXCEPTION_POINTERS* pExp)
{
switch (u) {
case EXCEPTION_INT_DIVIDE_BY_ZERO:
bbruntime_panic("Integer divide by zero");
case EXCEPTION_ACCESS_VIOLATION:
bbruntime_panic("Memory access violation");
case EXCEPTION_ILLEGAL_INSTRUCTION:
bbruntime_panic("Illegal instruction");
case EXCEPTION_STACK_OVERFLOW:
bbruntime_panic("Stack overflow!");
}
bbruntime_panic("Unknown runtime exception");
}
int Runtime::version()
{
return VERSION;
}
const char* Runtime::nextSym()
{
if (!syms.size()) {
bbruntime_link(rtSym);
sym_it = syms.begin();
}
if (sym_it == syms.end()) {
syms.clear();
return 0;
}
return (sym_it++)->first;
}
int Runtime::symValue(const char* sym)
{
map<const char*, void*>::iterator it = syms.find(sym);
if (it != syms.end())
return (int)it->second;
return -1;
}
void Runtime::startup(HINSTANCE h)
{
hinst = h;
}
void Runtime::shutdown()
{
trackmem(false);
syms.clear();
}
void Runtime::execute(void (*pc)(), const char* args, Debugger* dbg)
{
bool debug = !!dbg;
static DummyDebugger dummydebug;
if (!dbg)
dbg = &dummydebug;
trackmem(true);
_se_translator_function old_trans = _set_se_translator(seTranslator);
_control87(_RC_NEAR | _PC_24 | _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT
| _EM_DENORMAL,
0xfffff);
//strip spaces from ends of args...
string params = args;
while (params.size() && params[0] == ' ')
params = params.substr(1);
while (params.size() && params[params.size() - 1] == ' ')
params = params.substr(0, params.size() - 1);
if (gx_runtime = gxRuntime::openRuntime(hinst, params, dbg)) {
bbruntime_run(gx_runtime, pc, debug);
gxRuntime* t = gx_runtime;
gx_runtime = 0;
gxRuntime::closeRuntime(t);
}
_control87(_CW_DEFAULT, 0xfffff);
_set_se_translator(old_trans);
}
void Runtime::asyncStop()
{
if (gx_runtime)
gx_runtime->asyncStop();
}
void Runtime::asyncRun()
{
if (gx_runtime)
gx_runtime->asyncRun();
}
void Runtime::asyncEnd()
{
if (gx_runtime)
gx_runtime->asyncEnd();
}
void Runtime::checkmem(streambuf* buf)
{
ostream out(buf);
::checkmem(out);
}
Runtime* _cdecl runtimeGetRuntime()
{
static Runtime runtime;
return &runtime;
}
/********************** BUTT UGLY DLL->EXE HOOK! *************************/
static void* module_pc;
static map<string, int> module_syms;
static map<string, int> runtime_syms;
static Runtime* runtime;
static void fail()
{
MessageBox(0, "Unable to run Blitz Basic module", 0, 0);
ExitProcess(-1);
}
struct Sym {
string name;
int value;
};
static Sym getSym(void** p)
{
Sym sym;
char* t = (char*)*p;
while (char c = *t++)
sym.name += c;
sym.value = *(int*)t + (int)module_pc;
*p = t + 4;
return sym;
}
static int findSym(const string& t)
{
map<string, int>::iterator it;
it = module_syms.find(t);
if (it != module_syms.end())
return it->second;
it = runtime_syms.find(t);
if (it != runtime_syms.end())
return it->second;
string err = "Can't find symbol: " + t;
MessageBox(0, err.c_str(), 0, 0);
ExitProcess(0);
return 0;
}
static void link()
{
while (const char* sc = runtime->nextSym()) {
string t(sc);
if (t[0] == '_') {
runtime_syms["_" + t] = runtime->symValue(sc);
continue;
}
if (t[0] == '!')
t = t.substr(1);
if (!isalnum(t[0]))
t = t.substr(1);
for (int k = 0; k < t.size(); ++k) {
if (isalnum(t[k]) || t[k] == '_')
continue;
t = t.substr(0, k);
break;
}
runtime_syms["_f" + tolower(t)] = runtime->symValue(sc);
}
HRSRC hres = FindResource(0, MAKEINTRESOURCE(1111), RT_RCDATA);
if (!hres)
fail();
HGLOBAL hglo = LoadResource(0, hres);
if (!hglo)
fail();
void* p = LockResource(hglo);
if (!p)
fail();
int sz = *(int*)p;
p = (int*)p + 1;
//replace malloc for service pack 2 Data Execution Prevention (DEP).
module_pc = VirtualAlloc(0, sz, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(module_pc, p, sz);
p = (char*)p + sz;
int k, cnt;
cnt = *(int*)p;
p = (int*)p + 1;
for (k = 0; k < cnt; ++k) {
Sym sym = getSym(&p);
if (sym.value < (int)module_pc || sym.value >= (int)module_pc + sz)
fail();
module_syms[sym.name] = sym.value;
}
cnt = *(int*)p;
p = (int*)p + 1;
for (k = 0; k < cnt; ++k) {
Sym sym = getSym(&p);
int* pp = (int*)sym.value;
int dest = findSym(sym.name);
*pp += dest - (int)pp;
}
cnt = *(int*)p;
p = (int*)p + 1;
for (k = 0; k < cnt; ++k) {
Sym sym = getSym(&p);
int* pp = (int*)sym.value;
int dest = findSym(sym.name);
*pp += dest;
}
runtime_syms.clear();
module_syms.clear();
}
extern "C" _declspec(dllexport) int _stdcall bbWinMain();
extern "C" BOOL _stdcall _DllMainCRTStartup(HANDLE, DWORD, LPVOID);
bool WINAPI DllMain(HANDLE module, DWORD reason, void* reserved)
{
return TRUE;
}
int __stdcall bbWinMain()
{
HINSTANCE inst = GetModuleHandle(0);
_DllMainCRTStartup(inst, DLL_PROCESS_ATTACH, 0);
#ifdef BETA
int ver = VERSION & 0x7fff;
string t = "Created with Blitz3D Beta V" + itoa(ver / 100) + "." + itoa(ver % 100);
MessageBox(GetDesktopWindow(), t.c_str(), "Blitz3D Message", MB_OK);
#endif
#ifdef SCHOOLS
MessageBox(GetDesktopWindow(), "Created with the schools version of Blitz Basic", "Blitz Basic Message", MB_OK);
#endif
runtime = runtimeGetRuntime();
runtime->startup(inst);
link();
//get cmd_line and params
string cmd = GetCommandLine(), params;
while (cmd.size() && cmd[0] == ' ')
cmd = cmd.substr(1);
if (cmd.find('\"') == 0) {
int n = cmd.find('\"', 1);
if (n != string::npos) {
params = cmd.substr(n + 1);
cmd = cmd.substr(1, n - 1);
}
} else {
int n = cmd.find(' ');
if (n != string::npos) {
params = cmd.substr(n + 1);
cmd = cmd.substr(0, n);
}
}
runtime->execute((void (*)())module_pc, params.c_str(), 0);
runtime->shutdown();
_DllMainCRTStartup(inst, DLL_PROCESS_DETACH, 0);
ExitProcess(0);
return 0;
}