sourcepawn/jit/sp_vm_basecontext.cpp
author GoD-Tony <aangione@gmail.com>
Sun Aug 04 10:03:40 2013 -0400 (2013-08-04)
changeset 3971 d2e8100b2814
parent 2545 9cb1a1fefc2c
child 3977 fca2b54741ca
permissions -rw-r--r--
Added ISDKHooks interface with entity listeners (bug 5602, r=psychonic).
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@2193
    32
#include <string.h>
dvander@2193
    33
#include <stdarg.h>
dvander@2193
    34
#include <assert.h>
dvander@2193
    35
#include <limits.h>
dvander@2193
    36
#include "sp_vm_api.h"
dvander@2193
    37
#include "sp_vm_basecontext.h"
dvander@2193
    38
#include "sp_vm_engine.h"
dvander@2193
    39
#include "x86/jit_x86.h"
dvander@2193
    40
dvander@2193
    41
using namespace SourcePawn;
dvander@2193
    42
dvander@2193
    43
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@2193
    44
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@2193
    45
dvander@2193
    46
BaseContext::BaseContext(BaseRuntime *pRuntime)
dvander@2193
    47
{
dvander@2193
    48
	m_pRuntime = pRuntime;
dvander@2193
    49
	m_pPlugin = m_pRuntime->m_pPlugin;
dvander@2193
    50
dvander@2193
    51
	m_InExec = false;
dvander@2193
    52
	m_CustomMsg = false;
dvander@2193
    53
dvander@2226
    54
	/* Initialize the null references */
dvander@2226
    55
	uint32_t index;
dvander@2226
    56
	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@2226
    57
	{
dvander@2226
    58
		sp_pubvar_t *pubvar;
dvander@2226
    59
		GetPubvarByIndex(index, &pubvar);
dvander@2226
    60
		m_pNullVec = pubvar->offs;
dvander@2226
    61
	}
dvander@2226
    62
	else
dvander@2226
    63
	{
dvander@2226
    64
		m_pNullVec = NULL;
dvander@2226
    65
	}
dvander@2226
    66
dvander@2226
    67
	if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
dvander@2226
    68
	{
dvander@2226
    69
		sp_pubvar_t *pubvar;
dvander@2226
    70
		GetPubvarByIndex(index, &pubvar);
dvander@2226
    71
		m_pNullString = pubvar->offs;
dvander@2226
    72
	}
dvander@2226
    73
	else
dvander@2226
    74
	{
dvander@2226
    75
		m_pNullString = NULL;
dvander@2226
    76
	}
dvander@2226
    77
dvander@2226
    78
	m_ctx.hp = m_pPlugin->data_size;
dvander@2226
    79
	m_ctx.sp = m_pPlugin->mem_size - sizeof(cell_t);
dvander@2226
    80
	m_ctx.frm = m_ctx.sp;
dvander@2226
    81
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2226
    82
	m_ctx.n_idx = SP_ERROR_NONE;
dvander@2226
    83
	m_ctx.rp = 0;
dvander@2226
    84
dvander@2226
    85
	g_Jit.SetupContextVars(m_pRuntime, this, &m_ctx);
dvander@2193
    86
}
dvander@2193
    87
dvander@2193
    88
BaseContext::~BaseContext()
dvander@2193
    89
{
dvander@2226
    90
	g_Jit.FreeContextVars(&m_ctx);
dvander@2193
    91
}
dvander@2193
    92
dvander@2193
    93
IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@2193
    94
{
dvander@2193
    95
	return NULL;
dvander@2193
    96
}
dvander@2193
    97
dvander@2193
    98
sp_context_t *BaseContext::GetContext()
dvander@2193
    99
{
dvander@2193
   100
	return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
dvander@2193
   101
}
dvander@2193
   102
dvander@2193
   103
sp_context_t *BaseContext::GetCtx()
dvander@2193
   104
{
dvander@2193
   105
	return &m_ctx;
dvander@2193
   106
}
dvander@2193
   107
dvander@2193
   108
bool BaseContext::IsDebugging()
dvander@2193
   109
{
dvander@2226
   110
	return true;
dvander@2193
   111
}
dvander@2193
   112
dvander@2193
   113
int BaseContext::SetDebugBreak(void *newpfn, void *oldpfn)
dvander@2193
   114
{
dvander@2193
   115
	return SP_ERROR_ABORTED;
dvander@2193
   116
}
dvander@2193
   117
dvander@2193
   118
IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@2193
   119
{
dvander@2193
   120
	return NULL;
dvander@2193
   121
}
dvander@2193
   122
dvander@2193
   123
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
dvander@2193
   124
{
dvander@2193
   125
	return SP_ERROR_ABORTED;
dvander@2193
   126
}
dvander@2193
   127
