sourcepawn/jit/sp_vm_engine.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Wed Aug 14 14:20:57 2013 -0400 (2013-08-14)
changeset 4008 490b01aa0683
parent 3990 c7fb79059d7a
child 4013 6201c1180e0e
permissions -rw-r--r--
Updated some CS:GO gamedata.
dvander@2193
     1
/**
dvander@2193
     2
 * vim: set ts=4 :
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
danderson@3977
    61
#define ERROR_MESSAGE_MAX		29
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",
danderson@3977
    93
    "Integer overflow"
dvander@2193
    94
};
dvander@2193
    95
dvander@2193
    96
const char *SourcePawnEngine::GetErrorString(int error)
dvander@2193
    97
{
dvander@2193
    98
	if (error < 1 || error > ERROR_MESSAGE_MAX)
dvander@2193
    99
	{
dvander@2193
   100
		return NULL;
dvander@2193
   101
	}
dvander@2193
   102
dvander@2193
   103
	return g_ErrorMsgTable[error];
dvander@2193
   104
}
dvander@2193
   105
dvander@2193
   106
SourcePawnEngine::SourcePawnEngine()
dvander@2193
   107
{
dvander@2193
   108
	m_pDebugHook = NULL;
dvander@2193
   109
}
dvander@2193
   110
dvander@2193
   111
SourcePawnEngine::~SourcePawnEngine()
dvander@2193
   112
{
dvander@2193
   113
}
dvander@2193
   114
dvander@2193
   115
void *SourcePawnEngine::ExecAlloc(size_t size)
dvander@2193
   116
{
dvander@2193
   117
#if defined WIN32
dvander@2193
   118
	return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dvander@2193
   119
#elif defined __GNUC__
dvander@2471
   120
# if defined __APPLE__
dvander@2471
   121
	void *base = valloc(size);
dvander@2471
   122
# else
dvander@2193
   123
	void *base = memalign(sysconf(_SC_PAGESIZE), size);
dvander@2471
   124
# endif
dvander@2193
   125
	if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
dvander@2193
   126
	{
dvander@2193
   127
		free(base);
dvander@2193
   128
		return NULL;
dvander@2193
   129
	}
dvander@2193
   130
	return base;
dvander@2193
   131
#endif
dvander@2193
   132
}
dvander@2193
   133
dvander@2193
   134
void *SourcePawnEngine::AllocatePageMemory(size_t size)
dvander@2193
   135
{
dvander@2226
   136
	return g_Jit.AllocCode(size);
dvander@2193
   137
}
dvander@2193
   138
dvander@2193
   139
void SourcePawnEngine::SetReadExecute(void *ptr)
dvander@2193
   140
{
dvander@2226
   141
	/* already re */
dvander@2193
   142
}
dvander@2193
   143
dvander@2193
   144
void SourcePawnEngine::SetReadWrite(void *ptr)
dvander@2193
   145
{
dvander@2226
   146
	/* already rw */
dvander@2193
   147
}
dvander@2193
   148
dvander@2193
   149
void SourcePawnEngine::FreePageMemory(void *ptr)
dvander@2193
   150
{
dvander@2226
   151
	g_Jit.FreeCode(ptr);
dvander@2193
   152
}
dvander@2193
   153
dvander@2193
   154
void SourcePawnEngine::ExecFree(void *address)
dvander@2193
   155
{
dvander@2193
   156
#if defined WIN32
dvander@2193
   157
	VirtualFree(address, 0, MEM_RELEASE);
dvander@2193
   158
#elif defined __GNUC__
dvander@2193
   159
	free(address);
dvander@2193
   160
#endif
dvander@2193
   161
}
dvander@2193
   162
dvander@2226
   163
void SourcePawnEngine::SetReadWriteExecute(void *ptr)
dvander@2226
   164
{
dvander@2226
   165
//:TODO:	g_ExeMemory.SetRWE(ptr);
dvander@2226
   166
	SetReadExecute(ptr);
dvander@2226
   167
}
dvander@2226
   168
