sourcepawn/jit/sp_vm_engine.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4013 6201c1180e0e
permissions -rw-r--r--
Update CS:GO team score gamedata.
dvander@2193
     1
/**
dvander@4013
     2
 * vim: set ts=4 sw=4 tw=99 et:
dvander@2193
     3
 * =============================================================================
dvander@2193
     4
 * SourcePawn
dvander@2193
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2193
     6
 * =============================================================================
dvander@2193
     7
 *
dvander@2193
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2193
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2193
    10
 * Free Software Foundation.
dvander@2193
    11
 * 
dvander@2193
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2193
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2193
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2193
    15
 * details.
dvander@2193
    16
 *
dvander@2193
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2193
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2193
    19
 *
dvander@2193
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2193
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2193
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2193
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2193
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2193
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2193
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2193
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2193
    28
 *
dvander@2193
    29
 * Version: $Id$
dvander@2193
    30
 */
dvander@2193
    31
dvander@2471
    32
#include <stdlib.h>
dvander@2193
    33
#include <string.h>
dvander@2193
    34
#include <assert.h>
dvander@2228
    35
#include "sp_vm_types.h"
dvander@2226
    36
#include <KeCodeAllocator.h>
dvander@2193
    37
#include "sp_file_headers.h"
dvander@2193
    38
#include "sp_vm_engine.h"
dvander@2193
    39
#include "zlib/zlib.h"
dvander@2193
    40
#include "sp_vm_basecontext.h"
dvander@2226
    41
#include "jit_x86.h"
dvander@2226
    42
#if defined __GNUC__
dvander@2226
    43
#include <unistd.h>
dvander@2226
    44
#endif
dvander@2193
    45
dvander@2193
    46
SourcePawnEngine g_engine1;
dvander@2193
    47
dvander@2193
    48
#if defined WIN32
dvander@2193
    49
 #define WIN32_LEAN_AND_MEAN
dvander@2193
    50
 #include <windows.h>
dvander@2193
    51
#elif defined __GNUC__
dvander@2193
    52
 #include <sys/mman.h>
dvander@2193
    53
#endif
dvander@2193
    54
dvander@2473
    55
#if defined __linux__
dvander@2472
    56
#include <malloc.h>
dvander@2472
    57
#endif
dvander@2472
    58
dvander@2193
    59
using namespace SourcePawn;
dvander@2193
    60
dvander@4013
    61
#define ERROR_MESSAGE_MAX		30
dvander@2193
    62
static const char *g_ErrorMsgTable[] = 
dvander@2193
    63
{
dvander@2193
    64
	NULL,
dvander@2193
    65
	"Unrecognizable file format",
dvander@2193
    66
	"Decompressor was not found",
dvander@2193
    67
	"Not enough space on the heap",
dvander@2193
    68
	"Invalid parameter or parameter type",
dvander@2193
    69
	"Invalid plugin address",
dvander@2193
    70
	"Object or index not found",
dvander@2193
    71
	"Invalid index or index not found",
dvander@2193
    72
	"Not enough space on the stack",
dvander@2193
    73
	"Debug section not found or debug not enabled",
dvander@2193
    74
	"Invalid instruction",
dvander@2193
    75
	"Invalid memory access",
dvander@2193
    76
	"Stack went below stack boundary",
dvander@2193
    77
	"Heap went below heap boundary",
dvander@2193
    78
	"Divide by zero",
dvander@2193
    79
	"Array index is out of bounds",
dvander@2193
    80
	"Instruction contained invalid parameter",
dvander@2193
    81
	"Stack memory leaked by native",
dvander@2193
    82
	"Heap memory leaked by native",
dvander@2193
    83
	"Dynamic array is too big",
dvander@2193
    84
	"Tracker stack is out of bounds",
dvander@2193
    85
	"Native is not bound",
dvander@2193
    86
	"Maximum number of parameters reached",
dvander@2193
    87
	"Native detected error",
dvander@2193
    88
	"Plugin not runnable",
dvander@2193
    89
	"Call was aborted",
dvander@2226
    90
	"Plugin format is too old",
dvander@2226
    91
	"Plugin format is too new",
danderson@3977
    92
    "Out of memory",
dvander@4013
    93
    "Integer overflow",
dvander@4013
    94
    "Script execution timed out"
dvander@2193
    95
};
dvander@2193
    96
dvander@2193
    97
const char *SourcePawnEngine::GetErrorString(int error)
dvander@2193
    98
{
dvander@2193
    99
	if (error < 1 || error > ERROR_MESSAGE_MAX)
dvander@2193
   100
	{
dvander@2193
   101
		return NULL;
dvander@2193
   102
	}
dvander@2193
   103
dvander@2193
   104
	return g_ErrorMsgTable[error];
dvander@2193
   105
}
dvander@2193
   106
dvander@2193
   107
SourcePawnEngine::SourcePawnEngine()
dvander@2193
   108
{
dvander@2193
   109
	m_pDebugHook = NULL;
dvander@2193
   110
}
dvander@2193
   111
dvander@2193
   112