dvander@2193
   128
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@2193
   129
{
dvander@2193
   130
	m_CustomMsg = true;
dvander@2193
   131
dvander@2193
   132
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@2193
   133
}
dvander@2193
   134
dvander@2193
   135
void BaseContext::_SetErrorMessage(const char *msg, ...)
dvander@2193
   136
{
dvander@2193
   137
	va_list ap;
dvander@2193
   138
	va_start(ap, msg);
dvander@2193
   139
	SetErrorMessage(msg, ap);
dvander@2193
   140
	va_end(ap);
dvander@2193
   141
}
dvander@2193
   142
dvander@2193
   143
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@2193
   144
{
dvander@2193
   145
	if (!m_InExec)
dvander@2193
   146
	{
dvander@2193
   147
		return 0;
dvander@2193
   148
	}
dvander@2193
   149
dvander@2193
   150
	m_ctx.n_err = error;
dvander@2193
   151
	
dvander@2193
   152
	if (msg)
dvander@2193
   153
	{
dvander@2193
   154
		va_list ap;
dvander@2193
   155
		va_start(ap, msg);
dvander@2193
   156
		SetErrorMessage(msg, ap);
dvander@2193
   157
		va_end(ap);
dvander@2193
   158
	}
dvander@2193
   159
dvander@2193
   160
	return 0;
dvander@2193
   161
}
dvander@2193
   162
dvander@2193
   163
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@2193
   164
{
dvander@2193
   165
	if (!m_InExec)
dvander@2193
   166
	{
dvander@2193
   167
		return 0;
dvander@2193
   168
	}
dvander@2193
   169
dvander@2193
   170
	m_ctx.n_err = SP_ERROR_NATIVE;
dvander@2193
   171
dvander@2193
   172
	if (msg)
dvander@2193
   173
	{
dvander@2193
   174
		va_list ap;
dvander@2193
   175
		va_start(ap, msg);
dvander@2193
   176
		SetErrorMessage(msg, ap);
dvander@2193
   177
		va_end(ap);
dvander@2193
   178
	}
dvander@2193
   179
dvander@2193
   180
	return 0;
dvander@2193
   181
}
dvander@2193
   182
dvander@2193
   183
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@2193
   184
{
dvander@2193
   185
	cell_t *addr;
dvander@2193
   186
	ucell_t realmem;
dvander@2193
   187
dvander@2193
   188
#if 0
dvander@2193
   189
	if (cells > CELLBOUNDMAX)
dvander@2193
   190
	{
dvander@2193
   191
		return SP_ERROR_ARAM;
dvander@2193
   192
	}
dvander@2193
   193
#else
dvander@2193
   194
	assert(cells < CELLBOUNDMAX);
dvander@2193
   195
#endif
dvander@2193
   196
dvander@2193
   197
	realmem = cells * sizeof(cell_t);
dvander@2193
   198
dvander@2193
   199
	/**
dvander@2193
   200
	 * Check if the space between the heap and stack is sufficient.
dvander@2193
   201
	 */
dvander@2193
   202
	if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN)
dvander@2193
   203
	{
dvander@2193
   204
		return SP_ERROR_HEAPLOW;
dvander@2193
   205
	}
dvander@2193
   206
dvander@2193
   207
	addr = (cell_t *)(m_pPlugin->memory + m_ctx.hp);
dvander@2193
   208
	/* store size of allocation in cells */
dvander@2193
   209
	*addr = (cell_t)cells;
dvander@2193
   210
	addr++;
dvander@2193
   211
	m_ctx.hp += sizeof(cell_t);
dvander@2193
   212
dvander@2193
   213
	*local_addr = m_ctx.hp;
dvander@2193
   214
dvander@2193
   215
	if (phys_addr)
dvander@2193
   216
	{
dvander@2193
   217
		*phys_addr = addr;
dvander@2193
   218
	}
dvander@2193
   219
dvander@2193
   220
	m_ctx.hp += realmem;
dvander@2193
   221
dvander@2193
   222
	return SP_ERROR_NONE;
dvander@2193
   223
}
dvander@2193
   224
dvander@2193
   225
int BaseContext::HeapPop(cell_t local_addr)
dvander@2193
   226
{
dvander@2193
   227
	cell_t cellcount;
dvander@2193
   228
	cell_t *addr;
dvander@2193
   229
dvander@2193
   230
	/* check the bounds of this address */
dvander@2193
   231
	local_addr -= sizeof(cell_t);
dvander@2193
   232
	if (local_addr < (cell_t)m_pPlugin->data_size || local_addr >= m_ctx.sp)
dvander@2193
   233
	{
dvander@2193
   234
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   235
	}
dvander@2193
   236
dvander@2193
   237
	addr = (cell_t *)(m_pPlugin->memory + local_addr);
dvander@2193
   238
	cellcount = (*addr) * sizeof(cell_t);
dvander@2193
   239
	/* check if this memory count looks valid */
dvander@2193
   240
	if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@2193
   241
	{
dvander@2193
   242
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   243
	}
dvander@2193
   244
dvander@2193
   245
	m_ctx.hp = local_addr;
dvander@2193
   246
dvander@2193
   247
	return SP_ERROR_NONE;
dvander@2193
   248
}
dvander@2193
   249