dvander@2193
   169
void *SourcePawnEngine::BaseAlloc(size_t size)
dvander@2193
   170
{
dvander@2193
   171
	return malloc(size);
dvander@2193
   172
}
dvander@2193
   173
dvander@2193
   174
void SourcePawnEngine::BaseFree(void *memory)
dvander@2193
   175
{
dvander@2193
   176
	free(memory);
dvander@2193
   177
}
dvander@2193
   178
dvander@2193
   179
sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
dvander@2193
   180
{
dvander@2193
   181
	if (err != NULL)
dvander@2193
   182
	{
dvander@2193
   183
		*err = SP_ERROR_ABORTED;
dvander@2193
   184
	}
dvander@2193
   185
dvander@2193
   186
	return NULL;
dvander@2193
   187
}
dvander@2193
   188
dvander@2193
   189
sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
dvander@2193
   190
{
dvander@2193
   191
	if (err != NULL)
dvander@2193
   192
	{
dvander@2193
   193
		*err = SP_ERROR_ABORTED;
dvander@2193
   194
	}
dvander@2193
   195
dvander@2193
   196
	return NULL;
dvander@2193
   197
}
dvander@2193
   198
dvander@2193
   199
int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
dvander@2193
   200
{
dvander@2193
   201
	return SP_ERROR_ABORTED;
dvander@2193
   202
}
dvander@2193
   203
dvander@2193
   204
IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
dvander@2193
   205
{
dvander@2193
   206
	IDebugListener *old = m_pDebugHook;
dvander@2193
   207
dvander@2193
   208
	m_pDebugHook = pListener;
dvander@2193
   209
dvander@2193
   210
	return old;
dvander@2193
   211
}
dvander@2193
   212
dvander@2193
   213
unsigned int SourcePawnEngine::GetEngineAPIVersion()
dvander@2193
   214
{
dvander@2193
   215
	return SOURCEPAWN_ENGINE_API_VERSION;
dvander@2193
   216
}
dvander@2193
   217
dvander@2226
   218
unsigned int SourcePawnEngine::GetContextCallCount()
dvander@2226
   219
{
dvander@2226
   220
	return 0;
dvander@2226
   221
}
dvander@2226
   222
dvander@2226
   223
void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
dvander@2193
   224
{
dvander@2226
   225
	if (m_pDebugHook == NULL)
dvander@2226
   226
	{
dvander@2226
   227
		return;
dvander@2226
   228
	}
dvander@2226
   229
dvander@2226
   230
	CContextTrace trace(runtime, err, errstr, rp_start);
dvander@2226
   231
dvander@2226
   232
	m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
dvander@2226
   233
}
dvander@2226
   234
dvander@2226
   235
CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp) 
dvander@2226
   236
: m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0)
dvander@2226
   237
{
dvander@2226
   238
	m_ctx = pRuntime->m_pCtx->GetCtx();
dvander@2226
   239
	m_pDebug = m_pRuntime->GetDebugInfo();
dvander@2193
   240
}
dvander@2193
   241
dvander@2193
   242
bool CContextTrace::DebugInfoAvailable()
dvander@2193
   243
{
dvander@2226
   244
	return (m_pDebug != NULL);
dvander@2193
   245
}
dvander@2193
   246
dvander@2193
   247
const char *CContextTrace::GetCustomErrorString()
dvander@2193
   248
{
dvander@2193
   249
	return m_pMsg;
dvander@2193
   250
}
dvander@2193
   251
dvander@2193
   252
int CContextTrace::GetErrorCode()
dvander@2193
   253
{
dvander@2193
   254
	return m_Error;
dvander@2193
   255
}
dvander@2193
   256
dvander@2193
   257
