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