core/vm/sp_vm_basecontext.cpp
author David Anderson <dvander@alliedmods.net>
Fri Jun 15 20:23:40 2007 +0000 (2007-06-15)
changeset 938 8e95112b2501
parent 790 9b1474d03470
child 1000 aefbd36eaf91
permissions -rw-r--r--
added a hacky way to get NULL references
ds@763
     1
/**
ds@763
     2
 * vim: set ts=4 :
ds@763
     3
 * ================================================================
ds@763
     4
 * SourcePawn (C)2004-2007 AlliedModders LLC.  All rights reserved.
ds@763
     5
 * ================================================================
ds@763
     6
 *
ds@763
     7
 * This file is not open source and may not be copied without explicit
ds@763
     8
 * written permission of AlliedModders LLC.  This file may not be redistributed 
ds@763
     9
 * in whole or significant part.
ds@763
    10
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
ds@763
    11
 *
ds@763
    12
 * Version: $Id$
ds@763
    13
 */
ds@763
    14
ds@763
    15
#include <string.h>
ds@763
    16
#include <stdarg.h>
ds@763
    17
#include <assert.h>
ds@763
    18
#include <limits.h>
ds@763
    19
#include "sp_vm_api.h"
ds@763
    20
#include "sp_vm_basecontext.h"
ds@763
    21
#include "sp_vm_engine.h"
ds@763
    22
ds@763
    23
#ifdef SOURCEMOD_BUILD
ds@763
    24
#include "Logger.h"
ds@763
    25
#endif
ds@763
    26
ds@763
    27
using namespace SourcePawn;
ds@763
    28
ds@763
    29
extern SourcePawnEngine g_SourcePawn;
ds@763
    30
ds@763
    31
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
ds@763
    32
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
ds@763
    33
ds@763
    34
int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
ds@763
    35
{
ds@763
    36
	g_SourcePawn.RunTracer(ctx, frm, cip);
ds@763
    37
ds@763
    38
	return SP_ERROR_NONE;
ds@763
    39
}
ds@763
    40
ds@763
    41
BaseContext::BaseContext(sp_context_t *_ctx)
ds@763
    42
{
ds@763
    43
	ctx = _ctx;
ds@763
    44
	ctx->context = this;
ds@763
    45
	ctx->dbreak = GlobalDebugBreak;
ds@763
    46
	m_InExec = false;
ds@763
    47
	m_CustomMsg = false;
ds@763
    48
	m_funcsnum = ctx->vmbase->FunctionCount(ctx);
ds@763
    49
#if 0
ds@763
    50
	m_priv_funcs = NULL;
ds@763
    51
#endif
ds@763
    52
	m_pub_funcs = NULL;
ds@763
    53
ds@763
    54
#if 0
ds@763
    55
	/**
ds@763
    56
	 * Note: Since the m_plugin member will never change,
ds@763
    57
	 * it is safe to assume the function count will never change
ds@763
    58
	 */
ds@763
    59
	if (m_funcsnum && m_priv_funcs == NULL)
ds@763
    60
	{
ds@763
    61
		m_priv_funcs = new CFunction *[m_funcsnum];
ds@763
    62
		memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
ds@763
    63
	} else {
ds@763
    64
		m_priv_funcs = NULL;
ds@763
    65
	}
ds@763
    66
#endif
ds@763
    67
ds@763
    68
	if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
ds@763
    69
	{
ds@763
    70
		m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
ds@763
    71
		memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
ds@763
    72
	} else {
ds@763
    73
		m_pub_funcs = NULL;
ds@763
    74
	}
dvander@938
    75
dvander@938
    76
	/* Initialize the null references */
dvander@938
    77
	uint32_t index;
dvander@938
    78
	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@938
    79
	{
dvander@938
    80
		sp_pubvar_t *pubvar;
dvander@938
    81
		GetPubvarByIndex(index, &pubvar);
dvander@938
    82
		m_pNullVec = pubvar->offs;
dvander@938
    83
	} else {
dvander@938
    84
		m_pNullVec = NULL;
dvander@938
    85
	}
ds@763
    86
}
ds@763
    87
ds@763
    88
void BaseContext::FlushFunctionCache()
ds@763
    89
{
ds@763
    90
	if (m_pub_funcs)
ds@763
    91
	{
ds@763
    92
		for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
ds@763
    93
		{
ds@763
    94
			delete m_pub_funcs[i];
ds@763
    95
			m_pub_funcs[i] = NULL;
ds@763
    96
		}
ds@763
    97
	}
ds@763
    98
ds@763
    99
#if 0
ds@763
   100
	if (m_priv_funcs)
ds@763
   101
	{
ds@763
   102
		for (unsigned int i=0; i<m_funcsnum; i++)
ds@763
   103
		{
ds@763
   104
			delete m_priv_funcs[i];
ds@763
   105
			m_priv_funcs[i] = NULL;
ds@763
   106
		}
ds@763
   107
	}
ds@763
   108
#endif
ds@763
   109
}
ds@763
   110
