dvander@2193: /** dvander@2193: * vim: set ts=4 : dvander@2193: * ============================================================================= dvander@2193: * SourcePawn dvander@2193: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. dvander@2193: * ============================================================================= dvander@2193: * dvander@2193: * This program is free software; you can redistribute it and/or modify it under dvander@2193: * the terms of the GNU General Public License, version 3.0, as published by the dvander@2193: * Free Software Foundation. dvander@2193: * dvander@2193: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@2193: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@2193: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@2193: * details. dvander@2193: * dvander@2193: * You should have received a copy of the GNU General Public License along with dvander@2193: * this program. If not, see . dvander@2193: * dvander@2193: * As a special exception, AlliedModders LLC gives you permission to link the dvander@2193: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@2193: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@2193: * by the Valve Corporation. You must obey the GNU General Public License in dvander@2193: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@2193: * this exception to all derivative works. AlliedModders LLC defines further dvander@2193: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@2193: * or . dvander@2193: * dvander@2193: * Version: $Id$ dvander@2193: */ dvander@2193: dvander@2193: #include dvander@2193: #include dvander@2193: #include dvander@2228: #include "sp_vm_types.h" dvander@2226: #include dvander@2193: #include "sp_file_headers.h" dvander@2193: #include "sp_vm_engine.h" dvander@2193: #include "zlib/zlib.h" dvander@2193: #include "sp_vm_basecontext.h" dvander@2226: #include "jit_x86.h" dvander@2226: #if defined __GNUC__ dvander@2226: #include dvander@2226: #endif dvander@2193: dvander@2193: SourcePawnEngine g_engine1; dvander@2193: dvander@2193: #if defined WIN32 dvander@2193: #define WIN32_LEAN_AND_MEAN dvander@2193: #include dvander@2193: #elif defined __GNUC__ dvander@2193: #include dvander@2193: #endif dvander@2193: dvander@2193: using namespace SourcePawn; dvander@2193: dvander@2193: #define ERROR_MESSAGE_MAX 25 dvander@2193: static const char *g_ErrorMsgTable[] = dvander@2193: { dvander@2193: NULL, dvander@2193: "Unrecognizable file format", dvander@2193: "Decompressor was not found", dvander@2193: "Not enough space on the heap", dvander@2193: "Invalid parameter or parameter type", dvander@2193: "Invalid plugin address", dvander@2193: "Object or index not found", dvander@2193: "Invalid index or index not found", dvander@2193: "Not enough space on the stack", dvander@2193: "Debug section not found or debug not enabled", dvander@2193: "Invalid instruction", dvander@2193: "Invalid memory access", dvander@2193: "Stack went below stack boundary", dvander@2193: "Heap went below heap boundary", dvander@2193: "Divide by zero", dvander@2193: "Array index is out of bounds", dvander@2193: "Instruction contained invalid parameter", dvander@2193: "Stack memory leaked by native", dvander@2193: "Heap memory leaked by native", dvander@2193: "Dynamic array is too big", dvander@2193: "Tracker stack is out of bounds", dvander@2193: "Native is not bound", dvander@2193: "Maximum number of parameters reached", dvander@2193: "Native detected error", dvander@2193: "Plugin not runnable", dvander@2193: "Call was aborted", dvander@2226: "Plugin format is too old", dvander@2226: "Plugin format is too new", dvander@2193: }; dvander@2193: dvander@2193: const char *SourcePawnEngine::GetErrorString(int error) dvander@2193: { dvander@2193: if (error < 1 || error > ERROR_MESSAGE_MAX) dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: return g_ErrorMsgTable[error]; dvander@2193: } dvander@2193: dvander@2193: SourcePawnEngine::SourcePawnEngine() dvander@2193: { dvander@2193: m_pDebugHook = NULL; dvander@2193: } dvander@2193: dvander@2193: SourcePawnEngine::~SourcePawnEngine() dvander@2193: { dvander@2193: } dvander@2193: dvander@2193: void *SourcePawnEngine::ExecAlloc(size_t size) dvander@2193: { dvander@2193: #if defined WIN32 dvander@2193: return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); dvander@2193: #elif defined __GNUC__ dvander@2193: void *base = memalign(sysconf(_SC_PAGESIZE), size); dvander@2193: if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) dvander@2193: { dvander@2193: free(base); dvander@2193: return NULL; dvander@2193: } dvander@2193: return base; dvander@2193: #endif dvander@2193: } dvander@2193: dvander@2193: void *SourcePawnEngine::AllocatePageMemory(size_t size) dvander@2193: { dvander@2226: return g_Jit.AllocCode(size); dvander@2193: } dvander@2193: dvander@2193: void SourcePawnEngine::SetReadExecute(void *ptr) dvander@2193: { dvander@2226: /* already re */ dvander@2193: } dvander@2193: dvander@2193: void SourcePawnEngine::SetReadWrite(void *ptr) dvander@2193: { dvander@2226: /* already rw */ dvander@2193: } dvander@2193: dvander@2193: void SourcePawnEngine::FreePageMemory(void *ptr) dvander@2193: { dvander@2226: g_Jit.FreeCode(ptr); dvander@2193: } dvander@2193: dvander@2193: void SourcePawnEngine::ExecFree(void *address) dvander@2193: { dvander@2193: #if defined WIN32 dvander@2193: VirtualFree(address, 0, MEM_RELEASE); dvander@2193: #elif defined __GNUC__ dvander@2193: free(address); dvander@2193: #endif dvander@2193: } dvander@2193: dvander@2226: void SourcePawnEngine::SetReadWriteExecute(void *ptr) dvander@2226: { dvander@2226: //:TODO: g_ExeMemory.SetRWE(ptr); dvander@2226: SetReadExecute(ptr); dvander@2226: } dvander@2226: dvander@2193: void *SourcePawnEngine::BaseAlloc(size_t size) dvander@2193: { dvander@2193: return malloc(size); dvander@2193: } dvander@2193: dvander@2193: void SourcePawnEngine::BaseFree(void *memory) dvander@2193: { dvander@2193: free(memory); dvander@2193: } dvander@2193: dvander@2193: sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) dvander@2193: { dvander@2193: if (err != NULL) dvander@2193: { dvander@2193: *err = SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) dvander@2193: { dvander@2193: if (err != NULL) dvander@2193: { dvander@2193: *err = SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) dvander@2193: { dvander@2193: IDebugListener *old = m_pDebugHook; dvander@2193: dvander@2193: m_pDebugHook = pListener; dvander@2193: dvander@2193: return old; dvander@2193: } dvander@2193: dvander@2193: unsigned int SourcePawnEngine::GetEngineAPIVersion() dvander@2193: { dvander@2193: return SOURCEPAWN_ENGINE_API_VERSION; dvander@2193: } dvander@2193: dvander@2226: unsigned int SourcePawnEngine::GetContextCallCount() dvander@2226: { dvander@2226: return 0; dvander@2226: } dvander@2226: dvander@2226: void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start) dvander@2193: { dvander@2226: if (m_pDebugHook == NULL) dvander@2226: { dvander@2226: return; dvander@2226: } dvander@2226: dvander@2226: CContextTrace trace(runtime, err, errstr, rp_start); dvander@2226: dvander@2226: m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace); dvander@2226: } dvander@2226: dvander@2226: CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp) dvander@2226: : m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0) dvander@2226: { dvander@2226: m_ctx = pRuntime->m_pCtx->GetCtx(); dvander@2226: m_pDebug = m_pRuntime->GetDebugInfo(); dvander@2193: } dvander@2193: dvander@2193: bool CContextTrace::DebugInfoAvailable() dvander@2193: { dvander@2226: return (m_pDebug != NULL); dvander@2193: } dvander@2193: dvander@2193: const char *CContextTrace::GetCustomErrorString() dvander@2193: { dvander@2193: return m_pMsg; dvander@2193: } dvander@2193: dvander@2193: int CContextTrace::GetErrorCode() dvander@2193: { dvander@2193: return m_Error; dvander@2193: } dvander@2193: dvander@2193: const char *CContextTrace::GetErrorString() dvander@2193: { dvander@2226: if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1) dvander@2193: { dvander@2193: return "Invalid error code"; dvander@2226: } dvander@2226: else dvander@2226: { dvander@2193: return g_ErrorMsgTable[m_Error]; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: void CContextTrace::ResetTrace() dvander@2193: { dvander@2226: m_Level = 0; dvander@2193: } dvander@2193: dvander@2193: bool CContextTrace::GetTraceInfo(CallStackInfo *trace) dvander@2193: { dvander@2226: cell_t cip; dvander@2226: dvander@2226: if (m_Level == 0) dvander@2193: { dvander@2226: cip = m_ctx->err_cip; dvander@2193: } dvander@2226: else if (m_ctx->rp > 0) dvander@2193: { dvander@2226: /* Entries go from ctx.rp - 1 to m_StartRp */ dvander@2226: cell_t offs, start, end; dvander@2226: dvander@2226: offs = m_Level - 1; dvander@2226: start = m_ctx->rp - 1; dvander@2226: end = m_StartRp; dvander@2193: dvander@2226: if (start - offs < end) dvander@2226: { dvander@2226: return false; dvander@2226: } dvander@2193: dvander@2226: cip = m_ctx->rstk_cips[start - offs]; dvander@2226: } dvander@2226: else dvander@2193: { dvander@2193: return false; dvander@2193: } dvander@2193: dvander@2226: if (trace == NULL) dvander@2193: { dvander@2226: m_Level++; dvander@2193: return true; dvander@2193: } dvander@2193: dvander@2226: if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE) dvander@2193: { dvander@2193: trace->filename = NULL; dvander@2193: } dvander@2193: dvander@2226: if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE) dvander@2193: { dvander@2193: trace->function = NULL; dvander@2193: } dvander@2193: dvander@2226: if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE) dvander@2193: { dvander@2193: trace->line = 0; dvander@2193: } dvander@2193: dvander@2226: m_Level++; dvander@2193: dvander@2193: return true; dvander@2193: } dvander@2193: dvander@2193: const char *CContextTrace::GetLastNative(uint32_t *index) dvander@2193: { dvander@2226: if (m_ctx->n_err == SP_ERROR_NONE) dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: sp_native_t *native; dvander@2226: if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE) dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: if (index) dvander@2193: { dvander@2226: *index = m_ctx->n_idx; dvander@2193: } dvander@2193: dvander@2193: return native->name; dvander@2193: } dvander@2226: dvander@2226: IDebugListener *SourcePawnEngine::GetDebugHook() dvander@2226: { dvander@2226: return m_pDebugHook; dvander@2226: } dvander@2226: