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