ds@763
   111
void BaseContext::RefreshFunctionCache()
ds@763
   112
{
ds@763
   113
	if (m_pub_funcs)
ds@763
   114
	{
ds@763
   115
		sp_public_t *pub;
ds@763
   116
		for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
ds@763
   117
		{
ds@763
   118
			if (!m_pub_funcs[i])
ds@763
   119
			{
ds@763
   120
				continue;
ds@763
   121
			}
ds@763
   122
			if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
ds@763
   123
			{
ds@763
   124
				continue;
ds@763
   125
			}
ds@763
   126
			m_pub_funcs[i]->Set(pub->code_offs, this);
ds@763
   127
		}
ds@763
   128
	}
ds@763
   129
ds@763
   130
#if 0
ds@763
   131
	if (m_priv_funcs)
ds@763
   132
	{
ds@763
   133
		for (unsigned int i=0; i<m_funcsnum; i++)
ds@763
   134
		{
ds@763
   135
			if (!m_priv_funcs[i])
ds@763
   136
			{
ds@763
   137
				continue;
ds@763
   138
			}
ds@763
   139
			g_pVM->
ds@763
   140
		}
ds@763
   141
	}
ds@763
   142
#endif
ds@763
   143
}
ds@763
   144
ds@763
   145
BaseContext::~BaseContext()
ds@763
   146
{
ds@763
   147
	FlushFunctionCache();
ds@763
   148
	delete [] m_pub_funcs;
ds@763
   149
	m_pub_funcs = NULL;
ds@763
   150
#if 0
ds@763
   151
	delete [] m_priv_funcs;
ds@763
   152
	m_priv_funcs = NULL;
ds@763
   153
#endif
ds@763
   154
}
ds@763
   155
ds@763
   156
void BaseContext::SetContext(sp_context_t *_ctx)
ds@763
   157
{
ds@763
   158
	if (!_ctx)
ds@763
   159
	{
ds@763
   160
		return;
ds@763
   161
	}
ds@763
   162
	ctx = _ctx;
ds@763
   163
	ctx->context = this;
ds@763
   164
	ctx->dbreak = GlobalDebugBreak;
ds@763
   165
	RefreshFunctionCache();
ds@763
   166
}
ds@763
   167
ds@763
   168
IVirtualMachine *BaseContext::GetVirtualMachine()
ds@763
   169
{
ds@763
   170
	return (IVirtualMachine *)ctx->vmbase;
ds@763
   171
}
ds@763
   172
ds@763
   173
sp_context_t *BaseContext::GetContext()
ds@763
   174
{
ds@763
   175
	return ctx;
ds@763
   176
}
ds@763
   177
ds@763
   178
bool BaseContext::IsDebugging()
ds@763
   179
{
ds@763
   180
	return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
ds@763
   181
}
ds@763
   182
ds@763
   183
int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
ds@763
   184
{
ds@763
   185
	if (!IsDebugging())
ds@763
   186
	{
ds@763
   187
		return SP_ERROR_NOTDEBUGGING;
ds@763
   188
	}
ds@763
   189
ds@763
   190
	*oldpfn = ctx->dbreak;
ds@763
   191
	ctx->dbreak = newpfn;
ds@763
   192
ds@763
   193
	return SP_ERROR_NONE;
ds@763
   194
}
ds@763
   195
ds@763
   196
IPluginDebugInfo *BaseContext::GetDebugInfo()
ds@763
   197
{
ds@763
   198
	return this;
ds@763
   199
}
ds@763
   200
ds@763
   201
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
ds@763
   202
{
ds@763
   203
	if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
ds@763
   204
	{
ds@763
   205
		return SP_ERROR_NOT_RUNNABLE;
ds@763
   206
	}
ds@763
   207
dvander@790
   208
	/* tada, prevent a crash */
dvander@790
   209
	cell_t _ignore_result;
dvander@790
   210
	if (!result)
dvander@790
   211
	{
dvander@790
   212
		result = &_ignore_result;
dvander@790
   213
	}
dvander@790
   214
ds@763
   215
	IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
ds@763
   216
ds@763
   217
	uint32_t pushcount = ctx->pushcount;
ds@763
   218
	int err;
ds@763
   219
ds@763
   220
	PushCell(pushcount++);
ds@763
   221
	ctx->pushcount = 0;
ds@763
   222
ds@763
   223
	cell_t save_sp = ctx->sp;
ds@763
   224
	cell_t save_hp = ctx->hp;
ds@763
   225
	uint32_t n_idx = ctx->n_idx;
ds@763
   226
ds@763
   227
	bool wasExec = m_InExec;
ds@763
   228
ds@763
   229
	/* Clear the error state, if any */
ds@763
   230
	ctx->n_err = SP_ERROR_NONE;
ds@763
   231
	ctx->n_idx = 0;
ds@763
   232
	m_InExec = true;
ds@763
   233
	m_MsgCache[0] = '\0';
ds@763
   234
	m_CustomMsg = false;
ds@763
   235
ds@763
   236
	g_SourcePawn.PushTracer(ctx);
ds@763
   237
ds@763
   238
	err = vm->ContextExecute(ctx, code_addr, result);
ds@763
   239
ds@763
   240
	m_InExec = wasExec;
ds@763
   241
ds@763
   242
	/**
ds@763
   243
	 * :TODO: Calling from a plugin in here will erase the cached message...
ds@763
   244
	 * Should that be documented?
ds@763
   245
	 */
ds@763
   246
	g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
ds@763
   247
ds@763
   248
#if 1//defined _DEBUG
ds@763
   249
	//:TODO: debug code for leak detection, remove before the release?
ds@763
   250
	if (err == SP_ERROR_NONE)
ds@763
   251
	{
ds@763
   252
		if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp)
ds@763
   253
		{
ds@763
   254
			const char *name;
ds@763
   255
			ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
ds@763
   256
			g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name);
ds@763
   257
		}
