diff -r 7602d7fb60d9 -r 026da5437111 sourcepawn/jit/sp_vm_engine.cpp --- a/sourcepawn/jit/sp_vm_engine.cpp Fri Jul 11 06:51:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,456 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourcePawn - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include "sp_vm_types.h" -#include -/* HACK to avoid including sourcehook.h for just the SH_ASSERT definition */ -#if !defined SH_ASSERT - #define SH_ASSERT(x, info) - #include - #undef SH_ASSERT -#else - #include -#endif - -#include -#include -#include -#include "sp_file_headers.h" -#include "sp_vm_engine.h" -#include "zlib/zlib.h" -#include "sp_vm_basecontext.h" - -SourcePawnEngine g_engine1; - -#if defined WIN32 - #define WIN32_LEAN_AND_MEAN - #include -#elif defined __GNUC__ - #include -#endif - -#define INVALID_CIP 0xFFFFFFFF - -using namespace SourcePawn; - -SourceHook::CPageAlloc g_ExeMemory(16); - -#define ERROR_MESSAGE_MAX 25 -static const char *g_ErrorMsgTable[] = -{ - NULL, - "Unrecognizable file format", - "Decompressor was not found", - "Not enough space on the heap", - "Invalid parameter or parameter type", - "Invalid plugin address", - "Object or index not found", - "Invalid index or index not found", - "Not enough space on the stack", - "Debug section not found or debug not enabled", - "Invalid instruction", - "Invalid memory access", - "Stack went below stack boundary", - "Heap went below heap boundary", - "Divide by zero", - "Array index is out of bounds", - "Instruction contained invalid parameter", - "Stack memory leaked by native", - "Heap memory leaked by native", - "Dynamic array is too big", - "Tracker stack is out of bounds", - "Native is not bound", - "Maximum number of parameters reached", - "Native detected error", - "Plugin not runnable", - "Call was aborted", -}; - -const char *SourcePawnEngine::GetErrorString(int error) -{ - if (error < 1 || error > ERROR_MESSAGE_MAX) - { - return NULL; - } - - return g_ErrorMsgTable[error]; -} - -SourcePawnEngine::SourcePawnEngine() -{ - m_pDebugHook = NULL; - m_CallStack = NULL; - m_FreedCalls = NULL; - m_CurChain = 0; -#if 0 - m_pFreeFuncs = NULL; -#endif -} - -SourcePawnEngine::~SourcePawnEngine() -{ - TracedCall *pTemp; - while (m_FreedCalls) - { - pTemp = m_FreedCalls->next; - delete m_FreedCalls; - m_FreedCalls = pTemp; - } - -#if 0 - CFunction *pNext; - while (m_pFreeFuncs) - { - pNext = m_pFreeFuncs->m_pNext; - delete m_pFreeFuncs; - m_pFreeFuncs = pNext; - } -#endif -} - -void *SourcePawnEngine::ExecAlloc(size_t size) -{ -#if defined WIN32 - return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#elif defined __GNUC__ - void *base = memalign(sysconf(_SC_PAGESIZE), size); - if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) - { - free(base); - return NULL; - } - return base; -#endif -} - -void *SourcePawnEngine::AllocatePageMemory(size_t size) -{ - return g_ExeMemory.Alloc(size); -} - -void SourcePawnEngine::SetReadExecute(void *ptr) -{ - g_ExeMemory.SetRE(ptr); -} - -void SourcePawnEngine::SetReadWrite(void *ptr) -{ - g_ExeMemory.SetRW(ptr); -} - -void SourcePawnEngine::FreePageMemory(void *ptr) -{ - g_ExeMemory.Free(ptr); -} - -void SourcePawnEngine::ExecFree(void *address) -{ -#if defined WIN32 - VirtualFree(address, 0, MEM_RELEASE); -#elif defined __GNUC__ - free(address); -#endif -} - -void *SourcePawnEngine::BaseAlloc(size_t size) -{ - return malloc(size); -} - -void SourcePawnEngine::BaseFree(void *memory) -{ - free(memory); -} - -sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) -{ - if (err != NULL) - { - *err = SP_ERROR_ABORTED; - } - - return NULL; -} - -sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) -{ - if (err != NULL) - { - *err = SP_ERROR_ABORTED; - } - - return NULL; -} - -int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) -{ - return SP_ERROR_ABORTED; -} - -IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) -{ - IDebugListener *old = m_pDebugHook; - - m_pDebugHook = pListener; - - return old; -} - -unsigned int SourcePawnEngine::GetContextCallCount() -{ - if (!m_CallStack) - { - return 0; - } - - return m_CallStack->chain; -} - -TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain) -{ - TracedCall *pCall; - - if (!m_FreedCalls) - { - pCall = new TracedCall; - } else { - /* Unlink the head node from the free list */ - pCall = m_FreedCalls; - m_FreedCalls = m_FreedCalls->next; - } - - /* Link as the head node into the call stack */ - pCall->next = m_CallStack; - - if (new_chain) - { - pCall->chain = ++m_CurChain; - } else { - pCall->chain = m_CurChain; - } - - m_CallStack = pCall; - - return pCall; -} - -void SourcePawnEngine::FreeTracedCall(TracedCall *pCall) -{ - /* Check if this is the top of the call stack */ - if (pCall == m_CallStack) - { - m_CallStack = m_CallStack->next; - } - - /* Add this to our linked list of freed calls */ - if (!m_FreedCalls) - { - m_FreedCalls = pCall; - m_FreedCalls->next = NULL; - } else { - pCall->next = m_FreedCalls; - m_FreedCalls = pCall; - } -} - -void SourcePawnEngine::PushTracer(BaseContext *ctx) -{ - TracedCall *pCall = MakeTracedCall(true); - - pCall->cip = INVALID_CIP; - pCall->ctx = ctx; - pCall->frm = INVALID_CIP; -} - -void SourcePawnEngine::RunTracer(BaseContext *ctx, uint32_t frame, uint32_t codeip) -{ - assert(m_CallStack != NULL); - assert(m_CallStack->ctx == ctx); - assert(m_CallStack->chain == m_CurChain); - - if (m_CallStack->cip == INVALID_CIP) - { - /* We aren't logging anything yet, so begin the trace */ - m_CallStack->cip = codeip; - m_CallStack->frm = frame; - } else { - if (m_CallStack->frm > frame) - { - /* The last frame has moved down the stack, - * so we have to push a new call onto our list. - */ - TracedCall *pCall = MakeTracedCall(false); - pCall->ctx = ctx; - pCall->frm = frame; - } else if (m_CallStack->frm < frame) { - /* The last frame has moved up the stack, - * so we have to pop the call from our list. - */ - FreeTracedCall(m_CallStack); - } - /* no matter where we are, update the cip */ - m_CallStack->cip = codeip; - } -} - -void SourcePawnEngine::PopTracer(int error, const char *msg) -{ - assert(m_CallStack != NULL); - - if (error != SP_ERROR_NONE && m_pDebugHook) - { - uint32_t native = INVALID_CIP; - - if (m_CallStack->ctx->GetCtx()->n_err) - { - native = m_CallStack->ctx->GetCtx()->n_idx; - } - - CContextTrace trace(m_CallStack, error, msg, native); - m_pDebugHook->OnContextExecuteError(m_CallStack->ctx, &trace); - } - - /* Now pop the error chain */ - while (m_CallStack && m_CallStack->chain == m_CurChain) - { - FreeTracedCall(m_CallStack); - } - - m_CurChain--; -} - -unsigned int SourcePawnEngine::GetEngineAPIVersion() -{ - return SOURCEPAWN_ENGINE_API_VERSION; -} - -CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native) : - m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart), m_Native(native) -{ -} - -bool CContextTrace::DebugInfoAvailable() -{ - return m_pStart->ctx->IsDebugging(); -} - -const char *CContextTrace::GetCustomErrorString() -{ - return m_pMsg; -} - -int CContextTrace::GetErrorCode() -{ - return m_Error; -} - -const char *CContextTrace::GetErrorString() -{ - if (m_Error > ERROR_MESSAGE_MAX || - m_Error < 1) - { - return "Invalid error code"; - } else { - return g_ErrorMsgTable[m_Error]; - } -} - -void CContextTrace::ResetTrace() -{ - m_pIterator = m_pStart; -} - -bool CContextTrace::GetTraceInfo(CallStackInfo *trace) -{ - if (!m_pIterator || (m_pIterator->chain != m_pStart->chain)) - { - return false; - } - - if (m_pIterator->cip == INVALID_CIP) - { - return false; - } - - IPluginContext *pContext = m_pIterator->ctx; - IPluginDebugInfo *pInfo = pContext->GetDebugInfo(); - - if (!pInfo) - { - return false; - } - - if (!trace) - { - m_pIterator = m_pIterator->next; - return true; - } - - if (pInfo->LookupFile(m_pIterator->cip, &(trace->filename)) != SP_ERROR_NONE) - { - trace->filename = NULL; - } - - if (pInfo->LookupFunction(m_pIterator->cip, &(trace->function)) != SP_ERROR_NONE) - { - trace->function = NULL; - } - - if (pInfo->LookupLine(m_pIterator->cip, &(trace->line)) != SP_ERROR_NONE) - { - trace->line = 0; - } - - m_pIterator = m_pIterator->next; - - return true; -} - -const char *CContextTrace::GetLastNative(uint32_t *index) -{ - if (m_Native == INVALID_CIP) - { - return NULL; - } - - sp_native_t *native; - if (m_pIterator->ctx->GetNativeByIndex(m_Native, &native) != SP_ERROR_NONE) - { - return NULL; - } - - if (index) - { - *index = m_Native; - } - - return native->name; -}