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