ds@763
   258
		if (ctx->hp != save_hp)
ds@763
   259
		{
ds@763
   260
			const char *name;
ds@763
   261
			ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
ds@763
   262
			g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name);
ds@763
   263
		}
ds@763
   264
		//assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp);
ds@763
   265
		//assert(ctx->hp == save_hp);
ds@763
   266
	}
ds@763
   267
#endif
ds@763
   268
	if (err != SP_ERROR_NONE)
ds@763
   269
	{
ds@763
   270
		ctx->sp = save_sp;
ds@763
   271
		ctx->hp = save_hp;
ds@763
   272
	}
ds@763
   273
ds@763
   274
	ctx->n_idx = n_idx;
ds@763
   275
ds@763
   276
	return err;
ds@763
   277
}
ds@763
   278
ds@763
   279
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
ds@763
   280
{
ds@763
   281
	m_CustomMsg = true;
ds@763
   282
ds@763
   283
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
ds@763
   284
}
ds@763
   285
ds@763
   286
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
ds@763
   287
{
ds@763
   288
	if (!m_InExec)
ds@763
   289
	{
ds@763
   290
		return 0;
ds@763
   291
	}
ds@763
   292
ds@763
   293
	ctx->n_err = error;
ds@763
   294
	
ds@763
   295
	if (msg)
ds@763
   296
	{
ds@763
   297
		va_list ap;
ds@763
   298
		va_start(ap, msg);
ds@763
   299
		SetErrorMessage(msg, ap);
ds@763
   300
		va_end(ap);
ds@763
   301
	}
ds@763
   302
ds@763
   303
	return 0;
ds@763
   304
}
ds@763
   305
ds@763
   306
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
ds@763
   307
{
ds@763
   308
	if (!m_InExec)
ds@763
   309
	{
ds@763
   310
		return 0;
ds@763
   311
	}
ds@763
   312
ds@763
   313
	ctx->n_err = SP_ERROR_NATIVE;
ds@763
   314
ds@763
   315
	if (msg)
ds@763
   316
	{
ds@763
   317
		va_list ap;
ds@763
   318
		va_start(ap, msg);
ds@763
   319
		SetErrorMessage(msg, ap);
ds@763
   320
		va_end(ap);
ds@763
   321
	}
ds@763
   322
ds@763
   323
	return 0;
ds@763
   324
}
ds@763
   325
ds@763
   326
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
ds@763
   327
{
ds@763
   328
	cell_t *addr;
ds@763
   329
	ucell_t realmem;
ds@763
   330
ds@763
   331
#if 0
ds@763
   332
	if (cells > CELLBOUNDMAX)
ds@763
   333
	{
ds@763
   334
		return SP_ERROR_ARAM;
ds@763
   335
	}
ds@763
   336
#else
ds@763
   337
	assert(cells < CELLBOUNDMAX);
ds@763
   338
#endif
ds@763
   339
ds@763
   340
	realmem = cells * sizeof(cell_t);
ds@763
   341
ds@763
   342
	/**
ds@763
   343
	 * Check if the space between the heap and stack is sufficient.
ds@763
   344
	 */
ds@763
   345
	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
ds@763
   346
	{
ds@763
   347
		return SP_ERROR_HEAPLOW;
ds@763
   348
	}
ds@763
   349
ds@763
   350
	addr = (cell_t *)(ctx->memory + ctx->hp);
ds@763
   351
	/* store size of allocation in cells */
ds@763
   352
	*addr = (cell_t)cells;
ds@763
   353
	addr++;
ds@763
   354
	ctx->hp += sizeof(cell_t);
ds@763
   355
ds@763
   356
	*local_addr = ctx->hp;
ds@763
   357
ds@763
   358
	if (phys_addr)
ds@763
   359
	{
ds@763
   360
		*phys_addr = addr;
ds@763
   361
	}
ds@763
   362
ds@763
   363
	ctx->hp += realmem;
ds@763
   364
ds@763
   365
	return SP_ERROR_NONE;
ds@763
   366
}
ds@763
   367
ds@763
   368
int BaseContext::HeapPop(cell_t local_addr)
ds@763
   369
{
ds@763
   370
	cell_t cellcount;
ds@763
   371
	cell_t *addr;
ds@763
   372
ds@763
   373
	/* check the bounds of this address */
ds@763
   374
	local_addr -= sizeof(cell_t);
ds@763
   375
	if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
ds@763
   376
	{
ds@763
   377
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   378
	}
ds@763
   379
ds@763
   380
	addr = (cell_t *)(ctx->memory + local_addr);
ds@763
   381
	cellcount = (*addr) * sizeof(cell_t);
ds@763
   382
	/* check if this memory count looks valid */
ds@763
   383
	if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
ds@763
   384
	{
ds@763
   385
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   386
	}
ds@763
   387
ds@763
   388
	ctx->hp = local_addr;
ds@763
   389
ds@763
   390
	return SP_ERROR_NONE;
ds@763
   391
}
ds@763
   392
ds@763
   393
ds@763
   394
int BaseContext::HeapRelease(cell_t local_addr)
ds@763
   395
{
ds@763
   396
	if (local_addr < ctx->heap_base)
ds@763
   397
	{
ds@763
   398
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   399
	}
ds@763
   400
ds@763
   401
	ctx->hp = local_addr - sizeof(cell_t);
ds@763
   402
ds@763
   403
	return SP_ERROR_NONE;
ds@763
   404
}
ds@763
   405
ds@763
   406
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
ds@763
   407
{
ds@763
   408
	int high;
ds@763
   409
ds@763
   410
	high = ctx->plugin->info.natives_num - 1;
ds@763
   411
ds@763
   412
	for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
ds@763
   413
	{
ds@763
   414
		if (strcmp(ctx->natives[i].name, name) == 0)
ds@763
   415
		{
ds@763
   416
			if (index)
ds@763
   417
			{
ds@763
   418
				*index = i;
ds@763
   419
			}
ds@763
   420
			return SP_ERROR_NONE;
ds@763
   421
		}
ds@763
   422
	}
ds@763
   423
ds@763
   424
	return SP_ERROR_NOT_FOUND;
ds@763
   425
}
ds@763
   426
ds@763
   427
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
ds@763
   428
{
ds@763
   429
	if (index >= ctx->plugin->info.natives_num)
ds@763
   430
	{
ds@763
   431
		return SP_ERROR_INDEX;
ds@763
   432
	}
ds@763
   433
ds@763
   434
	if (native)
ds@763
   435
	{
ds@763
   436
		*native = &(ctx->natives[index]);
ds@763
   437
	}
ds@763
   438
ds@763
   439
	return SP_ERROR_NONE;
ds@763
   440
}
ds@763
   441
ds@763
   442
ds@763
   443
uint32_t BaseContext::GetNativesNum()
ds@763
   444
{
ds@763
   445
	return ctx->plugin->info.natives_num;
ds@763
   446
}
ds@763
   447
ds@763
   448
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
ds@763
   449
{
ds@763
   450
	int diff, high, low;
ds@763
   451
	uint32_t mid;
ds@763
   452
ds@763
   453
	high = ctx->plugin->info.publics_num - 1;
ds@763
   454
	low = 0;
ds@763
   455
ds@763
   456
	while (low <= high)
ds@763
   457
	{
ds@763
   458
		mid = (low + high) / 2;
ds@763
   459
		diff = strcmp(ctx->publics[mid].name, name);
ds@763
   460
		if (diff == 0)
ds@763
   461
		{
ds@763
   462
			if (index)
ds@763
   463
			{
ds@763
   464
				*index = mid;
ds@763
   465
			}
ds@763
   466
			return SP_ERROR_NONE;
ds@763
   467
		} else if (diff < 0) {
ds@763
   468
			low = mid + 1;
ds@763
   469
		} else {
ds@763
   470
			high = mid - 1;
ds@763
   471
		}
ds@763
   472
	}
ds@763
   473
ds@763
   474
	return SP_ERROR_NOT_FOUND;
ds@763
   475
}
ds@763
   476
ds@763
   477
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
ds@763
   478
{
ds@763
   479
	if (index >= ctx->plugin->info.publics_num)
ds@763
   480
	{
ds@763
   481
		return SP_ERROR_INDEX;
ds@763
   482
	}
ds@763
   483
ds@763
   484
	if (pblic)
ds@763
   485
	{
ds@763
   486
		*pblic = &(ctx->publics[index]);
ds@763
   487
	}
ds@763
   488
ds@763
   489
	return SP_ERROR_NONE;
ds@763
   490
}
ds@763
   491
ds@763
   492
uint32_t BaseContext::GetPublicsNum()
ds@763
   493
{
ds@763
   494
	return ctx->plugin->info.publics_num;
ds@763
   495
}
ds@763
   496
ds@763
   497
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
ds@763
   498
{
ds@763
   499
	if (index >= ctx->plugin->info.pubvars_num)
ds@763
   500
	{
ds@763
   501
		return SP_ERROR_INDEX;
ds@763
   502
	}
ds@763
   503
ds@763
   504
	if (pubvar)
ds@763
   505
	{
ds@763
   506
		*pubvar = &(ctx->pubvars[index]);
ds@763
   507
	}
ds@763
   508
ds@763
   509
	return SP_ERROR_NONE;
ds@763
   510
}
ds@763
   511
ds@763
   512
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
ds@763
   513
{
ds@763
   514
	int diff, high, low;
ds@763
   515
	uint32_t mid;
ds@763
   516
ds@763
   517
	high = ctx->plugin->info.pubvars_num - 1;
ds@763
   518
	low = 0;
ds@763
   519
ds@763
   520
	while (low <= high)
ds@763
   521
	{
ds@763
   522
		mid = (low + high) / 2;
ds@763
   523
		diff = strcmp(ctx->pubvars[mid].name, name);
ds@763
   524
		if (diff == 0)
ds@763
   525
		{
ds@763
   526
			if (index)
ds@763
   527
			{
ds@763
   528
				*index = mid;
ds@763
   529
			}
ds@763
   530
			return SP_ERROR_NONE;
ds@763
   531
		} else if (diff < 0) {
ds@763
   532
			low = mid + 1;
ds@763
   533
		} else {
ds@763
   534
			high = mid - 1;
ds@763
   535
		}
ds@763
   536
	}
ds@763
   537
ds@763
   538
	return SP_ERROR_NOT_FOUND;
ds@763
   539
}
ds@763
   540
ds@763
   541
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
ds@763
   542
{
ds@763
   543
	if (index >= ctx->plugin->info.pubvars_num)
ds@763
   544
	{
ds@763
   545
		return SP_ERROR_INDEX;
ds@763
   546
	}
ds@763
   547
ds@763
   548
	*local_addr = ctx->plugin->info.pubvars[index].address;
ds@763
   549
	*phys_addr = ctx->pubvars[index].offs;
ds@763
   550
ds@763
   551
	return SP_ERROR_NONE;
ds@763
   552
}
ds@763
   553
ds@763
   554
uint32_t BaseContext::GetPubVarsNum()
ds@763
   555
{
ds@763
   556
	return ctx->plugin->info.pubvars_num;
ds@763
   557
}
ds@763
   558
ds@763
   559
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
ds@763
   560
{
ds@763
   561
	uint32_t i, j, max;
ds@763
   562
ds@763
   563
	max = ctx->plugin->info.natives_num;
ds@763
   564
ds@763
   565
	for (i=0; i<max; i++)
ds@763
   566
	{
ds@763
   567
		if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
ds@763
   568
		{
ds@763
   569
			continue;
ds@763
   570
		}
ds@763
   571
ds@763
   572
		for (j=0; (natives[j].name) && (!num || j<num); j++)
ds@763
   573
		{
ds@763
   574
			if (!strcmp(ctx->natives[i].name, natives[j].name))
ds@763
   575
			{
ds@763
   576
				ctx->natives[i].pfn = natives[j].func;
ds@763
   577
				ctx->natives[i].status = SP_NATIVE_BOUND;
ds@763
   578
			}
ds@763
   579
		}
ds@763
   580
	}
ds@763
   581
ds@763
   582
	return SP_ERROR_NONE;
ds@763
   583
}
ds@763
   584
ds@763
   585
int BaseContext::BindNative(const sp_nativeinfo_t *native)
ds@763
   586
{
ds@763
   587
	uint32_t index;
ds@763
   588
	int err;
ds@763
   589
ds@763
   590
	if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
ds@763
   591
	{
ds@763
   592
		return err;
ds@763
   593
	}
ds@763
   594
ds@763
   595
	ctx->natives[index].pfn = native->func;
ds@763
   596
	ctx->natives[index].status = SP_NATIVE_BOUND;
ds@763
   597
ds@763
   598
	return SP_ERROR_NONE;
ds@763
   599
}
ds@763
   600
ds@763
   601
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
ds@763
   602
{
ds@763
   603
	uint32_t nativesnum, i;
ds@763
   604
ds@763
   605
	nativesnum = ctx->plugin->info.natives_num;
ds@763
   606
ds@763
   607
	for (i=0; i<nativesnum; i++)
ds@763
   608
	{
ds@763
   609
		if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
ds@763
   610
		{
ds@763
   611
			ctx->natives[i].pfn = native;
ds@763
   612
			ctx->natives[i].status = SP_NATIVE_BOUND;
ds@763
   613
		}
ds@763
   614
	}
ds@763
   615
ds@763
   616
	return SP_ERROR_NONE;
ds@763
   617
}
ds@763
   618
ds@763
   619
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
ds@763
   620
{
ds@763
   621
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
ds@763
   622
	{
ds@763
   623
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   624
	}
ds@763
   625
ds@763
   626
	if (phys_addr)
ds@763
   627
	{
ds@763
   628
		*phys_addr = (cell_t *)(ctx->memory + local_addr);
ds@763
   629
	}
ds@763
   630
ds@763
   631
	return SP_ERROR_NONE;
ds@763
   632
}
ds@763
   633
ds@763
   634
int BaseContext::PushCell(cell_t value)
ds@763
   635
{
ds@763
   636
	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
ds@763
   637
	{
ds@763
   638
		return SP_ERROR_STACKLOW;
ds@763
   639
	}
ds@763
   640
ds@763
   641
	ctx->sp -= sizeof(cell_t);
ds@763
   642
	*(cell_t *)(ctx->memory + ctx->sp) = value;
ds@763
   643
	ctx->pushcount++;
ds@763
   644
ds@763
   645
	return SP_ERROR_NONE;
ds@763
   646
}
ds@763
   647
ds@763
   648
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
ds@763
   649
{
ds@763
   650
	unsigned int i;
ds@763
   651
	int err;
ds@763
   652
ds@763
   653
	for (i=0; i<numcells; i++)
ds@763
   654
	{
ds@763
   655
		if ((err = PushCell(array[i])) != SP_ERROR_NONE)
ds@763
   656
		{
ds@763
   657
			ctx->sp += (cell_t)(i * sizeof(cell_t));
ds@763
   658
			ctx->pushcount -= i;
ds@763
   659
			return err;
ds@763
   660
		}
ds@763
   661
	}
ds@763
   662
ds@763
   663
	return SP_ERROR_NONE;
ds@763
   664
}
ds@763
   665
ds@763
   666
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
ds@763
   667
{
ds@763
   668
	cell_t *ph_addr;
ds@763
   669
	int err;
ds@763
   670
ds@763
   671
	if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
ds@763
   672
	{
ds@763
   673
		return err;
ds@763
   674
	}
ds@763
   675
ds@763
   676
	memcpy(ph_addr, array, numcells * sizeof(cell_t));
ds@763
   677
ds@763
   678
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
ds@763
   679
	{
ds@763
   680
		HeapRelease(*local_addr);
ds@763
   681
		return err;
ds@763
   682
	}
ds@763
   683
ds@763
   684
	if (phys_addr)
ds@763
   685
	{
ds@763
   686
		*phys_addr = ph_addr;
ds@763
   687
	}
ds@763
   688
ds@763
   689
	return SP_ERROR_NONE;
ds@763
   690
}
ds@763
   691
ds@763
   692
int BaseContext::LocalToString(cell_t local_addr, char **addr)
ds@763
   693
{
ds@763
   694
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
ds@763
   695
	{
ds@763
   696
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   697
	}
ds@763
   698
	*addr = (char *)(ctx->memory + local_addr);
ds@763
   699
ds@763
   700
	return SP_ERROR_NONE;
ds@763
   701
}
ds@763
   702
ds@763
   703
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
ds@763
   704
{
ds@763
   705
	char *ph_addr;
ds@763
   706
	int err;
ds@763
   707
	unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
ds@763
   708
ds@763
   709
	if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
ds@763
   710
	{
ds@763
   711
		return err;
ds@763
   712
	}
ds@763
   713
ds@763
   714
	memcpy(ph_addr, string, len);
ds@763
   715
	ph_addr[len] = '\0';
ds@763
   716
ds@763
   717
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
ds@763
   718
	{
ds@763
   719
		HeapRelease(*local_addr);
ds@763
   720
		return err;
ds@763
   721
	}
ds@763
   722
ds@763
   723
	if (phys_addr)
ds@763
   724
	{
ds@763
   725
		*phys_addr = ph_addr;
ds@763
   726
	}
ds@763
   727
ds@763
   728
	return SP_ERROR_NONE;
ds@763
   729
}
ds@763
   730
ds@763
   731
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
ds@763
   732
{
ds@763
   733
	char *dest;
ds@763
   734
	size_t len;
ds@763
   735
ds@763
   736
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
ds@763
   737
	{
ds@763
   738
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   739
	}
ds@763
   740
ds@763
   741
	if (bytes == 0)
ds@763
   742
	{
ds@763
   743
		return SP_ERROR_NONE;
ds@763
   744
	}
ds@763
   745
ds@763
   746
	len = strlen(source);
ds@763
   747
	dest = (char *)(ctx->memory + local_addr);
ds@763
   748
ds@763
   749
	if (len >= bytes)
ds@763
   750
	{
ds@763
   751
		len = bytes - 1;
ds@763
   752
	}
ds@763
   753
ds@763
   754
	memcpy(dest, source, len);
ds@763
   755
	dest[len] = '\0';
ds@763
   756
ds@763
   757
	return SP_ERROR_NONE;
ds@763
   758
}
ds@763
   759
ds@763
   760