dvander@2193
   250
dvander@2193
   251
int BaseContext::HeapRelease(cell_t local_addr)
dvander@2193
   252
{
dvander@2193
   253
	if (local_addr < (cell_t)m_pPlugin->data_size)
dvander@2193
   254
	{
dvander@2193
   255
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   256
	}
dvander@2193
   257
dvander@2193
   258
	m_ctx.hp = local_addr - sizeof(cell_t);
dvander@2193
   259
dvander@2193
   260
	return SP_ERROR_NONE;
dvander@2193
   261
}
dvander@2193
   262
dvander@2193
   263
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@2193
   264
{
dvander@2193
   265
	return m_pRuntime->FindNativeByName(name, index);
dvander@2193
   266
}
dvander@2193
   267
dvander@2193
   268
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@2193
   269
{
dvander@2193
   270
	return m_pRuntime->GetNativeByIndex(index, native);
dvander@2193
   271
}
dvander@2193
   272
dvander@2193
   273
dvander@2193
   274
uint32_t BaseContext::GetNativesNum()
dvander@2193
   275
{
dvander@2193
   276
	return m_pRuntime->GetNativesNum();
dvander@2193
   277
}
dvander@2193
   278
dvander@2193
   279
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@2193
   280
{
dvander@2193
   281
	return m_pRuntime->FindPublicByName(name, index);
dvander@2193
   282
}
dvander@2193
   283
dvander@2193
   284
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@2193
   285
{
dvander@2193
   286
	return m_pRuntime->GetPublicByIndex(index, pblic);
dvander@2193
   287
}
dvander@2193
   288
dvander@2193
   289
uint32_t BaseContext::GetPublicsNum()
dvander@2193
   290
{
dvander@2193
   291
	return m_pRuntime->GetPublicsNum();
dvander@2193
   292
}
dvander@2193
   293
dvander@2193
   294
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@2193
   295
{
dvander@2193
   296
	return m_pRuntime->GetPubvarByIndex(index, pubvar);
dvander@2193
   297
}
dvander@2193
   298
dvander@2193
   299
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@2193
   300
{
dvander@2193
   301
	return m_pRuntime->FindPubvarByName(name, index);
dvander@2193
   302
}
dvander@2193
   303
dvander@2193
   304
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@2193
   305
{
dvander@2193
   306
	return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
dvander@2193
   307
}
dvander@2193
   308
dvander@2193
   309
uint32_t BaseContext::GetPubVarsNum()
dvander@2193
   310
{
dvander@2193
   311
	return m_pRuntime->GetPubVarsNum();
dvander@2193
   312
}
dvander@2193
   313
dvander@2193
   314
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@2193
   315
{
dvander@2193
   316
	return SP_ERROR_ABORTED;
dvander@2193
   317
}
dvander@2193
   318
dvander@2193
   319
int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@2193
   320
{
dvander@2193
   321
	return SP_ERROR_ABORTED;
dvander@2193
   322
}
dvander@2193
   323
dvander@2193
   324
int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
dvander@2193
   325
{
dvander@2193
   326
	return SP_ERROR_ABORTED;
dvander@2193
   327
}
dvander@2193
   328
dvander@2193
   329
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@2193
   330
{
dvander@2193
   331
	return SP_ERROR_ABORTED;
dvander@2193
   332
}
dvander@2193
   333
dvander@2193
   334
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@2193
   335
{
dvander@2193
   336
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) 
dvander@2193
   337
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2193
   338
	{
dvander@2193
   339
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   340
	}
dvander@2193
   341
dvander@2193
   342
	if (phys_addr)
dvander@2193
   343
	{
dvander@2193
   344
		*phys_addr = (cell_t *)(m_pPlugin->memory + local_addr);
dvander@2193
   345
	}
dvander@2193
   346
dvander@2193
   347
	return SP_ERROR_NONE;
dvander@2193
   348
}
dvander@2193
   349
dvander@2193
   350
int BaseContext::PushCell(cell_t value)
dvander@2193
   351
{
dvander@2193
   352
	return SP_ERROR_ABORTED;
dvander@2193
   353
}
dvander@2193
   354
dvander@2193
   355
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@2193
   356
{
dvander@2193
   357
	return SP_ERROR_ABORTED;
dvander@2193
   358
}
dvander@2193
   359
