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