inline int __CheckValidChar(char *c)
ds@763
   761
{
ds@763
   762
	int count;
ds@763
   763
	int bytecount = 0;
ds@763
   764
ds@763
   765
	for (count=1; (*c & 0xC0) == 0x80; count++)
ds@763
   766
	{
ds@763
   767
		c--;
ds@763
   768
	}
ds@763
   769
ds@763
   770
	switch (*c & 0xF0)
ds@763
   771
	{
ds@763
   772
	case 0xC0:
ds@763
   773
	case 0xD0:
ds@763
   774
		{
ds@763
   775
			bytecount = 2;
ds@763
   776
			break;
ds@763
   777
		}
ds@763
   778
	case 0xE0:
ds@763
   779
		{
ds@763
   780
			bytecount = 3;
ds@763
   781
			break;
ds@763
   782
		}
ds@763
   783
	case 0xF0:
ds@763
   784
		{
ds@763
   785
			bytecount = 4;
ds@763
   786
			break;
ds@763
   787
		}
ds@763
   788
	}
ds@763
   789
ds@763
   790
	if (bytecount != count)
ds@763
   791
	{
ds@763
   792
		return count;
ds@763
   793
	}
ds@763
   794
ds@763
   795
	return 0;
ds@763
   796
}
ds@763
   797
ds@763
   798
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
ds@763
   799
{
ds@763
   800
	char *dest;
ds@763
   801
	size_t len;
ds@763
   802
	bool needtocheck = false;
ds@763
   803
ds@763
   804
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
ds@763
   805
	{
ds@763
   806
		return SP_ERROR_INVALID_ADDRESS;
ds@763
   807
	}
ds@763
   808
	
ds@763
   809
	if (maxbytes == 0)
ds@763
   810
	{
ds@763
   811
		return SP_ERROR_NONE;
ds@763
   812
	}
ds@763
   813
ds@763
   814
	len = strlen(source);
ds@763
   815
	dest = (char *)(ctx->memory + local_addr);
ds@763
   816
ds@763
   817
	if ((size_t)len >= maxbytes)
ds@763
   818
	{
ds@763
   819
		len = maxbytes - 1;
ds@763
   820
		needtocheck = true;
ds@763
   821
	}
ds@763
   822
ds@763
   823
	memcpy(dest, source, len);
ds@763
   824
	if ((dest[len-1] & 1<<7) && needtocheck)
ds@763
   825
	{
ds@763
   826
		len -= __CheckValidChar(dest+len-1);
ds@763
   827
	}
ds@763
   828
	dest[len] = '\0';
ds@763
   829
ds@763
   830
	if (wrtnbytes)
ds@763
   831
	{
ds@763
   832
		*wrtnbytes = len;
ds@763
   833
	}
ds@763
   834
ds@763
   835
	return SP_ERROR_NONE;
ds@763
   836
}
ds@763
   837
ds@763
   838
#define USHR(x) ((unsigned int)(x)>>1)
ds@763
   839
ds@763
   840
int BaseContext::LookupFile(ucell_t addr, const char **filename)
ds@763
   841
{
ds@763
   842
	int high, low, mid;
ds@763
   843
ds@763
   844
	high = ctx->plugin->debug.files_num;
ds@763
   845
	low = -1;
ds@763
   846
ds@763
   847
	while (high - low > 1)
ds@763
   848
	{
ds@763
   849
		mid = USHR(low + high);
ds@763
   850
		if (ctx->files[mid].addr <= addr)
ds@763
   851
		{
ds@763
   852
			low = mid;
ds@763
   853
		} else {
ds@763
   854
			high = mid;
ds@763
   855
		}
ds@763
   856
	}
ds@763
   857
ds@763
   858
	if (low == -1)
ds@763
   859
	{
ds@763
   860
		return SP_ERROR_NOT_FOUND;
ds@763
   861
	}
ds@763
   862
ds@763
   863
	*filename = ctx->files[low].name;
ds@763
   864
ds@763
   865
	return SP_ERROR_NONE;
ds@763
   866
}
ds@763
   867
ds@763
   868
int BaseContext::LookupFunction(ucell_t addr, const char **name)
ds@763
   869
{
ds@763
   870
	uint32_t iter, max = ctx->plugin->debug.syms_num;
ds@763
   871
ds@763
   872
	for (iter=0; iter<max; iter++)
ds@763
   873
	{
ds@763
   874
		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
ds@763
   875
			&& (ctx->symbols[iter].codestart <= addr) 
ds@763
   876
			&& (ctx->symbols[iter].codeend > addr))
ds@763
   877
		{
ds@763
   878
			break;
ds@763
   879
		}
ds@763
   880
	}
ds@763
   881
ds@763
   882
	if (iter >= max)
ds@763
   883
	{
ds@763
   884
		return SP_ERROR_NOT_FOUND;
ds@763
   885
	}
ds@763
   886
ds@763
   887
	*name = ctx->symbols[iter].name;
ds@763
   888
ds@763
   889
	return SP_ERROR_NONE;
ds@763
   890
}
ds@763
   891
ds@763
   892