dvander@2193
   360
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@2193
   361
{
dvander@2193
   362
	return SP_ERROR_ABORTED;
dvander@2193
   363
}
dvander@2193
   364
dvander@2193
   365
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@2193
   366
{
dvander@2193
   367
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2193
   368
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2193
   369
	{
dvander@2193
   370
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   371
	}
dvander@2193
   372
	*addr = (char *)(m_pPlugin->memory + local_addr);
dvander@2193
   373
dvander@2193
   374
	return SP_ERROR_NONE;
dvander@2193
   375
}
dvander@2193
   376
dvander@2193
   377
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@2193
   378
{
dvander@2193
   379
	return SP_ERROR_ABORTED;
dvander@2193
   380
}
dvander@2193
   381
dvander@2193
   382
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@2193
   383
{
dvander@2193
   384
	char *dest;
dvander@2193
   385
	size_t len;
dvander@2193
   386
dvander@2193
   387
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2193
   388
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2193
   389
	{
dvander@2193
   390
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   391
	}
dvander@2193
   392
dvander@2193
   393
	if (bytes == 0)
dvander@2193
   394
	{
dvander@2193
   395
		return SP_ERROR_NONE;
dvander@2193
   396
	}
dvander@2193
   397
dvander@2193
   398
	len = strlen(source);
dvander@2193
   399
	dest = (char *)(m_pPlugin->memory + local_addr);
dvander@2193
   400
dvander@2193
   401
	if (len >= bytes)
dvander@2193
   402
	{
dvander@2193
   403
		len = bytes - 1;
dvander@2193
   404
	}
dvander@2193
   405
dvander@2193
   406
	memmove(dest, source, len);
dvander@2193
   407
	dest[len] = '\0';
dvander@2193
   408
dvander@2193
   409
	return SP_ERROR_NONE;
dvander@2193
   410
}
dvander@2193
   411
dvander@2193
   412
inline int __CheckValidChar(char *c)
dvander@2193
   413
{
dvander@2193
   414
	int count;
dvander@2193
   415
	int bytecount = 0;
dvander@2193
   416
dvander@2193
   417
	for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@2193
   418
	{
dvander@2193
   419
		c--;
dvander@2193
   420
	}
dvander@2193
   421
dvander@2193
   422
	switch (*c & 0xF0)
dvander@2193
   423
	{
dvander@2193
   424
	case 0xC0:
dvander@2193
   425
	case 0xD0:
dvander@2193
   426
		{
dvander@2193
   427
			bytecount = 2;
dvander@2193
   428
			break;
dvander@2193
   429
		}
dvander@2193
   430
	case 0xE0:
dvander@2193
   431
		{
dvander@2193
   432
			bytecount = 3;
dvander@2193
   433
			break;
dvander@2193
   434
		}
dvander@2193
   435
	case 0xF0:
dvander@2193
   436
		{
dvander@2193
   437
			bytecount = 4;
dvander@2193
   438
			break;
dvander@2193
   439
		}
dvander@2193
   440
	}
dvander@2193
   441
dvander@2193
   442
	if (bytecount != count)
dvander@2193
   443
	{
dvander@2193
   444
		return count;
dvander@2193
   445
	}
dvander@2193
   446
dvander@2193
   447
	return 0;
dvander@2193
   448
}
dvander@2193
   449
dvander@2193
   450
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@2193
   451
{
dvander@2193
   452
	char *dest;
dvander@2193
   453
	size_t len;
dvander@2193
   454
	bool needtocheck = false;
dvander@2193
   455
dvander@2193
   456
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2193
   457
		|| (local_addr < 0)
dvander@2193
   458
		|| ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2193
   459
	{
dvander@2193
   460
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   461
	}
dvander@2193
   462
	
dvander@2193
   463
	if (maxbytes == 0)
dvander@2193
   464
	{
dvander@2193
   465
		return SP_ERROR_NONE;
dvander@2193
   466
	}
dvander@2193
   467
dvander@2193
   468
	len = strlen(source);
dvander@2193
   469
	dest = (char *)(m_pPlugin->memory + local_addr);
dvander@2193
   470
dvander@2193
   471
	if ((size_t)len >= maxbytes)
dvander@2193
   472
	{
dvander@2193
   473
		len = maxbytes - 1;
dvander@2193
   474
		needtocheck = true;
dvander@2193
   475
	}
dvander@2193
   476
dvander@2193
   477
	memmove(dest, source, len);
dvander@2193
   478
	if ((dest[len-1] & 1<<7) && needtocheck)
dvander@2193
   479
	{
dvander@2193
   480
		len -= __CheckValidChar(dest+len-1);
dvander@2193
   481
	}
dvander@2193
   482
	dest[len] = '\0';
dvander@2193
   483
dvander@2193
   484
	if (wrtnbytes)
dvander@2193
   485
	{
dvander@2193
   486
		*wrtnbytes = len;
dvander@2193
   487
	}
dvander@2193
   488
dvander@2193
   489
	return SP_ERROR_NONE;
dvander@2193
   490
}
dvander@2193
   491
