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