1.1 --- a/sourcepawn/jit/sp_vm_engine.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,456 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourcePawn
1.8 - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include "sp_vm_types.h"
1.36 -#include <sh_memory.h>
1.37 -/* HACK to avoid including sourcehook.h for just the SH_ASSERT definition */
1.38 -#if !defined SH_ASSERT
1.39 - #define SH_ASSERT(x, info)
1.40 - #include <sh_pagealloc.h>
1.41 - #undef SH_ASSERT
1.42 -#else
1.43 - #include <sh_pagealloc.h>
1.44 -#endif
1.45 -
1.46 -#include <malloc.h>
1.47 -#include <string.h>
1.48 -#include <assert.h>
1.49 -#include "sp_file_headers.h"
1.50 -#include "sp_vm_engine.h"
1.51 -#include "zlib/zlib.h"
1.52 -#include "sp_vm_basecontext.h"
1.53 -
1.54 -SourcePawnEngine g_engine1;
1.55 -
1.56 -#if defined WIN32
1.57 - #define WIN32_LEAN_AND_MEAN
1.58 - #include <windows.h>
1.59 -#elif defined __GNUC__
1.60 - #include <sys/mman.h>
1.61 -#endif
1.62 -
1.63 -#define INVALID_CIP 0xFFFFFFFF
1.64 -
1.65 -using namespace SourcePawn;
1.66 -
1.67 -SourceHook::CPageAlloc g_ExeMemory(16);
1.68 -
1.69 -#define ERROR_MESSAGE_MAX 25
1.70 -static const char *g_ErrorMsgTable[] =
1.71 -{
1.72 - NULL,
1.73 - "Unrecognizable file format",
1.74 - "Decompressor was not found",
1.75 - "Not enough space on the heap",
1.76 - "Invalid parameter or parameter type",
1.77 - "Invalid plugin address",
1.78 - "Object or index not found",
1.79 - "Invalid index or index not found",
1.80 - "Not enough space on the stack",
1.81 - "Debug section not found or debug not enabled",
1.82 - "Invalid instruction",
1.83 - "Invalid memory access",
1.84 - "Stack went below stack boundary",
1.85 - "Heap went below heap boundary",
1.86 - "Divide by zero",
1.87 - "Array index is out of bounds",
1.88 - "Instruction contained invalid parameter",
1.89 - "Stack memory leaked by native",
1.90 - "Heap memory leaked by native",
1.91 - "Dynamic array is too big",
1.92 - "Tracker stack is out of bounds",
1.93 - "Native is not bound",
1.94 - "Maximum number of parameters reached",
1.95 - "Native detected error",
1.96 - "Plugin not runnable",
1.97 - "Call was aborted",
1.98 -};
1.99 -
1.100 -const char *SourcePawnEngine::GetErrorString(int error)
1.101 -{
1.102 - if (error < 1 || error > ERROR_MESSAGE_MAX)
1.103 - {
1.104 - return NULL;
1.105 - }
1.106 -
1.107 - return g_ErrorMsgTable[error];
1.108 -}
1.109 -
1.110 -SourcePawnEngine::SourcePawnEngine()
1.111 -{
1.112 - m_pDebugHook = NULL;
1.113 - m_CallStack = NULL;
1.114 - m_FreedCalls = NULL;
1.115 - m_CurChain = 0;
1.116 -#if 0
1.117 - m_pFreeFuncs = NULL;
1.118 -#endif
1.119 -}
1.120 -
1.121 -SourcePawnEngine::~SourcePawnEngine()
1.122 -{
1.123 - TracedCall *pTemp;
1.124 - while (m_FreedCalls)
1.125 - {
1.126 - pTemp = m_FreedCalls->next;
1.127 - delete m_FreedCalls;
1.128 - m_FreedCalls = pTemp;
1.129 - }
1.130 -
1.131 -#if 0
1.132 - CFunction *pNext;
1.133 - while (m_pFreeFuncs)
1.134 - {
1.135 - pNext = m_pFreeFuncs->m_pNext;
1.136 - delete m_pFreeFuncs;
1.137 - m_pFreeFuncs = pNext;
1.138 - }
1.139 -#endif
1.140 -}
1.141 -
1.142 -void *SourcePawnEngine::ExecAlloc(size_t size)
1.143 -{
1.144 -#if defined WIN32
1.145 - return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1.146 -#elif defined __GNUC__
1.147 - void *base = memalign(sysconf(_SC_PAGESIZE), size);
1.148 - if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
1.149 - {
1.150 - free(base);
1.151 - return NULL;
1.152 - }
1.153 - return base;
1.154 -#endif
1.155 -}
1.156 -
1.157 -void *SourcePawnEngine::AllocatePageMemory(size_t size)
1.158 -{
1.159 - return g_ExeMemory.Alloc(size);
1.160 -}
1.161 -
1.162 -void SourcePawnEngine::SetReadExecute(void *ptr)
1.163 -{
1.164 - g_ExeMemory.SetRE(ptr);
1.165 -}
1.166 -
1.167 -void SourcePawnEngine::SetReadWrite(void *ptr)
1.168 -{
1.169 - g_ExeMemory.SetRW(ptr);
1.170 -}
1.171 -
1.172 -void SourcePawnEngine::FreePageMemory(void *ptr)
1.173 -{
1.174 - g_ExeMemory.Free(ptr);
1.175 -}
1.176 -
1.177 -void SourcePawnEngine::ExecFree(void *address)
1.178 -{
1.179 -#if defined WIN32
1.180 - VirtualFree(address, 0, MEM_RELEASE);
1.181 -#elif defined __GNUC__
1.182 - free(address);
1.183 -#endif
1.184 -}
1.185 -
1.186 -void *SourcePawnEngine::BaseAlloc(size_t size)
1.187 -{
1.188 - return malloc(size);
1.189 -}
1.190 -
1.191 -void SourcePawnEngine::BaseFree(void *memory)
1.192 -{
1.193 - free(memory);
1.194 -}
1.195 -
1.196 -sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
1.197 -{
1.198 - if (err != NULL)
1.199 - {
1.200 - *err = SP_ERROR_ABORTED;
1.201 - }
1.202 -
1.203 - return NULL;
1.204 -}
1.205 -
1.206 -sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
1.207 -{
1.208 - if (err != NULL)
1.209 - {
1.210 - *err = SP_ERROR_ABORTED;
1.211 - }
1.212 -
1.213 - return NULL;
1.214 -}
1.215 -
1.216 -int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
1.217 -{
1.218 - return SP_ERROR_ABORTED;
1.219 -}
1.220 -
1.221 -IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
1.222 -{
1.223 - IDebugListener *old = m_pDebugHook;
1.224 -
1.225 - m_pDebugHook = pListener;
1.226 -
1.227 - return old;
1.228 -}
1.229 -
1.230 -unsigned int SourcePawnEngine::GetContextCallCount()
1.231 -{
1.232 - if (!m_CallStack)
1.233 - {
1.234 - return 0;
1.235 - }
1.236 -
1.237 - return m_CallStack->chain;
1.238 -}
1.239 -
1.240 -TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain)
1.241 -{
1.242 - TracedCall *pCall;
1.243 -
1.244 - if (!m_FreedCalls)
1.245 - {
1.246 - pCall = new TracedCall;
1.247 - } else {
1.248 - /* Unlink the head node from the free list */
1.249 - pCall = m_FreedCalls;
1.250 - m_FreedCalls = m_FreedCalls->next;
1.251 - }
1.252 -
1.253 - /* Link as the head node into the call stack */
1.254 - pCall->next = m_CallStack;
1.255 -
1.256 - if (new_chain)
1.257 - {
1.258 - pCall->chain = ++m_CurChain;
1.259 - } else {
1.260 - pCall->chain = m_CurChain;
1.261 - }
1.262 -
1.263 - m_CallStack = pCall;
1.264 -
1.265 - return pCall;
1.266 -}
1.267 -
1.268 -void SourcePawnEngine::FreeTracedCall(TracedCall *pCall)
1.269 -{
1.270 - /* Check if this is the top of the call stack */
1.271 - if (pCall == m_CallStack)
1.272 - {
1.273 - m_CallStack = m_CallStack->next;
1.274 - }
1.275 -
1.276 - /* Add this to our linked list of freed calls */
1.277 - if (!m_FreedCalls)
1.278 - {
1.279 - m_FreedCalls = pCall;
1.280 - m_FreedCalls->next = NULL;
1.281 - } else {
1.282 - pCall->next = m_FreedCalls;
1.283 - m_FreedCalls = pCall;
1.284 - }
1.285 -}
1.286 -
1.287 -void SourcePawnEngine::PushTracer(BaseContext *ctx)
1.288 -{
1.289 - TracedCall *pCall = MakeTracedCall(true);
1.290 -
1.291 - pCall->cip = INVALID_CIP;
1.292 - pCall->ctx = ctx;
1.293 - pCall->frm = INVALID_CIP;
1.294 -}
1.295 -
1.296 -void SourcePawnEngine::RunTracer(BaseContext *ctx, uint32_t frame, uint32_t codeip)
1.297 -{
1.298 - assert(m_CallStack != NULL);
1.299 - assert(m_CallStack->ctx == ctx);
1.300 - assert(m_CallStack->chain == m_CurChain);
1.301 -
1.302 - if (m_CallStack->cip == INVALID_CIP)
1.303 - {
1.304 - /* We aren't logging anything yet, so begin the trace */
1.305 - m_CallStack->cip = codeip;
1.306 - m_CallStack->frm = frame;
1.307 - } else {
1.308 - if (m_CallStack->frm > frame)
1.309 - {
1.310 - /* The last frame has moved down the stack,
1.311 - * so we have to push a new call onto our list.
1.312 - */
1.313 - TracedCall *pCall = MakeTracedCall(false);
1.314 - pCall->ctx = ctx;
1.315 - pCall->frm = frame;
1.316 - } else if (m_CallStack->frm < frame) {
1.317 - /* The last frame has moved up the stack,
1.318 - * so we have to pop the call from our list.
1.319 - */
1.320 - FreeTracedCall(m_CallStack);
1.321 - }
1.322 - /* no matter where we are, update the cip */
1.323 - m_CallStack->cip = codeip;
1.324 - }
1.325 -}
1.326 -
1.327 -void SourcePawnEngine::PopTracer(int error, const char *msg)
1.328 -{
1.329 - assert(m_CallStack != NULL);
1.330 -
1.331 - if (error != SP_ERROR_NONE && m_pDebugHook)
1.332 - {
1.333 - uint32_t native = INVALID_CIP;
1.334 -
1.335 - if (m_CallStack->ctx->GetCtx()->n_err)
1.336 - {
1.337 - native = m_CallStack->ctx->GetCtx()->n_idx;
1.338 - }
1.339 -
1.340 - CContextTrace trace(m_CallStack, error, msg, native);
1.341 - m_pDebugHook->OnContextExecuteError(m_CallStack->ctx, &trace);
1.342 - }
1.343 -
1.344 - /* Now pop the error chain */
1.345 - while (m_CallStack && m_CallStack->chain == m_CurChain)
1.346 - {
1.347 - FreeTracedCall(m_CallStack);
1.348 - }
1.349 -
1.350 - m_CurChain--;
1.351 -}
1.352 -
1.353 -unsigned int SourcePawnEngine::GetEngineAPIVersion()
1.354 -{
1.355 - return SOURCEPAWN_ENGINE_API_VERSION;
1.356 -}
1.357 -
1.358 -CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native) :
1.359 - m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart), m_Native(native)
1.360 -{
1.361 -}
1.362 -
1.363 -bool CContextTrace::DebugInfoAvailable()
1.364 -{
1.365 - return m_pStart->ctx->IsDebugging();
1.366 -}
1.367 -
1.368 -const char *CContextTrace::GetCustomErrorString()
1.369 -{
1.370 - return m_pMsg;
1.371 -}
1.372 -
1.373 -int CContextTrace::GetErrorCode()
1.374 -{
1.375 - return m_Error;
1.376 -}
1.377 -
1.378 -const char *CContextTrace::GetErrorString()
1.379 -{
1.380 - if (m_Error > ERROR_MESSAGE_MAX ||
1.381 - m_Error < 1)
1.382 - {
1.383 - return "Invalid error code";
1.384 - } else {
1.385 - return g_ErrorMsgTable[m_Error];
1.386 - }
1.387 -}
1.388 -
1.389 -void CContextTrace::ResetTrace()
1.390 -{
1.391 - m_pIterator = m_pStart;
1.392 -}
1.393 -
1.394 -bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
1.395 -{
1.396 - if (!m_pIterator || (m_pIterator->chain != m_pStart->chain))
1.397 - {
1.398 - return false;
1.399 - }
1.400 -
1.401 - if (m_pIterator->cip == INVALID_CIP)
1.402 - {
1.403 - return false;
1.404 - }
1.405 -
1.406 - IPluginContext *pContext = m_pIterator->ctx;
1.407 - IPluginDebugInfo *pInfo = pContext->GetDebugInfo();
1.408 -
1.409 - if (!pInfo)
1.410 - {
1.411 - return false;
1.412 - }
1.413 -
1.414 - if (!trace)
1.415 - {
1.416 - m_pIterator = m_pIterator->next;
1.417 - return true;
1.418 - }
1.419 -
1.420 - if (pInfo->LookupFile(m_pIterator->cip, &(trace->filename)) != SP_ERROR_NONE)
1.421 - {
1.422 - trace->filename = NULL;
1.423 - }
1.424 -
1.425 - if (pInfo->LookupFunction(m_pIterator->cip, &(trace->function)) != SP_ERROR_NONE)
1.426 - {
1.427 - trace->function = NULL;
1.428 - }
1.429 -
1.430 - if (pInfo->LookupLine(m_pIterator->cip, &(trace->line)) != SP_ERROR_NONE)
1.431 - {
1.432 - trace->line = 0;
1.433 - }
1.434 -
1.435 - m_pIterator = m_pIterator->next;
1.436 -
1.437 - return true;
1.438 -}
1.439 -
1.440 -const char *CContextTrace::GetLastNative(uint32_t *index)
1.441 -{
1.442 - if (m_Native == INVALID_CIP)
1.443 - {
1.444 - return NULL;
1.445 - }
1.446 -
1.447 - sp_native_t *native;
1.448 - if (m_pIterator->ctx->GetNativeByIndex(m_Native, &native) != SP_ERROR_NONE)
1.449 - {
1.450 - return NULL;
1.451 - }
1.452 -
1.453 - if (index)
1.454 - {
1.455 - *index = m_Native;
1.456 - }
1.457 -
1.458 - return native->name;
1.459 -}