dvander@2193
   492
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@2193
   493
{
dvander@2193
   494
	return m_pRuntime->GetFunctionById(func_id);
dvander@2193
   495
}
dvander@2193
   496
dvander@2193
   497
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@2193
   498
{
dvander@2193
   499
	return m_pRuntime->GetFunctionByName(public_name);
dvander@2193
   500
}
dvander@2193
   501
dvander@2193
   502
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@2193
   503
{
dvander@2193
   504
	int err;
dvander@2193
   505
	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@2193
   506
	{
dvander@2193
   507
		return err;
dvander@2193
   508
	}
dvander@2193
   509
dvander@2193
   510
	if ((cell_t *)*addr == m_pNullString)
dvander@2193
   511
	{
dvander@2193
   512
		*addr = NULL;
dvander@2193
   513
	}
dvander@2193
   514
dvander@2193
   515
	return SP_ERROR_NONE;
dvander@2193
   516
}
dvander@2193
   517
dvander@2193
   518
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@2193
   519
{
dvander@2193
   520
	SourceMod::IdentityToken_t *tok;
dvander@2193
   521
dvander@2193
   522
	if (GetKey(1, (void **)&tok))
dvander@2193
   523
	{
dvander@2193
   524
		return tok;
dvander@2193
   525
	}
dvander@2193
   526
dvander@2193
   527
	return NULL;
dvander@2193
   528
}
dvander@2193
   529
dvander@2193
   530
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@2193
   531
{
dvander@2193
   532
	if (type == SP_NULL_VECTOR)
dvander@2193
   533
	{
dvander@2193
   534
		return m_pNullVec;
dvander@2193
   535
	}
dvander@2193
   536
dvander@2193
   537
	return NULL;
dvander@2193
   538
}
dvander@2193
   539
dvander@2193
   540
bool BaseContext::IsInExec()
dvander@2193
   541
{
dvander@2193
   542
	return m_InExec;
dvander@2193
   543
}
dvander@2193
   544
dvander@2193
   545
int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
dvander@2193
   546
{
dvander@2193
   547
	int ir;
dvander@2193
   548
	int serial;
dvander@2193
   549
	cell_t *sp;
dvander@2193
   550
	funcid_t fnid;
dvander@2226
   551
	JitFunction *fn;
dvander@2193
   552
	sp_public_t *pubfunc;
dvander@2193
   553
	cell_t _ignore_result;
dvander@2226
   554
	unsigned int public_id;
dvander@2193
   555
dvander@2193
   556
	fnid = function->GetFunctionID();
dvander@2193
   557
dvander@2193
   558
	if (fnid & 1)
dvander@2226
   559
	{	
dvander@2193
   560
		public_id = fnid >> 1;
dvander@2193
   561
dvander@2193
   562
		if (m_pRuntime->GetPublicByIndex(public_id, &pubfunc) != SP_ERROR_NONE)
dvander@2193
   563
		{
dvander@2193
   564
			return SP_ERROR_NOT_FOUND;
dvander@2193
   565
		}
dvander@2193
   566
	}
dvander@2193
   567
	else
dvander@2193
   568
	{
dvander@2193
   569
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   570
	}
dvander@2193
   571
dvander@2193
   572
	if (m_pRuntime->IsPaused())
dvander@2193
   573
	{
dvander@2193
   574
		return SP_ERROR_NOT_RUNNABLE;
dvander@2193
   575
	}
dvander@2193
   576
dvander@2193
   577
	if ((cell_t)(m_ctx.hp + 16*sizeof(cell_t)) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1))))
dvander@2193
   578
	{
dvander@2193
   579
		return SP_ERROR_STACKLOW;
dvander@2193
   580
	}
dvander@2193
   581
dvander@2193
   582
	if (result == NULL)
dvander@2193
   583
	{
dvander@2193
   584
		result = &_ignore_result;
dvander@2193
   585
	}
dvander@2193
   586
dvander@2193
   587
	/* We got this far.  It's time to start profiling. */
dvander@2193
   588
	
dvander@2193
   589
	if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
dvander@2193
   590
	{
dvander@2193
   591
		serial = m_pPlugin->profiler->OnCallbackBegin(this, pubfunc);
dvander@2193
   592
	}
dvander@2193
   593
dvander@2226
   594
	/* See if we have to compile the callee. */