const char *CContextTrace::GetErrorString()
dvander@2193
   258
{
dvander@2226
   259
	if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
dvander@2193
   260
	{
dvander@2193
   261
		return "Invalid error code";
dvander@2226
   262
	}
dvander@2226
   263
	else
dvander@2226
   264
	{
dvander@2193
   265
		return g_ErrorMsgTable[m_Error];
dvander@2193
   266
	}
dvander@2193
   267
}
dvander@2193
   268
dvander@2193
   269
void CContextTrace::ResetTrace()
dvander@2193
   270
{
dvander@2226
   271
	m_Level = 0;
dvander@2193
   272
}
dvander@2193
   273
dvander@2193
   274
bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
dvander@2193
   275
{
dvander@2226
   276
	cell_t cip;
dvander@2226
   277
dvander@2226
   278
	if (m_Level == 0)
dvander@2193
   279
	{
dvander@3990
   280
		cip = m_ctx->cip;
dvander@2193
   281
	}
dvander@2226
   282
	else if (m_ctx->rp > 0)
dvander@2193
   283
	{
dvander@2226
   284
		/* Entries go from ctx.rp - 1 to m_StartRp */
dvander@2226
   285
		cell_t offs, start, end;
dvander@2226
   286
dvander@2226
   287
		offs = m_Level - 1;
dvander@2226
   288
		start = m_ctx->rp - 1;
dvander@2226
   289
		end = m_StartRp;
dvander@2193
   290
dvander@2226
   291
		if (start - offs < end)
dvander@2226
   292
		{
dvander@2226
   293
			return false;
dvander@2226
   294
		}
dvander@2193
   295
dvander@2226
   296
		cip = m_ctx->rstk_cips[start - offs];
dvander@2226
   297
	}
dvander@2226
   298
	else
dvander@2193
   299
	{
dvander@2193
   300
		return false;
dvander@2193
   301
	}
dvander@2193
   302
dvander@2226
   303
	if (trace == NULL)
dvander@2193
   304
	{
dvander@2226
   305
		m_Level++;
dvander@2193
   306
		return true;
dvander@2193
   307
	}
dvander@2193
   308
dvander@2226
   309
	if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
dvander@2193
   310
	{
dvander@2193
   311
		trace->filename = NULL;
dvander@2193
   312
	}
dvander@2193
   313
dvander@2226
   314
	if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
dvander@2193
   315
	{
dvander@2193
   316
		trace->function = NULL;
dvander@2193
   317
	}
dvander@2193
   318
dvander@2226
   319
	if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
dvander@2193
   320
	{
dvander@2193
   321
		trace->line = 0;
dvander@2193
   322
	}
dvander@2193
   323
dvander@2226
   324
	m_Level++;
dvander@2193
   325
dvander@2193
   326
	return true;
dvander@2193
   327
}
dvander@2193
   328
dvander@2193
   329
const char *CContextTrace::GetLastNative(uint32_t *index)
dvander@2193
   330
{
dvander@2226
   331
	if (m_ctx->n_err == SP_ERROR_NONE)
dvander@2193
   332
	{
dvander@2193
   333
		return NULL;
dvander@2193
   334
	}
dvander@2193
   335
dvander@2193
   336
	sp_native_t *native;
dvander@2226
   337
	if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
dvander@2193
   338
	{
dvander@2193
   339
		return NULL;
dvander@2193
   340
	}
dvander@2193
   341
dvander@2193
   342
	if (index)
dvander@2193
   343
	{
dvander@2226
   344
		*index = m_ctx->n_idx;
dvander@2193
   345
	}
dvander@2193
   346
dvander@2193
   347
	return native->name;
dvander@2193
   348
}
dvander@2226
   349
dvander@2226
   350
IDebugListener *SourcePawnEngine::GetDebugHook()
dvander@2226
   351
{
dvander@2226
   352
	return m_pDebugHook;
dvander@2226
   353
}
dvander@2226
   354