1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/vm/sp_vm_basecontext.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,1120 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourcePawn
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <string.h>
1.36 +#include <stdarg.h>
1.37 +#include <assert.h>
1.38 +#include <limits.h>
1.39 +#include "sp_vm_api.h"
1.40 +#include "sp_vm_basecontext.h"
1.41 +#include "sp_vm_engine.h"
1.42 +
1.43 +#ifdef SOURCEMOD_BUILD
1.44 +#include "Logger.h"
1.45 +#include "DebugReporter.h"
1.46 +#endif
1.47 +
1.48 +using namespace SourcePawn;
1.49 +
1.50 +extern SourcePawnEngine g_SourcePawn;
1.51 +
1.52 +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
1.53 +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
1.54 +
1.55 +int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
1.56 +{
1.57 + g_SourcePawn.RunTracer(ctx, frm, cip);
1.58 +
1.59 + return SP_ERROR_NONE;
1.60 +}
1.61 +
1.62 +BaseContext::BaseContext(sp_context_t *_ctx)
1.63 +{
1.64 + ctx = _ctx;
1.65 + ctx->context = this;
1.66 + ctx->dbreak = GlobalDebugBreak;
1.67 +
1.68 + if (ctx->prof_flags != 0)
1.69 + {
1.70 + ctx->profiler = sm_profiler;
1.71 + }
1.72 +
1.73 + m_InExec = false;
1.74 + m_CustomMsg = false;
1.75 + m_funcsnum = ctx->vmbase->FunctionCount(ctx);
1.76 +#if 0
1.77 + m_priv_funcs = NULL;
1.78 +#endif
1.79 + m_pub_funcs = NULL;
1.80 +
1.81 +#if 0
1.82 + /**
1.83 + * Note: Since the m_plugin member will never change,
1.84 + * it is safe to assume the function count will never change
1.85 + */
1.86 + if (m_funcsnum && m_priv_funcs == NULL)
1.87 + {
1.88 + m_priv_funcs = new CFunction *[m_funcsnum];
1.89 + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
1.90 + } else {
1.91 + m_priv_funcs = NULL;
1.92 + }
1.93 +#endif
1.94 +
1.95 + if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
1.96 + {
1.97 + m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
1.98 + memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
1.99 + } else {
1.100 + m_pub_funcs = NULL;
1.101 + }
1.102 +
1.103 + /* Initialize the null references */
1.104 + uint32_t index;
1.105 + if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
1.106 + {
1.107 + sp_pubvar_t *pubvar;
1.108 + GetPubvarByIndex(index, &pubvar);
1.109 + m_pNullVec = pubvar->offs;
1.110 + } else {
1.111 + m_pNullVec = NULL;
1.112 + }
1.113 +
1.114 + if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
1.115 + {
1.116 + sp_pubvar_t *pubvar;
1.117 + GetPubvarByIndex(index, &pubvar);
1.118 + m_pNullString = pubvar->offs;
1.119 + } else {
1.120 + m_pNullString = NULL;
1.121 + }
1.122 +}
1.123 +
1.124 +void BaseContext::FlushFunctionCache()
1.125 +{
1.126 + if (m_pub_funcs)
1.127 + {
1.128 + for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
1.129 + {
1.130 + delete m_pub_funcs[i];
1.131 + m_pub_funcs[i] = NULL;
1.132 + }
1.133 + }
1.134 +
1.135 +#if 0
1.136 + if (m_priv_funcs)
1.137 + {
1.138 + for (unsigned int i=0; i<m_funcsnum; i++)
1.139 + {
1.140 + delete m_priv_funcs[i];
1.141 + m_priv_funcs[i] = NULL;
1.142 + }
1.143 + }
1.144 +#endif
1.145 +}
1.146 +
1.147 +void BaseContext::RefreshFunctionCache()
1.148 +{
1.149 + if (m_pub_funcs)
1.150 + {
1.151 + sp_public_t *pub;
1.152 + for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
1.153 + {
1.154 + if (!m_pub_funcs[i])
1.155 + {
1.156 + continue;
1.157 + }
1.158 + if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
1.159 + {
1.160 + continue;
1.161 + }
1.162 + m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid, i);
1.163 + }
1.164 + }
1.165 +
1.166 +#if 0
1.167 + if (m_priv_funcs)
1.168 + {
1.169 + for (unsigned int i=0; i<m_funcsnum; i++)
1.170 + {
1.171 + if (!m_priv_funcs[i])
1.172 + {
1.173 + continue;
1.174 + }
1.175 + g_pVM->
1.176 + }
1.177 + }
1.178 +#endif
1.179 +}
1.180 +
1.181 +BaseContext::~BaseContext()
1.182 +{
1.183 + FlushFunctionCache();
1.184 + delete [] m_pub_funcs;
1.185 + m_pub_funcs = NULL;
1.186 +#if 0
1.187 + delete [] m_priv_funcs;
1.188 + m_priv_funcs = NULL;
1.189 +#endif
1.190 +}
1.191 +
1.192 +void BaseContext::SetContext(sp_context_t *_ctx)
1.193 +{
1.194 + if (!_ctx)
1.195 + {
1.196 + return;
1.197 + }
1.198 +
1.199 + ctx = _ctx;
1.200 + ctx->context = this;
1.201 + ctx->dbreak = GlobalDebugBreak;
1.202 +
1.203 + if (ctx->prof_flags != 0)
1.204 + {
1.205 + ctx->profiler = sm_profiler;
1.206 + }
1.207 +
1.208 + RefreshFunctionCache();
1.209 +}
1.210 +
1.211 +IVirtualMachine *BaseContext::GetVirtualMachine()
1.212 +{
1.213 + return (IVirtualMachine *)ctx->vmbase;
1.214 +}
1.215 +
1.216 +sp_context_t *BaseContext::GetContext()
1.217 +{
1.218 + return ctx;
1.219 +}
1.220 +
1.221 +bool BaseContext::IsDebugging()
1.222 +{
1.223 + return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
1.224 +}
1.225 +
1.226 +int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
1.227 +{
1.228 + if (!IsDebugging())
1.229 + {
1.230 + return SP_ERROR_NOTDEBUGGING;
1.231 + }
1.232 +
1.233 + *oldpfn = ctx->dbreak;
1.234 + ctx->dbreak = newpfn;
1.235 +
1.236 + return SP_ERROR_NONE;
1.237 +}
1.238 +
1.239 +IPluginDebugInfo *BaseContext::GetDebugInfo()
1.240 +{
1.241 + if (!IsDebugging())
1.242 + {
1.243 + return NULL;
1.244 + }
1.245 + return this;
1.246 +}
1.247 +
1.248 +int BaseContext::Execute(uint32_t code_addr, cell_t *result)
1.249 +{
1.250 + if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
1.251 + {
1.252 + return SP_ERROR_NOT_RUNNABLE;
1.253 + }
1.254 +
1.255 + /* tada, prevent a crash */
1.256 + cell_t _ignore_result;
1.257 + if (!result)
1.258 + {
1.259 + result = &_ignore_result;
1.260 + }
1.261 +
1.262 + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
1.263 +
1.264 + uint32_t pushcount = ctx->pushcount;
1.265 + int err;
1.266 +
1.267 + if ((err = PushCell(pushcount++)) != SP_ERROR_NONE)
1.268 + {
1.269 +#if defined SOURCEMOD_BUILD
1.270 + g_DbgReporter.GenerateCodeError(this, code_addr, err, "Stack error; cannot complete execution!");
1.271 +#endif
1.272 + return SP_ERROR_NOT_RUNNABLE;
1.273 + }
1.274 + ctx->pushcount = 0;
1.275 +
1.276 + cell_t save_sp = ctx->sp + (pushcount * sizeof(cell_t));
1.277 + cell_t save_hp = ctx->hp;
1.278 + uint32_t n_idx = ctx->n_idx;
1.279 +
1.280 + bool wasExec = m_InExec;
1.281 +
1.282 + /* Clear the error state, if any */
1.283 + ctx->n_err = SP_ERROR_NONE;
1.284 + ctx->n_idx = 0;
1.285 + m_InExec = true;
1.286 + m_MsgCache[0] = '\0';
1.287 + m_CustomMsg = false;
1.288 +
1.289 + g_SourcePawn.PushTracer(ctx);
1.290 +
1.291 + err = vm->ContextExecute(ctx, code_addr, result);
1.292 +
1.293 + m_InExec = wasExec;
1.294 +
1.295 + /**
1.296 + * :TODO: Calling from a plugin in here will erase the cached message...
1.297 + * Should that be documented?
1.298 + */
1.299 + g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
1.300 +
1.301 +#if defined SOURCEMOD_BUILD
1.302 + if (err == SP_ERROR_NONE)
1.303 + {
1.304 + if (ctx->sp != save_sp)
1.305 + {
1.306 + g_DbgReporter.GenerateCodeError(this,
1.307 + code_addr,
1.308 + SP_ERROR_STACKLEAK,
1.309 + "Stack leak detected: sp:%d should be %d!",
1.310 + ctx->sp,
1.311 + save_sp);
1.312 + }
1.313 + if (ctx->hp != save_hp)
1.314 + {
1.315 + g_DbgReporter.GenerateCodeError(this,
1.316 + code_addr,
1.317 + SP_ERROR_HEAPLEAK,
1.318 + "Heap leak detected: sp:%d should be %d!",
1.319 + ctx->hp,
1.320 + save_hp);
1.321 + }
1.322 + }
1.323 +#endif
1.324 +
1.325 + if (err != SP_ERROR_NONE)
1.326 + {
1.327 + ctx->sp = save_sp;
1.328 + ctx->hp = save_hp;
1.329 + }
1.330 +
1.331 + ctx->n_idx = n_idx;
1.332 + ctx->n_err = SP_ERROR_NONE;
1.333 + m_MsgCache[0] = '\0';
1.334 + m_CustomMsg = false;
1.335 +
1.336 + return err;
1.337 +}
1.338 +
1.339 +void BaseContext::SetErrorMessage(const char *msg, va_list ap)
1.340 +{
1.341 + m_CustomMsg = true;
1.342 +
1.343 + vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
1.344 +}
1.345 +
1.346 +cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
1.347 +{
1.348 + if (!m_InExec)
1.349 + {
1.350 + return 0;
1.351 + }
1.352 +
1.353 + ctx->n_err = error;
1.354 +
1.355 + if (msg)
1.356 + {
1.357 + va_list ap;
1.358 + va_start(ap, msg);
1.359 + SetErrorMessage(msg, ap);
1.360 + va_end(ap);
1.361 + }
1.362 +
1.363 + return 0;
1.364 +}
1.365 +
1.366 +cell_t BaseContext::ThrowNativeError(const char *msg, ...)
1.367 +{
1.368 + if (!m_InExec)
1.369 + {
1.370 + return 0;
1.371 + }
1.372 +
1.373 + ctx->n_err = SP_ERROR_NATIVE;
1.374 +
1.375 + if (msg)
1.376 + {
1.377 + va_list ap;
1.378 + va_start(ap, msg);
1.379 + SetErrorMessage(msg, ap);
1.380 + va_end(ap);
1.381 + }
1.382 +
1.383 + return 0;
1.384 +}
1.385 +
1.386 +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
1.387 +{
1.388 + cell_t *addr;
1.389 + ucell_t realmem;
1.390 +
1.391 +#if 0
1.392 + if (cells > CELLBOUNDMAX)
1.393 + {
1.394 + return SP_ERROR_ARAM;
1.395 + }
1.396 +#else
1.397 + assert(cells < CELLBOUNDMAX);
1.398 +#endif
1.399 +
1.400 + realmem = cells * sizeof(cell_t);
1.401 +
1.402 + /**
1.403 + * Check if the space between the heap and stack is sufficient.
1.404 + */
1.405 + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
1.406 + {
1.407 + return SP_ERROR_HEAPLOW;
1.408 + }
1.409 +
1.410 + addr = (cell_t *)(ctx->memory + ctx->hp);
1.411 + /* store size of allocation in cells */
1.412 + *addr = (cell_t)cells;
1.413 + addr++;
1.414 + ctx->hp += sizeof(cell_t);
1.415 +
1.416 + *local_addr = ctx->hp;
1.417 +
1.418 + if (phys_addr)
1.419 + {
1.420 + *phys_addr = addr;
1.421 + }
1.422 +
1.423 + ctx->hp += realmem;
1.424 +
1.425 + return SP_ERROR_NONE;
1.426 +}
1.427 +
1.428 +int BaseContext::HeapPop(cell_t local_addr)
1.429 +{
1.430 + cell_t cellcount;
1.431 + cell_t *addr;
1.432 +
1.433 + /* check the bounds of this address */
1.434 + local_addr -= sizeof(cell_t);
1.435 + if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
1.436 + {
1.437 + return SP_ERROR_INVALID_ADDRESS;
1.438 + }
1.439 +
1.440 + addr = (cell_t *)(ctx->memory + local_addr);
1.441 + cellcount = (*addr) * sizeof(cell_t);
1.442 + /* check if this memory count looks valid */
1.443 + if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
1.444 + {
1.445 + return SP_ERROR_INVALID_ADDRESS;
1.446 + }
1.447 +
1.448 + ctx->hp = local_addr;
1.449 +
1.450 + return SP_ERROR_NONE;
1.451 +}
1.452 +
1.453 +
1.454 +int BaseContext::HeapRelease(cell_t local_addr)
1.455 +{
1.456 + if (local_addr < ctx->heap_base)
1.457 + {
1.458 + return SP_ERROR_INVALID_ADDRESS;
1.459 + }
1.460 +
1.461 + ctx->hp = local_addr - sizeof(cell_t);
1.462 +
1.463 + return SP_ERROR_NONE;
1.464 +}
1.465 +
1.466 +int BaseContext::FindNativeByName(const char *name, uint32_t *index)
1.467 +{
1.468 + int high;
1.469 +
1.470 + high = ctx->plugin->info.natives_num - 1;
1.471 +
1.472 + for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
1.473 + {
1.474 + if (strcmp(ctx->natives[i].name, name) == 0)
1.475 + {
1.476 + if (index)
1.477 + {
1.478 + *index = i;
1.479 + }
1.480 + return SP_ERROR_NONE;
1.481 + }
1.482 + }
1.483 +
1.484 + return SP_ERROR_NOT_FOUND;
1.485 +}
1.486 +
1.487 +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
1.488 +{
1.489 + if (index >= ctx->plugin->info.natives_num)
1.490 + {
1.491 + return SP_ERROR_INDEX;
1.492 + }
1.493 +
1.494 + if (native)
1.495 + {
1.496 + *native = &(ctx->natives[index]);
1.497 + }
1.498 +
1.499 + return SP_ERROR_NONE;
1.500 +}
1.501 +
1.502 +
1.503 +uint32_t BaseContext::GetNativesNum()
1.504 +{
1.505 + return ctx->plugin->info.natives_num;
1.506 +}
1.507 +
1.508 +int BaseContext::FindPublicByName(const char *name, uint32_t *index)
1.509 +{
1.510 + int diff, high, low;
1.511 + uint32_t mid;
1.512 +
1.513 + high = ctx->plugin->info.publics_num - 1;
1.514 + low = 0;
1.515 +
1.516 + while (low <= high)
1.517 + {
1.518 + mid = (low + high) / 2;
1.519 + diff = strcmp(ctx->publics[mid].name, name);
1.520 + if (diff == 0)
1.521 + {
1.522 + if (index)
1.523 + {
1.524 + *index = mid;
1.525 + }
1.526 + return SP_ERROR_NONE;
1.527 + } else if (diff < 0) {
1.528 + low = mid + 1;
1.529 + } else {
1.530 + high = mid - 1;
1.531 + }
1.532 + }
1.533 +
1.534 + return SP_ERROR_NOT_FOUND;
1.535 +}
1.536 +
1.537 +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
1.538 +{
1.539 + if (index >= ctx->plugin->info.publics_num)
1.540 + {
1.541 + return SP_ERROR_INDEX;
1.542 + }
1.543 +
1.544 + if (pblic)
1.545 + {
1.546 + *pblic = &(ctx->publics[index]);
1.547 + }
1.548 +
1.549 + return SP_ERROR_NONE;
1.550 +}
1.551 +
1.552 +uint32_t BaseContext::GetPublicsNum()
1.553 +{
1.554 + return ctx->plugin->info.publics_num;
1.555 +}
1.556 +
1.557 +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
1.558 +{
1.559 + if (index >= ctx->plugin->info.pubvars_num)
1.560 + {
1.561 + return SP_ERROR_INDEX;
1.562 + }
1.563 +
1.564 + if (pubvar)
1.565 + {
1.566 + *pubvar = &(ctx->pubvars[index]);
1.567 + }
1.568 +
1.569 + return SP_ERROR_NONE;
1.570 +}
1.571 +
1.572 +int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
1.573 +{
1.574 + int diff, high, low;
1.575 + uint32_t mid;
1.576 +
1.577 + high = ctx->plugin->info.pubvars_num - 1;
1.578 + low = 0;
1.579 +
1.580 + while (low <= high)
1.581 + {
1.582 + mid = (low + high) / 2;
1.583 + diff = strcmp(ctx->pubvars[mid].name, name);
1.584 + if (diff == 0)
1.585 + {
1.586 + if (index)
1.587 + {
1.588 + *index = mid;
1.589 + }
1.590 + return SP_ERROR_NONE;
1.591 + } else if (diff < 0) {
1.592 + low = mid + 1;
1.593 + } else {
1.594 + high = mid - 1;
1.595 + }
1.596 + }
1.597 +
1.598 + return SP_ERROR_NOT_FOUND;
1.599 +}
1.600 +
1.601 +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
1.602 +{
1.603 + if (index >= ctx->plugin->info.pubvars_num)
1.604 + {
1.605 + return SP_ERROR_INDEX;
1.606 + }
1.607 +
1.608 + *local_addr = ctx->plugin->info.pubvars[index].address;
1.609 + *phys_addr = ctx->pubvars[index].offs;
1.610 +
1.611 + return SP_ERROR_NONE;
1.612 +}
1.613 +
1.614 +uint32_t BaseContext::GetPubVarsNum()
1.615 +{
1.616 + return ctx->plugin->info.pubvars_num;
1.617 +}
1.618 +
1.619 +int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
1.620 +{
1.621 + uint32_t i, j, max;
1.622 +
1.623 + max = ctx->plugin->info.natives_num;
1.624 +
1.625 + for (i=0; i<max; i++)
1.626 + {
1.627 + if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
1.628 + {
1.629 + continue;
1.630 + }
1.631 +
1.632 + for (j=0; (natives[j].name) && (!num || j<num); j++)
1.633 + {
1.634 + if (!strcmp(ctx->natives[i].name, natives[j].name))
1.635 + {
1.636 + ctx->natives[i].pfn = natives[j].func;
1.637 + ctx->natives[i].status = SP_NATIVE_BOUND;
1.638 + }
1.639 + }
1.640 + }
1.641 +
1.642 + return SP_ERROR_NONE;
1.643 +}
1.644 +
1.645 +int BaseContext::BindNative(const sp_nativeinfo_t *native)
1.646 +{
1.647 + uint32_t index;
1.648 + int err;
1.649 +
1.650 + if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
1.651 + {
1.652 + return err;
1.653 + }
1.654 +
1.655 + ctx->natives[index].pfn = native->func;
1.656 + ctx->natives[index].status = SP_NATIVE_BOUND;
1.657 +
1.658 + return SP_ERROR_NONE;
1.659 +}
1.660 +
1.661 +int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
1.662 +{
1.663 + int err;
1.664 + sp_native_t *native;
1.665 +
1.666 + if ((err = GetNativeByIndex(index, &native)) != SP_ERROR_NONE)
1.667 + {
1.668 + return err;
1.669 + }
1.670 +
1.671 + ctx->natives[index].pfn = func;
1.672 + ctx->natives[index].status = SP_NATIVE_BOUND;
1.673 +
1.674 + return SP_ERROR_NONE;
1.675 +}
1.676 +
1.677 +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
1.678 +{
1.679 + uint32_t nativesnum, i;
1.680 +
1.681 + nativesnum = ctx->plugin->info.natives_num;
1.682 +
1.683 + for (i=0; i<nativesnum; i++)
1.684 + {
1.685 + if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
1.686 + {
1.687 + ctx->natives[i].pfn = native;
1.688 + ctx->natives[i].status = SP_NATIVE_BOUND;
1.689 + }
1.690 + }
1.691 +
1.692 + return SP_ERROR_NONE;
1.693 +}
1.694 +
1.695 +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_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 +
1.702 + if (phys_addr)
1.703 + {
1.704 + *phys_addr = (cell_t *)(ctx->memory + local_addr);
1.705 + }
1.706 +
1.707 + return SP_ERROR_NONE;
1.708 +}
1.709 +
1.710 +int BaseContext::PushCell(cell_t value)
1.711 +{
1.712 + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
1.713 + {
1.714 + return SP_ERROR_STACKLOW;
1.715 + }
1.716 +
1.717 + ctx->sp -= sizeof(cell_t);
1.718 + *(cell_t *)(ctx->memory + ctx->sp) = value;
1.719 + ctx->pushcount++;
1.720 +
1.721 + return SP_ERROR_NONE;
1.722 +}
1.723 +
1.724 +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
1.725 +{
1.726 + unsigned int i;
1.727 + int err;
1.728 +
1.729 + for (i=0; i<numcells; i++)
1.730 + {
1.731 + if ((err = PushCell(array[i])) != SP_ERROR_NONE)
1.732 + {
1.733 + ctx->sp += (cell_t)(i * sizeof(cell_t));
1.734 + ctx->pushcount -= i;
1.735 + return err;
1.736 + }
1.737 + }
1.738 +
1.739 + return SP_ERROR_NONE;
1.740 +}
1.741 +
1.742 +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
1.743 +{
1.744 + cell_t *ph_addr;
1.745 + int err;
1.746 +
1.747 + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
1.748 + {
1.749 + return err;
1.750 + }
1.751 +
1.752 + memcpy(ph_addr, array, numcells * sizeof(cell_t));
1.753 +
1.754 + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.755 + {
1.756 + HeapRelease(*local_addr);
1.757 + return err;
1.758 + }
1.759 +
1.760 + if (phys_addr)
1.761 + {
1.762 + *phys_addr = ph_addr;
1.763 + }
1.764 +
1.765 + return SP_ERROR_NONE;
1.766 +}
1.767 +
1.768 +int BaseContext::LocalToString(cell_t local_addr, char **addr)
1.769 +{
1.770 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.771 + {
1.772 + return SP_ERROR_INVALID_ADDRESS;
1.773 + }
1.774 + *addr = (char *)(ctx->memory + local_addr);
1.775 +
1.776 + return SP_ERROR_NONE;
1.777 +}
1.778 +
1.779 +int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
1.780 +{
1.781 + char *ph_addr;
1.782 + int err;
1.783 + unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
1.784 +
1.785 + if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
1.786 + {
1.787 + return err;
1.788 + }
1.789 +
1.790 + memcpy(ph_addr, string, len);
1.791 + ph_addr[len] = '\0';
1.792 +
1.793 + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.794 + {
1.795 + HeapRelease(*local_addr);
1.796 + return err;
1.797 + }
1.798 +
1.799 + if (phys_addr)
1.800 + {
1.801 + *phys_addr = ph_addr;
1.802 + }
1.803 +
1.804 + return SP_ERROR_NONE;
1.805 +}
1.806 +
1.807 +int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
1.808 +{
1.809 + char *dest;
1.810 + size_t len;
1.811 +
1.812 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.813 + {
1.814 + return SP_ERROR_INVALID_ADDRESS;
1.815 + }
1.816 +
1.817 + if (bytes == 0)
1.818 + {
1.819 + return SP_ERROR_NONE;
1.820 + }
1.821 +
1.822 + len = strlen(source);
1.823 + dest = (char *)(ctx->memory + local_addr);
1.824 +
1.825 + if (len >= bytes)
1.826 + {
1.827 + len = bytes - 1;
1.828 + }
1.829 +
1.830 + memmove(dest, source, len);
1.831 + dest[len] = '\0';
1.832 +
1.833 + return SP_ERROR_NONE;
1.834 +}
1.835 +
1.836 +inline int __CheckValidChar(char *c)
1.837 +{
1.838 + int count;
1.839 + int bytecount = 0;
1.840 +
1.841 + for (count=1; (*c & 0xC0) == 0x80; count++)
1.842 + {
1.843 + c--;
1.844 + }
1.845 +
1.846 + switch (*c & 0xF0)
1.847 + {
1.848 + case 0xC0:
1.849 + case 0xD0:
1.850 + {
1.851 + bytecount = 2;
1.852 + break;
1.853 + }
1.854 + case 0xE0:
1.855 + {
1.856 + bytecount = 3;
1.857 + break;
1.858 + }
1.859 + case 0xF0:
1.860 + {
1.861 + bytecount = 4;
1.862 + break;
1.863 + }
1.864 + }
1.865 +
1.866 + if (bytecount != count)
1.867 + {
1.868 + return count;
1.869 + }
1.870 +
1.871 + return 0;
1.872 +}
1.873 +
1.874 +int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
1.875 +{
1.876 + char *dest;
1.877 + size_t len;
1.878 + bool needtocheck = false;
1.879 +
1.880 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.881 + {
1.882 + return SP_ERROR_INVALID_ADDRESS;
1.883 + }
1.884 +
1.885 + if (maxbytes == 0)
1.886 + {
1.887 + return SP_ERROR_NONE;
1.888 + }
1.889 +
1.890 + len = strlen(source);
1.891 + dest = (char *)(ctx->memory + local_addr);
1.892 +
1.893 + if ((size_t)len >= maxbytes)
1.894 + {
1.895 + len = maxbytes - 1;
1.896 + needtocheck = true;
1.897 + }
1.898 +
1.899 + memmove(dest, source, len);
1.900 + if ((dest[len-1] & 1<<7) && needtocheck)
1.901 + {
1.902 + len -= __CheckValidChar(dest+len-1);
1.903 + }
1.904 + dest[len] = '\0';
1.905 +
1.906 + if (wrtnbytes)
1.907 + {
1.908 + *wrtnbytes = len;
1.909 + }
1.910 +
1.911 + return SP_ERROR_NONE;
1.912 +}
1.913 +
1.914 +#define USHR(x) ((unsigned int)(x)>>1)
1.915 +
1.916 +int BaseContext::LookupFile(ucell_t addr, const char **filename)
1.917 +{
1.918 + int high, low, mid;
1.919 +
1.920 + high = ctx->plugin->debug.files_num;
1.921 + low = -1;
1.922 +
1.923 + while (high - low > 1)
1.924 + {
1.925 + mid = USHR(low + high);
1.926 + if (ctx->files[mid].addr <= addr)
1.927 + {
1.928 + low = mid;
1.929 + } else {
1.930 + high = mid;
1.931 + }
1.932 + }
1.933 +
1.934 + if (low == -1)
1.935 + {
1.936 + return SP_ERROR_NOT_FOUND;
1.937 + }
1.938 +
1.939 + *filename = ctx->files[low].name;
1.940 +
1.941 + return SP_ERROR_NONE;
1.942 +}
1.943 +
1.944 +int BaseContext::LookupFunction(ucell_t addr, const char **name)
1.945 +{
1.946 + uint32_t iter, max = ctx->plugin->debug.syms_num;
1.947 +
1.948 + for (iter=0; iter<max; iter++)
1.949 + {
1.950 + if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION)
1.951 + && (ctx->symbols[iter].codestart <= addr)
1.952 + && (ctx->symbols[iter].codeend > addr))
1.953 + {
1.954 + break;
1.955 + }
1.956 + }
1.957 +
1.958 + if (iter >= max)
1.959 + {
1.960 + return SP_ERROR_NOT_FOUND;
1.961 + }
1.962 +
1.963 + *name = ctx->symbols[iter].name;
1.964 +
1.965 + return SP_ERROR_NONE;
1.966 +}
1.967 +
1.968 +int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
1.969 +{
1.970 + int high, low, mid;
1.971 +
1.972 + high = ctx->plugin->debug.lines_num;
1.973 + low = -1;
1.974 +
1.975 + while (high - low > 1)
1.976 + {
1.977 + mid = USHR(low + high);
1.978 + if (ctx->lines[mid].addr <= addr)
1.979 + {
1.980 + low = mid;
1.981 + } else {
1.982 + high = mid;
1.983 + }
1.984 + }
1.985 +
1.986 + if (low == -1)
1.987 + {
1.988 + return SP_ERROR_NOT_FOUND;
1.989 + }
1.990 +
1.991 + /* Since the CIP occurs BEFORE the line, we have to add one */
1.992 + *line = ctx->lines[low].line + 1;
1.993 +
1.994 + return SP_ERROR_NONE;
1.995 +}
1.996 +
1.997 +IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
1.998 +{
1.999 + CFunction *pFunc = NULL;
1.1000 +
1.1001 + if (func_id & 1)
1.1002 + {
1.1003 + func_id >>= 1;
1.1004 + if (func_id >= ctx->plugin->info.publics_num)
1.1005 + {
1.1006 + return NULL;
1.1007 + }
1.1008 + pFunc = m_pub_funcs[func_id];
1.1009 + if (!pFunc)
1.1010 + {
1.1011 + m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs,
1.1012 + this,
1.1013 + ctx->publics[func_id].funcid,
1.1014 + func_id);
1.1015 + pFunc = m_pub_funcs[func_id];
1.1016 + }
1.1017 + else if (pFunc->IsInvalidated())
1.1018 + {
1.1019 + pFunc->Set(ctx->publics[func_id].code_offs,
1.1020 + this,
1.1021 + ctx->publics[func_id].funcid,
1.1022 + func_id);
1.1023 + }
1.1024 + } else {
1.1025 + /* :TODO: currently not used */
1.1026 +#if 0
1.1027 + func_id >>= 1;
1.1028 + unsigned int index;
1.1029 + if (!g_pVM->FunctionLookup(ctx, func_id, &index))
1.1030 + {
1.1031 + return NULL;
1.1032 + }
1.1033 + pFunc = m_priv_funcs[func_id];
1.1034 + if (!pFunc)
1.1035 + {
1.1036 + m_priv_funcs[func_id] = new CFunction(save, this);
1.1037 + pFunc = m_priv_funcs[func_id];
1.1038 + }
1.1039 +#endif
1.1040 + }
1.1041 +
1.1042 + return pFunc;
1.1043 +}
1.1044 +
1.1045 +IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
1.1046 +{
1.1047 + uint32_t index;
1.1048 +
1.1049 + if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
1.1050 + {
1.1051 + return NULL;
1.1052 + }
1.1053 +
1.1054 + CFunction *pFunc = m_pub_funcs[index];
1.1055 + if (!pFunc)
1.1056 + {
1.1057 + sp_public_t *pub = NULL;
1.1058 + GetPublicByIndex(index, &pub);
1.1059 + if (pub)
1.1060 + {
1.1061 + m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid, index);
1.1062 + }
1.1063 + pFunc = m_pub_funcs[index];
1.1064 + }
1.1065 + else if (pFunc->IsInvalidated())
1.1066 + {
1.1067 + sp_public_t *pub = NULL;
1.1068 + GetPublicByIndex(index, &pub);
1.1069 + if (pub)
1.1070 + {
1.1071 + pFunc->Set(pub->code_offs, this, pub->funcid, index);
1.1072 + }
1.1073 + else
1.1074 + {
1.1075 + pFunc = NULL;
1.1076 + }
1.1077 + }
1.1078 +
1.1079 + return pFunc;
1.1080 +}
1.1081 +
1.1082 +int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
1.1083 +{
1.1084 + int err;
1.1085 + if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
1.1086 + {
1.1087 + return err;
1.1088 + }
1.1089 +
1.1090 + if ((cell_t *)*addr == m_pNullString)
1.1091 + {
1.1092 + *addr = NULL;
1.1093 + }
1.1094 +
1.1095 + return SP_ERROR_NONE;
1.1096 +}
1.1097 +
1.1098 +#if defined SOURCEMOD_BUILD
1.1099 +SourceMod::IdentityToken_t *BaseContext::GetIdentity()
1.1100 +{
1.1101 + return m_pToken;
1.1102 +}
1.1103 +
1.1104 +void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
1.1105 +{
1.1106 + m_pToken = token;
1.1107 +}
1.1108 +
1.1109 +cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
1.1110 +{
1.1111 + if (type == SP_NULL_VECTOR)
1.1112 + {
1.1113 + return m_pNullVec;
1.1114 + }
1.1115 +
1.1116 + return NULL;
1.1117 +}
1.1118 +#endif
1.1119 +
1.1120 +bool BaseContext::IsInExec()
1.1121 +{
1.1122 + return m_InExec;
1.1123 +}