dvander@2226
   595
	if ((fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL)
dvander@2226
   596
	{
dvander@2226
   597
		uint32_t func_idx;
dvander@2226
   598
dvander@2226
   599
		/* We might not have to - check pcode offset. */
dvander@2226
   600
		if ((func_idx = FuncLookup((CompData *)m_pRuntime->m_pCo, pubfunc->code_offs)) != 0)
dvander@2226
   601
		{
dvander@2226
   602
			fn = m_pRuntime->GetJittedFunction(func_idx);
dvander@2226
   603
			assert(fn != NULL);
dvander@2226
   604
			m_pRuntime->m_PubJitFuncs[public_id] = fn;
dvander@2226
   605
		}
dvander@2226
   606
		else
dvander@2226
   607
		{
dvander@2226
   608
			if ((fn = g_Jit.CompileFunction(m_pRuntime, pubfunc->code_offs, &ir)) == NULL)
dvander@2226
   609
			{
dvander@2226
   610
				return ir;
dvander@2226
   611
			}
dvander@2226
   612
			m_pRuntime->m_PubJitFuncs[public_id] = fn;
dvander@2226
   613
		}
dvander@2226
   614
	}
dvander@2226
   615
dvander@2193
   616
	/* Save our previous state. */
dvander@2193
   617
dvander@2193
   618
	bool save_exec;
dvander@2193
   619
	uint32_t save_n_idx;
dvander@2226
   620
	cell_t save_sp, save_hp, save_rp, save_cip;
dvander@2193
   621
dvander@2193
   622
	save_sp = m_ctx.sp;
dvander@2193
   623
	save_hp = m_ctx.hp;
dvander@2193
   624
	save_exec = m_InExec;
dvander@2193
   625
	save_n_idx = m_ctx.n_idx;
dvander@2226
   626
	save_rp = m_ctx.rp;
dvander@2226
   627
	save_cip = m_ctx.err_cip;
dvander@2193
   628
dvander@2193
   629
	/* Push parameters */
dvander@2193
   630
dvander@2193
   631
	m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
dvander@2193
   632
	sp = (cell_t *)(m_pPlugin->memory + m_ctx.sp);
dvander@2193
   633
dvander@2193
   634
	sp[0] = num_params;
dvander@2193
   635
	for (unsigned int i = 0; i < num_params; i++)
dvander@2193
   636
	{
dvander@2193
   637
		sp[i + 1] = params[i];
dvander@2193
   638
	}
dvander@2193
   639
dvander@2193
   640
	/* Clear internal state */
dvander@2193
   641
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2193
   642
	m_ctx.n_idx = 0;
dvander@2193
   643
	m_MsgCache[0] = '\0';
dvander@2193
   644
	m_CustomMsg = false;
dvander@2214
   645
	m_InExec = true;
dvander@2193
   646
dvander@2226
   647
	/* Start the frame tracer */
dvander@2193
   648
dvander@2226
   649
	ir = g_Jit.InvokeFunction(m_pRuntime, fn, result);
dvander@2193
   650
dvander@2226
   651
	/* Restore some states, stop the frame tracer */
dvander@2193
   652
dvander@2193
   653
	m_InExec = save_exec;
dvander@2193
   654
dvander@2193
   655
	if (ir == SP_ERROR_NONE)
dvander@2193
   656
	{
dvander@2193
   657
		m_ctx.n_err = SP_ERROR_NONE;
dvander@2193
   658
		if (m_ctx.sp != save_sp)
dvander@2193
   659
		{
dvander@2193
   660
			ir = SP_ERROR_STACKLEAK;
dvander@2193
   661
			_SetErrorMessage("Stack leak detected: sp:%d should be %d!", 
dvander@2193
   662
				m_ctx.sp, 
dvander@2193
   663
				save_sp);
dvander@2193
   664
		}
dvander@2193
   665
		if (m_ctx.hp != save_hp)
dvander@2193
   666
		{
dvander@2193
   667
			ir = SP_ERROR_HEAPLEAK;
dvander@2193
   668
			_SetErrorMessage("Heap leak detected: hp:%d should be %d!", 
dvander@2193
   669
				m_ctx.hp, 
dvander@2193
   670
				save_hp);
dvander@2193
   671
		}
dvander@2226
   672
		if (m_ctx.rp != save_rp)
dvander@2226
   673
		{
dvander@2226
   674
			ir = SP_ERROR_STACKLEAK;
dvander@2226
   675
			_SetErrorMessage("Return stack leak detected: rp:%d should be %d!",
dvander@2226
   676
				m_ctx.rp,
dvander@2226
   677
				save_rp);
dvander@2226
   678
		}
dvander@2226
   679
	}
dvander@2226
   680
dvander@2226
   681
	if (ir != SP_ERROR_NONE)
dvander@2226
   682
	{
dvander@2226
   683
		g_engine1.ReportError(m_pRuntime, ir, m_MsgCache, save_rp);
dvander@2193
   684
	}
dvander@2193
   685
dvander@2193
   686
	m_ctx.sp = save_sp;
dvander@2193
   687
	m_ctx.hp = save_hp;
dvander@2226
   688
	m_ctx.rp = save_rp;
dvander@2226
   689
	
dvander@2193
   690
	if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
dvander@2193
   691
	{
dvander@2193
   692
		m_pPlugin->profiler->OnCallbackEnd(serial);
dvander@2193
   693
	}
dvander@2193
   694
dvander@2226
   695
	m_ctx.err_cip = save_cip;
dvander@2193
   696
	m_ctx.n_idx = save_n_idx;
dvander@2193
   697
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2193
   698
	m_MsgCache[0] = '\0';
dvander@2193
   699
	m_CustomMsg = false;
dvander@2193
   700
dvander@2193
   701
	return ir;
dvander@2193
   702
}
dvander@2193
   703
