sourcepawn/jit/sp_vm_engine.cpp
author GoD-Tony <aangione@gmail.com>
Sun Aug 04 10:03:40 2013 -0400 (2013-08-04)
changeset 3971 d2e8100b2814
parent 2473 2df0a0591913
child 3977 fca2b54741ca
permissions -rw-r--r--
Added ISDKHooks interface with entity listeners (bug 5602, r=psychonic).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourcePawn
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <stdlib.h>
    33 #include <string.h>
    34 #include <assert.h>
    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"
    41 #include "jit_x86.h"
    42 #if defined __GNUC__
    43 #include <unistd.h>
    44 #endif
    45 
    46 SourcePawnEngine g_engine1;
    47 
    48 #if defined WIN32
    49  #define WIN32_LEAN_AND_MEAN
    50  #include <windows.h>
    51 #elif defined __GNUC__
    52  #include <sys/mman.h>
    53 #endif
    54 
    55 #if defined __linux__
    56 #include <malloc.h>
    57 #endif
    58 
    59 using namespace SourcePawn;
    60 
    61 #define ERROR_MESSAGE_MAX		25
    62 static const char *g_ErrorMsgTable[] = 
    63 {
    64 	NULL,
    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",
    78 	"Divide by zero",
    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",
    89 	"Call was aborted",
    90 	"Plugin format is too old",
    91 	"Plugin format is too new",
    92 };
    93 
    94 const char *SourcePawnEngine::GetErrorString(int error)
    95 {
    96 	if (error < 1 || error > ERROR_MESSAGE_MAX)
    97 	{
    98 		return NULL;
    99 	}
   100 
   101 	return g_ErrorMsgTable[error];
   102 }
   103 
   104 SourcePawnEngine::SourcePawnEngine()
   105 {
   106 	m_pDebugHook = NULL;
   107 }
   108 
   109 SourcePawnEngine::~SourcePawnEngine()
   110 {
   111 }
   112 
   113 void *SourcePawnEngine::ExecAlloc(size_t size)
   114 {
   115 #if defined WIN32
   116 	return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
   117 #elif defined __GNUC__
   118 # if defined __APPLE__
   119 	void *base = valloc(size);
   120 # else
   121 	void *base = memalign(sysconf(_SC_PAGESIZE), size);
   122 # endif
   123 	if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
   124 	{
   125 		free(base);
   126 		return NULL;
   127 	}
   128 	return base;
   129 #endif
   130 }
   131 
   132 void *SourcePawnEngine::AllocatePageMemory(size_t size)
   133 {
   134 	return g_Jit.AllocCode(size);
   135 }
   136 
   137 void SourcePawnEngine::SetReadExecute(void *ptr)
   138 {
   139 	/* already re */
   140 }
   141 
   142 void SourcePawnEngine::SetReadWrite(void *ptr)
   143 {
   144 	/* already rw */
   145 }
   146 
   147 void SourcePawnEngine::FreePageMemory(void *ptr)
   148 {
   149 	g_Jit.FreeCode(ptr);
   150 }
   151 
   152 void SourcePawnEngine::ExecFree(void *address)
   153 {
   154 #if defined WIN32
   155 	VirtualFree(address, 0, MEM_RELEASE);
   156 #elif defined __GNUC__
   157 	free(address);
   158 #endif
   159 }
   160 
   161 void SourcePawnEngine::SetReadWriteExecute(void *ptr)
   162 {
   163 //:TODO:	g_ExeMemory.SetRWE(ptr);
   164 	SetReadExecute(ptr);
   165 }
   166 
   167 void *SourcePawnEngine::BaseAlloc(size_t size)
   168 {
   169 	return malloc(size);
   170 }
   171 
   172 void SourcePawnEngine::BaseFree(void *memory)
   173 {
   174 	free(memory);
   175 }
   176 
   177 sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
   178 {
   179 	if (err != NULL)
   180 	{
   181 		*err = SP_ERROR_ABORTED;
   182 	}
   183 
   184 	return NULL;
   185 }
   186 
   187 sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
   188 {
   189 	if (err != NULL)
   190 	{
   191 		*err = SP_ERROR_ABORTED;
   192 	}
   193 
   194 	return NULL;
   195 }
   196 
   197 int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
   198 {
   199 	return SP_ERROR_ABORTED;
   200 }
   201 
   202 IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
   203 {
   204 	IDebugListener *old = m_pDebugHook;
   205 
   206 	m_pDebugHook = pListener;
   207 
   208 	return old;
   209 }
   210 
   211 unsigned int SourcePawnEngine::GetEngineAPIVersion()
   212 {
   213 	return SOURCEPAWN_ENGINE_API_VERSION;
   214 }
   215 
   216 unsigned int SourcePawnEngine::GetContextCallCount()
   217 {
   218 	return 0;
   219 }
   220 
   221 void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
   222 {
   223 	if (m_pDebugHook == NULL)
   224 	{
   225 		return;
   226 	}
   227 
   228 	CContextTrace trace(runtime, err, errstr, rp_start);
   229 
   230 	m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
   231 }
   232 
   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)
   235 {
   236 	m_ctx = pRuntime->m_pCtx->GetCtx();
   237 	m_pDebug = m_pRuntime->GetDebugInfo();
   238 }
   239 
   240 bool CContextTrace::DebugInfoAvailable()
   241 {
   242 	return (m_pDebug != NULL);
   243 }
   244 
   245 const char *CContextTrace::GetCustomErrorString()
   246 {
   247 	return m_pMsg;
   248 }
   249 
   250 int CContextTrace::GetErrorCode()
   251 {
   252 	return m_Error;
   253 }
   254 
   255 const char *CContextTrace::GetErrorString()
   256 {
   257 	if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
   258 	{
   259 		return "Invalid error code";
   260 	}
   261 	else
   262 	{
   263 		return g_ErrorMsgTable[m_Error];
   264 	}
   265 }
   266 
   267 void CContextTrace::ResetTrace()
   268 {
   269 	m_Level = 0;
   270 }
   271 
   272 bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
   273 {
   274 	cell_t cip;
   275 
   276 	if (m_Level == 0)
   277 	{
   278 		cip = m_ctx->err_cip;
   279 	}
   280 	else if (m_ctx->rp > 0)
   281 	{
   282 		/* Entries go from ctx.rp - 1 to m_StartRp */
   283 		cell_t offs, start, end;
   284 
   285 		offs = m_Level - 1;
   286 		start = m_ctx->rp - 1;
   287 		end = m_StartRp;
   288 
   289 		if (start - offs < end)
   290 		{
   291 			return false;
   292 		}
   293 
   294 		cip = m_ctx->rstk_cips[start - offs];
   295 	}
   296 	else
   297 	{
   298 		return false;
   299 	}
   300 
   301 	if (trace == NULL)
   302 	{
   303 		m_Level++;
   304 		return true;
   305 	}
   306 
   307 	if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
   308 	{
   309 		trace->filename = NULL;
   310 	}
   311 
   312 	if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
   313 	{
   314 		trace->function = NULL;
   315 	}
   316 
   317 	if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
   318 	{
   319 		trace->line = 0;
   320 	}
   321 
   322 	m_Level++;
   323 
   324 	return true;
   325 }
   326 
   327 const char *CContextTrace::GetLastNative(uint32_t *index)
   328 {
   329 	if (m_ctx->n_err == SP_ERROR_NONE)
   330 	{
   331 		return NULL;
   332 	}
   333 
   334 	sp_native_t *native;
   335 	if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
   336 	{
   337 		return NULL;
   338 	}
   339 
   340 	if (index)
   341 	{
   342 		*index = m_ctx->n_idx;
   343 	}
   344 
   345 	return native->name;
   346 }
   347 
   348 IDebugListener *SourcePawnEngine::GetDebugHook()
   349 {
   350 	return m_pDebugHook;
   351 }
   352