SourcePawnEngine::~SourcePawnEngine()
dvander@2193
   113
{
dvander@2193
   114
}
dvander@2193
   115
dvander@2193
   116
void *SourcePawnEngine::ExecAlloc(size_t size)
dvander@2193
   117
{
dvander@2193
   118
#if defined WIN32
dvander@2193
   119
	return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dvander@2193
   120
#elif defined __GNUC__
dvander@2471
   121
# if defined __APPLE__
dvander@2471
   122
	void *base = valloc(size);
dvander@2471
   123
# else
dvander@2193
   124
	void *base = memalign(sysconf(_SC_PAGESIZE), size);
dvander@2471
   125
# endif
dvander@2193
   126
	if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
dvander@2193
   127
	{
dvander@2193
   128
		free(base);
dvander@2193
   129
		return NULL;
dvander@2193
   130
	}
dvander@2193
   131
	return base;
dvander@2193
   132
#endif
dvander@2193
   133
}
dvander@2193
   134
dvander@2193
   135
void *SourcePawnEngine::AllocatePageMemory(size_t size)
dvander@2193
   136
{
dvander@2226
   137
	return g_Jit.AllocCode(size);
dvander@2193
   138
}
dvander@2193
   139
dvander@2193
   140
void SourcePawnEngine::SetReadExecute(void *ptr)
dvander@2193
   141
{
dvander@2226
   142
	/* already re */
dvander@2193
   143
}
dvander@2193
   144
dvander@2193
   145
void SourcePawnEngine::SetReadWrite(void *ptr)
dvander@2193
   146
{
dvander@2226
   147
	/* already rw */
dvander@2193
   148
}
dvander@2193
   149
dvander@2193
   150
void SourcePawnEngine::FreePageMemory(void *ptr)
dvander@2193
   151
{
dvander@2226
   152
	g_Jit.FreeCode(ptr);
dvander@2193
   153
}
dvander@2193
   154
dvander@2193
   155
void SourcePawnEngine::ExecFree(void *address)
dvander@2193
   156
{
dvander@2193
   157
#if defined WIN32
dvander@2193
   158
	VirtualFree(address, 0, MEM_RELEASE);
dvander@2193
   159
#elif defined __GNUC__
dvander@2193
   160
	free(address);
dvander@2193
   161
#endif
dvander@2193
   162
}
dvander@2193
   163
dvander@2226
   164
void SourcePawnEngine::SetReadWriteExecute(void *ptr)
dvander@2226
   165
{
dvander@2226
   166
//:TODO:	g_ExeMemory.SetRWE(ptr);
dvander@2226
   167
	SetReadExecute(ptr);
dvander@2226
   168
}
dvander@2226
   169
dvander@2193
   170
void *SourcePawnEngine::BaseAlloc(size_t size)
dvander@2193
   171
{
dvander@2193
   172
	return malloc(size);
dvander@2193
   173
}
dvander@2193
   174
dvander@2193
   175
void SourcePawnEngine::BaseFree(void *memory)
dvander@2193
   176
{
dvander@2193
   177
	free(memory);
dvander@2193
   178
}
dvander@2193
   179
dvander@2193
   180
sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
dvander@2193
   181
{
dvander@2193
   182
	if (err != NULL)
dvander@2193
   183
	{
dvander@2193
   184
		*err = SP_ERROR_ABORTED;
dvander@2193
   185
	}
dvander@2193
   186
dvander@2193
   187
	return NULL;
dvander@2193
   188
}
dvander@2193
   189
dvander@2193
   190
sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
dvander@2193
   191
{
dvander@2193
   192
	if (err != NULL)
dvander@2193
   193
	{
dvander@2193
   194
		*err = SP_ERROR_ABORTED;
dvander@2193
   195
	}
dvander@2193
   196
dvander@2193
   197
	return NULL;
dvander@2193
   198
}
dvander@2193
   199
dvander@2193
   200
int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
dvander@2193
   201
{
dvander@2193
   202
	return SP_ERROR_ABORTED;
dvander@2193
   203
}
dvander@2193
   204
dvander@2193
   205
IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
dvander@2193
   206
{
dvander@2193
   207
	IDebugListener *old = m_pDebugHook;
dvander@2193
   208
dvander@2193
   209
	m_pDebugHook = pListener;
dvander@2193
   210
dvander@2193
   211
	return old;
dvander@2193
   212
}
dvander@2193
   213
dvander@2193
   214
unsigned int SourcePawnEngine::GetEngineAPIVersion()
dvander@2193
   215
{
dvander@2193
   216
	return SOURCEPAWN_ENGINE_API_VERSION;
dvander@2193
   217
}
dvander@2193
   218
dvander@2226
   219
unsigned int SourcePawnEngine::GetContextCallCount()
dvander@2226
   220
{
dvander@2226
   221
	return 0;
dvander@2226
   222
}
dvander@2226
   223
dvander@2226
   224
void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
dvander@2193
   225
{
dvander@2226
   226
	if (m_pDebugHook == NULL)
dvander@2226
   227
	{
dvander@2226
   228
		return;
dvander@2226
   229
	}
dvander@2226
   230
dvander@2226
   231
	CContextTrace trace(runtime, err, errstr, rp_start);
dvander@2226
   232
dvander@2226
   233
	m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
dvander@2226
   234
}
dvander@2226
   235