int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
ds@763
   893
{
ds@763
   894
	int high, low, mid;
ds@763
   895
ds@763
   896
	high = ctx->plugin->debug.lines_num;
ds@763
   897
	low = -1;
ds@763
   898
ds@763
   899
	while (high - low > 1)
ds@763
   900
	{
ds@763
   901
		mid = USHR(low + high);
ds@763
   902
		if (ctx->lines[mid].addr <= addr)
ds@763
   903
		{
ds@763
   904
			low = mid;
ds@763
   905
		} else {
ds@763
   906
			high = mid;
ds@763
   907
		}
ds@763
   908
	}
ds@763
   909
ds@763
   910
	if (low == -1)
ds@763
   911
	{
ds@763
   912
		return SP_ERROR_NOT_FOUND;
ds@763
   913
	}
ds@763
   914
ds@763
   915
	/* Since the CIP occurs BEFORE the line, we have to add one */
ds@763
   916
	*line = ctx->lines[low].line + 1;
ds@763
   917
ds@763
   918
	return SP_ERROR_NONE;
ds@763
   919
}
ds@763
   920
ds@763
   921
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
ds@763
   922
{
ds@763
   923
	CFunction *pFunc = NULL;
ds@763
   924
ds@763
   925
	if (func_id & 1)
ds@763
   926
	{
ds@763
   927
		func_id >>= 1;
ds@763
   928
		if (func_id >= ctx->plugin->info.publics_num)
ds@763
   929
		{
ds@763
   930
			return NULL;
ds@763
   931
		}
ds@763
   932
		pFunc = m_pub_funcs[func_id];
ds@763
   933
		if (!pFunc)
ds@763
   934
		{
ds@763
   935
			m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this);
ds@763
   936
			pFunc = m_pub_funcs[func_id];
ds@763
   937
		} else if (pFunc->IsInvalidated()) {
ds@763
   938
			pFunc->Set(ctx->publics[func_id].code_offs, this);
ds@763
   939
		}
ds@763
   940
	} else {
ds@763
   941
		/* :TODO: currently not used */
ds@763
   942
#if 0
ds@763
   943
		func_id >>= 1;
ds@763
   944
		unsigned int index;
ds@763
   945
		if (!g_pVM->FunctionLookup(ctx, func_id, &index))
ds@763
   946
		{
ds@763
   947
			return NULL;
ds@763
   948
		}
ds@763
   949
		pFunc = m_priv_funcs[func_id];
ds@763
   950
		if (!pFunc)
ds@763
   951
		{
ds@763
   952
			m_priv_funcs[func_id] = new CFunction(save, this);
ds@763
   953
			pFunc = m_priv_funcs[func_id];
ds@763
   954
		}
ds@763
   955
#endif
ds@763
   956
		assert(false);
ds@763
   957
	}
ds@763
   958
ds@763
   959
	return pFunc;
ds@763
   960
}
ds@763
   961
ds@763
   962
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
ds@763
   963
{
ds@763
   964
	uint32_t index;
ds@763
   965
ds@763
   966
	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
ds@763
   967
	{
ds@763
   968
		return NULL;
ds@763
   969
	}
ds@763
   970
ds@763
   971
	CFunction *pFunc = m_pub_funcs[index];
ds@763
   972
	if (!pFunc)
ds@763
   973
	{
ds@763
   974
		sp_public_t *pub = NULL;
ds@763
   975
		GetPublicByIndex(index, &pub);
ds@763
   976
		if (pub)
ds@763
   977
		{
ds@763
   978
			m_pub_funcs[index] = new CFunction(pub->code_offs, this);
ds@763
   979
		}
ds@763
   980
		pFunc = m_pub_funcs[index];
ds@763
   981
	} else if (pFunc->IsInvalidated()) {
ds@763
   982
		sp_public_t *pub = NULL;
ds@763
   983
		GetPublicByIndex(index, &pub);
ds@763
   984
		if (pub)
ds@763
   985
		{
ds@763
   986
			pFunc->Set(pub->code_offs, this);
ds@763
   987
		} else {
ds@763
   988
			pFunc = NULL;
ds@763
   989
		}
ds@763
   990
	}
ds@763
   991
ds@763
   992
	return pFunc;
ds@763
   993
}
ds@763
   994
ds@763
   995
#if defined SOURCEMOD_BUILD
ds@763
   996
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
ds@763
   997
{
ds@763
   998
	return m_pToken;
ds@763
   999
}
ds@763
  1000
ds@763
  1001
void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
ds@763
  1002
{
ds@763
  1003
	m_pToken = token;
ds@763
  1004
}
dvander@938
  1005
dvander@938
  1006
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@938
  1007
{
dvander@938
  1008
	if (type == SP_NULL_VECTOR)
dvander@938
  1009
	{
dvander@938
  1010
		return m_pNullVec;
dvander@938
  1011
	}
dvander@938
  1012
dvander@938
  1013
	return NULL;
dvander@938
  1014
}
ds@763
  1015
#endif