1.1 --- a/core/vm/sp_vm_basecontext.cpp Tue Aug 07 22:11:00 2007 +0000
1.2 +++ b/core/vm/sp_vm_basecontext.cpp Wed Aug 08 02:27:10 2007 +0000
1.3 @@ -28,1031 +28,1031 @@
1.4 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
1.5 *
1.6 * Version: $Id$
1.7 - */
1.8 -
1.9 -#include <string.h>
1.10 -#include <stdarg.h>
1.11 -#include <assert.h>
1.12 -#include <limits.h>
1.13 -#include "sp_vm_api.h"
1.14 -#include "sp_vm_basecontext.h"
1.15 -#include "sp_vm_engine.h"
1.16 -
1.17 -#ifdef SOURCEMOD_BUILD
1.18 -#include "Logger.h"
1.19 -#endif
1.20 -
1.21 -using namespace SourcePawn;
1.22 -
1.23 -extern SourcePawnEngine g_SourcePawn;
1.24 -
1.25 -#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
1.26 -#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
1.27 -
1.28 -int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
1.29 -{
1.30 - g_SourcePawn.RunTracer(ctx, frm, cip);
1.31 -
1.32 - return SP_ERROR_NONE;
1.33 -}
1.34 -
1.35 -BaseContext::BaseContext(sp_context_t *_ctx)
1.36 -{
1.37 - ctx = _ctx;
1.38 - ctx->context = this;
1.39 - ctx->dbreak = GlobalDebugBreak;
1.40 - m_InExec = false;
1.41 - m_CustomMsg = false;
1.42 - m_funcsnum = ctx->vmbase->FunctionCount(ctx);
1.43 -#if 0
1.44 - m_priv_funcs = NULL;
1.45 -#endif
1.46 - m_pub_funcs = NULL;
1.47 -
1.48 -#if 0
1.49 - /**
1.50 - * Note: Since the m_plugin member will never change,
1.51 - * it is safe to assume the function count will never change
1.52 - */
1.53 - if (m_funcsnum && m_priv_funcs == NULL)
1.54 - {
1.55 - m_priv_funcs = new CFunction *[m_funcsnum];
1.56 - memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
1.57 - } else {
1.58 - m_priv_funcs = NULL;
1.59 - }
1.60 -#endif
1.61 -
1.62 - if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
1.63 - {
1.64 - m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
1.65 - memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
1.66 - } else {
1.67 - m_pub_funcs = NULL;
1.68 - }
1.69 -
1.70 - /* Initialize the null references */
1.71 - uint32_t index;
1.72 - if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
1.73 - {
1.74 - sp_pubvar_t *pubvar;
1.75 - GetPubvarByIndex(index, &pubvar);
1.76 - m_pNullVec = pubvar->offs;
1.77 - } else {
1.78 - m_pNullVec = NULL;
1.79 - }
1.80 -
1.81 - if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
1.82 - {
1.83 - sp_pubvar_t *pubvar;
1.84 - GetPubvarByIndex(index, &pubvar);
1.85 - m_pNullString = pubvar->offs;
1.86 - } else {
1.87 - m_pNullString = NULL;
1.88 - }
1.89 -}
1.90 -
1.91 -void BaseContext::FlushFunctionCache()
1.92 -{
1.93 - if (m_pub_funcs)
1.94 - {
1.95 - for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
1.96 - {
1.97 - delete m_pub_funcs[i];
1.98 - m_pub_funcs[i] = NULL;
1.99 - }
1.100 - }
1.101 -
1.102 -#if 0
1.103 - if (m_priv_funcs)
1.104 - {
1.105 - for (unsigned int i=0; i<m_funcsnum; i++)
1.106 - {
1.107 - delete m_priv_funcs[i];
1.108 - m_priv_funcs[i] = NULL;
1.109 - }
1.110 - }
1.111 -#endif
1.112 -}
1.113 -
1.114 -void BaseContext::RefreshFunctionCache()
1.115 -{
1.116 - if (m_pub_funcs)
1.117 - {
1.118 - sp_public_t *pub;
1.119 - for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
1.120 - {
1.121 - if (!m_pub_funcs[i])
1.122 - {
1.123 - continue;
1.124 - }
1.125 - if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
1.126 - {
1.127 - continue;
1.128 - }
1.129 - m_pub_funcs[i]->Set(pub->code_offs, this);
1.130 - }
1.131 - }
1.132 -
1.133 -#if 0
1.134 - if (m_priv_funcs)
1.135 - {
1.136 - for (unsigned int i=0; i<m_funcsnum; i++)
1.137 - {
1.138 - if (!m_priv_funcs[i])
1.139 - {
1.140 - continue;
1.141 - }
1.142 - g_pVM->
1.143 - }
1.144 - }
1.145 -#endif
1.146 -}
1.147 -
1.148 -BaseContext::~BaseContext()
1.149 -{
1.150 - FlushFunctionCache();
1.151 - delete [] m_pub_funcs;
1.152 - m_pub_funcs = NULL;
1.153 -#if 0
1.154 - delete [] m_priv_funcs;
1.155 - m_priv_funcs = NULL;
1.156 -#endif
1.157 -}
1.158 -
1.159 -void BaseContext::SetContext(sp_context_t *_ctx)
1.160 -{
1.161 - if (!_ctx)
1.162 - {
1.163 - return;
1.164 - }
1.165 - ctx = _ctx;
1.166 - ctx->context = this;
1.167 - ctx->dbreak = GlobalDebugBreak;
1.168 - RefreshFunctionCache();
1.169 -}
1.170 -
1.171 -IVirtualMachine *BaseContext::GetVirtualMachine()
1.172 -{
1.173 - return (IVirtualMachine *)ctx->vmbase;
1.174 -}
1.175 -
1.176 -sp_context_t *BaseContext::GetContext()
1.177 -{
1.178 - return ctx;
1.179 -}
1.180 -
1.181 -bool BaseContext::IsDebugging()
1.182 -{
1.183 - return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
1.184 -}
1.185 -
1.186 -int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
1.187 -{
1.188 - if (!IsDebugging())
1.189 - {
1.190 - return SP_ERROR_NOTDEBUGGING;
1.191 - }
1.192 -
1.193 - *oldpfn = ctx->dbreak;
1.194 - ctx->dbreak = newpfn;
1.195 -
1.196 - return SP_ERROR_NONE;
1.197 -}
1.198 -
1.199 -IPluginDebugInfo *BaseContext::GetDebugInfo()
1.200 -{
1.201 - return this;
1.202 -}
1.203 -
1.204 -int BaseContext::Execute(uint32_t code_addr, cell_t *result)
1.205 -{
1.206 - if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
1.207 - {
1.208 - return SP_ERROR_NOT_RUNNABLE;
1.209 - }
1.210 -
1.211 - /* tada, prevent a crash */
1.212 - cell_t _ignore_result;
1.213 - if (!result)
1.214 - {
1.215 - result = &_ignore_result;
1.216 - }
1.217 -
1.218 - IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
1.219 -
1.220 - uint32_t pushcount = ctx->pushcount;
1.221 - int err;
1.222 -
1.223 - PushCell(pushcount++);
1.224 - ctx->pushcount = 0;
1.225 -
1.226 - cell_t save_sp = ctx->sp;
1.227 - cell_t save_hp = ctx->hp;
1.228 - uint32_t n_idx = ctx->n_idx;
1.229 -
1.230 - bool wasExec = m_InExec;
1.231 -
1.232 - /* Clear the error state, if any */
1.233 - ctx->n_err = SP_ERROR_NONE;
1.234 - ctx->n_idx = 0;
1.235 - m_InExec = true;
1.236 - m_MsgCache[0] = '\0';
1.237 - m_CustomMsg = false;
1.238 -
1.239 - g_SourcePawn.PushTracer(ctx);
1.240 -
1.241 - err = vm->ContextExecute(ctx, code_addr, result);
1.242 -
1.243 - m_InExec = wasExec;
1.244 -
1.245 - /**
1.246 - * :TODO: Calling from a plugin in here will erase the cached message...
1.247 - * Should that be documented?
1.248 - */
1.249 - g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
1.250 -
1.251 -#if 1//defined _DEBUG
1.252 - //:TODO: debug code for leak detection, remove before the release?
1.253 - if (err == SP_ERROR_NONE)
1.254 - {
1.255 - if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp)
1.256 - {
1.257 - const char *name;
1.258 - ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
1.259 - g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name);
1.260 - }
1.261 - if (ctx->hp != save_hp)
1.262 - {
1.263 - const char *name;
1.264 - ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
1.265 - g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name);
1.266 - }
1.267 - //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp);
1.268 - //assert(ctx->hp == save_hp);
1.269 - }
1.270 -#endif
1.271 - if (err != SP_ERROR_NONE)
1.272 - {
1.273 - ctx->sp = save_sp;
1.274 - ctx->hp = save_hp;
1.275 - }
1.276 -
1.277 - ctx->n_idx = n_idx;
1.278 -
1.279 - return err;
1.280 -}
1.281 -
1.282 -void BaseContext::SetErrorMessage(const char *msg, va_list ap)
1.283 -{
1.284 - m_CustomMsg = true;
1.285 -
1.286 - vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
1.287 -}
1.288 -
1.289 -cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
1.290 -{
1.291 - if (!m_InExec)
1.292 - {
1.293 - return 0;
1.294 - }
1.295 -
1.296 - ctx->n_err = error;
1.297 -
1.298 - if (msg)
1.299 - {
1.300 - va_list ap;
1.301 - va_start(ap, msg);
1.302 - SetErrorMessage(msg, ap);
1.303 - va_end(ap);
1.304 - }
1.305 -
1.306 - return 0;
1.307 -}
1.308 -
1.309 -cell_t BaseContext::ThrowNativeError(const char *msg, ...)
1.310 -{
1.311 - if (!m_InExec)
1.312 - {
1.313 - return 0;
1.314 - }
1.315 -
1.316 - ctx->n_err = SP_ERROR_NATIVE;
1.317 -
1.318 - if (msg)
1.319 - {
1.320 - va_list ap;
1.321 - va_start(ap, msg);
1.322 - SetErrorMessage(msg, ap);
1.323 - va_end(ap);
1.324 - }
1.325 -
1.326 - return 0;
1.327 -}
1.328 -
1.329 -int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
1.330 -{
1.331 - cell_t *addr;
1.332 - ucell_t realmem;
1.333 -
1.334 -#if 0
1.335 - if (cells > CELLBOUNDMAX)
1.336 - {
1.337 - return SP_ERROR_ARAM;
1.338 - }
1.339 -#else
1.340 - assert(cells < CELLBOUNDMAX);
1.341 -#endif
1.342 -
1.343 - realmem = cells * sizeof(cell_t);
1.344 -
1.345 - /**
1.346 - * Check if the space between the heap and stack is sufficient.
1.347 - */
1.348 - if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
1.349 - {
1.350 - return SP_ERROR_HEAPLOW;
1.351 - }
1.352 -
1.353 - addr = (cell_t *)(ctx->memory + ctx->hp);
1.354 - /* store size of allocation in cells */
1.355 - *addr = (cell_t)cells;
1.356 - addr++;
1.357 - ctx->hp += sizeof(cell_t);
1.358 -
1.359 - *local_addr = ctx->hp;
1.360 -
1.361 - if (phys_addr)
1.362 - {
1.363 - *phys_addr = addr;
1.364 - }
1.365 -
1.366 - ctx->hp += realmem;
1.367 -
1.368 - return SP_ERROR_NONE;
1.369 -}
1.370 -
1.371 -int BaseContext::HeapPop(cell_t local_addr)
1.372 -{
1.373 - cell_t cellcount;
1.374 - cell_t *addr;
1.375 -
1.376 - /* check the bounds of this address */
1.377 - local_addr -= sizeof(cell_t);
1.378 - if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
1.379 - {
1.380 - return SP_ERROR_INVALID_ADDRESS;
1.381 - }
1.382 -
1.383 - addr = (cell_t *)(ctx->memory + local_addr);
1.384 - cellcount = (*addr) * sizeof(cell_t);
1.385 - /* check if this memory count looks valid */
1.386 - if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
1.387 - {
1.388 - return SP_ERROR_INVALID_ADDRESS;
1.389 - }
1.390 -
1.391 - ctx->hp = local_addr;
1.392 -
1.393 - return SP_ERROR_NONE;
1.394 -}
1.395 -
1.396 -
1.397 -int BaseContext::HeapRelease(cell_t local_addr)
1.398 -{
1.399 - if (local_addr < ctx->heap_base)
1.400 - {
1.401 - return SP_ERROR_INVALID_ADDRESS;
1.402 - }
1.403 -
1.404 - ctx->hp = local_addr - sizeof(cell_t);
1.405 -
1.406 - return SP_ERROR_NONE;
1.407 -}
1.408 -
1.409 -int BaseContext::FindNativeByName(const char *name, uint32_t *index)
1.410 -{
1.411 - int high;
1.412 -
1.413 - high = ctx->plugin->info.natives_num - 1;
1.414 -
1.415 - for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
1.416 - {
1.417 - if (strcmp(ctx->natives[i].name, name) == 0)
1.418 - {
1.419 - if (index)
1.420 - {
1.421 - *index = i;
1.422 - }
1.423 - return SP_ERROR_NONE;
1.424 - }
1.425 - }
1.426 -
1.427 - return SP_ERROR_NOT_FOUND;
1.428 -}
1.429 -
1.430 -int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
1.431 -{
1.432 - if (index >= ctx->plugin->info.natives_num)
1.433 - {
1.434 - return SP_ERROR_INDEX;
1.435 - }
1.436 -
1.437 - if (native)
1.438 - {
1.439 - *native = &(ctx->natives[index]);
1.440 - }
1.441 -
1.442 - return SP_ERROR_NONE;
1.443 -}
1.444 -
1.445 -
1.446 -uint32_t BaseContext::GetNativesNum()
1.447 -{
1.448 - return ctx->plugin->info.natives_num;
1.449 -}
1.450 -
1.451 -int BaseContext::FindPublicByName(const char *name, uint32_t *index)
1.452 -{
1.453 - int diff, high, low;
1.454 - uint32_t mid;
1.455 -
1.456 - high = ctx->plugin->info.publics_num - 1;
1.457 - low = 0;
1.458 -
1.459 - while (low <= high)
1.460 - {
1.461 - mid = (low + high) / 2;
1.462 - diff = strcmp(ctx->publics[mid].name, name);
1.463 - if (diff == 0)
1.464 - {
1.465 - if (index)
1.466 - {
1.467 - *index = mid;
1.468 - }
1.469 - return SP_ERROR_NONE;
1.470 - } else if (diff < 0) {
1.471 - low = mid + 1;
1.472 - } else {
1.473 - high = mid - 1;
1.474 - }
1.475 - }
1.476 -
1.477 - return SP_ERROR_NOT_FOUND;
1.478 -}
1.479 -
1.480 -int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
1.481 -{
1.482 - if (index >= ctx->plugin->info.publics_num)
1.483 - {
1.484 - return SP_ERROR_INDEX;
1.485 - }
1.486 -
1.487 - if (pblic)
1.488 - {
1.489 - *pblic = &(ctx->publics[index]);
1.490 - }
1.491 -
1.492 - return SP_ERROR_NONE;
1.493 -}
1.494 -
1.495 -uint32_t BaseContext::GetPublicsNum()
1.496 -{
1.497 - return ctx->plugin->info.publics_num;
1.498 -}
1.499 -
1.500 -int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
1.501 -{
1.502 - if (index >= ctx->plugin->info.pubvars_num)
1.503 - {
1.504 - return SP_ERROR_INDEX;
1.505 - }
1.506 -
1.507 - if (pubvar)
1.508 - {
1.509 - *pubvar = &(ctx->pubvars[index]);
1.510 - }
1.511 -
1.512 - return SP_ERROR_NONE;
1.513 -}
1.514 -
1.515 -int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
1.516 -{
1.517 - int diff, high, low;
1.518 - uint32_t mid;
1.519 -
1.520 - high = ctx->plugin->info.pubvars_num - 1;
1.521 - low = 0;
1.522 -
1.523 - while (low <= high)
1.524 - {
1.525 - mid = (low + high) / 2;
1.526 - diff = strcmp(ctx->pubvars[mid].name, name);
1.527 - if (diff == 0)
1.528 - {
1.529 - if (index)
1.530 - {
1.531 - *index = mid;
1.532 - }
1.533 - return SP_ERROR_NONE;
1.534 - } else if (diff < 0) {
1.535 - low = mid + 1;
1.536 - } else {
1.537 - high = mid - 1;
1.538 - }
1.539 - }
1.540 -
1.541 - return SP_ERROR_NOT_FOUND;
1.542 -}
1.543 -
1.544 -int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
1.545 -{
1.546 - if (index >= ctx->plugin->info.pubvars_num)
1.547 - {
1.548 - return SP_ERROR_INDEX;
1.549 - }
1.550 -
1.551 - *local_addr = ctx->plugin->info.pubvars[index].address;
1.552 - *phys_addr = ctx->pubvars[index].offs;
1.553 -
1.554 - return SP_ERROR_NONE;
1.555 -}
1.556 -
1.557 -uint32_t BaseContext::GetPubVarsNum()
1.558 -{
1.559 - return ctx->plugin->info.pubvars_num;
1.560 -}
1.561 -
1.562 -int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
1.563 -{
1.564 - uint32_t i, j, max;
1.565 -
1.566 - max = ctx->plugin->info.natives_num;
1.567 -
1.568 - for (i=0; i<max; i++)
1.569 - {
1.570 - if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
1.571 - {
1.572 - continue;
1.573 - }
1.574 -
1.575 - for (j=0; (natives[j].name) && (!num || j<num); j++)
1.576 - {
1.577 - if (!strcmp(ctx->natives[i].name, natives[j].name))
1.578 - {
1.579 - ctx->natives[i].pfn = natives[j].func;
1.580 - ctx->natives[i].status = SP_NATIVE_BOUND;
1.581 - }
1.582 - }
1.583 - }
1.584 -
1.585 - return SP_ERROR_NONE;
1.586 -}
1.587 -
1.588 -int BaseContext::BindNative(const sp_nativeinfo_t *native)
1.589 -{
1.590 - uint32_t index;
1.591 - int err;
1.592 -
1.593 - if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
1.594 - {
1.595 - return err;
1.596 - }
1.597 -
1.598 - ctx->natives[index].pfn = native->func;
1.599 - ctx->natives[index].status = SP_NATIVE_BOUND;
1.600 -
1.601 - return SP_ERROR_NONE;
1.602 -}
1.603 -
1.604 -int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
1.605 -{
1.606 - uint32_t nativesnum, i;
1.607 -
1.608 - nativesnum = ctx->plugin->info.natives_num;
1.609 -
1.610 - for (i=0; i<nativesnum; i++)
1.611 - {
1.612 - if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
1.613 - {
1.614 - ctx->natives[i].pfn = native;
1.615 - ctx->natives[i].status = SP_NATIVE_BOUND;
1.616 - }
1.617 - }
1.618 -
1.619 - return SP_ERROR_NONE;
1.620 -}
1.621 -
1.622 -int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
1.623 -{
1.624 - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.625 - {
1.626 - return SP_ERROR_INVALID_ADDRESS;
1.627 - }
1.628 -
1.629 - if (phys_addr)
1.630 - {
1.631 - *phys_addr = (cell_t *)(ctx->memory + local_addr);
1.632 - }
1.633 -
1.634 - return SP_ERROR_NONE;
1.635 -}
1.636 -
1.637 -int BaseContext::PushCell(cell_t value)
1.638 -{
1.639 - if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
1.640 - {
1.641 - return SP_ERROR_STACKLOW;
1.642 - }
1.643 -
1.644 - ctx->sp -= sizeof(cell_t);
1.645 - *(cell_t *)(ctx->memory + ctx->sp) = value;
1.646 - ctx->pushcount++;
1.647 -
1.648 - return SP_ERROR_NONE;
1.649 -}
1.650 -
1.651 -int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
1.652 -{
1.653 - unsigned int i;
1.654 - int err;
1.655 -
1.656 - for (i=0; i<numcells; i++)
1.657 - {
1.658 - if ((err = PushCell(array[i])) != SP_ERROR_NONE)
1.659 - {
1.660 - ctx->sp += (cell_t)(i * sizeof(cell_t));
1.661 - ctx->pushcount -= i;
1.662 - return err;
1.663 - }
1.664 - }
1.665 -
1.666 - return SP_ERROR_NONE;
1.667 -}
1.668 -
1.669 -int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
1.670 -{
1.671 - cell_t *ph_addr;
1.672 - int err;
1.673 -
1.674 - if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
1.675 - {
1.676 - return err;
1.677 - }
1.678 -
1.679 - memcpy(ph_addr, array, numcells * sizeof(cell_t));
1.680 -
1.681 - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.682 - {
1.683 - HeapRelease(*local_addr);
1.684 - return err;
1.685 - }
1.686 -
1.687 - if (phys_addr)
1.688 - {
1.689 - *phys_addr = ph_addr;
1.690 - }
1.691 -
1.692 - return SP_ERROR_NONE;
1.693 -}
1.694 -
1.695 -int BaseContext::LocalToString(cell_t local_addr, char **addr)
1.696 -{
1.697 - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.698 - {
1.699 - return SP_ERROR_INVALID_ADDRESS;
1.700 - }
1.701 - *addr = (char *)(ctx->memory + local_addr);
1.702 -
1.703 - return SP_ERROR_NONE;
1.704 -}
1.705 -
1.706 -int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
1.707 -{
1.708 - char *ph_addr;
1.709 - int err;
1.710 - unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
1.711 -
1.712 - if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
1.713 - {
1.714 - return err;
1.715 - }
1.716 -
1.717 - memcpy(ph_addr, string, len);
1.718 - ph_addr[len] = '\0';
1.719 -
1.720 - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.721 - {
1.722 - HeapRelease(*local_addr);
1.723 - return err;
1.724 - }
1.725 -
1.726 - if (phys_addr)
1.727 - {
1.728 - *phys_addr = ph_addr;
1.729 - }
1.730 -
1.731 - return SP_ERROR_NONE;
1.732 -}
1.733 -
1.734 -int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
1.735 -{
1.736 - char *dest;
1.737 - size_t len;
1.738 -
1.739 - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.740 - {
1.741 - return SP_ERROR_INVALID_ADDRESS;
1.742 - }
1.743 -
1.744 - if (bytes == 0)
1.745 - {
1.746 - return SP_ERROR_NONE;
1.747 - }
1.748 -
1.749 - len = strlen(source);
1.750 - dest = (char *)(ctx->memory + local_addr);
1.751 -
1.752 - if (len >= bytes)
1.753 - {
1.754 - len = bytes - 1;
1.755 - }
1.756 -
1.757 - memcpy(dest, source, len);
1.758 - dest[len] = '\0';
1.759 -
1.760 - return SP_ERROR_NONE;
1.761 -}
1.762 -
1.763 -inline int __CheckValidChar(char *c)
1.764 -{
1.765 - int count;
1.766 - int bytecount = 0;
1.767 -
1.768 - for (count=1; (*c & 0xC0) == 0x80; count++)
1.769 - {
1.770 - c--;
1.771 - }
1.772 -
1.773 - switch (*c & 0xF0)
1.774 - {
1.775 - case 0xC0:
1.776 - case 0xD0:
1.777 - {
1.778 - bytecount = 2;
1.779 - break;
1.780 - }
1.781 - case 0xE0:
1.782 - {
1.783 - bytecount = 3;
1.784 - break;
1.785 - }
1.786 - case 0xF0:
1.787 - {
1.788 - bytecount = 4;
1.789 - break;
1.790 - }
1.791 - }
1.792 -
1.793 - if (bytecount != count)
1.794 - {
1.795 - return count;
1.796 - }
1.797 -
1.798 - return 0;
1.799 -}
1.800 -
1.801 -int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
1.802 -{
1.803 - char *dest;
1.804 - size_t len;
1.805 - bool needtocheck = false;
1.806 -
1.807 - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.808 - {
1.809 - return SP_ERROR_INVALID_ADDRESS;
1.810 - }
1.811 -
1.812 - if (maxbytes == 0)
1.813 - {
1.814 - return SP_ERROR_NONE;
1.815 - }
1.816 -
1.817 - len = strlen(source);
1.818 - dest = (char *)(ctx->memory + local_addr);
1.819 -
1.820 - if ((size_t)len >= maxbytes)
1.821 - {
1.822 - len = maxbytes - 1;
1.823 - needtocheck = true;
1.824 - }
1.825 -
1.826 - memcpy(dest, source, len);
1.827 - if ((dest[len-1] & 1<<7) && needtocheck)
1.828 - {
1.829 - len -= __CheckValidChar(dest+len-1);
1.830 - }
1.831 - dest[len] = '\0';
1.832 -
1.833 - if (wrtnbytes)
1.834 - {
1.835 - *wrtnbytes = len;
1.836 - }
1.837 -
1.838 - return SP_ERROR_NONE;
1.839 -}
1.840 -
1.841 -#define USHR(x) ((unsigned int)(x)>>1)
1.842 -
1.843 -int BaseContext::LookupFile(ucell_t addr, const char **filename)
1.844 -{
1.845 - int high, low, mid;
1.846 -
1.847 - high = ctx->plugin->debug.files_num;
1.848 - low = -1;
1.849 -
1.850 - while (high - low > 1)
1.851 - {
1.852 - mid = USHR(low + high);
1.853 - if (ctx->files[mid].addr <= addr)
1.854 - {
1.855 - low = mid;
1.856 - } else {
1.857 - high = mid;
1.858 - }
1.859 - }
1.860 -
1.861 - if (low == -1)
1.862 - {
1.863 - return SP_ERROR_NOT_FOUND;
1.864 - }
1.865 -
1.866 - *filename = ctx->files[low].name;
1.867 -
1.868 - return SP_ERROR_NONE;
1.869 -}
1.870 -
1.871 -int BaseContext::LookupFunction(ucell_t addr, const char **name)
1.872 -{
1.873 - uint32_t iter, max = ctx->plugin->debug.syms_num;
1.874 -
1.875 - for (iter=0; iter<max; iter++)
1.876 - {
1.877 - if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION)
1.878 - && (ctx->symbols[iter].codestart <= addr)
1.879 - && (ctx->symbols[iter].codeend > addr))
1.880 - {
1.881 - break;
1.882 - }
1.883 - }
1.884 -
1.885 - if (iter >= max)
1.886 - {
1.887 - return SP_ERROR_NOT_FOUND;
1.888 - }
1.889 -
1.890 - *name = ctx->symbols[iter].name;
1.891 -
1.892 - return SP_ERROR_NONE;
1.893 -}
1.894 -
1.895 -int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
1.896 -{
1.897 - int high, low, mid;
1.898 -
1.899 - high = ctx->plugin->debug.lines_num;
1.900 - low = -1;
1.901 -
1.902 - while (high - low > 1)
1.903 - {
1.904 - mid = USHR(low + high);
1.905 - if (ctx->lines[mid].addr <= addr)
1.906 - {
1.907 - low = mid;
1.908 - } else {
1.909 - high = mid;
1.910 - }
1.911 - }
1.912 -
1.913 - if (low == -1)
1.914 - {
1.915 - return SP_ERROR_NOT_FOUND;
1.916 - }
1.917 -
1.918 - /* Since the CIP occurs BEFORE the line, we have to add one */
1.919 - *line = ctx->lines[low].line + 1;
1.920 -
1.921 - return SP_ERROR_NONE;
1.922 -}
1.923 -
1.924 -IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
1.925 -{
1.926 - CFunction *pFunc = NULL;
1.927 -
1.928 - if (func_id & 1)
1.929 - {
1.930 - func_id >>= 1;
1.931 - if (func_id >= ctx->plugin->info.publics_num)
1.932 - {
1.933 - return NULL;
1.934 - }
1.935 - pFunc = m_pub_funcs[func_id];
1.936 - if (!pFunc)
1.937 - {
1.938 - m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this);
1.939 - pFunc = m_pub_funcs[func_id];
1.940 - } else if (pFunc->IsInvalidated()) {
1.941 - pFunc->Set(ctx->publics[func_id].code_offs, this);
1.942 - }
1.943 - } else {
1.944 - /* :TODO: currently not used */
1.945 -#if 0
1.946 - func_id >>= 1;
1.947 - unsigned int index;
1.948 - if (!g_pVM->FunctionLookup(ctx, func_id, &index))
1.949 - {
1.950 - return NULL;
1.951 - }
1.952 - pFunc = m_priv_funcs[func_id];
1.953 - if (!pFunc)
1.954 - {
1.955 - m_priv_funcs[func_id] = new CFunction(save, this);
1.956 - pFunc = m_priv_funcs[func_id];
1.957 - }
1.958 -#endif
1.959 - assert(false);
1.960 - }
1.961 -
1.962 - return pFunc;
1.963 -}
1.964 -
1.965 -IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
1.966 -{
1.967 - uint32_t index;
1.968 -
1.969 - if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
1.970 - {
1.971 - return NULL;
1.972 - }
1.973 -
1.974 - CFunction *pFunc = m_pub_funcs[index];
1.975 - if (!pFunc)
1.976 - {
1.977 - sp_public_t *pub = NULL;
1.978 - GetPublicByIndex(index, &pub);
1.979 - if (pub)
1.980 - {
1.981 - m_pub_funcs[index] = new CFunction(pub->code_offs, this);
1.982 - }
1.983 - pFunc = m_pub_funcs[index];
1.984 - } else if (pFunc->IsInvalidated()) {
1.985 - sp_public_t *pub = NULL;
1.986 - GetPublicByIndex(index, &pub);
1.987 - if (pub)
1.988 - {
1.989 - pFunc->Set(pub->code_offs, this);
1.990 - } else {
1.991 - pFunc = NULL;
1.992 - }
1.993 - }
1.994 -
1.995 - return pFunc;
1.996 -}
1.997 -
1.998 -int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
1.999 -{
1.1000 - int err;
1.1001 - if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
1.1002 - {
1.1003 - return err;
1.1004 - }
1.1005 -
1.1006 - if ((cell_t *)*addr == m_pNullString)
1.1007 - {
1.1008 - *addr = NULL;
1.1009 - }
1.1010 -
1.1011 - return SP_ERROR_NONE;
1.1012 -}
1.1013 -
1.1014 -#if defined SOURCEMOD_BUILD
1.1015 -SourceMod::IdentityToken_t *BaseContext::GetIdentity()
1.1016 -{
1.1017 - return m_pToken;
1.1018 -}
1.1019 -
1.1020 -void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
1.1021 -{
1.1022 - m_pToken = token;
1.1023 -}
1.1024 -
1.1025 -cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
1.1026 -{
1.1027 - if (type == SP_NULL_VECTOR)
1.1028 - {
1.1029 - return m_pNullVec;
1.1030 - }
1.1031 -
1.1032 - return NULL;
1.1033 -}
1.1034 -#endif
1.1035 + */
1.1036 +
1.1037 +#include <string.h>
1.1038 +#include <stdarg.h>
1.1039 +#include <assert.h>
1.1040 +#include <limits.h>
1.1041 +#include "sp_vm_api.h"
1.1042 +#include "sp_vm_basecontext.h"
1.1043 +#include "sp_vm_engine.h"
1.1044 +
1.1045 +#ifdef SOURCEMOD_BUILD
1.1046 +#include "Logger.h"
1.1047 +#endif
1.1048 +
1.1049 +using namespace SourcePawn;
1.1050 +
1.1051 +extern SourcePawnEngine g_SourcePawn;
1.1052 +
1.1053 +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
1.1054 +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
1.1055 +
1.1056 +int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
1.1057 +{
1.1058 + g_SourcePawn.RunTracer(ctx, frm, cip);
1.1059 +
1.1060 + return SP_ERROR_NONE;
1.1061 +}
1.1062 +
1.1063 +BaseContext::BaseContext(sp_context_t *_ctx)
1.1064 +{
1.1065 + ctx = _ctx;
1.1066 + ctx->context = this;
1.1067 + ctx->dbreak = GlobalDebugBreak;
1.1068 + m_InExec = false;
1.1069 + m_CustomMsg = false;
1.1070 + m_funcsnum = ctx->vmbase->FunctionCount(ctx);
1.1071 +#if 0
1.1072 + m_priv_funcs = NULL;
1.1073 +#endif
1.1074 + m_pub_funcs = NULL;
1.1075 +
1.1076 +#if 0
1.1077 + /**
1.1078 + * Note: Since the m_plugin member will never change,
1.1079 + * it is safe to assume the function count will never change
1.1080 + */
1.1081 + if (m_funcsnum && m_priv_funcs == NULL)
1.1082 + {
1.1083 + m_priv_funcs = new CFunction *[m_funcsnum];
1.1084 + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
1.1085 + } else {
1.1086 + m_priv_funcs = NULL;
1.1087 + }
1.1088 +#endif
1.1089 +
1.1090 + if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
1.1091 + {
1.1092 + m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
1.1093 + memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
1.1094 + } else {
1.1095 + m_pub_funcs = NULL;
1.1096 + }
1.1097 +
1.1098 + /* Initialize the null references */
1.1099 + uint32_t index;
1.1100 + if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
1.1101 + {
1.1102 + sp_pubvar_t *pubvar;
1.1103 + GetPubvarByIndex(index, &pubvar);
1.1104 + m_pNullVec = pubvar->offs;
1.1105 + } else {
1.1106 + m_pNullVec = NULL;
1.1107 + }
1.1108 +
1.1109 + if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
1.1110 + {
1.1111 + sp_pubvar_t *pubvar;
1.1112 + GetPubvarByIndex(index, &pubvar);
1.1113 + m_pNullString = pubvar->offs;
1.1114 + } else {
1.1115 + m_pNullString = NULL;
1.1116 + }
1.1117 +}
1.1118 +
1.1119 +void BaseContext::FlushFunctionCache()
1.1120 +{
1.1121 + if (m_pub_funcs)
1.1122 + {
1.1123 + for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
1.1124 + {
1.1125 + delete m_pub_funcs[i];
1.1126 + m_pub_funcs[i] = NULL;
1.1127 + }
1.1128 + }
1.1129 +
1.1130 +#if 0
1.1131 + if (m_priv_funcs)
1.1132 + {
1.1133 + for (unsigned int i=0; i<m_funcsnum; i++)
1.1134 + {
1.1135 + delete m_priv_funcs[i];
1.1136 + m_priv_funcs[i] = NULL;
1.1137 + }
1.1138 + }
1.1139 +#endif
1.1140 +}
1.1141 +
1.1142 +void BaseContext::RefreshFunctionCache()
1.1143 +{
1.1144 + if (m_pub_funcs)
1.1145 + {
1.1146 + sp_public_t *pub;
1.1147 + for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
1.1148 + {
1.1149 + if (!m_pub_funcs[i])
1.1150 + {
1.1151 + continue;
1.1152 + }
1.1153 + if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
1.1154 + {
1.1155 + continue;
1.1156 + }
1.1157 + m_pub_funcs[i]->Set(pub->code_offs, this);
1.1158 + }
1.1159 + }
1.1160 +
1.1161 +#if 0
1.1162 + if (m_priv_funcs)
1.1163 + {
1.1164 + for (unsigned int i=0; i<m_funcsnum; i++)
1.1165 + {
1.1166 + if (!m_priv_funcs[i])
1.1167 + {
1.1168 + continue;
1.1169 + }
1.1170 + g_pVM->
1.1171 + }
1.1172 + }
1.1173 +#endif
1.1174 +}
1.1175 +
1.1176 +BaseContext::~BaseContext()
1.1177 +{
1.1178 + FlushFunctionCache();
1.1179 + delete [] m_pub_funcs;
1.1180 + m_pub_funcs = NULL;
1.1181 +#if 0
1.1182 + delete [] m_priv_funcs;
1.1183 + m_priv_funcs = NULL;
1.1184 +#endif
1.1185 +}
1.1186 +
1.1187 +void BaseContext::SetContext(sp_context_t *_ctx)
1.1188 +{
1.1189 + if (!_ctx)
1.1190 + {
1.1191 + return;
1.1192 + }
1.1193 + ctx = _ctx;
1.1194 + ctx->context = this;
1.1195 + ctx->dbreak = GlobalDebugBreak;
1.1196 + RefreshFunctionCache();
1.1197 +}
1.1198 +
1.1199 +IVirtualMachine *BaseContext::GetVirtualMachine()
1.1200 +{
1.1201 + return (IVirtualMachine *)ctx->vmbase;
1.1202 +}
1.1203 +
1.1204 +sp_context_t *BaseContext::GetContext()
1.1205 +{
1.1206 + return ctx;
1.1207 +}
1.1208 +
1.1209 +bool BaseContext::IsDebugging()
1.1210 +{
1.1211 + return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
1.1212 +}
1.1213 +
1.1214 +int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
1.1215 +{
1.1216 + if (!IsDebugging())
1.1217 + {
1.1218 + return SP_ERROR_NOTDEBUGGING;
1.1219 + }
1.1220 +
1.1221 + *oldpfn = ctx->dbreak;
1.1222 + ctx->dbreak = newpfn;
1.1223 +
1.1224 + return SP_ERROR_NONE;
1.1225 +}
1.1226 +
1.1227 +IPluginDebugInfo *BaseContext::GetDebugInfo()
1.1228 +{
1.1229 + return this;
1.1230 +}
1.1231 +
1.1232 +int BaseContext::Execute(uint32_t code_addr, cell_t *result)
1.1233 +{
1.1234 + if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
1.1235 + {
1.1236 + return SP_ERROR_NOT_RUNNABLE;
1.1237 + }
1.1238 +
1.1239 + /* tada, prevent a crash */
1.1240 + cell_t _ignore_result;
1.1241 + if (!result)
1.1242 + {
1.1243 + result = &_ignore_result;
1.1244 + }
1.1245 +
1.1246 + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
1.1247 +
1.1248 + uint32_t pushcount = ctx->pushcount;
1.1249 + int err;
1.1250 +
1.1251 + PushCell(pushcount++);
1.1252 + ctx->pushcount = 0;
1.1253 +
1.1254 + cell_t save_sp = ctx->sp;
1.1255 + cell_t save_hp = ctx->hp;
1.1256 + uint32_t n_idx = ctx->n_idx;
1.1257 +
1.1258 + bool wasExec = m_InExec;
1.1259 +
1.1260 + /* Clear the error state, if any */
1.1261 + ctx->n_err = SP_ERROR_NONE;
1.1262 + ctx->n_idx = 0;
1.1263 + m_InExec = true;
1.1264 + m_MsgCache[0] = '\0';
1.1265 + m_CustomMsg = false;
1.1266 +
1.1267 + g_SourcePawn.PushTracer(ctx);
1.1268 +
1.1269 + err = vm->ContextExecute(ctx, code_addr, result);
1.1270 +
1.1271 + m_InExec = wasExec;
1.1272 +
1.1273 + /**
1.1274 + * :TODO: Calling from a plugin in here will erase the cached message...
1.1275 + * Should that be documented?
1.1276 + */
1.1277 + g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
1.1278 +
1.1279 +#if 1//defined _DEBUG
1.1280 + //:TODO: debug code for leak detection, remove before the release?
1.1281 + if (err == SP_ERROR_NONE)
1.1282 + {
1.1283 + if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp)
1.1284 + {
1.1285 + const char *name;
1.1286 + ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
1.1287 + g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name);
1.1288 + }
1.1289 + if (ctx->hp != save_hp)
1.1290 + {
1.1291 + const char *name;
1.1292 + ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
1.1293 + g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name);
1.1294 + }
1.1295 + //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp);
1.1296 + //assert(ctx->hp == save_hp);
1.1297 + }
1.1298 +#endif
1.1299 + if (err != SP_ERROR_NONE)
1.1300 + {
1.1301 + ctx->sp = save_sp;
1.1302 + ctx->hp = save_hp;
1.1303 + }
1.1304 +
1.1305 + ctx->n_idx = n_idx;
1.1306 +
1.1307 + return err;
1.1308 +}
1.1309 +
1.1310 +void BaseContext::SetErrorMessage(const char *msg, va_list ap)
1.1311 +{
1.1312 + m_CustomMsg = true;
1.1313 +
1.1314 + vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
1.1315 +}
1.1316 +
1.1317 +cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
1.1318 +{
1.1319 + if (!m_InExec)
1.1320 + {
1.1321 + return 0;
1.1322 + }
1.1323 +
1.1324 + ctx->n_err = error;
1.1325 +
1.1326 + if (msg)
1.1327 + {
1.1328 + va_list ap;
1.1329 + va_start(ap, msg);
1.1330 + SetErrorMessage(msg, ap);
1.1331 + va_end(ap);
1.1332 + }
1.1333 +
1.1334 + return 0;
1.1335 +}
1.1336 +
1.1337 +cell_t BaseContext::ThrowNativeError(const char *msg, ...)
1.1338 +{
1.1339 + if (!m_InExec)
1.1340 + {
1.1341 + return 0;
1.1342 + }
1.1343 +
1.1344 + ctx->n_err = SP_ERROR_NATIVE;
1.1345 +
1.1346 + if (msg)
1.1347 + {
1.1348 + va_list ap;
1.1349 + va_start(ap, msg);
1.1350 + SetErrorMessage(msg, ap);
1.1351 + va_end(ap);
1.1352 + }
1.1353 +
1.1354 + return 0;
1.1355 +}
1.1356 +
1.1357 +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
1.1358 +{
1.1359 + cell_t *addr;
1.1360 + ucell_t realmem;
1.1361 +
1.1362 +#if 0
1.1363 + if (cells > CELLBOUNDMAX)
1.1364 + {
1.1365 + return SP_ERROR_ARAM;
1.1366 + }
1.1367 +#else
1.1368 + assert(cells < CELLBOUNDMAX);
1.1369 +#endif
1.1370 +
1.1371 + realmem = cells * sizeof(cell_t);
1.1372 +
1.1373 + /**
1.1374 + * Check if the space between the heap and stack is sufficient.
1.1375 + */
1.1376 + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
1.1377 + {
1.1378 + return SP_ERROR_HEAPLOW;
1.1379 + }
1.1380 +
1.1381 + addr = (cell_t *)(ctx->memory + ctx->hp);
1.1382 + /* store size of allocation in cells */
1.1383 + *addr = (cell_t)cells;
1.1384 + addr++;
1.1385 + ctx->hp += sizeof(cell_t);
1.1386 +
1.1387 + *local_addr = ctx->hp;
1.1388 +
1.1389 + if (phys_addr)
1.1390 + {
1.1391 + *phys_addr = addr;
1.1392 + }
1.1393 +
1.1394 + ctx->hp += realmem;
1.1395 +
1.1396 + return SP_ERROR_NONE;
1.1397 +}
1.1398 +
1.1399 +int BaseContext::HeapPop(cell_t local_addr)
1.1400 +{
1.1401 + cell_t cellcount;
1.1402 + cell_t *addr;
1.1403 +
1.1404 + /* check the bounds of this address */
1.1405 + local_addr -= sizeof(cell_t);
1.1406 + if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
1.1407 + {
1.1408 + return SP_ERROR_INVALID_ADDRESS;
1.1409 + }
1.1410 +
1.1411 + addr = (cell_t *)(ctx->memory + local_addr);
1.1412 + cellcount = (*addr) * sizeof(cell_t);
1.1413 + /* check if this memory count looks valid */
1.1414 + if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
1.1415 + {
1.1416 + return SP_ERROR_INVALID_ADDRESS;
1.1417 + }
1.1418 +
1.1419 + ctx->hp = local_addr;
1.1420 +
1.1421 + return SP_ERROR_NONE;
1.1422 +}
1.1423 +
1.1424 +
1.1425 +int BaseContext::HeapRelease(cell_t local_addr)
1.1426 +{
1.1427 + if (local_addr < ctx->heap_base)
1.1428 + {
1.1429 + return SP_ERROR_INVALID_ADDRESS;
1.1430 + }
1.1431 +
1.1432 + ctx->hp = local_addr - sizeof(cell_t);
1.1433 +
1.1434 + return SP_ERROR_NONE;
1.1435 +}
1.1436 +
1.1437 +int BaseContext::FindNativeByName(const char *name, uint32_t *index)
1.1438 +{
1.1439 + int high;
1.1440 +
1.1441 + high = ctx->plugin->info.natives_num - 1;
1.1442 +
1.1443 + for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
1.1444 + {
1.1445 + if (strcmp(ctx->natives[i].name, name) == 0)
1.1446 + {
1.1447 + if (index)
1.1448 + {
1.1449 + *index = i;
1.1450 + }
1.1451 + return SP_ERROR_NONE;
1.1452 + }
1.1453 + }
1.1454 +
1.1455 + return SP_ERROR_NOT_FOUND;
1.1456 +}
1.1457 +
1.1458 +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
1.1459 +{
1.1460 + if (index >= ctx->plugin->info.natives_num)
1.1461 + {
1.1462 + return SP_ERROR_INDEX;
1.1463 + }
1.1464 +
1.1465 + if (native)
1.1466 + {
1.1467 + *native = &(ctx->natives[index]);
1.1468 + }
1.1469 +
1.1470 + return SP_ERROR_NONE;
1.1471 +}
1.1472 +
1.1473 +
1.1474 +uint32_t BaseContext::GetNativesNum()
1.1475 +{
1.1476 + return ctx->plugin->info.natives_num;
1.1477 +}
1.1478 +
1.1479 +int BaseContext::FindPublicByName(const char *name, uint32_t *index)
1.1480 +{
1.1481 + int diff, high, low;
1.1482 + uint32_t mid;
1.1483 +
1.1484 + high = ctx->plugin->info.publics_num - 1;
1.1485 + low = 0;
1.1486 +
1.1487 + while (low <= high)
1.1488 + {
1.1489 + mid = (low + high) / 2;
1.1490 + diff = strcmp(ctx->publics[mid].name, name);
1.1491 + if (diff == 0)
1.1492 + {
1.1493 + if (index)
1.1494 + {
1.1495 + *index = mid;
1.1496 + }
1.1497 + return SP_ERROR_NONE;
1.1498 + } else if (diff < 0) {
1.1499 + low = mid + 1;
1.1500 + } else {
1.1501 + high = mid - 1;
1.1502 + }
1.1503 + }
1.1504 +
1.1505 + return SP_ERROR_NOT_FOUND;
1.1506 +}
1.1507 +
1.1508 +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
1.1509 +{
1.1510 + if (index >= ctx->plugin->info.publics_num)
1.1511 + {
1.1512 + return SP_ERROR_INDEX;
1.1513 + }
1.1514 +
1.1515 + if (pblic)
1.1516 + {
1.1517 + *pblic = &(ctx->publics[index]);
1.1518 + }
1.1519 +
1.1520 + return SP_ERROR_NONE;
1.1521 +}
1.1522 +
1.1523 +uint32_t BaseContext::GetPublicsNum()
1.1524 +{
1.1525 + return ctx->plugin->info.publics_num;
1.1526 +}
1.1527 +
1.1528 +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
1.1529 +{
1.1530 + if (index >= ctx->plugin->info.pubvars_num)
1.1531 + {
1.1532 + return SP_ERROR_INDEX;
1.1533 + }
1.1534 +
1.1535 + if (pubvar)
1.1536 + {
1.1537 + *pubvar = &(ctx->pubvars[index]);
1.1538 + }
1.1539 +
1.1540 + return SP_ERROR_NONE;
1.1541 +}
1.1542 +
1.1543 +int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
1.1544 +{
1.1545 + int diff, high, low;
1.1546 + uint32_t mid;
1.1547 +
1.1548 + high = ctx->plugin->info.pubvars_num - 1;
1.1549 + low = 0;
1.1550 +
1.1551 + while (low <= high)
1.1552 + {
1.1553 + mid = (low + high) / 2;
1.1554 + diff = strcmp(ctx->pubvars[mid].name, name);
1.1555 + if (diff == 0)
1.1556 + {
1.1557 + if (index)
1.1558 + {
1.1559 + *index = mid;
1.1560 + }
1.1561 + return SP_ERROR_NONE;
1.1562 + } else if (diff < 0) {
1.1563 + low = mid + 1;
1.1564 + } else {
1.1565 + high = mid - 1;
1.1566 + }
1.1567 + }
1.1568 +
1.1569 + return SP_ERROR_NOT_FOUND;
1.1570 +}
1.1571 +
1.1572 +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
1.1573 +{
1.1574 + if (index >= ctx->plugin->info.pubvars_num)
1.1575 + {
1.1576 + return SP_ERROR_INDEX;
1.1577 + }
1.1578 +
1.1579 + *local_addr = ctx->plugin->info.pubvars[index].address;
1.1580 + *phys_addr = ctx->pubvars[index].offs;
1.1581 +
1.1582 + return SP_ERROR_NONE;
1.1583 +}
1.1584 +
1.1585 +uint32_t BaseContext::GetPubVarsNum()
1.1586 +{
1.1587 + return ctx->plugin->info.pubvars_num;
1.1588 +}
1.1589 +
1.1590 +int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
1.1591 +{
1.1592 + uint32_t i, j, max;
1.1593 +
1.1594 + max = ctx->plugin->info.natives_num;
1.1595 +
1.1596 + for (i=0; i<max; i++)
1.1597 + {
1.1598 + if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
1.1599 + {
1.1600 + continue;
1.1601 + }
1.1602 +
1.1603 + for (j=0; (natives[j].name) && (!num || j<num); j++)
1.1604 + {
1.1605 + if (!strcmp(ctx->natives[i].name, natives[j].name))
1.1606 + {
1.1607 + ctx->natives[i].pfn = natives[j].func;
1.1608 + ctx->natives[i].status = SP_NATIVE_BOUND;
1.1609 + }
1.1610 + }
1.1611 + }
1.1612 +
1.1613 + return SP_ERROR_NONE;
1.1614 +}
1.1615 +
1.1616 +int BaseContext::BindNative(const sp_nativeinfo_t *native)
1.1617 +{
1.1618 + uint32_t index;
1.1619 + int err;
1.1620 +
1.1621 + if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
1.1622 + {
1.1623 + return err;
1.1624 + }
1.1625 +
1.1626 + ctx->natives[index].pfn = native->func;
1.1627 + ctx->natives[index].status = SP_NATIVE_BOUND;
1.1628 +
1.1629 + return SP_ERROR_NONE;
1.1630 +}
1.1631 +
1.1632 +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
1.1633 +{
1.1634 + uint32_t nativesnum, i;
1.1635 +
1.1636 + nativesnum = ctx->plugin->info.natives_num;
1.1637 +
1.1638 + for (i=0; i<nativesnum; i++)
1.1639 + {
1.1640 + if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
1.1641 + {
1.1642 + ctx->natives[i].pfn = native;
1.1643 + ctx->natives[i].status = SP_NATIVE_BOUND;
1.1644 + }
1.1645 + }
1.1646 +
1.1647 + return SP_ERROR_NONE;
1.1648 +}
1.1649 +
1.1650 +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
1.1651 +{
1.1652 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.1653 + {
1.1654 + return SP_ERROR_INVALID_ADDRESS;
1.1655 + }
1.1656 +
1.1657 + if (phys_addr)
1.1658 + {
1.1659 + *phys_addr = (cell_t *)(ctx->memory + local_addr);
1.1660 + }
1.1661 +
1.1662 + return SP_ERROR_NONE;
1.1663 +}
1.1664 +
1.1665 +int BaseContext::PushCell(cell_t value)
1.1666 +{
1.1667 + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
1.1668 + {
1.1669 + return SP_ERROR_STACKLOW;
1.1670 + }
1.1671 +
1.1672 + ctx->sp -= sizeof(cell_t);
1.1673 + *(cell_t *)(ctx->memory + ctx->sp) = value;
1.1674 + ctx->pushcount++;
1.1675 +
1.1676 + return SP_ERROR_NONE;
1.1677 +}
1.1678 +
1.1679 +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
1.1680 +{
1.1681 + unsigned int i;
1.1682 + int err;
1.1683 +
1.1684 + for (i=0; i<numcells; i++)
1.1685 + {
1.1686 + if ((err = PushCell(array[i])) != SP_ERROR_NONE)
1.1687 + {
1.1688 + ctx->sp += (cell_t)(i * sizeof(cell_t));
1.1689 + ctx->pushcount -= i;
1.1690 + return err;
1.1691 + }
1.1692 + }
1.1693 +
1.1694 + return SP_ERROR_NONE;
1.1695 +}
1.1696 +
1.1697 +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
1.1698 +{
1.1699 + cell_t *ph_addr;
1.1700 + int err;
1.1701 +
1.1702 + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
1.1703 + {
1.1704 + return err;
1.1705 + }
1.1706 +
1.1707 + memcpy(ph_addr, array, numcells * sizeof(cell_t));
1.1708 +
1.1709 + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.1710 + {
1.1711 + HeapRelease(*local_addr);
1.1712 + return err;
1.1713 + }
1.1714 +
1.1715 + if (phys_addr)
1.1716 + {
1.1717 + *phys_addr = ph_addr;
1.1718 + }
1.1719 +
1.1720 + return SP_ERROR_NONE;
1.1721 +}
1.1722 +
1.1723 +int BaseContext::LocalToString(cell_t local_addr, char **addr)
1.1724 +{
1.1725 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.1726 + {
1.1727 + return SP_ERROR_INVALID_ADDRESS;
1.1728 + }
1.1729 + *addr = (char *)(ctx->memory + local_addr);
1.1730 +
1.1731 + return SP_ERROR_NONE;
1.1732 +}
1.1733 +
1.1734 +int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
1.1735 +{
1.1736 + char *ph_addr;
1.1737 + int err;
1.1738 + unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
1.1739 +
1.1740 + if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
1.1741 + {
1.1742 + return err;
1.1743 + }
1.1744 +
1.1745 + memcpy(ph_addr, string, len);
1.1746 + ph_addr[len] = '\0';
1.1747 +
1.1748 + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.1749 + {
1.1750 + HeapRelease(*local_addr);
1.1751 + return err;
1.1752 + }
1.1753 +
1.1754 + if (phys_addr)
1.1755 + {
1.1756 + *phys_addr = ph_addr;
1.1757 + }
1.1758 +
1.1759 + return SP_ERROR_NONE;
1.1760 +}
1.1761 +
1.1762 +int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
1.1763 +{
1.1764 + char *dest;
1.1765 + size_t len;
1.1766 +
1.1767 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.1768 + {
1.1769 + return SP_ERROR_INVALID_ADDRESS;
1.1770 + }
1.1771 +
1.1772 + if (bytes == 0)
1.1773 + {
1.1774 + return SP_ERROR_NONE;
1.1775 + }
1.1776 +
1.1777 + len = strlen(source);
1.1778 + dest = (char *)(ctx->memory + local_addr);
1.1779 +
1.1780 + if (len >= bytes)
1.1781 + {
1.1782 + len = bytes - 1;
1.1783 + }
1.1784 +
1.1785 + memcpy(dest, source, len);
1.1786 + dest[len] = '\0';
1.1787 +
1.1788 + return SP_ERROR_NONE;
1.1789 +}
1.1790 +
1.1791 +inline int __CheckValidChar(char *c)
1.1792 +{
1.1793 + int count;
1.1794 + int bytecount = 0;
1.1795 +
1.1796 + for (count=1; (*c & 0xC0) == 0x80; count++)
1.1797 + {
1.1798 + c--;
1.1799 + }
1.1800 +
1.1801 + switch (*c & 0xF0)
1.1802 + {
1.1803 + case 0xC0:
1.1804 + case 0xD0:
1.1805 + {
1.1806 + bytecount = 2;
1.1807 + break;
1.1808 + }
1.1809 + case 0xE0:
1.1810 + {
1.1811 + bytecount = 3;
1.1812 + break;
1.1813 + }
1.1814 + case 0xF0:
1.1815 + {
1.1816 + bytecount = 4;
1.1817 + break;
1.1818 + }
1.1819 + }
1.1820 +
1.1821 + if (bytecount != count)
1.1822 + {
1.1823 + return count;
1.1824 + }
1.1825 +
1.1826 + return 0;
1.1827 +}
1.1828 +
1.1829 +int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
1.1830 +{
1.1831 + char *dest;
1.1832 + size_t len;
1.1833 + bool needtocheck = false;
1.1834 +
1.1835 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.1836 + {
1.1837 + return SP_ERROR_INVALID_ADDRESS;
1.1838 + }
1.1839 +
1.1840 + if (maxbytes == 0)
1.1841 + {
1.1842 + return SP_ERROR_NONE;
1.1843 + }
1.1844 +
1.1845 + len = strlen(source);
1.1846 + dest = (char *)(ctx->memory + local_addr);
1.1847 +
1.1848 + if ((size_t)len >= maxbytes)
1.1849 + {
1.1850 + len = maxbytes - 1;
1.1851 + needtocheck = true;
1.1852 + }
1.1853 +
1.1854 + memcpy(dest, source, len);
1.1855 + if ((dest[len-1] & 1<<7) && needtocheck)
1.1856 + {
1.1857 + len -= __CheckValidChar(dest+len-1);
1.1858 + }
1.1859 + dest[len] = '\0';
1.1860 +
1.1861 + if (wrtnbytes)
1.1862 + {
1.1863 + *wrtnbytes = len;
1.1864 + }
1.1865 +
1.1866 + return SP_ERROR_NONE;
1.1867 +}
1.1868 +
1.1869 +#define USHR(x) ((unsigned int)(x)>>1)
1.1870 +
1.1871 +int BaseContext::LookupFile(ucell_t addr, const char **filename)
1.1872 +{
1.1873 + int high, low, mid;
1.1874 +
1.1875 + high = ctx->plugin->debug.files_num;
1.1876 + low = -1;
1.1877 +
1.1878 + while (high - low > 1)
1.1879 + {
1.1880 + mid = USHR(low + high);
1.1881 + if (ctx->files[mid].addr <= addr)
1.1882 + {
1.1883 + low = mid;
1.1884 + } else {
1.1885 + high = mid;
1.1886 + }
1.1887 + }
1.1888 +
1.1889 + if (low == -1)
1.1890 + {
1.1891 + return SP_ERROR_NOT_FOUND;
1.1892 + }
1.1893 +
1.1894 + *filename = ctx->files[low].name;
1.1895 +
1.1896 + return SP_ERROR_NONE;
1.1897 +}
1.1898 +
1.1899 +int BaseContext::LookupFunction(ucell_t addr, const char **name)
1.1900 +{
1.1901 + uint32_t iter, max = ctx->plugin->debug.syms_num;
1.1902 +
1.1903 + for (iter=0; iter<max; iter++)
1.1904 + {
1.1905 + if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION)
1.1906 + && (ctx->symbols[iter].codestart <= addr)
1.1907 + && (ctx->symbols[iter].codeend > addr))
1.1908 + {
1.1909 + break;
1.1910 + }
1.1911 + }
1.1912 +
1.1913 + if (iter >= max)
1.1914 + {
1.1915 + return SP_ERROR_NOT_FOUND;
1.1916 + }
1.1917 +
1.1918 + *name = ctx->symbols[iter].name;
1.1919 +
1.1920 + return SP_ERROR_NONE;
1.1921 +}
1.1922 +
1.1923 +int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
1.1924 +{
1.1925 + int high, low, mid;
1.1926 +
1.1927 + high = ctx->plugin->debug.lines_num;
1.1928 + low = -1;
1.1929 +
1.1930 + while (high - low > 1)
1.1931 + {
1.1932 + mid = USHR(low + high);
1.1933 + if (ctx->lines[mid].addr <= addr)
1.1934 + {
1.1935 + low = mid;
1.1936 + } else {
1.1937 + high = mid;
1.1938 + }
1.1939 + }
1.1940 +
1.1941 + if (low == -1)
1.1942 + {
1.1943 + return SP_ERROR_NOT_FOUND;
1.1944 + }
1.1945 +
1.1946 + /* Since the CIP occurs BEFORE the line, we have to add one */
1.1947 + *line = ctx->lines[low].line + 1;
1.1948 +
1.1949 + return SP_ERROR_NONE;
1.1950 +}
1.1951 +
1.1952 +IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
1.1953 +{
1.1954 + CFunction *pFunc = NULL;
1.1955 +
1.1956 + if (func_id & 1)
1.1957 + {
1.1958 + func_id >>= 1;
1.1959 + if (func_id >= ctx->plugin->info.publics_num)
1.1960 + {
1.1961 + return NULL;
1.1962 + }
1.1963 + pFunc = m_pub_funcs[func_id];
1.1964 + if (!pFunc)
1.1965 + {
1.1966 + m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this);
1.1967 + pFunc = m_pub_funcs[func_id];
1.1968 + } else if (pFunc->IsInvalidated()) {
1.1969 + pFunc->Set(ctx->publics[func_id].code_offs, this);
1.1970 + }
1.1971 + } else {
1.1972 + /* :TODO: currently not used */
1.1973 +#if 0
1.1974 + func_id >>= 1;
1.1975 + unsigned int index;
1.1976 + if (!g_pVM->FunctionLookup(ctx, func_id, &index))
1.1977 + {
1.1978 + return NULL;
1.1979 + }
1.1980 + pFunc = m_priv_funcs[func_id];
1.1981 + if (!pFunc)
1.1982 + {
1.1983 + m_priv_funcs[func_id] = new CFunction(save, this);
1.1984 + pFunc = m_priv_funcs[func_id];
1.1985 + }
1.1986 +#endif
1.1987 + assert(false);
1.1988 + }
1.1989 +
1.1990 + return pFunc;
1.1991 +}
1.1992 +
1.1993 +IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
1.1994 +{
1.1995 + uint32_t index;
1.1996 +
1.1997 + if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
1.1998 + {
1.1999 + return NULL;
1.2000 + }
1.2001 +
1.2002 + CFunction *pFunc = m_pub_funcs[index];
1.2003 + if (!pFunc)
1.2004 + {
1.2005 + sp_public_t *pub = NULL;
1.2006 + GetPublicByIndex(index, &pub);
1.2007 + if (pub)
1.2008 + {
1.2009 + m_pub_funcs[index] = new CFunction(pub->code_offs, this);
1.2010 + }
1.2011 + pFunc = m_pub_funcs[index];
1.2012 + } else if (pFunc->IsInvalidated()) {
1.2013 + sp_public_t *pub = NULL;
1.2014 + GetPublicByIndex(index, &pub);
1.2015 + if (pub)
1.2016 + {
1.2017 + pFunc->Set(pub->code_offs, this);
1.2018 + } else {
1.2019 + pFunc = NULL;
1.2020 + }
1.2021 + }
1.2022 +
1.2023 + return pFunc;
1.2024 +}
1.2025 +
1.2026 +int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
1.2027 +{
1.2028 + int err;
1.2029 + if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
1.2030 + {
1.2031 + return err;
1.2032 + }
1.2033 +
1.2034 + if ((cell_t *)*addr == m_pNullString)
1.2035 + {
1.2036 + *addr = NULL;
1.2037 + }
1.2038 +
1.2039 + return SP_ERROR_NONE;
1.2040 +}
1.2041 +
1.2042 +#if defined SOURCEMOD_BUILD
1.2043 +SourceMod::IdentityToken_t *BaseContext::GetIdentity()
1.2044 +{
1.2045 + return m_pToken;
1.2046 +}
1.2047 +
1.2048 +void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
1.2049 +{
1.2050 + m_pToken = token;
1.2051 +}
1.2052 +
1.2053 +cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
1.2054 +{
1.2055 + if (type == SP_NULL_VECTOR)
1.2056 + {
1.2057 + return m_pNullVec;
1.2058 + }
1.2059 +
1.2060 + return NULL;
1.2061 +}
1.2062 +#endif