dvander@2193: /** dvander@2193: * vim: set ts=4 : dvander@2193: * ============================================================================= dvander@2193: * SourcePawn dvander@2193: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. dvander@2193: * ============================================================================= dvander@2193: * dvander@2193: * This program is free software; you can redistribute it and/or modify it under dvander@2193: * the terms of the GNU General Public License, version 3.0, as published by the dvander@2193: * Free Software Foundation. dvander@2193: * dvander@2193: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@2193: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@2193: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@2193: * details. dvander@2193: * dvander@2193: * You should have received a copy of the GNU General Public License along with dvander@2193: * this program. If not, see . dvander@2193: * dvander@2193: * As a special exception, AlliedModders LLC gives you permission to link the dvander@2193: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@2193: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@2193: * by the Valve Corporation. You must obey the GNU General Public License in dvander@2193: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@2193: * this exception to all derivative works. AlliedModders LLC defines further dvander@2193: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@2193: * or . dvander@2193: * dvander@2193: * Version: $Id$ dvander@2193: */ dvander@2193: dvander@2193: #include dvander@2193: #include dvander@2193: #include dvander@2193: #include dvander@2193: #include "sp_vm_api.h" dvander@2193: #include "sp_vm_basecontext.h" dvander@2193: #include "sp_vm_engine.h" dvander@2193: #include "x86/jit_x86.h" dvander@2193: dvander@2193: using namespace SourcePawn; dvander@2193: dvander@2193: #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) dvander@2193: #define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) dvander@2193: dvander@2193: BaseContext::BaseContext(BaseRuntime *pRuntime) dvander@2193: { dvander@2193: m_pRuntime = pRuntime; dvander@2193: m_pPlugin = m_pRuntime->m_pPlugin; dvander@2193: dvander@2193: m_InExec = false; dvander@2193: m_CustomMsg = false; dvander@2193: dvander@2226: /* Initialize the null references */ dvander@2226: uint32_t index; dvander@2226: if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE) dvander@2226: { dvander@2226: sp_pubvar_t *pubvar; dvander@2226: GetPubvarByIndex(index, &pubvar); dvander@2226: m_pNullVec = pubvar->offs; dvander@2226: } dvander@2226: else dvander@2226: { dvander@2226: m_pNullVec = NULL; dvander@2226: } dvander@2226: dvander@2226: if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE) dvander@2226: { dvander@2226: sp_pubvar_t *pubvar; dvander@2226: GetPubvarByIndex(index, &pubvar); dvander@2226: m_pNullString = pubvar->offs; dvander@2226: } dvander@2226: else dvander@2226: { dvander@2226: m_pNullString = NULL; dvander@2226: } dvander@2226: dvander@2226: m_ctx.hp = m_pPlugin->data_size; dvander@2226: m_ctx.sp = m_pPlugin->mem_size - sizeof(cell_t); dvander@2226: m_ctx.frm = m_ctx.sp; dvander@2226: m_ctx.n_err = SP_ERROR_NONE; dvander@2226: m_ctx.n_idx = SP_ERROR_NONE; dvander@2226: m_ctx.rp = 0; dvander@2226: dvander@2226: g_Jit.SetupContextVars(m_pRuntime, this, &m_ctx); dvander@2193: } dvander@2193: dvander@2193: BaseContext::~BaseContext() dvander@2193: { dvander@2226: g_Jit.FreeContextVars(&m_ctx); dvander@2193: } dvander@2193: dvander@2193: IVirtualMachine *BaseContext::GetVirtualMachine() dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: sp_context_t *BaseContext::GetContext() dvander@2193: { dvander@2193: return reinterpret_cast((IPluginContext * )this); dvander@2193: } dvander@2193: dvander@2193: sp_context_t *BaseContext::GetCtx() dvander@2193: { dvander@2193: return &m_ctx; dvander@2193: } dvander@2193: dvander@2193: bool BaseContext::IsDebugging() dvander@2193: { dvander@2226: return true; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::SetDebugBreak(void *newpfn, void *oldpfn) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: IPluginDebugInfo *BaseContext::GetDebugInfo() dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::Execute(uint32_t code_addr, cell_t *result) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: void BaseContext::SetErrorMessage(const char *msg, va_list ap) dvander@2193: { dvander@2193: m_CustomMsg = true; dvander@2193: dvander@2193: vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); dvander@2193: } dvander@2193: dvander@2193: void BaseContext::_SetErrorMessage(const char *msg, ...) dvander@2193: { dvander@2193: va_list ap; dvander@2193: va_start(ap, msg); dvander@2193: SetErrorMessage(msg, ap); dvander@2193: va_end(ap); dvander@2193: } dvander@2193: dvander@2193: cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) dvander@2193: { dvander@2193: if (!m_InExec) dvander@2193: { dvander@2193: return 0; dvander@2193: } dvander@2193: dvander@2193: m_ctx.n_err = error; dvander@2193: dvander@2193: if (msg) dvander@2193: { dvander@2193: va_list ap; dvander@2193: va_start(ap, msg); dvander@2193: SetErrorMessage(msg, ap); dvander@2193: va_end(ap); dvander@2193: } dvander@2193: dvander@2193: return 0; dvander@2193: } dvander@2193: dvander@2193: cell_t BaseContext::ThrowNativeError(const char *msg, ...) dvander@2193: { dvander@2193: if (!m_InExec) dvander@2193: { dvander@2193: return 0; dvander@2193: } dvander@2193: dvander@2193: m_ctx.n_err = SP_ERROR_NATIVE; dvander@2193: dvander@2193: if (msg) dvander@2193: { dvander@2193: va_list ap; dvander@2193: va_start(ap, msg); dvander@2193: SetErrorMessage(msg, ap); dvander@2193: va_end(ap); dvander@2193: } dvander@2193: dvander@2193: return 0; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) dvander@2193: { dvander@2193: cell_t *addr; dvander@2193: ucell_t realmem; dvander@2193: dvander@2193: #if 0 dvander@2193: if (cells > CELLBOUNDMAX) dvander@2193: { dvander@2193: return SP_ERROR_ARAM; dvander@2193: } dvander@2193: #else dvander@2193: assert(cells < CELLBOUNDMAX); dvander@2193: #endif dvander@2193: dvander@2193: realmem = cells * sizeof(cell_t); dvander@2193: dvander@2193: /** dvander@2193: * Check if the space between the heap and stack is sufficient. dvander@2193: */ dvander@2193: if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN) dvander@2193: { dvander@2193: return SP_ERROR_HEAPLOW; dvander@2193: } dvander@2193: dvander@2193: addr = (cell_t *)(m_pPlugin->memory + m_ctx.hp); dvander@2193: /* store size of allocation in cells */ dvander@2193: *addr = (cell_t)cells; dvander@2193: addr++; dvander@2193: m_ctx.hp += sizeof(cell_t); dvander@2193: dvander@2193: *local_addr = m_ctx.hp; dvander@2193: dvander@2193: if (phys_addr) dvander@2193: { dvander@2193: *phys_addr = addr; dvander@2193: } dvander@2193: dvander@2193: m_ctx.hp += realmem; dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::HeapPop(cell_t local_addr) dvander@2193: { dvander@2193: cell_t cellcount; dvander@2193: cell_t *addr; dvander@2193: dvander@2193: /* check the bounds of this address */ dvander@2193: local_addr -= sizeof(cell_t); dvander@2193: if (local_addr < (cell_t)m_pPlugin->data_size || local_addr >= m_ctx.sp) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: addr = (cell_t *)(m_pPlugin->memory + local_addr); dvander@2193: cellcount = (*addr) * sizeof(cell_t); dvander@2193: /* check if this memory count looks valid */ dvander@2193: if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: m_ctx.hp = local_addr; dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: dvander@2193: int BaseContext::HeapRelease(cell_t local_addr) dvander@2193: { dvander@2193: if (local_addr < (cell_t)m_pPlugin->data_size) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: m_ctx.hp = local_addr - sizeof(cell_t); dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::FindNativeByName(const char *name, uint32_t *index) dvander@2193: { dvander@2193: return m_pRuntime->FindNativeByName(name, index); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) dvander@2193: { dvander@2193: return m_pRuntime->GetNativeByIndex(index, native); dvander@2193: } dvander@2193: dvander@2193: dvander@2193: uint32_t BaseContext::GetNativesNum() dvander@2193: { dvander@2193: return m_pRuntime->GetNativesNum(); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::FindPublicByName(const char *name, uint32_t *index) dvander@2193: { dvander@2193: return m_pRuntime->FindPublicByName(name, index); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) dvander@2193: { dvander@2193: return m_pRuntime->GetPublicByIndex(index, pblic); dvander@2193: } dvander@2193: dvander@2193: uint32_t BaseContext::GetPublicsNum() dvander@2193: { dvander@2193: return m_pRuntime->GetPublicsNum(); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) dvander@2193: { dvander@2193: return m_pRuntime->GetPubvarByIndex(index, pubvar); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::FindPubvarByName(const char *name, uint32_t *index) dvander@2193: { dvander@2193: return m_pRuntime->FindPubvarByName(name, index); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) dvander@2193: { dvander@2193: return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr); dvander@2193: } dvander@2193: dvander@2193: uint32_t BaseContext::GetPubVarsNum() dvander@2193: { dvander@2193: return m_pRuntime->GetPubVarsNum(); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::BindNative(const sp_nativeinfo_t *native) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) dvander@2193: { dvander@2193: if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) dvander@2193: || (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size)) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: if (phys_addr) dvander@2193: { dvander@2193: *phys_addr = (cell_t *)(m_pPlugin->memory + local_addr); dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::PushCell(cell_t value) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::LocalToString(cell_t local_addr, char **addr) dvander@2193: { dvander@2193: if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) dvander@2193: || (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size)) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: *addr = (char *)(m_pPlugin->memory + local_addr); dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) dvander@2193: { dvander@2193: return SP_ERROR_ABORTED; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source) dvander@2193: { dvander@2193: char *dest; dvander@2193: size_t len; dvander@2193: dvander@2193: if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) dvander@2193: || (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size)) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: if (bytes == 0) dvander@2193: { dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: len = strlen(source); dvander@2193: dest = (char *)(m_pPlugin->memory + local_addr); dvander@2193: dvander@2193: if (len >= bytes) dvander@2193: { dvander@2193: len = bytes - 1; dvander@2193: } dvander@2193: dvander@2193: memmove(dest, source, len); dvander@2193: dest[len] = '\0'; dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: inline int __CheckValidChar(char *c) dvander@2193: { dvander@2193: int count; dvander@2193: int bytecount = 0; dvander@2193: dvander@2193: for (count=1; (*c & 0xC0) == 0x80; count++) dvander@2193: { dvander@2193: c--; dvander@2193: } dvander@2193: dvander@2193: switch (*c & 0xF0) dvander@2193: { dvander@2193: case 0xC0: dvander@2193: case 0xD0: dvander@2193: { dvander@2193: bytecount = 2; dvander@2193: break; dvander@2193: } dvander@2193: case 0xE0: dvander@2193: { dvander@2193: bytecount = 3; dvander@2193: break; dvander@2193: } dvander@2193: case 0xF0: dvander@2193: { dvander@2193: bytecount = 4; dvander@2193: break; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: if (bytecount != count) dvander@2193: { dvander@2193: return count; dvander@2193: } dvander@2193: dvander@2193: return 0; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) dvander@2193: { dvander@2193: char *dest; dvander@2193: size_t len; dvander@2193: bool needtocheck = false; dvander@2193: dvander@2193: if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) dvander@2193: || (local_addr < 0) dvander@2193: || ((ucell_t)local_addr >= m_pPlugin->mem_size)) dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: if (maxbytes == 0) dvander@2193: { dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: len = strlen(source); dvander@2193: dest = (char *)(m_pPlugin->memory + local_addr); dvander@2193: dvander@2193: if ((size_t)len >= maxbytes) dvander@2193: { dvander@2193: len = maxbytes - 1; dvander@2193: needtocheck = true; dvander@2193: } dvander@2193: dvander@2193: memmove(dest, source, len); dvander@2193: if ((dest[len-1] & 1<<7) && needtocheck) dvander@2193: { dvander@2193: len -= __CheckValidChar(dest+len-1); dvander@2193: } dvander@2193: dest[len] = '\0'; dvander@2193: dvander@2193: if (wrtnbytes) dvander@2193: { dvander@2193: *wrtnbytes = len; dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) dvander@2193: { dvander@2193: return m_pRuntime->GetFunctionById(func_id); dvander@2193: } dvander@2193: dvander@2193: IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) dvander@2193: { dvander@2193: return m_pRuntime->GetFunctionByName(public_name); dvander@2193: } dvander@2193: dvander@2193: int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr) dvander@2193: { dvander@2193: int err; dvander@2193: if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE) dvander@2193: { dvander@2193: return err; dvander@2193: } dvander@2193: dvander@2193: if ((cell_t *)*addr == m_pNullString) dvander@2193: { dvander@2193: *addr = NULL; dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: SourceMod::IdentityToken_t *BaseContext::GetIdentity() dvander@2193: { dvander@2193: SourceMod::IdentityToken_t *tok; dvander@2193: dvander@2193: if (GetKey(1, (void **)&tok)) dvander@2193: { dvander@2193: return tok; dvander@2193: } dvander@2193: dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type) dvander@2193: { dvander@2193: if (type == SP_NULL_VECTOR) dvander@2193: { dvander@2193: return m_pNullVec; dvander@2193: } dvander@2193: dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: bool BaseContext::IsInExec() dvander@2193: { dvander@2193: return m_InExec; dvander@2193: } dvander@2193: dvander@2193: int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result) dvander@2193: { dvander@2193: int ir; dvander@2193: int serial; dvander@2193: cell_t *sp; dvander@2193: funcid_t fnid; dvander@2226: JitFunction *fn; dvander@2193: sp_public_t *pubfunc; dvander@2193: cell_t _ignore_result; dvander@2226: unsigned int public_id; dvander@2193: dvander@2193: fnid = function->GetFunctionID(); dvander@2193: dvander@2193: if (fnid & 1) dvander@2226: { dvander@2193: public_id = fnid >> 1; dvander@2193: dvander@2193: if (m_pRuntime->GetPublicByIndex(public_id, &pubfunc) != SP_ERROR_NONE) dvander@2193: { dvander@2193: return SP_ERROR_NOT_FOUND; dvander@2193: } dvander@2193: } dvander@2193: else dvander@2193: { dvander@2193: return SP_ERROR_INVALID_ADDRESS; dvander@2193: } dvander@2193: dvander@2193: if (m_pRuntime->IsPaused()) dvander@2193: { dvander@2193: return SP_ERROR_NOT_RUNNABLE; dvander@2193: } dvander@2193: dvander@2193: if ((cell_t)(m_ctx.hp + 16*sizeof(cell_t)) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1)))) dvander@2193: { dvander@2193: return SP_ERROR_STACKLOW; dvander@2193: } dvander@2193: dvander@2193: if (result == NULL) dvander@2193: { dvander@2193: result = &_ignore_result; dvander@2193: } dvander@2193: dvander@2193: /* We got this far. It's time to start profiling. */ dvander@2193: dvander@2193: if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS) dvander@2193: { dvander@2193: serial = m_pPlugin->profiler->OnCallbackBegin(this, pubfunc); dvander@2193: } dvander@2193: dvander@2226: /* See if we have to compile the callee. */ dvander@2226: if ((fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL) dvander@2226: { dvander@2226: uint32_t func_idx; dvander@2226: dvander@2226: /* We might not have to - check pcode offset. */ dvander@2226: if ((func_idx = FuncLookup((CompData *)m_pRuntime->m_pCo, pubfunc->code_offs)) != 0) dvander@2226: { dvander@2226: fn = m_pRuntime->GetJittedFunction(func_idx); dvander@2226: assert(fn != NULL); dvander@2226: m_pRuntime->m_PubJitFuncs[public_id] = fn; dvander@2226: } dvander@2226: else dvander@2226: { dvander@2226: if ((fn = g_Jit.CompileFunction(m_pRuntime, pubfunc->code_offs, &ir)) == NULL) dvander@2226: { dvander@2226: return ir; dvander@2226: } dvander@2226: m_pRuntime->m_PubJitFuncs[public_id] = fn; dvander@2226: } dvander@2226: } dvander@2226: dvander@2193: /* Save our previous state. */ dvander@2193: dvander@2193: bool save_exec; dvander@2193: uint32_t save_n_idx; dvander@2226: cell_t save_sp, save_hp, save_rp, save_cip; dvander@2193: dvander@2193: save_sp = m_ctx.sp; dvander@2193: save_hp = m_ctx.hp; dvander@2193: save_exec = m_InExec; dvander@2193: save_n_idx = m_ctx.n_idx; dvander@2226: save_rp = m_ctx.rp; dvander@2226: save_cip = m_ctx.err_cip; dvander@2193: dvander@2193: /* Push parameters */ dvander@2193: dvander@2193: m_ctx.sp -= sizeof(cell_t) * (num_params + 1); dvander@2193: sp = (cell_t *)(m_pPlugin->memory + m_ctx.sp); dvander@2193: dvander@2193: sp[0] = num_params; dvander@2193: for (unsigned int i = 0; i < num_params; i++) dvander@2193: { dvander@2193: sp[i + 1] = params[i]; dvander@2193: } dvander@2193: dvander@2193: /* Clear internal state */ dvander@2193: m_ctx.n_err = SP_ERROR_NONE; dvander@2193: m_ctx.n_idx = 0; dvander@2193: m_MsgCache[0] = '\0'; dvander@2193: m_CustomMsg = false; dvander@2214: m_InExec = true; dvander@2193: dvander@2226: /* Start the frame tracer */ dvander@2193: dvander@2226: ir = g_Jit.InvokeFunction(m_pRuntime, fn, result); dvander@2193: dvander@2226: /* Restore some states, stop the frame tracer */ dvander@2193: dvander@2193: m_InExec = save_exec; dvander@2193: dvander@2193: if (ir == SP_ERROR_NONE) dvander@2193: { dvander@2193: m_ctx.n_err = SP_ERROR_NONE; dvander@2193: if (m_ctx.sp != save_sp) dvander@2193: { dvander@2193: ir = SP_ERROR_STACKLEAK; dvander@2193: _SetErrorMessage("Stack leak detected: sp:%d should be %d!", dvander@2193: m_ctx.sp, dvander@2193: save_sp); dvander@2193: } dvander@2193: if (m_ctx.hp != save_hp) dvander@2193: { dvander@2193: ir = SP_ERROR_HEAPLEAK; dvander@2193: _SetErrorMessage("Heap leak detected: hp:%d should be %d!", dvander@2193: m_ctx.hp, dvander@2193: save_hp); dvander@2193: } dvander@2226: if (m_ctx.rp != save_rp) dvander@2226: { dvander@2226: ir = SP_ERROR_STACKLEAK; dvander@2226: _SetErrorMessage("Return stack leak detected: rp:%d should be %d!", dvander@2226: m_ctx.rp, dvander@2226: save_rp); dvander@2226: } dvander@2226: } dvander@2226: dvander@2226: if (ir != SP_ERROR_NONE) dvander@2226: { dvander@2226: g_engine1.ReportError(m_pRuntime, ir, m_MsgCache, save_rp); dvander@2193: } dvander@2193: dvander@2193: m_ctx.sp = save_sp; dvander@2193: m_ctx.hp = save_hp; dvander@2226: m_ctx.rp = save_rp; dvander@2226: dvander@2193: if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS) dvander@2193: { dvander@2193: m_pPlugin->profiler->OnCallbackEnd(serial); dvander@2193: } dvander@2193: dvander@2226: m_ctx.err_cip = save_cip; dvander@2193: m_ctx.n_idx = save_n_idx; dvander@2193: m_ctx.n_err = SP_ERROR_NONE; dvander@2193: m_MsgCache[0] = '\0'; dvander@2193: m_CustomMsg = false; dvander@2193: dvander@2193: return ir; dvander@2193: } dvander@2193: dvander@2193: IPluginRuntime *BaseContext::GetRuntime() dvander@2193: { dvander@2193: return m_pRuntime; dvander@2193: } dvander@2193: dvander@2193: DebugInfo::DebugInfo(sp_plugin_t *plugin) : m_pPlugin(plugin) dvander@2193: { dvander@2193: } dvander@2193: dvander@2193: #define USHR(x) ((unsigned int)(x)>>1) dvander@2193: dvander@2193: int DebugInfo::LookupFile(ucell_t addr, const char **filename) dvander@2193: { dvander@2193: int high, low, mid; dvander@2193: dvander@2193: high = m_pPlugin->debug.files_num; dvander@2193: low = -1; dvander@2193: dvander@2193: while (high - low > 1) dvander@2193: { dvander@2193: mid = USHR(low + high); dvander@2226: if (m_pPlugin->debug.files[mid].addr <= addr) dvander@2193: { dvander@2193: low = mid; dvander@2193: } else { dvander@2193: high = mid; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: if (low == -1) dvander@2193: { dvander@2193: return SP_ERROR_NOT_FOUND; dvander@2193: } dvander@2193: dvander@2226: *filename = m_pPlugin->debug.stringbase + m_pPlugin->debug.files[low].name; dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int DebugInfo::LookupFunction(ucell_t addr, const char **name) dvander@2193: { dvander@2226: uint32_t max, iter; dvander@2226: sp_fdbg_symbol_t *sym; dvander@2226: sp_fdbg_arraydim_t *arr; dvander@2226: uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols); dvander@2193: dvander@2226: max = m_pPlugin->debug.syms_num; dvander@2226: for (iter = 0; iter < max; iter++) dvander@2193: { dvander@2226: sym = (sp_fdbg_symbol_t *)cursor; dvander@2226: dvander@2226: if (sym->ident == SP_SYM_FUNCTION dvander@2226: && sym->codestart <= addr dvander@2226: && sym->codeend > addr) dvander@2193: { dvander@2226: *name = m_pPlugin->debug.stringbase + sym->name; dvander@2226: return SP_ERROR_NONE; dvander@2193: } dvander@2226: dvander@2226: if (sym->dimcount > 0) dvander@2226: { dvander@2226: cursor += sizeof(sp_fdbg_symbol_t); dvander@2226: arr = (sp_fdbg_arraydim_t *)cursor; dvander@2226: cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; dvander@2226: continue; dvander@2226: } dvander@2226: dvander@2226: cursor += sizeof(sp_fdbg_symbol_t); dvander@2193: } dvander@2193: dvander@2226: return SP_ERROR_NOT_FOUND; dvander@2193: dvander@2193: } dvander@2193: dvander@2193: int DebugInfo::LookupLine(ucell_t addr, uint32_t *line) dvander@2193: { dvander@2193: int high, low, mid; dvander@2193: dvander@2193: high = m_pPlugin->debug.lines_num; dvander@2193: low = -1; dvander@2193: dvander@2193: while (high - low > 1) dvander@2193: { dvander@2193: mid = USHR(low + high); dvander@2226: if (m_pPlugin->debug.lines[mid].addr <= addr) dvander@2193: { dvander@2193: low = mid; dvander@2193: } else { dvander@2193: high = mid; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: if (low == -1) dvander@2193: { dvander@2193: return SP_ERROR_NOT_FOUND; dvander@2193: } dvander@2193: dvander@2193: /* Since the CIP occurs BEFORE the line, we have to add one */ dvander@2226: *line = m_pPlugin->debug.lines[low].line + 1; dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: #undef USHR dvander@2193: dvander@2193: int BaseContext::GetLastNativeError() dvander@2193: { dvander@2193: return m_ctx.n_err; dvander@2193: } dvander@2193: dvander@2193: cell_t *BaseContext::GetLocalParams() dvander@2193: { dvander@2193: return (cell_t *)(m_pPlugin->memory + m_ctx.frm + (2 * sizeof(cell_t))); dvander@2193: } dvander@2193: dvander@2193: void BaseContext::SetKey(int k, void *value) dvander@2193: { dvander@2193: if (k < 1 || k > 4) dvander@2193: { dvander@2193: return; dvander@2193: } dvander@2193: dvander@2193: m_keys[k - 1] = value; dvander@2193: m_keys_set[k - 1] = true; dvander@2193: } dvander@2193: dvander@2193: bool BaseContext::GetKey(int k, void **value) dvander@2193: { dvander@2193: if (k < 1 || k > 4 || m_keys_set[k - 1] == false) dvander@2193: { dvander@2193: return false; dvander@2193: } dvander@2193: dvander@2193: *value = m_keys[k - 1]; dvander@2193: dvander@2193: return true; dvander@2193: }