dvander@1231: /**
dvander@1231: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourcePawn
dvander@1231: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@1231: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@1231: *
dvander@1231: * Version: $Id$
dvander@1269: */
dvander@1269:
dvander@1269: #include
dvander@1269: #include
dvander@1269: #include
dvander@1269: #include
dvander@1269: #include "sp_vm_api.h"
dvander@1269: #include "sp_vm_basecontext.h"
dvander@1269: #include "sp_vm_engine.h"
dvander@1269:
dvander@1269: #ifdef SOURCEMOD_BUILD
dvander@1269: #include "Logger.h"
dvander@1339: #include "DebugReporter.h"
dvander@1269: #endif
dvander@1269:
dvander@1269: using namespace SourcePawn;
dvander@1269:
dvander@1269: extern SourcePawnEngine g_SourcePawn;
dvander@1269:
dvander@1269: #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
dvander@1269: #define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
dvander@1269:
dvander@1269: int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
dvander@1269: {
dvander@1269: g_SourcePawn.RunTracer(ctx, frm, cip);
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: BaseContext::BaseContext(sp_context_t *_ctx)
dvander@1269: {
dvander@1269: ctx = _ctx;
dvander@1269: ctx->context = this;
dvander@1269: ctx->dbreak = GlobalDebugBreak;
dvander@1269: m_InExec = false;
dvander@1269: m_CustomMsg = false;
dvander@1269: m_funcsnum = ctx->vmbase->FunctionCount(ctx);
dvander@1269: #if 0
dvander@1269: m_priv_funcs = NULL;
dvander@1269: #endif
dvander@1269: m_pub_funcs = NULL;
dvander@1269:
dvander@1269: #if 0
dvander@1269: /**
dvander@1269: * Note: Since the m_plugin member will never change,
dvander@1269: * it is safe to assume the function count will never change
dvander@1269: */
dvander@1269: if (m_funcsnum && m_priv_funcs == NULL)
dvander@1269: {
dvander@1269: m_priv_funcs = new CFunction *[m_funcsnum];
dvander@1269: memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
dvander@1269: } else {
dvander@1269: m_priv_funcs = NULL;
dvander@1269: }
dvander@1269: #endif
dvander@1269:
dvander@1269: if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
dvander@1269: {
dvander@1269: m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
dvander@1269: memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
dvander@1269: } else {
dvander@1269: m_pub_funcs = NULL;
dvander@1269: }
dvander@1269:
dvander@1269: /* Initialize the null references */
dvander@1269: uint32_t index;
dvander@1269: if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@1269: {
dvander@1269: sp_pubvar_t *pubvar;
dvander@1269: GetPubvarByIndex(index, &pubvar);
dvander@1269: m_pNullVec = pubvar->offs;
dvander@1269: } else {
dvander@1269: m_pNullVec = NULL;
dvander@1269: }
dvander@1269:
dvander@1269: if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
dvander@1269: {
dvander@1269: sp_pubvar_t *pubvar;
dvander@1269: GetPubvarByIndex(index, &pubvar);
dvander@1269: m_pNullString = pubvar->offs;
dvander@1269: } else {
dvander@1269: m_pNullString = NULL;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: void BaseContext::FlushFunctionCache()
dvander@1269: {
dvander@1269: if (m_pub_funcs)
dvander@1269: {
dvander@1269: for (uint32_t i=0; iplugin->info.publics_num; i++)
dvander@1269: {
dvander@1269: delete m_pub_funcs[i];
dvander@1269: m_pub_funcs[i] = NULL;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: #if 0
dvander@1269: if (m_priv_funcs)
dvander@1269: {
dvander@1269: for (unsigned int i=0; iplugin->info.publics_num; i++)
dvander@1269: {
dvander@1269: if (!m_pub_funcs[i])
dvander@1269: {
dvander@1269: continue;
dvander@1269: }
dvander@1269: if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: continue;
dvander@1269: }
dvander@1339: m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid);
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: #if 0
dvander@1269: if (m_priv_funcs)
dvander@1269: {
dvander@1269: for (unsigned int i=0; i
dvander@1269: }
dvander@1269: }
dvander@1269: #endif
dvander@1269: }
dvander@1269:
dvander@1269: BaseContext::~BaseContext()
dvander@1269: {
dvander@1269: FlushFunctionCache();
dvander@1269: delete [] m_pub_funcs;
dvander@1269: m_pub_funcs = NULL;
dvander@1269: #if 0
dvander@1269: delete [] m_priv_funcs;
dvander@1269: m_priv_funcs = NULL;
dvander@1269: #endif
dvander@1269: }
dvander@1269:
dvander@1269: void BaseContext::SetContext(sp_context_t *_ctx)
dvander@1269: {
dvander@1269: if (!_ctx)
dvander@1269: {
dvander@1269: return;
dvander@1269: }
dvander@1269: ctx = _ctx;
dvander@1269: ctx->context = this;
dvander@1269: ctx->dbreak = GlobalDebugBreak;
dvander@1269: RefreshFunctionCache();
dvander@1269: }
dvander@1269:
dvander@1269: IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@1269: {
dvander@1269: return (IVirtualMachine *)ctx->vmbase;
dvander@1269: }
dvander@1269:
dvander@1269: sp_context_t *BaseContext::GetContext()
dvander@1269: {
dvander@1269: return ctx;
dvander@1269: }
dvander@1269:
dvander@1269: bool BaseContext::IsDebugging()
dvander@1269: {
dvander@1269: return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
dvander@1269: {
dvander@1269: if (!IsDebugging())
dvander@1269: {
dvander@1269: return SP_ERROR_NOTDEBUGGING;
dvander@1269: }
dvander@1269:
dvander@1269: *oldpfn = ctx->dbreak;
dvander@1269: ctx->dbreak = newpfn;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@1269: {
dvander@1339: if (!IsDebugging())
dvander@1339: {
dvander@1339: return NULL;
dvander@1339: }
dvander@1269: return this;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::Execute(uint32_t code_addr, cell_t *result)
dvander@1269: {
dvander@1269: if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
dvander@1269: {
dvander@1269: return SP_ERROR_NOT_RUNNABLE;
dvander@1269: }
dvander@1269:
dvander@1269: /* tada, prevent a crash */
dvander@1269: cell_t _ignore_result;
dvander@1269: if (!result)
dvander@1269: {
dvander@1269: result = &_ignore_result;
dvander@1269: }
dvander@1269:
dvander@1269: IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
dvander@1269:
dvander@1269: uint32_t pushcount = ctx->pushcount;
dvander@1269: int err;
dvander@1269:
dvander@1339: if ((err = PushCell(pushcount++)) != SP_ERROR_NONE)
dvander@1339: {
dvander@1339: #if defined SOURCEMOD_BUILD
dvander@1339: g_DbgReporter.GenerateCodeError(this, code_addr, err, "Stack error; cannot complete execution!");
dvander@1339: #endif
dvander@1339: return SP_ERROR_NOT_RUNNABLE;
dvander@1339: }
dvander@1269: ctx->pushcount = 0;
dvander@1269:
dvander@1367: cell_t save_sp = ctx->sp + (pushcount * sizeof(cell_t));
dvander@1269: cell_t save_hp = ctx->hp;
dvander@1269: uint32_t n_idx = ctx->n_idx;
dvander@1269:
dvander@1269: bool wasExec = m_InExec;
dvander@1269:
dvander@1269: /* Clear the error state, if any */
dvander@1269: ctx->n_err = SP_ERROR_NONE;
dvander@1269: ctx->n_idx = 0;
dvander@1269: m_InExec = true;
dvander@1269: m_MsgCache[0] = '\0';
dvander@1269: m_CustomMsg = false;
dvander@1269:
dvander@1269: g_SourcePawn.PushTracer(ctx);
dvander@1269:
dvander@1269: err = vm->ContextExecute(ctx, code_addr, result);
dvander@1269:
dvander@1269: m_InExec = wasExec;
dvander@1269:
dvander@1269: /**
dvander@1269: * :TODO: Calling from a plugin in here will erase the cached message...
dvander@1269: * Should that be documented?
dvander@1269: */
dvander@1269: g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
dvander@1269:
dvander@1339: #if defined SOURCEMOD_BUILD
dvander@1269: if (err == SP_ERROR_NONE)
dvander@1269: {
dvander@1367: if (ctx->sp != save_sp)
dvander@1269: {
dvander@1339: g_DbgReporter.GenerateCodeError(this,
dvander@1339: code_addr,
dvander@1339: SP_ERROR_STACKLEAK,
dvander@1339: "Stack leak detected: sp:%d should be %d!",
dvander@1339: ctx->sp,
dvander@1339: save_sp);
dvander@1269: }
dvander@1269: if (ctx->hp != save_hp)
dvander@1269: {
dvander@1339: g_DbgReporter.GenerateCodeError(this,
dvander@1339: code_addr,
dvander@1339: SP_ERROR_HEAPLEAK,
dvander@1339: "Heap leak detected: sp:%d should be %d!",
dvander@1339: ctx->hp,
dvander@1339: save_hp);
dvander@1269: }
dvander@1269: }
dvander@1269: #endif
dvander@1339:
dvander@1269: if (err != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: ctx->sp = save_sp;
dvander@1269: ctx->hp = save_hp;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->n_idx = n_idx;
dvander@1367: ctx->n_err = SP_ERROR_NONE;
dvander@1367: m_MsgCache[0] = '\0';
dvander@1367: m_CustomMsg = false;
dvander@1269:
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@1269: {
dvander@1269: m_CustomMsg = true;
dvander@1269:
dvander@1269: vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@1269: }
dvander@1269:
dvander@1269: cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@1269: {
dvander@1269: if (!m_InExec)
dvander@1269: {
dvander@1269: return 0;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->n_err = error;
dvander@1269:
dvander@1269: if (msg)
dvander@1269: {
dvander@1269: va_list ap;
dvander@1269: va_start(ap, msg);
dvander@1269: SetErrorMessage(msg, ap);
dvander@1269: va_end(ap);
dvander@1269: }
dvander@1269:
dvander@1269: return 0;
dvander@1269: }
dvander@1269:
dvander@1269: cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@1269: {
dvander@1269: if (!m_InExec)
dvander@1269: {
dvander@1269: return 0;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->n_err = SP_ERROR_NATIVE;
dvander@1269:
dvander@1269: if (msg)
dvander@1269: {
dvander@1269: va_list ap;
dvander@1269: va_start(ap, msg);
dvander@1269: SetErrorMessage(msg, ap);
dvander@1269: va_end(ap);
dvander@1269: }
dvander@1269:
dvander@1269: return 0;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@1269: {
dvander@1269: cell_t *addr;
dvander@1269: ucell_t realmem;
dvander@1269:
dvander@1269: #if 0
dvander@1269: if (cells > CELLBOUNDMAX)
dvander@1269: {
dvander@1269: return SP_ERROR_ARAM;
dvander@1269: }
dvander@1269: #else
dvander@1269: assert(cells < CELLBOUNDMAX);
dvander@1269: #endif
dvander@1269:
dvander@1269: realmem = cells * sizeof(cell_t);
dvander@1269:
dvander@1269: /**
dvander@1269: * Check if the space between the heap and stack is sufficient.
dvander@1269: */
dvander@1269: if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
dvander@1269: {
dvander@1269: return SP_ERROR_HEAPLOW;
dvander@1269: }
dvander@1269:
dvander@1269: addr = (cell_t *)(ctx->memory + ctx->hp);
dvander@1269: /* store size of allocation in cells */
dvander@1269: *addr = (cell_t)cells;
dvander@1269: addr++;
dvander@1269: ctx->hp += sizeof(cell_t);
dvander@1269:
dvander@1269: *local_addr = ctx->hp;
dvander@1269:
dvander@1269: if (phys_addr)
dvander@1269: {
dvander@1269: *phys_addr = addr;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->hp += realmem;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::HeapPop(cell_t local_addr)
dvander@1269: {
dvander@1269: cell_t cellcount;
dvander@1269: cell_t *addr;
dvander@1269:
dvander@1269: /* check the bounds of this address */
dvander@1269: local_addr -= sizeof(cell_t);
dvander@1269: if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269:
dvander@1269: addr = (cell_t *)(ctx->memory + local_addr);
dvander@1269: cellcount = (*addr) * sizeof(cell_t);
dvander@1269: /* check if this memory count looks valid */
dvander@1269: if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->hp = local_addr;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269:
dvander@1269: int BaseContext::HeapRelease(cell_t local_addr)
dvander@1269: {
dvander@1269: if (local_addr < ctx->heap_base)
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->hp = local_addr - sizeof(cell_t);
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@1269: {
dvander@1269: int high;
dvander@1269:
dvander@1269: high = ctx->plugin->info.natives_num - 1;
dvander@1269:
dvander@1269: for (uint32_t i=0; iplugin->info.natives_num; i++)
dvander@1269: {
dvander@1269: if (strcmp(ctx->natives[i].name, name) == 0)
dvander@1269: {
dvander@1269: if (index)
dvander@1269: {
dvander@1269: *index = i;
dvander@1269: }
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NOT_FOUND;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@1269: {
dvander@1269: if (index >= ctx->plugin->info.natives_num)
dvander@1269: {
dvander@1269: return SP_ERROR_INDEX;
dvander@1269: }
dvander@1269:
dvander@1269: if (native)
dvander@1269: {
dvander@1269: *native = &(ctx->natives[index]);
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269:
dvander@1269: uint32_t BaseContext::GetNativesNum()
dvander@1269: {
dvander@1269: return ctx->plugin->info.natives_num;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@1269: {
dvander@1269: int diff, high, low;
dvander@1269: uint32_t mid;
dvander@1269:
dvander@1269: high = ctx->plugin->info.publics_num - 1;
dvander@1269: low = 0;
dvander@1269:
dvander@1269: while (low <= high)
dvander@1269: {
dvander@1269: mid = (low + high) / 2;
dvander@1269: diff = strcmp(ctx->publics[mid].name, name);
dvander@1269: if (diff == 0)
dvander@1269: {
dvander@1269: if (index)
dvander@1269: {
dvander@1269: *index = mid;
dvander@1269: }
dvander@1269: return SP_ERROR_NONE;
dvander@1269: } else if (diff < 0) {
dvander@1269: low = mid + 1;
dvander@1269: } else {
dvander@1269: high = mid - 1;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NOT_FOUND;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@1269: {
dvander@1269: if (index >= ctx->plugin->info.publics_num)
dvander@1269: {
dvander@1269: return SP_ERROR_INDEX;
dvander@1269: }
dvander@1269:
dvander@1269: if (pblic)
dvander@1269: {
dvander@1269: *pblic = &(ctx->publics[index]);
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: uint32_t BaseContext::GetPublicsNum()
dvander@1269: {
dvander@1269: return ctx->plugin->info.publics_num;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@1269: {
dvander@1269: if (index >= ctx->plugin->info.pubvars_num)
dvander@1269: {
dvander@1269: return SP_ERROR_INDEX;
dvander@1269: }
dvander@1269:
dvander@1269: if (pubvar)
dvander@1269: {
dvander@1269: *pubvar = &(ctx->pubvars[index]);
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@1269: {
dvander@1269: int diff, high, low;
dvander@1269: uint32_t mid;
dvander@1269:
dvander@1269: high = ctx->plugin->info.pubvars_num - 1;
dvander@1269: low = 0;
dvander@1269:
dvander@1269: while (low <= high)
dvander@1269: {
dvander@1269: mid = (low + high) / 2;
dvander@1269: diff = strcmp(ctx->pubvars[mid].name, name);
dvander@1269: if (diff == 0)
dvander@1269: {
dvander@1269: if (index)
dvander@1269: {
dvander@1269: *index = mid;
dvander@1269: }
dvander@1269: return SP_ERROR_NONE;
dvander@1269: } else if (diff < 0) {
dvander@1269: low = mid + 1;
dvander@1269: } else {
dvander@1269: high = mid - 1;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NOT_FOUND;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@1269: {
dvander@1269: if (index >= ctx->plugin->info.pubvars_num)
dvander@1269: {
dvander@1269: return SP_ERROR_INDEX;
dvander@1269: }
dvander@1269:
dvander@1269: *local_addr = ctx->plugin->info.pubvars[index].address;
dvander@1269: *phys_addr = ctx->pubvars[index].offs;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: uint32_t BaseContext::GetPubVarsNum()
dvander@1269: {
dvander@1269: return ctx->plugin->info.pubvars_num;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@1269: {
dvander@1269: uint32_t i, j, max;
dvander@1269:
dvander@1269: max = ctx->plugin->info.natives_num;
dvander@1269:
dvander@1269: for (i=0; inatives[i].status == SP_NATIVE_BOUND) && !overwrite)
dvander@1269: {
dvander@1269: continue;
dvander@1269: }
dvander@1269:
dvander@1269: for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name))
dvander@1269: {
dvander@1269: ctx->natives[i].pfn = natives[j].func;
dvander@1269: ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@1269: }
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@1269: {
dvander@1269: uint32_t index;
dvander@1269: int err;
dvander@1269:
dvander@1269: if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->natives[index].pfn = native->func;
dvander@1269: ctx->natives[index].status = SP_NATIVE_BOUND;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@1269: {
dvander@1269: uint32_t nativesnum, i;
dvander@1269:
dvander@1269: nativesnum = ctx->plugin->info.natives_num;
dvander@1269:
dvander@1269: for (i=0; inatives[i].status == SP_NATIVE_UNBOUND)
dvander@1269: {
dvander@1269: ctx->natives[i].pfn = native;
dvander@1269: ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@1269: {
dvander@1269: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269:
dvander@1269: if (phys_addr)
dvander@1269: {
dvander@1269: *phys_addr = (cell_t *)(ctx->memory + local_addr);
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::PushCell(cell_t value)
dvander@1269: {
dvander@1269: if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
dvander@1269: {
dvander@1269: return SP_ERROR_STACKLOW;
dvander@1269: }
dvander@1269:
dvander@1269: ctx->sp -= sizeof(cell_t);
dvander@1269: *(cell_t *)(ctx->memory + ctx->sp) = value;
dvander@1269: ctx->pushcount++;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@1269: {
dvander@1269: unsigned int i;
dvander@1269: int err;
dvander@1269:
dvander@1269: for (i=0; isp += (cell_t)(i * sizeof(cell_t));
dvander@1269: ctx->pushcount -= i;
dvander@1269: return err;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@1269: {
dvander@1269: cell_t *ph_addr;
dvander@1269: int err;
dvander@1269:
dvander@1269: if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: memcpy(ph_addr, array, numcells * sizeof(cell_t));
dvander@1269:
dvander@1269: if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: HeapRelease(*local_addr);
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: if (phys_addr)
dvander@1269: {
dvander@1269: *phys_addr = ph_addr;
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@1269: {
dvander@1269: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269: *addr = (char *)(ctx->memory + local_addr);
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@1269: {
dvander@1269: char *ph_addr;
dvander@1269: int err;
dvander@1269: unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
dvander@1269:
dvander@1269: if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: memcpy(ph_addr, string, len);
dvander@1269: ph_addr[len] = '\0';
dvander@1269:
dvander@1269: if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: HeapRelease(*local_addr);
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: if (phys_addr)
dvander@1269: {
dvander@1269: *phys_addr = ph_addr;
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@1269: {
dvander@1269: char *dest;
dvander@1269: size_t len;
dvander@1269:
dvander@1269: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269:
dvander@1269: if (bytes == 0)
dvander@1269: {
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: len = strlen(source);
dvander@1269: dest = (char *)(ctx->memory + local_addr);
dvander@1269:
dvander@1269: if (len >= bytes)
dvander@1269: {
dvander@1269: len = bytes - 1;
dvander@1269: }
dvander@1269:
dvander@1269: memcpy(dest, source, len);
dvander@1269: dest[len] = '\0';
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: inline int __CheckValidChar(char *c)
dvander@1269: {
dvander@1269: int count;
dvander@1269: int bytecount = 0;
dvander@1269:
dvander@1269: for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@1269: {
dvander@1269: c--;
dvander@1269: }
dvander@1269:
dvander@1269: switch (*c & 0xF0)
dvander@1269: {
dvander@1269: case 0xC0:
dvander@1269: case 0xD0:
dvander@1269: {
dvander@1269: bytecount = 2;
dvander@1269: break;
dvander@1269: }
dvander@1269: case 0xE0:
dvander@1269: {
dvander@1269: bytecount = 3;
dvander@1269: break;
dvander@1269: }
dvander@1269: case 0xF0:
dvander@1269: {
dvander@1269: bytecount = 4;
dvander@1269: break;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: if (bytecount != count)
dvander@1269: {
dvander@1269: return count;
dvander@1269: }
dvander@1269:
dvander@1269: return 0;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@1269: {
dvander@1269: char *dest;
dvander@1269: size_t len;
dvander@1269: bool needtocheck = false;
dvander@1269:
dvander@1269: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269: {
dvander@1269: return SP_ERROR_INVALID_ADDRESS;
dvander@1269: }
dvander@1269:
dvander@1269: if (maxbytes == 0)
dvander@1269: {
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: len = strlen(source);
dvander@1269: dest = (char *)(ctx->memory + local_addr);
dvander@1269:
dvander@1269: if ((size_t)len >= maxbytes)
dvander@1269: {
dvander@1269: len = maxbytes - 1;
dvander@1269: needtocheck = true;
dvander@1269: }
dvander@1269:
dvander@1269: memcpy(dest, source, len);
dvander@1269: if ((dest[len-1] & 1<<7) && needtocheck)
dvander@1269: {
dvander@1269: len -= __CheckValidChar(dest+len-1);
dvander@1269: }
dvander@1269: dest[len] = '\0';
dvander@1269:
dvander@1269: if (wrtnbytes)
dvander@1269: {
dvander@1269: *wrtnbytes = len;
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: #define USHR(x) ((unsigned int)(x)>>1)
dvander@1269:
dvander@1269: int BaseContext::LookupFile(ucell_t addr, const char **filename)
dvander@1269: {
dvander@1269: int high, low, mid;
dvander@1269:
dvander@1269: high = ctx->plugin->debug.files_num;
dvander@1269: low = -1;
dvander@1269:
dvander@1269: while (high - low > 1)
dvander@1269: {
dvander@1269: mid = USHR(low + high);
dvander@1269: if (ctx->files[mid].addr <= addr)
dvander@1269: {
dvander@1269: low = mid;
dvander@1269: } else {
dvander@1269: high = mid;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: if (low == -1)
dvander@1269: {
dvander@1269: return SP_ERROR_NOT_FOUND;
dvander@1269: }
dvander@1269:
dvander@1269: *filename = ctx->files[low].name;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::LookupFunction(ucell_t addr, const char **name)
dvander@1269: {
dvander@1269: uint32_t iter, max = ctx->plugin->debug.syms_num;
dvander@1269:
dvander@1269: for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION)
dvander@1269: && (ctx->symbols[iter].codestart <= addr)
dvander@1269: && (ctx->symbols[iter].codeend > addr))
dvander@1269: {
dvander@1269: break;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: if (iter >= max)
dvander@1269: {
dvander@1269: return SP_ERROR_NOT_FOUND;
dvander@1269: }
dvander@1269:
dvander@1269: *name = ctx->symbols[iter].name;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
dvander@1269: {
dvander@1269: int high, low, mid;
dvander@1269:
dvander@1269: high = ctx->plugin->debug.lines_num;
dvander@1269: low = -1;
dvander@1269:
dvander@1269: while (high - low > 1)
dvander@1269: {
dvander@1269: mid = USHR(low + high);
dvander@1269: if (ctx->lines[mid].addr <= addr)
dvander@1269: {
dvander@1269: low = mid;
dvander@1269: } else {
dvander@1269: high = mid;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: if (low == -1)
dvander@1269: {
dvander@1269: return SP_ERROR_NOT_FOUND;
dvander@1269: }
dvander@1269:
dvander@1269: /* Since the CIP occurs BEFORE the line, we have to add one */
dvander@1269: *line = ctx->lines[low].line + 1;
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@1269: {
dvander@1269: CFunction *pFunc = NULL;
dvander@1269:
dvander@1269: if (func_id & 1)
dvander@1269: {
dvander@1269: func_id >>= 1;
dvander@1269: if (func_id >= ctx->plugin->info.publics_num)
dvander@1269: {
dvander@1269: return NULL;
dvander@1269: }
dvander@1269: pFunc = m_pub_funcs[func_id];
dvander@1269: if (!pFunc)
dvander@1269: {
dvander@1339: m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
dvander@1269: pFunc = m_pub_funcs[func_id];
dvander@1269: } else if (pFunc->IsInvalidated()) {
dvander@1339: pFunc->Set(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
dvander@1269: }
dvander@1269: } else {
dvander@1269: /* :TODO: currently not used */
dvander@1269: #if 0
dvander@1269: func_id >>= 1;
dvander@1269: unsigned int index;
dvander@1269: if (!g_pVM->FunctionLookup(ctx, func_id, &index))
dvander@1269: {
dvander@1269: return NULL;
dvander@1269: }
dvander@1269: pFunc = m_priv_funcs[func_id];
dvander@1269: if (!pFunc)
dvander@1269: {
dvander@1269: m_priv_funcs[func_id] = new CFunction(save, this);
dvander@1269: pFunc = m_priv_funcs[func_id];
dvander@1269: }
dvander@1269: #endif
dvander@1269: }
dvander@1269:
dvander@1269: return pFunc;
dvander@1269: }
dvander@1269:
dvander@1269: IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@1269: {
dvander@1269: uint32_t index;
dvander@1269:
dvander@1269: if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: return NULL;
dvander@1269: }
dvander@1269:
dvander@1269: CFunction *pFunc = m_pub_funcs[index];
dvander@1269: if (!pFunc)
dvander@1269: {
dvander@1269: sp_public_t *pub = NULL;
dvander@1269: GetPublicByIndex(index, &pub);
dvander@1269: if (pub)
dvander@1269: {
dvander@1339: m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid);
dvander@1269: }
dvander@1269: pFunc = m_pub_funcs[index];
dvander@1269: } else if (pFunc->IsInvalidated()) {
dvander@1269: sp_public_t *pub = NULL;
dvander@1269: GetPublicByIndex(index, &pub);
dvander@1269: if (pub)
dvander@1269: {
dvander@1339: pFunc->Set(pub->code_offs, this, pub->funcid);
dvander@1269: } else {
dvander@1269: pFunc = NULL;
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: return pFunc;
dvander@1269: }
dvander@1269:
dvander@1269: int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@1269: {
dvander@1269: int err;
dvander@1269: if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: return err;
dvander@1269: }
dvander@1269:
dvander@1269: if ((cell_t *)*addr == m_pNullString)
dvander@1269: {
dvander@1269: *addr = NULL;
dvander@1269: }
dvander@1269:
dvander@1269: return SP_ERROR_NONE;
dvander@1269: }
dvander@1269:
dvander@1269: #if defined SOURCEMOD_BUILD
dvander@1269: SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@1269: {
dvander@1269: return m_pToken;
dvander@1269: }
dvander@1269:
dvander@1269: void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
dvander@1269: {
dvander@1269: m_pToken = token;
dvander@1269: }
dvander@1269:
dvander@1269: cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@1269: {
dvander@1269: if (type == SP_NULL_VECTOR)
dvander@1269: {
dvander@1269: return m_pNullVec;
dvander@1269: }
dvander@1269:
dvander@1269: return NULL;
dvander@1269: }
dvander@1269: #endif