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