dvander@2193
   704
IPluginRuntime *BaseContext::GetRuntime()
dvander@2193
   705
{
dvander@2193
   706
	return m_pRuntime;
dvander@2193
   707
}
dvander@2193
   708
dvander@2193
   709
DebugInfo::DebugInfo(sp_plugin_t *plugin) : m_pPlugin(plugin)
dvander@2193
   710
{
dvander@2193
   711
}
dvander@2193
   712
dvander@2193
   713
#define USHR(x) ((unsigned int)(x)>>1)
dvander@2193
   714
dvander@2193
   715
int DebugInfo::LookupFile(ucell_t addr, const char **filename)
dvander@2193
   716
{
dvander@2193
   717
	int high, low, mid;
dvander@2193
   718
dvander@2193
   719
	high = m_pPlugin->debug.files_num;
dvander@2193
   720
	low = -1;
dvander@2193
   721
dvander@2193
   722
	while (high - low > 1)
dvander@2193
   723
	{
dvander@2193
   724
		mid = USHR(low + high);
dvander@2226
   725
		if (m_pPlugin->debug.files[mid].addr <= addr)
dvander@2193
   726
		{
dvander@2193
   727
			low = mid;
dvander@2193
   728
		} else {
dvander@2193
   729
			high = mid;
dvander@2193
   730
		}
dvander@2193
   731
	}
dvander@2193
   732
dvander@2193
   733
	if (low == -1)
dvander@2193
   734
	{
dvander@2193
   735
		return SP_ERROR_NOT_FOUND;
dvander@2193
   736
	}
dvander@2193
   737
dvander@2226
   738
	*filename = m_pPlugin->debug.stringbase + m_pPlugin->debug.files[low].name;
dvander@2193
   739
dvander@2193
   740
	return SP_ERROR_NONE;
dvander@2193
   741
}
dvander@2193
   742
dvander@2193
   743
int DebugInfo::LookupFunction(ucell_t addr, const char **name)
dvander@2193
   744
{
dvander@2378
   745
	if (!m_pPlugin->debug.unpacked)
dvander@2193
   746
	{
dvander@2378
   747
		uint32_t max, iter;
dvander@2378
   748
		sp_fdbg_symbol_t *sym;
dvander@2378
   749
		sp_fdbg_arraydim_t *arr;
dvander@2378
   750
		uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols);
dvander@2378
   751
dvander@2378
   752
		max = m_pPlugin->debug.syms_num;
dvander@2378
   753
		for (iter = 0; iter < max; iter++)
dvander@2378
   754
		{
dvander@2378
   755
			sym = (sp_fdbg_symbol_t *)cursor;
dvander@2226
   756
dvander@2378
   757
			if (sym->ident == SP_SYM_FUNCTION
dvander@2378
   758
				&& sym->codestart <= addr 
dvander@2378
   759
				&& sym->codeend > addr)
dvander@2378
   760
			{
dvander@2378
   761
				*name = m_pPlugin->debug.stringbase + sym->name;
dvander@2378
   762
				return SP_ERROR_NONE;
dvander@2378
   763
			}
dvander@2378
   764
dvander@2378
   765
			if (sym->dimcount > 0)
dvander@2378
   766
			{
dvander@2378
   767
				cursor += sizeof(sp_fdbg_symbol_t);
dvander@2378
   768
				arr = (sp_fdbg_arraydim_t *)cursor;
dvander@2378
   769
				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
dvander@2378
   770
				continue;
dvander@2378
   771
			}
dvander@2378
   772
dvander@2378
   773
			cursor += sizeof(sp_fdbg_symbol_t);
dvander@2193
   774
		}
dvander@2226
   775
dvander@2378
   776
		return SP_ERROR_NOT_FOUND;
dvander@2378
   777
	}
dvander@2378
   778
	else
