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