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 25
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",
94 const char *SourcePawnEngine::GetErrorString(int error)
96 if (error < 1 || error > ERROR_MESSAGE_MAX)
101 return g_ErrorMsgTable[error];
104 SourcePawnEngine::SourcePawnEngine()
109 SourcePawnEngine::~SourcePawnEngine()
113 void *SourcePawnEngine::ExecAlloc(size_t size)
116 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
117 #elif defined __GNUC__
118 # if defined __APPLE__
119 void *base = valloc(size);
121 void *base = memalign(sysconf(_SC_PAGESIZE), size);
123 if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
132 void *SourcePawnEngine::AllocatePageMemory(size_t size)
134 return g_Jit.AllocCode(size);
137 void SourcePawnEngine::SetReadExecute(void *ptr)
142 void SourcePawnEngine::SetReadWrite(void *ptr)
147 void SourcePawnEngine::FreePageMemory(void *ptr)
152 void SourcePawnEngine::ExecFree(void *address)
155 VirtualFree(address, 0, MEM_RELEASE);
156 #elif defined __GNUC__
161 void SourcePawnEngine::SetReadWriteExecute(void *ptr)
163 //:TODO: g_ExeMemory.SetRWE(ptr);
167 void *SourcePawnEngine::BaseAlloc(size_t size)
172 void SourcePawnEngine::BaseFree(void *memory)
177 sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
181 *err = SP_ERROR_ABORTED;
187 sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
191 *err = SP_ERROR_ABORTED;
197 int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
199 return SP_ERROR_ABORTED;
202 IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
204 IDebugListener *old = m_pDebugHook;
206 m_pDebugHook = pListener;
211 unsigned int SourcePawnEngine::GetEngineAPIVersion()
213 return SOURCEPAWN_ENGINE_API_VERSION;
216 unsigned int SourcePawnEngine::GetContextCallCount()
221 void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
223 if (m_pDebugHook == NULL)
228 CContextTrace trace(runtime, err, errstr, rp_start);
230 m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
233 CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp)
234 : m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0)
236 m_ctx = pRuntime->m_pCtx->GetCtx();
237 m_pDebug = m_pRuntime->GetDebugInfo();
240 bool CContextTrace::DebugInfoAvailable()
242 return (m_pDebug != NULL);
245 const char *CContextTrace::GetCustomErrorString()
250 int CContextTrace::GetErrorCode()
255 const char *CContextTrace::GetErrorString()
257 if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
259 return "Invalid error code";
263 return g_ErrorMsgTable[m_Error];
267 void CContextTrace::ResetTrace()
272 bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
278 cip = m_ctx->err_cip;
280 else if (m_ctx->rp > 0)
282 /* Entries go from ctx.rp - 1 to m_StartRp */
283 cell_t offs, start, end;
286 start = m_ctx->rp - 1;
289 if (start - offs < end)
294 cip = m_ctx->rstk_cips[start - offs];
307 if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
309 trace->filename = NULL;
312 if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
314 trace->function = NULL;
317 if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
327 const char *CContextTrace::GetLastNative(uint32_t *index)
329 if (m_ctx->n_err == SP_ERROR_NONE)
335 if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
342 *index = m_ctx->n_idx;
348 IDebugListener *SourcePawnEngine::GetDebugHook()