dvander@2378
   779
	{
dvander@2378
   780
		uint32_t max, iter;
dvander@2378
   781
		sp_u_fdbg_symbol_t *sym;
dvander@2378
   782
		sp_u_fdbg_arraydim_t *arr;
dvander@2378
   783
		uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols);
dvander@2378
   784
dvander@2378
   785
		max = m_pPlugin->debug.syms_num;
dvander@2378
   786
		for (iter = 0; iter < max; iter++)
dvander@2226
   787
		{
dvander@2378
   788
			sym = (sp_u_fdbg_symbol_t *)cursor;
dvander@2378
   789
dvander@2378
   790
			if (sym->ident == SP_SYM_FUNCTION
dvander@2378
   791
				&& sym->codestart <= addr 
dvander@2378
   792
				&& sym->codeend > addr)
dvander@2378
   793
			{
dvander@2378
   794
				*name = m_pPlugin->debug.stringbase + sym->name;
dvander@2378
   795
				return SP_ERROR_NONE;
dvander@2378
   796
			}
dvander@2378
   797
dvander@2378
   798
			if (sym->dimcount > 0)
dvander@2378
   799
			{
dvander@2378
   800
				cursor += sizeof(sp_u_fdbg_symbol_t);
dvander@2378
   801
				arr = (sp_u_fdbg_arraydim_t *)cursor;
dvander@2378
   802
				cursor += sizeof(sp_u_fdbg_arraydim_t) * sym->dimcount;
dvander@2378
   803
				continue;
dvander@2378
   804
			}
dvander@2378
   805
dvander@2378
   806
			cursor += sizeof(sp_u_fdbg_symbol_t);
dvander@2226
   807
		}
dvander@2226
   808
dvander@2378
   809
		return SP_ERROR_NOT_FOUND;
dvander@2193
   810
	}
dvander@2193
   811
}
dvander@2193
   812
dvander@2193
   813
int DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
dvander@2193
   814
{
dvander@2193
   815
	int high, low, mid;
dvander@2193
   816
dvander@2193
   817
	high = m_pPlugin->debug.lines_num;
dvander@2193
   818
	low = -1;
dvander@2193
   819
dvander@2193
   820
	while (high - low > 1)
dvander@2193
   821
	{
dvander@2193
   822
		mid = USHR(low + high);
dvander@2226
   823
		if (m_pPlugin->debug.lines[mid].addr <= addr)
dvander@2193
   824
		{
dvander@2193
   825
			low = mid;
dvander@2193
   826
		} else {
dvander@2193
   827
			high = mid;
dvander@2193
   828
		}
dvander@2193
   829
	}
dvander@2193
   830
dvander@2193
   831
	if (low == -1)
dvander@2193
   832
	{
dvander@2193
   833
		return SP_ERROR_NOT_FOUND;
dvander@2193
   834
	}
dvander@2193
   835
dvander@2193
   836
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@2226
   837
	*line = m_pPlugin->debug.lines[low].line + 1;
dvander@2193
   838
dvander@2193
   839
	return SP_ERROR_NONE;
dvander@2193
   840
}
dvander@2193
   841
dvander@2193
   842
#undef USHR
dvander@2193
   843
dvander@2193
   844
int BaseContext::GetLastNativeError()
dvander@2193
   845
{
dvander@2193
   846
	return m_ctx.n_err;
dvander@2193
   847
}
dvander@2193
   848
dvander@2193
   849
cell_t *BaseContext::GetLocalParams()
dvander@2193
   850
{
dvander@2193
   851
	return (cell_t *)(m_pPlugin->memory + m_ctx.frm + (2 * sizeof(cell_t)));
dvander@2193
   852
}
dvander@2193
   853
dvander@2193
   854
void BaseContext::SetKey(int k, void *value)
dvander@2193
   855
{
dvander@2193
   856
	if (k < 1 || k > 4)
dvander@2193
   857
	{
dvander@2193
   858
		return;
dvander@2193
   859
	}
dvander@2193
   860
dvander@2193
   861
	m_keys[k - 1] = value;
dvander@2193
   862
	m_keys_set[k - 1] = true;
dvander@2193
   863
}
dvander@2193
   864
dvander@2193
   865
bool BaseContext::GetKey(int k, void **value)
dvander@2193
   866
{
dvander@2193
   867
	if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
dvander@2193
   868
	{
dvander@2193
   869
		return false;
dvander@2193
   870
	}
dvander@2193
   871
dvander@2193
   872
	*value = m_keys[k - 1];
dvander@2193
   873
dvander@2193
   874
	return true;
dvander@2193
   875
}
dvander@2545
   876
dvander@2545
   877
void BaseContext::ClearLastNativeError()
dvander@2545
   878
{
dvander@2545
   879
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2545
   880
}