3 * ================================================================
4 * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ================================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
19 #include "sp_vm_api.h"
20 #include "sp_vm_basecontext.h"
21 #include "sp_vm_engine.h"
23 #ifdef SOURCEMOD_BUILD
27 using namespace SourcePawn;
29 extern SourcePawnEngine g_SourcePawn;
31 #define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
32 #define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
34 int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
36 g_SourcePawn.RunTracer(ctx, frm, cip);
41 BaseContext::BaseContext(sp_context_t *_ctx)
45 ctx->dbreak = GlobalDebugBreak;
48 m_funcsnum = ctx->vmbase->FunctionCount(ctx);
56 * Note: Since the m_plugin member will never change,
57 * it is safe to assume the function count will never change
59 if (m_funcsnum && m_priv_funcs == NULL)
61 m_priv_funcs = new CFunction *[m_funcsnum];
62 memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
68 if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
70 m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
71 memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
76 /* Initialize the null references */
78 if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
81 GetPubvarByIndex(index, &pubvar);
82 m_pNullVec = pubvar->offs;
87 if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
90 GetPubvarByIndex(index, &pubvar);
91 m_pNullString = pubvar->offs;
97 void BaseContext::FlushFunctionCache()
101 for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
103 delete m_pub_funcs[i];
104 m_pub_funcs[i] = NULL;
111 for (unsigned int i=0; i<m_funcsnum; i++)
113 delete m_priv_funcs[i];
114 m_priv_funcs[i] = NULL;
120 void BaseContext::RefreshFunctionCache()
125 for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
131 if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
135 m_pub_funcs[i]->Set(pub->code_offs, this);
142 for (unsigned int i=0; i<m_funcsnum; i++)
144 if (!m_priv_funcs[i])
154 BaseContext::~BaseContext()
156 FlushFunctionCache();
157 delete [] m_pub_funcs;
160 delete [] m_priv_funcs;
165 void BaseContext::SetContext(sp_context_t *_ctx)
173 ctx->dbreak = GlobalDebugBreak;
174 RefreshFunctionCache();
177 IVirtualMachine *BaseContext::GetVirtualMachine()
179 return (IVirtualMachine *)ctx->vmbase;
182 sp_context_t *BaseContext::GetContext()
187 bool BaseContext::IsDebugging()
189 return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
192 int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
196 return SP_ERROR_NOTDEBUGGING;
199 *oldpfn = ctx->dbreak;
200 ctx->dbreak = newpfn;
202 return SP_ERROR_NONE;
205 IPluginDebugInfo *BaseContext::GetDebugInfo()
210 int BaseContext::Execute(uint32_t code_addr, cell_t *result)
212 if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
214 return SP_ERROR_NOT_RUNNABLE;
217 /* tada, prevent a crash */
218 cell_t _ignore_result;
221 result = &_ignore_result;
224 IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
226 uint32_t pushcount = ctx->pushcount;
229 PushCell(pushcount++);
232 cell_t save_sp = ctx->sp;
233 cell_t save_hp = ctx->hp;
234 uint32_t n_idx = ctx->n_idx;
236 bool wasExec = m_InExec;
238 /* Clear the error state, if any */
239 ctx->n_err = SP_ERROR_NONE;
242 m_MsgCache[0] = '\0';
245 g_SourcePawn.PushTracer(ctx);
247 err = vm->ContextExecute(ctx, code_addr, result);
252 * :TODO: Calling from a plugin in here will erase the cached message...
253 * Should that be documented?
255 g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
257 #if 1//defined _DEBUG
258 //:TODO: debug code for leak detection, remove before the release?
259 if (err == SP_ERROR_NONE)
261 if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != save_sp)
264 ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
265 g_Logger.LogError("Stack leak detected: sp:%d should be %d on function %s", ctx->sp, save_sp, name);
267 if (ctx->hp != save_hp)
270 ctx->context->GetDebugInfo()->LookupFunction(code_addr, &name);
271 g_Logger.LogError("Heap leak detected: hp:%d should be %d on function %s", ctx->hp, save_hp, name);
273 //assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp);
274 //assert(ctx->hp == save_hp);
277 if (err != SP_ERROR_NONE)
288 void BaseContext::SetErrorMessage(const char *msg, va_list ap)
292 vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
295 cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
308 SetErrorMessage(msg, ap);
315 cell_t BaseContext::ThrowNativeError(const char *msg, ...)
322 ctx->n_err = SP_ERROR_NATIVE;
328 SetErrorMessage(msg, ap);
335 int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
341 if (cells > CELLBOUNDMAX)
343 return SP_ERROR_ARAM;
346 assert(cells < CELLBOUNDMAX);
349 realmem = cells * sizeof(cell_t);
352 * Check if the space between the heap and stack is sufficient.
354 if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
356 return SP_ERROR_HEAPLOW;
359 addr = (cell_t *)(ctx->memory + ctx->hp);
360 /* store size of allocation in cells */
361 *addr = (cell_t)cells;
363 ctx->hp += sizeof(cell_t);
365 *local_addr = ctx->hp;
374 return SP_ERROR_NONE;
377 int BaseContext::HeapPop(cell_t local_addr)
382 /* check the bounds of this address */
383 local_addr -= sizeof(cell_t);
384 if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
386 return SP_ERROR_INVALID_ADDRESS;
389 addr = (cell_t *)(ctx->memory + local_addr);
390 cellcount = (*addr) * sizeof(cell_t);
391 /* check if this memory count looks valid */
392 if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
394 return SP_ERROR_INVALID_ADDRESS;
397 ctx->hp = local_addr;
399 return SP_ERROR_NONE;
403 int BaseContext::HeapRelease(cell_t local_addr)
405 if (local_addr < ctx->heap_base)
407 return SP_ERROR_INVALID_ADDRESS;
410 ctx->hp = local_addr - sizeof(cell_t);
412 return SP_ERROR_NONE;
415 int BaseContext::FindNativeByName(const char *name, uint32_t *index)
419 high = ctx->plugin->info.natives_num - 1;
421 for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
423 if (strcmp(ctx->natives[i].name, name) == 0)
429 return SP_ERROR_NONE;
433 return SP_ERROR_NOT_FOUND;
436 int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
438 if (index >= ctx->plugin->info.natives_num)
440 return SP_ERROR_INDEX;
445 *native = &(ctx->natives[index]);
448 return SP_ERROR_NONE;
452 uint32_t BaseContext::GetNativesNum()
454 return ctx->plugin->info.natives_num;
457 int BaseContext::FindPublicByName(const char *name, uint32_t *index)
462 high = ctx->plugin->info.publics_num - 1;
467 mid = (low + high) / 2;
468 diff = strcmp(ctx->publics[mid].name, name);
475 return SP_ERROR_NONE;
476 } else if (diff < 0) {
483 return SP_ERROR_NOT_FOUND;
486 int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
488 if (index >= ctx->plugin->info.publics_num)
490 return SP_ERROR_INDEX;
495 *pblic = &(ctx->publics[index]);
498 return SP_ERROR_NONE;
501 uint32_t BaseContext::GetPublicsNum()
503 return ctx->plugin->info.publics_num;
506 int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
508 if (index >= ctx->plugin->info.pubvars_num)
510 return SP_ERROR_INDEX;
515 *pubvar = &(ctx->pubvars[index]);
518 return SP_ERROR_NONE;
521 int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
526 high = ctx->plugin->info.pubvars_num - 1;
531 mid = (low + high) / 2;
532 diff = strcmp(ctx->pubvars[mid].name, name);
539 return SP_ERROR_NONE;
540 } else if (diff < 0) {
547 return SP_ERROR_NOT_FOUND;
550 int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
552 if (index >= ctx->plugin->info.pubvars_num)
554 return SP_ERROR_INDEX;
557 *local_addr = ctx->plugin->info.pubvars[index].address;
558 *phys_addr = ctx->pubvars[index].offs;
560 return SP_ERROR_NONE;
563 uint32_t BaseContext::GetPubVarsNum()
565 return ctx->plugin->info.pubvars_num;
568 int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
572 max = ctx->plugin->info.natives_num;
574 for (i=0; i<max; i++)
576 if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
581 for (j=0; (natives[j].name) && (!num || j<num); j++)
583 if (!strcmp(ctx->natives[i].name, natives[j].name))
585 ctx->natives[i].pfn = natives[j].func;
586 ctx->natives[i].status = SP_NATIVE_BOUND;
591 return SP_ERROR_NONE;
594 int BaseContext::BindNative(const sp_nativeinfo_t *native)
599 if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
604 ctx->natives[index].pfn = native->func;
605 ctx->natives[index].status = SP_NATIVE_BOUND;
607 return SP_ERROR_NONE;
610 int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
612 uint32_t nativesnum, i;
614 nativesnum = ctx->plugin->info.natives_num;
616 for (i=0; i<nativesnum; i++)
618 if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
620 ctx->natives[i].pfn = native;
621 ctx->natives[i].status = SP_NATIVE_BOUND;
625 return SP_ERROR_NONE;
628 int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
630 if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
632 return SP_ERROR_INVALID_ADDRESS;
637 *phys_addr = (cell_t *)(ctx->memory + local_addr);
640 return SP_ERROR_NONE;
643 int BaseContext::PushCell(cell_t value)
645 if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
647 return SP_ERROR_STACKLOW;
650 ctx->sp -= sizeof(cell_t);
651 *(cell_t *)(ctx->memory + ctx->sp) = value;
654 return SP_ERROR_NONE;
657 int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
662 for (i=0; i<numcells; i++)
664 if ((err = PushCell(array[i])) != SP_ERROR_NONE)
666 ctx->sp += (cell_t)(i * sizeof(cell_t));
672 return SP_ERROR_NONE;
675 int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
680 if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
685 memcpy(ph_addr, array, numcells * sizeof(cell_t));
687 if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
689 HeapRelease(*local_addr);
695 *phys_addr = ph_addr;
698 return SP_ERROR_NONE;
701 int BaseContext::LocalToString(cell_t local_addr, char **addr)
703 if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
705 return SP_ERROR_INVALID_ADDRESS;
707 *addr = (char *)(ctx->memory + local_addr);
709 return SP_ERROR_NONE;
712 int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
716 unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
718 if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
723 memcpy(ph_addr, string, len);
726 if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
728 HeapRelease(*local_addr);
734 *phys_addr = ph_addr;
737 return SP_ERROR_NONE;
740 int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
745 if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
747 return SP_ERROR_INVALID_ADDRESS;
752 return SP_ERROR_NONE;
755 len = strlen(source);
756 dest = (char *)(ctx->memory + local_addr);
763 memcpy(dest, source, len);
766 return SP_ERROR_NONE;
769 inline int __CheckValidChar(char *c)
774 for (count=1; (*c & 0xC0) == 0x80; count++)
799 if (bytecount != count)
807 int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
811 bool needtocheck = false;
813 if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
815 return SP_ERROR_INVALID_ADDRESS;
820 return SP_ERROR_NONE;
823 len = strlen(source);
824 dest = (char *)(ctx->memory + local_addr);
826 if ((size_t)len >= maxbytes)
832 memcpy(dest, source, len);
833 if ((dest[len-1] & 1<<7) && needtocheck)
835 len -= __CheckValidChar(dest+len-1);
844 return SP_ERROR_NONE;
847 #define USHR(x) ((unsigned int)(x)>>1)
849 int BaseContext::LookupFile(ucell_t addr, const char **filename)
853 high = ctx->plugin->debug.files_num;
856 while (high - low > 1)
858 mid = USHR(low + high);
859 if (ctx->files[mid].addr <= addr)
869 return SP_ERROR_NOT_FOUND;
872 *filename = ctx->files[low].name;
874 return SP_ERROR_NONE;
877 int BaseContext::LookupFunction(ucell_t addr, const char **name)
879 uint32_t iter, max = ctx->plugin->debug.syms_num;
881 for (iter=0; iter<max; iter++)
883 if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION)
884 && (ctx->symbols[iter].codestart <= addr)
885 && (ctx->symbols[iter].codeend > addr))
893 return SP_ERROR_NOT_FOUND;
896 *name = ctx->symbols[iter].name;
898 return SP_ERROR_NONE;
901 int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
905 high = ctx->plugin->debug.lines_num;
908 while (high - low > 1)
910 mid = USHR(low + high);
911 if (ctx->lines[mid].addr <= addr)
921 return SP_ERROR_NOT_FOUND;
924 /* Since the CIP occurs BEFORE the line, we have to add one */
925 *line = ctx->lines[low].line + 1;
927 return SP_ERROR_NONE;
930 IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
932 CFunction *pFunc = NULL;
937 if (func_id >= ctx->plugin->info.publics_num)
941 pFunc = m_pub_funcs[func_id];
944 m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this);
945 pFunc = m_pub_funcs[func_id];
946 } else if (pFunc->IsInvalidated()) {
947 pFunc->Set(ctx->publics[func_id].code_offs, this);
950 /* :TODO: currently not used */
954 if (!g_pVM->FunctionLookup(ctx, func_id, &index))
958 pFunc = m_priv_funcs[func_id];
961 m_priv_funcs[func_id] = new CFunction(save, this);
962 pFunc = m_priv_funcs[func_id];
971 IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
975 if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
980 CFunction *pFunc = m_pub_funcs[index];
983 sp_public_t *pub = NULL;
984 GetPublicByIndex(index, &pub);
987 m_pub_funcs[index] = new CFunction(pub->code_offs, this);
989 pFunc = m_pub_funcs[index];
990 } else if (pFunc->IsInvalidated()) {
991 sp_public_t *pub = NULL;
992 GetPublicByIndex(index, &pub);
995 pFunc->Set(pub->code_offs, this);
1004 int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
1007 if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
1012 if ((cell_t *)*addr == m_pNullString)
1017 return SP_ERROR_NONE;
1020 #if defined SOURCEMOD_BUILD
1021 SourceMod::IdentityToken_t *BaseContext::GetIdentity()
1026 void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
1031 cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
1033 if (type == SP_NULL_VECTOR)