dvander@2226
   236
CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp) 
dvander@2226
   237
: m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0)
dvander@2226
   238
{
dvander@2226
   239
	m_ctx = pRuntime->m_pCtx->GetCtx();
dvander@2226
   240
	m_pDebug = m_pRuntime->GetDebugInfo();
dvander@2193
   241
}
dvander@2193
   242
dvander@2193
   243
bool CContextTrace::DebugInfoAvailable()
dvander@2193
   244
{
dvander@2226
   245
	return (m_pDebug != NULL);
dvander@2193
   246
}
dvander@2193
   247
dvander@2193
   248
const char *CContextTrace::GetCustomErrorString()
dvander@2193
   249
{
dvander@2193
   250
	return m_pMsg;
dvander@2193
   251
}
dvander@2193
   252
dvander@2193
   253
int CContextTrace::GetErrorCode()
dvander@2193
   254
{
dvander@2193
   255
	return m_Error;
dvander@2193
   256
}
dvander@2193
   257
dvander@2193
   258
const char *CContextTrace::GetErrorString()
dvander@2193
   259
{
dvander@2226
   260
	if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
dvander@2193
   261
	{
dvander@2193
   262
		return "Invalid error code";
dvander@2226
   263
	}
dvander@2226
   264
	else
dvander@2226
   265
	{
dvander@2193
   266
		return g_ErrorMsgTable[m_Error];
dvander@2193
   267
	}
dvander@2193
   268
}
dvander@2193
   269
dvander@2193
   270
void CContextTrace::ResetTrace()
dvander@2193
   271
{
dvander@2226
   272
	m_Level = 0;
dvander@2193
   273
}
dvander@2193
   274
dvander@2193
   275
bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
dvander@2193
   276
{
dvander@2226
   277
	cell_t cip;
dvander@2226
   278
dvander@2226
   279
	if (m_Level == 0)
dvander@2193
   280
	{
dvander@3990
   281
		cip = m_ctx->cip;
dvander@2193
   282
	}
dvander@2226
   283
	else if (m_ctx->rp > 0)
dvander@2193
   284
	{
dvander@2226
   285
		/* Entries go from ctx.rp - 1 to m_StartRp */
dvander@2226
   286
		cell_t offs, start, end;
dvander@2226
   287
dvander@2226
   288
		offs = m_Level - 1;
dvander@2226
   289
		start = m_ctx->rp - 1;
dvander@2226
   290
		end = m_StartRp;
dvander@2193
   291
dvander@2226
   292
		if (start - offs < end)
dvander@2226
   293
		{
dvander@2226
   294
			return false;
dvander@2226
   295
		}
dvander@2193
   296
dvander@2226
   297
		cip = m_ctx->rstk_cips[start - offs];
dvander@2226
   298
	}
dvander@2226
   299
	else
dvander@2193
   300
	{
dvander@2193
   301
		return false;
dvander@2193
   302
	}
dvander@2193
   303
dvander@2226
   304
	if (trace == NULL)
dvander@2193
   305
	{
dvander@2226
   306
		m_Level++;
dvander@2193
   307
		return true;
dvander@2193
   308
	}
dvander@2193
   309
dvander@2226
   310
	if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
dvander@2193
   311
	{
dvander@2193
   312
		trace->filename = NULL;
dvander@2193
   313
	}
dvander@2193
   314
dvander@2226
   315
	if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
dvander@2193
   316
	{
dvander@2193
   317
		trace->function = NULL;
dvander@2193
   318
	}
dvander@2193
   319
dvander@2226
   320
	if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
dvander@2193
   321
	{
dvander@2193
   322
		trace->line = 0;
dvander@2193
   323
	}
dvander@2193
   324
dvander@2226
   325
	m_Level++;
dvander@2193
   326
dvander@2193
   327
	return true;
dvander@2193
   328
}
dvander@2193
   329
dvander@2193
   330
const char *CContextTrace::GetLastNative(uint32_t *index)
dvander@2193
   331
{
dvander@2226
   332
	if (m_ctx->n_err == SP_ERROR_NONE)
dvander@2193
   333
	{
dvander@2193
   334
		return NULL;
dvander@2193
   335
	}
dvander@2193
   336
dvander@2193
   337
	sp_native_t *native;
dvander@2226
   338
	if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
dvander@2193
   339
	{
dvander@2193
   340
		return NULL;
dvander@2193
   341
	}
dvander@2193
   342
dvander@2193
   343
	if (index)
dvander@2193
   344
	{
dvander@2226
   345
		*index = m_ctx->n_idx;
dvander@2193
   346
	}
dvander@2193
   347
dvander@2193
   348
	return native->name;
dvander@2193
   349
}
dvander@2226
   350
dvander@2226
   351
IDebugListener *SourcePawnEngine::GetDebugHook()
dvander@2226
   352
{
dvander@2226
   353
	return m_pDebugHook;
dvander@2226
   354
}
dvander@2226
   355