3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
35 #include "sp_vm_types.h"
36 #include <KeCodeAllocator.h>
37 #include "sp_file_headers.h"
38 #include "sp_vm_engine.h"
39 #include "zlib/zlib.h"
40 #include "sp_vm_basecontext.h"
46 SourcePawnEngine g_engine1;
49 #define WIN32_LEAN_AND_MEAN
51 #elif defined __GNUC__
59 using namespace SourcePawn;
61 #define ERROR_MESSAGE_MAX 29
62 static const char *g_ErrorMsgTable[] =
65 "Unrecognizable file format",
66 "Decompressor was not found",
67 "Not enough space on the heap",
68 "Invalid parameter or parameter type",
69 "Invalid plugin address",
70 "Object or index not found",
71 "Invalid index or index not found",
72 "Not enough space on the stack",
73 "Debug section not found or debug not enabled",
74 "Invalid instruction",
75 "Invalid memory access",
76 "Stack went below stack boundary",
77 "Heap went below heap boundary",
79 "Array index is out of bounds",
80 "Instruction contained invalid parameter",
81 "Stack memory leaked by native",
82 "Heap memory leaked by native",
83 "Dynamic array is too big",
84 "Tracker stack is out of bounds",
85 "Native is not bound",
86 "Maximum number of parameters reached",
87 "Native detected error",
88 "Plugin not runnable",
90 "Plugin format is too old",
91 "Plugin format is too new",
96 const char *SourcePawnEngine::GetErrorString(int error)
98 if (error < 1 || error > ERROR_MESSAGE_MAX)
103 return g_ErrorMsgTable[error];
106 SourcePawnEngine::SourcePawnEngine()
111 SourcePawnEngine::~SourcePawnEngine()
115 void *SourcePawnEngine::ExecAlloc(size_t size)
118 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
119 #elif defined __GNUC__
120 # if defined __APPLE__
121 void *base = valloc(size);
123 void *base = memalign(sysconf(_SC_PAGESIZE), size);
125 if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
134 void *SourcePawnEngine::AllocatePageMemory(size_t size)
136 return g_Jit.AllocCode(size);
139 void SourcePawnEngine::SetReadExecute(void *ptr)
144 void SourcePawnEngine::SetReadWrite(void *ptr)
149 void SourcePawnEngine::FreePageMemory(void *ptr)
154 void SourcePawnEngine::ExecFree(void *address)
157 VirtualFree(address, 0, MEM_RELEASE);
158 #elif defined __GNUC__
163 void SourcePawnEngine::SetReadWriteExecute(void *ptr)
165 //:TODO: g_ExeMemory.SetRWE(ptr);
169 void *SourcePawnEngine::BaseAlloc(size_t size)
174 void SourcePawnEngine::BaseFree(void *memory)
179 sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
183 *err = SP_ERROR_ABORTED;
189 sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
193 *err = SP_ERROR_ABORTED;
199 int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
201 return SP_ERROR_ABORTED;
204 IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
206 IDebugListener *old = m_pDebugHook;
208 m_pDebugHook = pListener;
213 unsigned int SourcePawnEngine::GetEngineAPIVersion()
215 return SOURCEPAWN_ENGINE_API_VERSION;
218 unsigned int SourcePawnEngine::GetContextCallCount()
223 void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
225 if (m_pDebugHook == NULL)
230 CContextTrace trace(runtime, err, errstr, rp_start);
232 m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
235 CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp)
236 : m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0)
238 m_ctx = pRuntime->m_pCtx->GetCtx();
239 m_pDebug = m_pRuntime->GetDebugInfo();
242 bool CContextTrace::DebugInfoAvailable()
244 return (m_pDebug != NULL);
247 const char *CContextTrace::GetCustomErrorString()
252 int CContextTrace::GetErrorCode()
257 const char *CContextTrace::GetErrorString()
259 if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
261 return "Invalid error code";
265 return g_ErrorMsgTable[m_Error];
269 void CContextTrace::ResetTrace()
274 bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
280 cip = m_ctx->err_cip;
282 else if (m_ctx->rp > 0)
284 /* Entries go from ctx.rp - 1 to m_StartRp */
285 cell_t offs, start, end;
288 start = m_ctx->rp - 1;
291 if (start - offs < end)
296 cip = m_ctx->rstk_cips[start - offs];
309 if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
311 trace->filename = NULL;
314 if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
316 trace->function = NULL;
319 if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
329 const char *CContextTrace::GetLastNative(uint32_t *index)
331 if (m_ctx->n_err == SP_ERROR_NONE)
337 if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
344 *index = m_ctx->n_idx;
350 IDebugListener *SourcePawnEngine::GetDebugHook()