ds@763: /** ds@763: * vim: set ts=4 : ds@763: * ================================================================ ds@763: * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved. ds@763: * ================================================================ ds@763: * ds@763: * This file is not open source and may not be copied without explicit ds@763: * written permission of AlliedModders LLC. This file may not be redistributed ds@763: * in whole or significant part. ds@763: * For information, see LICENSE.txt or http://www.sourcemod.net/license.php ds@763: * ds@763: * Version: $Id$ ds@763: */ ds@763: ds@763: #include ds@763: #include ds@763: #include ds@763: #include ds@763: #include "sp_vm_api.h" ds@763: #include "sp_vm_basecontext.h" ds@763: #include "sp_vm_engine.h" ds@763: ds@763: #ifdef SOURCEMOD_BUILD ds@763: #include "Logger.h" ds@763: #endif ds@763: ds@763: using namespace SourcePawn; ds@763: ds@763: extern SourcePawnEngine g_SourcePawn; ds@763: ds@763: #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) ds@763: #define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) ds@763: ds@763: int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip) ds@763: { ds@763: g_SourcePawn.RunTracer(ctx, frm, cip); ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: BaseContext::BaseContext(sp_context_t *_ctx) ds@763: { ds@763: ctx = _ctx; ds@763: ctx->context = this; ds@763: ctx->dbreak = GlobalDebugBreak; ds@763: m_InExec = false; ds@763: m_CustomMsg = false; ds@763: m_funcsnum = ctx->vmbase->FunctionCount(ctx); ds@763: #if 0 ds@763: m_priv_funcs = NULL; ds@763: #endif ds@763: m_pub_funcs = NULL; ds@763: ds@763: #if 0 ds@763: /** ds@763: * Note: Since the m_plugin member will never change, ds@763: * it is safe to assume the function count will never change ds@763: */ ds@763: if (m_funcsnum && m_priv_funcs == NULL) ds@763: { ds@763: m_priv_funcs = new CFunction *[m_funcsnum]; ds@763: memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); ds@763: } else { ds@763: m_priv_funcs = NULL; ds@763: } ds@763: #endif ds@763: ds@763: if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) ds@763: { ds@763: m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num]; ds@763: memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num); ds@763: } else { ds@763: m_pub_funcs = NULL; ds@763: } dvander@938: dvander@938: /* Initialize the null references */ dvander@938: uint32_t index; dvander@938: if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE) dvander@938: { dvander@938: sp_pubvar_t *pubvar; dvander@938: GetPubvarByIndex(index, &pubvar); dvander@938: m_pNullVec = pubvar->offs; dvander@938: } else { dvander@938: m_pNullVec = NULL; dvander@938: } dvander@1000: dvander@1000: if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE) dvander@1000: { dvander@1000: sp_pubvar_t *pubvar; dvander@1000: GetPubvarByIndex(index, &pubvar); dvander@1000: m_pNullString = pubvar->offs; dvander@1000: } else { dvander@1000: m_pNullString = NULL; dvander@1000: } ds@763: } ds@763: ds@763: void BaseContext::FlushFunctionCache() ds@763: { ds@763: if (m_pub_funcs) ds@763: { ds@763: for (uint32_t i=0; iplugin->info.publics_num; i++) ds@763: { ds@763: delete m_pub_funcs[i]; ds@763: m_pub_funcs[i] = NULL; ds@763: } ds@763: } ds@763: ds@763: #if 0 ds@763: if (m_priv_funcs) ds@763: { ds@763: for (unsigned int i=0; iplugin->info.publics_num; i++) ds@763: { ds@763: if (!m_pub_funcs[i]) ds@763: { ds@763: continue; ds@763: } ds@763: if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE) ds@763: { ds@763: continue; ds@763: } ds@763: m_pub_funcs[i]->Set(pub->code_offs, this); ds@763: } ds@763: } ds@763: ds@763: #if 0 ds@763: if (m_priv_funcs) ds@763: { ds@763: for (unsigned int i=0; i ds@763: } ds@763: } ds@763: #endif ds@763: } ds@763: ds@763: BaseContext::~BaseContext() ds@763: { ds@763: FlushFunctionCache(); ds@763: delete [] m_pub_funcs; ds@763: m_pub_funcs = NULL; ds@763: #if 0 ds@763: delete [] m_priv_funcs; ds@763: m_priv_funcs = NULL; ds@763: #endif ds@763: } ds@763: ds@763: void BaseContext::SetContext(sp_context_t *_ctx) ds@763: { ds@763: if (!_ctx) ds@763: { ds@763: return; ds@763: } ds@763: ctx = _ctx; ds@763: ctx->context = this; ds@763: ctx->dbreak = GlobalDebugBreak; ds@763: RefreshFunctionCache(); ds@763: } ds@763: ds@763: IVirtualMachine *BaseContext::GetVirtualMachine() ds@763: { ds@763: return (IVirtualMachine *)ctx->vmbase; ds@763: } ds@763: ds@763: sp_context_t *BaseContext::GetContext() ds@763: { ds@763: return ctx; ds@763: } ds@763: ds@763: bool BaseContext::IsDebugging() ds@763: { ds@763: return (ctx->flags & SPFLAG_PLUGIN_DEBUG); ds@763: } ds@763: ds@763: int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) ds@763: { ds@763: if (!IsDebugging()) ds@763: { ds@763: return SP_ERROR_NOTDEBUGGING; ds@763: } ds@763: ds@763: *oldpfn = ctx->dbreak; ds@763: ctx->dbreak = newpfn; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: IPluginDebugInfo *BaseContext::GetDebugInfo() ds@763: { ds@763: return this; ds@763: } ds@763: ds@763: int BaseContext::Execute(uint32_t code_addr, cell_t *result) ds@763: { ds@763: if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) ds@763: { ds@763: return SP_ERROR_NOT_RUNNABLE; ds@763: } ds@763: dvander@790: /* tada, prevent a crash */ dvander@790: cell_t _ignore_result; dvander@790: if (!result) dvander@790: { dvander@790: result = &_ignore_result; dvander@790: } dvander@790: ds@763: IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; ds@763: ds@763: uint32_t pushcount = ctx->pushcount; ds@763: int err; ds@763: ds@763: PushCell(pushcount++); ds@763: ctx->pushcount = 0; ds@763: ds@763: cell_t save_sp = ctx->sp; ds@763: cell_t save_hp = ctx->hp; ds@763: uint32_t n_idx = ctx->n_idx; ds@763: ds@763: bool wasExec = m_InExec; ds@763: ds@763: /* Clear the error state, if any */ ds@763: ctx->n_err = SP_ERROR_NONE; ds@763: ctx->n_idx = 0; ds@763: m_InExec = true; ds@763: m_MsgCache[0] = '\0'; ds@763: m_CustomMsg = false; ds@763: ds@763: g_SourcePawn.PushTracer(ctx); ds@763: ds@763: err = vm->ContextExecute(ctx, code_addr, result); ds@763: ds@763: m_InExec = wasExec; ds@763: ds@763: /** ds@763: * :TODO: Calling from a plugin in here will erase the cached message... ds@763: * Should that be documented? ds@763: */ ds@763: g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); ds@763: ds@763: #if 1//defined _DEBUG ds@763: //:TODO: debug code for leak detection, remove before the release? ds@763: if (err == SP_ERROR_NONE) ds@763: { ds@763: if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp) ds@763: { ds@763: const char *name; ds@763: ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); ds@763: g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name); ds@763: } ds@763: if (ctx->hp != save_hp) ds@763: { ds@763: const char *name; ds@763: ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name); ds@763: g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name); ds@763: } ds@763: //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp); ds@763: //assert(ctx->hp == save_hp); ds@763: } ds@763: #endif ds@763: if (err != SP_ERROR_NONE) ds@763: { ds@763: ctx->sp = save_sp; ds@763: ctx->hp = save_hp; ds@763: } ds@763: ds@763: ctx->n_idx = n_idx; ds@763: ds@763: return err; ds@763: } ds@763: ds@763: void BaseContext::SetErrorMessage(const char *msg, va_list ap) ds@763: { ds@763: m_CustomMsg = true; ds@763: ds@763: vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); ds@763: } ds@763: ds@763: cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) ds@763: { ds@763: if (!m_InExec) ds@763: { ds@763: return 0; ds@763: } ds@763: ds@763: ctx->n_err = error; ds@763: ds@763: if (msg) ds@763: { ds@763: va_list ap; ds@763: va_start(ap, msg); ds@763: SetErrorMessage(msg, ap); ds@763: va_end(ap); ds@763: } ds@763: ds@763: return 0; ds@763: } ds@763: ds@763: cell_t BaseContext::ThrowNativeError(const char *msg, ...) ds@763: { ds@763: if (!m_InExec) ds@763: { ds@763: return 0; ds@763: } ds@763: ds@763: ctx->n_err = SP_ERROR_NATIVE; ds@763: ds@763: if (msg) ds@763: { ds@763: va_list ap; ds@763: va_start(ap, msg); ds@763: SetErrorMessage(msg, ap); ds@763: va_end(ap); ds@763: } ds@763: ds@763: return 0; ds@763: } ds@763: ds@763: int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) ds@763: { ds@763: cell_t *addr; ds@763: ucell_t realmem; ds@763: ds@763: #if 0 ds@763: if (cells > CELLBOUNDMAX) ds@763: { ds@763: return SP_ERROR_ARAM; ds@763: } ds@763: #else ds@763: assert(cells < CELLBOUNDMAX); ds@763: #endif ds@763: ds@763: realmem = cells * sizeof(cell_t); ds@763: ds@763: /** ds@763: * Check if the space between the heap and stack is sufficient. ds@763: */ ds@763: if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) ds@763: { ds@763: return SP_ERROR_HEAPLOW; ds@763: } ds@763: ds@763: addr = (cell_t *)(ctx->memory + ctx->hp); ds@763: /* store size of allocation in cells */ ds@763: *addr = (cell_t)cells; ds@763: addr++; ds@763: ctx->hp += sizeof(cell_t); ds@763: ds@763: *local_addr = ctx->hp; ds@763: ds@763: if (phys_addr) ds@763: { ds@763: *phys_addr = addr; ds@763: } ds@763: ds@763: ctx->hp += realmem; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::HeapPop(cell_t local_addr) ds@763: { ds@763: cell_t cellcount; ds@763: cell_t *addr; ds@763: ds@763: /* check the bounds of this address */ ds@763: local_addr -= sizeof(cell_t); ds@763: if (local_addr < ctx->heap_base || local_addr >= ctx->sp) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: ds@763: addr = (cell_t *)(ctx->memory + local_addr); ds@763: cellcount = (*addr) * sizeof(cell_t); ds@763: /* check if this memory count looks valid */ ds@763: if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: ds@763: ctx->hp = local_addr; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: ds@763: int BaseContext::HeapRelease(cell_t local_addr) ds@763: { ds@763: if (local_addr < ctx->heap_base) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: ds@763: ctx->hp = local_addr - sizeof(cell_t); ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::FindNativeByName(const char *name, uint32_t *index) ds@763: { ds@763: int high; ds@763: ds@763: high = ctx->plugin->info.natives_num - 1; ds@763: ds@763: for (uint32_t i=0; iplugin->info.natives_num; i++) ds@763: { ds@763: if (strcmp(ctx->natives[i].name, name) == 0) ds@763: { ds@763: if (index) ds@763: { ds@763: *index = i; ds@763: } ds@763: return SP_ERROR_NONE; ds@763: } ds@763: } ds@763: ds@763: return SP_ERROR_NOT_FOUND; ds@763: } ds@763: ds@763: int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) ds@763: { ds@763: if (index >= ctx->plugin->info.natives_num) ds@763: { ds@763: return SP_ERROR_INDEX; ds@763: } ds@763: ds@763: if (native) ds@763: { ds@763: *native = &(ctx->natives[index]); ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: ds@763: uint32_t BaseContext::GetNativesNum() ds@763: { ds@763: return ctx->plugin->info.natives_num; ds@763: } ds@763: ds@763: int BaseContext::FindPublicByName(const char *name, uint32_t *index) ds@763: { ds@763: int diff, high, low; ds@763: uint32_t mid; ds@763: ds@763: high = ctx->plugin->info.publics_num - 1; ds@763: low = 0; ds@763: ds@763: while (low <= high) ds@763: { ds@763: mid = (low + high) / 2; ds@763: diff = strcmp(ctx->publics[mid].name, name); ds@763: if (diff == 0) ds@763: { ds@763: if (index) ds@763: { ds@763: *index = mid; ds@763: } ds@763: return SP_ERROR_NONE; ds@763: } else if (diff < 0) { ds@763: low = mid + 1; ds@763: } else { ds@763: high = mid - 1; ds@763: } ds@763: } ds@763: ds@763: return SP_ERROR_NOT_FOUND; ds@763: } ds@763: ds@763: int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) ds@763: { ds@763: if (index >= ctx->plugin->info.publics_num) ds@763: { ds@763: return SP_ERROR_INDEX; ds@763: } ds@763: ds@763: if (pblic) ds@763: { ds@763: *pblic = &(ctx->publics[index]); ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: uint32_t BaseContext::GetPublicsNum() ds@763: { ds@763: return ctx->plugin->info.publics_num; ds@763: } ds@763: ds@763: int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) ds@763: { ds@763: if (index >= ctx->plugin->info.pubvars_num) ds@763: { ds@763: return SP_ERROR_INDEX; ds@763: } ds@763: ds@763: if (pubvar) ds@763: { ds@763: *pubvar = &(ctx->pubvars[index]); ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::FindPubvarByName(const char *name, uint32_t *index) ds@763: { ds@763: int diff, high, low; ds@763: uint32_t mid; ds@763: ds@763: high = ctx->plugin->info.pubvars_num - 1; ds@763: low = 0; ds@763: ds@763: while (low <= high) ds@763: { ds@763: mid = (low + high) / 2; ds@763: diff = strcmp(ctx->pubvars[mid].name, name); ds@763: if (diff == 0) ds@763: { ds@763: if (index) ds@763: { ds@763: *index = mid; ds@763: } ds@763: return SP_ERROR_NONE; ds@763: } else if (diff < 0) { ds@763: low = mid + 1; ds@763: } else { ds@763: high = mid - 1; ds@763: } ds@763: } ds@763: ds@763: return SP_ERROR_NOT_FOUND; ds@763: } ds@763: ds@763: int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) ds@763: { ds@763: if (index >= ctx->plugin->info.pubvars_num) ds@763: { ds@763: return SP_ERROR_INDEX; ds@763: } ds@763: ds@763: *local_addr = ctx->plugin->info.pubvars[index].address; ds@763: *phys_addr = ctx->pubvars[index].offs; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: uint32_t BaseContext::GetPubVarsNum() ds@763: { ds@763: return ctx->plugin->info.pubvars_num; ds@763: } ds@763: ds@763: int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) ds@763: { ds@763: uint32_t i, j, max; ds@763: ds@763: max = ctx->plugin->info.natives_num; ds@763: ds@763: for (i=0; inatives[i].status == SP_NATIVE_BOUND) && !overwrite) ds@763: { ds@763: continue; ds@763: } ds@763: ds@763: for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) ds@763: { ds@763: ctx->natives[i].pfn = natives[j].func; ds@763: ctx->natives[i].status = SP_NATIVE_BOUND; ds@763: } ds@763: } ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::BindNative(const sp_nativeinfo_t *native) ds@763: { ds@763: uint32_t index; ds@763: int err; ds@763: ds@763: if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) ds@763: { ds@763: return err; ds@763: } ds@763: ds@763: ctx->natives[index].pfn = native->func; ds@763: ctx->natives[index].status = SP_NATIVE_BOUND; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) ds@763: { ds@763: uint32_t nativesnum, i; ds@763: ds@763: nativesnum = ctx->plugin->info.natives_num; ds@763: ds@763: for (i=0; inatives[i].status == SP_NATIVE_UNBOUND) ds@763: { ds@763: ctx->natives[i].pfn = native; ds@763: ctx->natives[i].status = SP_NATIVE_BOUND; ds@763: } ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) ds@763: { ds@763: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: ds@763: if (phys_addr) ds@763: { ds@763: *phys_addr = (cell_t *)(ctx->memory + local_addr); ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::PushCell(cell_t value) ds@763: { ds@763: if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) ds@763: { ds@763: return SP_ERROR_STACKLOW; ds@763: } ds@763: ds@763: ctx->sp -= sizeof(cell_t); ds@763: *(cell_t *)(ctx->memory + ctx->sp) = value; ds@763: ctx->pushcount++; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) ds@763: { ds@763: unsigned int i; ds@763: int err; ds@763: ds@763: for (i=0; isp += (cell_t)(i * sizeof(cell_t)); ds@763: ctx->pushcount -= i; ds@763: return err; ds@763: } ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) ds@763: { ds@763: cell_t *ph_addr; ds@763: int err; ds@763: ds@763: if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) ds@763: { ds@763: return err; ds@763: } ds@763: ds@763: memcpy(ph_addr, array, numcells * sizeof(cell_t)); ds@763: ds@763: if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) ds@763: { ds@763: HeapRelease(*local_addr); ds@763: return err; ds@763: } ds@763: ds@763: if (phys_addr) ds@763: { ds@763: *phys_addr = ph_addr; ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::LocalToString(cell_t local_addr, char **addr) ds@763: { ds@763: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: *addr = (char *)(ctx->memory + local_addr); ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) ds@763: { ds@763: char *ph_addr; ds@763: int err; ds@763: unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t); ds@763: ds@763: if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE) ds@763: { ds@763: return err; ds@763: } ds@763: ds@763: memcpy(ph_addr, string, len); ds@763: ph_addr[len] = '\0'; ds@763: ds@763: if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) ds@763: { ds@763: HeapRelease(*local_addr); ds@763: return err; ds@763: } ds@763: ds@763: if (phys_addr) ds@763: { ds@763: *phys_addr = ph_addr; ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source) ds@763: { ds@763: char *dest; ds@763: size_t len; ds@763: ds@763: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: ds@763: if (bytes == 0) ds@763: { ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: len = strlen(source); ds@763: dest = (char *)(ctx->memory + local_addr); ds@763: ds@763: if (len >= bytes) ds@763: { ds@763: len = bytes - 1; ds@763: } ds@763: ds@763: memcpy(dest, source, len); ds@763: dest[len] = '\0'; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: inline int __CheckValidChar(char *c) ds@763: { ds@763: int count; ds@763: int bytecount = 0; ds@763: ds@763: for (count=1; (*c & 0xC0) == 0x80; count++) ds@763: { ds@763: c--; ds@763: } ds@763: ds@763: switch (*c & 0xF0) ds@763: { ds@763: case 0xC0: ds@763: case 0xD0: ds@763: { ds@763: bytecount = 2; ds@763: break; ds@763: } ds@763: case 0xE0: ds@763: { ds@763: bytecount = 3; ds@763: break; ds@763: } ds@763: case 0xF0: ds@763: { ds@763: bytecount = 4; ds@763: break; ds@763: } ds@763: } ds@763: ds@763: if (bytecount != count) ds@763: { ds@763: return count; ds@763: } ds@763: ds@763: return 0; ds@763: } ds@763: ds@763: int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) ds@763: { ds@763: char *dest; ds@763: size_t len; ds@763: bool needtocheck = false; ds@763: ds@763: if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) ds@763: { ds@763: return SP_ERROR_INVALID_ADDRESS; ds@763: } ds@763: ds@763: if (maxbytes == 0) ds@763: { ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: len = strlen(source); ds@763: dest = (char *)(ctx->memory + local_addr); ds@763: ds@763: if ((size_t)len >= maxbytes) ds@763: { ds@763: len = maxbytes - 1; ds@763: needtocheck = true; ds@763: } ds@763: ds@763: memcpy(dest, source, len); ds@763: if ((dest[len-1] & 1<<7) && needtocheck) ds@763: { ds@763: len -= __CheckValidChar(dest+len-1); ds@763: } ds@763: dest[len] = '\0'; ds@763: ds@763: if (wrtnbytes) ds@763: { ds@763: *wrtnbytes = len; ds@763: } ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: #define USHR(x) ((unsigned int)(x)>>1) ds@763: ds@763: int BaseContext::LookupFile(ucell_t addr, const char **filename) ds@763: { ds@763: int high, low, mid; ds@763: ds@763: high = ctx->plugin->debug.files_num; ds@763: low = -1; ds@763: ds@763: while (high - low > 1) ds@763: { ds@763: mid = USHR(low + high); ds@763: if (ctx->files[mid].addr <= addr) ds@763: { ds@763: low = mid; ds@763: } else { ds@763: high = mid; ds@763: } ds@763: } ds@763: ds@763: if (low == -1) ds@763: { ds@763: return SP_ERROR_NOT_FOUND; ds@763: } ds@763: ds@763: *filename = ctx->files[low].name; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::LookupFunction(ucell_t addr, const char **name) ds@763: { ds@763: uint32_t iter, max = ctx->plugin->debug.syms_num; ds@763: ds@763: for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) ds@763: && (ctx->symbols[iter].codestart <= addr) ds@763: && (ctx->symbols[iter].codeend > addr)) ds@763: { ds@763: break; ds@763: } ds@763: } ds@763: ds@763: if (iter >= max) ds@763: { ds@763: return SP_ERROR_NOT_FOUND; ds@763: } ds@763: ds@763: *name = ctx->symbols[iter].name; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: int BaseContext::LookupLine(ucell_t addr, uint32_t *line) ds@763: { ds@763: int high, low, mid; ds@763: ds@763: high = ctx->plugin->debug.lines_num; ds@763: low = -1; ds@763: ds@763: while (high - low > 1) ds@763: { ds@763: mid = USHR(low + high); ds@763: if (ctx->lines[mid].addr <= addr) ds@763: { ds@763: low = mid; ds@763: } else { ds@763: high = mid; ds@763: } ds@763: } ds@763: ds@763: if (low == -1) ds@763: { ds@763: return SP_ERROR_NOT_FOUND; ds@763: } ds@763: ds@763: /* Since the CIP occurs BEFORE the line, we have to add one */ ds@763: *line = ctx->lines[low].line + 1; ds@763: ds@763: return SP_ERROR_NONE; ds@763: } ds@763: ds@763: IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) ds@763: { ds@763: CFunction *pFunc = NULL; ds@763: ds@763: if (func_id & 1) ds@763: { ds@763: func_id >>= 1; ds@763: if (func_id >= ctx->plugin->info.publics_num) ds@763: { ds@763: return NULL; ds@763: } ds@763: pFunc = m_pub_funcs[func_id]; ds@763: if (!pFunc) ds@763: { ds@763: m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this); ds@763: pFunc = m_pub_funcs[func_id]; ds@763: } else if (pFunc->IsInvalidated()) { ds@763: pFunc->Set(ctx->publics[func_id].code_offs, this); ds@763: } ds@763: } else { ds@763: /* :TODO: currently not used */ ds@763: #if 0 ds@763: func_id >>= 1; ds@763: unsigned int index; ds@763: if (!g_pVM->FunctionLookup(ctx, func_id, &index)) ds@763: { ds@763: return NULL; ds@763: } ds@763: pFunc = m_priv_funcs[func_id]; ds@763: if (!pFunc) ds@763: { ds@763: m_priv_funcs[func_id] = new CFunction(save, this); ds@763: pFunc = m_priv_funcs[func_id]; ds@763: } ds@763: #endif ds@763: assert(false); ds@763: } ds@763: ds@763: return pFunc; ds@763: } ds@763: ds@763: IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) ds@763: { ds@763: uint32_t index; ds@763: ds@763: if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) ds@763: { ds@763: return NULL; ds@763: } ds@763: ds@763: CFunction *pFunc = m_pub_funcs[index]; ds@763: if (!pFunc) ds@763: { ds@763: sp_public_t *pub = NULL; ds@763: GetPublicByIndex(index, &pub); ds@763: if (pub) ds@763: { ds@763: m_pub_funcs[index] = new CFunction(pub->code_offs, this); ds@763: } ds@763: pFunc = m_pub_funcs[index]; ds@763: } else if (pFunc->IsInvalidated()) { ds@763: sp_public_t *pub = NULL; ds@763: GetPublicByIndex(index, &pub); ds@763: if (pub) ds@763: { ds@763: pFunc->Set(pub->code_offs, this); ds@763: } else { ds@763: pFunc = NULL; ds@763: } ds@763: } ds@763: ds@763: return pFunc; ds@763: } ds@763: dvander@1000: int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr) dvander@1000: { dvander@1000: int err; dvander@1000: if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE) dvander@1000: { dvander@1000: return err; dvander@1000: } dvander@1000: dvander@1000: if ((cell_t *)*addr == m_pNullString) dvander@1000: { dvander@1000: *addr = NULL; dvander@1000: } dvander@1000: dvander@1000: return SP_ERROR_NONE; dvander@1000: } dvander@1000: ds@763: #if defined SOURCEMOD_BUILD ds@763: SourceMod::IdentityToken_t *BaseContext::GetIdentity() ds@763: { ds@763: return m_pToken; ds@763: } ds@763: ds@763: void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) ds@763: { ds@763: m_pToken = token; ds@763: } dvander@938: dvander@938: cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type) dvander@938: { dvander@938: if (type == SP_NULL_VECTOR) dvander@938: { dvander@938: return m_pNullVec; dvander@938: } dvander@938: dvander@938: return NULL; dvander@938: } ds@763: #endif