Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.
(This day shall henceforth be known as the Eighty Column Massacre of '07)
3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
35 #include "sp_file_headers.h"
36 #include "sp_vm_types.h"
37 #include "sp_vm_engine.h"
38 #include "zlib/zlib.h"
39 #include "sp_vm_basecontext.h"
42 #define WIN32_LEAN_AND_MEAN
44 #elif defined __GNUC__
48 #define INVALID_CIP 0xFFFFFFFF
50 using namespace SourcePawn;
52 #define ERROR_MESSAGE_MAX 25
53 static const char *g_ErrorMsgTable[] =
56 "Unrecognizable file format",
57 "Decompressor was not found",
58 "Not enough space on the heap",
59 "Invalid parameter or parameter type",
60 "Invalid plugin address",
61 "Object or index not found",
62 "Invalid index or index not found",
63 "Not enough space on the stack",
64 "Debug section not found or debug not enabled",
65 "Invalid instruction",
66 "Invalid memory access",
67 "Stack went below stack boundary",
68 "Heap went below heap boundary",
70 "Array index is out of bounds",
71 "Instruction contained invalid parameter",
72 "Stack memory leaked by native",
73 "Heap memory leaked by native",
74 "Dynamic array is too big",
75 "Tracker stack is out of bounds",
76 "Native is not bound",
77 "Maximum number of parameters reached",
78 "Native detected error",
79 "Plugin not runnable",
83 const char *GetSourcePawnErrorMessage(int error)
85 if (error < 1 || error > ERROR_MESSAGE_MAX)
90 return g_ErrorMsgTable[error];
93 SourcePawnEngine::SourcePawnEngine()
104 SourcePawnEngine::~SourcePawnEngine()
109 pTemp = m_FreedCalls->next;
111 m_FreedCalls = pTemp;
118 pNext = m_pFreeFuncs->m_pNext;
120 m_pFreeFuncs = pNext;
125 void *SourcePawnEngine::ExecAlloc(size_t size)
128 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
129 #elif defined __GNUC__
130 void *base = memalign(sysconf(_SC_PAGESIZE), size);
131 if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
140 void SourcePawnEngine::ExecFree(void *address)
143 VirtualFree(address, 0, MEM_RELEASE);
144 #elif defined __GNUC__
149 void *SourcePawnEngine::BaseAlloc(size_t size)
154 void SourcePawnEngine::BaseFree(void *memory)
159 IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx)
161 return new BaseContext(ctx);
164 void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx)
169 sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err)
173 sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
175 memset(plugin, 0, sizeof(sp_plugin_t));
179 while (sectnum < hdr->sections)
181 nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
183 if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
185 sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
186 plugin->pcode = base + secptr->dataoffs + cod->code;
187 plugin->pcode_size = cod->codesize;
188 plugin->flags = cod->flags;
190 else if (!(plugin->data) && !strcmp(nameptr, ".data"))
192 sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
193 plugin->data = base + secptr->dataoffs + dat->data;
194 plugin->data_size = dat->datasize;
195 plugin->memory = dat->memsize;
197 else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics"))
199 plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t);
200 plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs);
202 else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars"))
204 plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t);
205 plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
207 else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives"))
209 plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t);
210 plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs);
212 else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names"))
214 plugin->info.stringbase = (const char *)(base + secptr->dataoffs);
216 else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
218 plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
220 else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
222 plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
224 else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
226 plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
228 else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
230 sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
231 plugin->debug.files_num = inf->num_files;
232 plugin->debug.lines_num = inf->num_lines;
233 plugin->debug.syms_num = inf->num_syms;
235 else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
237 plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
244 if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase))
249 if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
256 *err = SP_ERROR_NONE;
264 *err = SP_ERROR_FILE_FORMAT;
270 sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
280 error = SP_ERROR_NOT_FOUND;
284 /* Rewind for safety */
286 fread(&hdr, sizeof(sp_file_hdr_t), 1, fp);
288 if (hdr.magic != SPFILE_MAGIC)
290 error = SP_ERROR_FILE_FORMAT;
294 switch (hdr.compression)
296 case SPFILE_COMPRESSION_GZ:
298 uint32_t uncompsize = hdr.imagesize - hdr.dataoffs;
299 uint32_t compsize = hdr.disksize - hdr.dataoffs;
300 uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t);
301 uLongf destlen = uncompsize;
303 char *tempbuf = (char *)malloc(compsize);
304 void *uncompdata = malloc(uncompsize);
305 void *sectheader = malloc(sectsize);
307 fread(sectheader, sectsize, 1, fp);
308 fread(tempbuf, compsize, 1, fp);
310 z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize);
312 if (z_result != Z_OK)
316 error = SP_ERROR_DECOMPRESSOR;
320 base = (uint8_t *)malloc(hdr.imagesize);
321 memcpy(base, &hdr, sizeof(sp_file_hdr_t));
322 memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize);
324 memcpy(base + hdr.dataoffs, uncompdata, uncompsize);
328 case SPFILE_COMPRESSION_NONE:
330 base = (uint8_t *)malloc(hdr.imagesize);
332 fread(base, hdr.imagesize, 1, fp);
337 error = SP_ERROR_DECOMPRESSOR;
342 plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t));
343 if (!_ReadPlugin(&hdr, base, plugin, err))
350 plugin->allocflags = 0;
362 sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
367 memcpy(&hdr, base, sizeof(sp_file_hdr_t));
371 plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t));
375 if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err))
386 plugin->allocflags |= SP_FA_SELF_EXTERNAL;
388 plugin->allocflags |= SP_FA_BASE_EXTERNAL;
393 int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
395 if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL))
400 if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL))
405 return SP_ERROR_NONE;
409 void SourcePawnEngine::ReleaseFunctionToPool(CFunction *func)
416 func->m_pNext = m_pFreeFuncs;
420 CFunction *SourcePawnEngine::GetFunctionFromPool(funcid_t f, IPluginContext *plugin)
424 return new CFunction(f, plugin);
426 CFunction *pFunc = m_pFreeFuncs;
427 m_pFreeFuncs = m_pFreeFuncs->m_pNext;
428 pFunc->Set(f, plugin);
434 IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
436 IDebugListener *old = m_pDebugHook;
438 m_pDebugHook = pListener;
443 unsigned int SourcePawnEngine::GetContextCallCount()
450 return m_CallStack->chain;
453 TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain)
459 pCall = new TracedCall;
461 /* Unlink the head node from the free list */
462 pCall = m_FreedCalls;
463 m_FreedCalls = m_FreedCalls->next;
466 /* Link as the head node into the call stack */
467 pCall->next = m_CallStack;
471 pCall->chain = ++m_CurChain;
473 pCall->chain = m_CurChain;
481 void SourcePawnEngine::FreeTracedCall(TracedCall *pCall)
483 /* Check if this is the top of the call stack */
484 if (pCall == m_CallStack)
486 m_CallStack = m_CallStack->next;
489 /* Add this to our linked list of freed calls */
492 m_FreedCalls = pCall;
493 m_FreedCalls->next = NULL;
495 pCall->next = m_FreedCalls;
496 m_FreedCalls = pCall;
500 void SourcePawnEngine::PushTracer(sp_context_t *ctx)
502 TracedCall *pCall = MakeTracedCall(true);
504 pCall->cip = INVALID_CIP;
506 pCall->frm = INVALID_CIP;
509 void SourcePawnEngine::RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip)
511 assert(m_CallStack != NULL);
512 assert(m_CallStack->ctx == ctx);
513 assert(m_CallStack->chain == m_CurChain);
515 if (m_CallStack->cip == INVALID_CIP)
517 /* We aren't logging anything yet, so begin the trace */
518 m_CallStack->cip = codeip;
519 m_CallStack->frm = frame;
521 if (m_CallStack->frm > frame)
523 /* The last frame has moved down the stack,
524 * so we have to push a new call onto our list.
526 TracedCall *pCall = MakeTracedCall(false);
529 } else if (m_CallStack->frm < frame) {
530 /* The last frame has moved up the stack,
531 * so we have to pop the call from our list.
533 FreeTracedCall(m_CallStack);
535 /* no matter where we are, update the cip */
536 m_CallStack->cip = codeip;
540 void SourcePawnEngine::PopTracer(int error, const char *msg)
542 assert(m_CallStack != NULL);
544 if (error != SP_ERROR_NONE && m_pDebugHook)
546 uint32_t native = INVALID_CIP;
548 if (m_CallStack->ctx->n_err)
550 native = m_CallStack->ctx->n_idx;
553 CContextTrace trace(m_CallStack, error, msg, native);
554 m_pDebugHook->OnContextExecuteError(m_CallStack->ctx->context, &trace);
557 /* Now pop the error chain */
558 while (m_CallStack && m_CallStack->chain == m_CurChain)
560 FreeTracedCall(m_CallStack);
566 unsigned int SourcePawnEngine::GetEngineAPIVersion()
568 return SOURCEPAWN_ENGINE_API_VERSION;
571 CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native) :
572 m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart), m_Native(native)
576 bool CContextTrace::DebugInfoAvailable()
578 return ((m_pStart->ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
581 const char *CContextTrace::GetCustomErrorString()
586 int CContextTrace::GetErrorCode()
591 const char *CContextTrace::GetErrorString()
593 if (m_Error > ERROR_MESSAGE_MAX ||
596 return "Invalid error code";
598 return g_ErrorMsgTable[m_Error];
602 void CContextTrace::ResetTrace()
604 m_pIterator = m_pStart;
607 bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
609 if (!m_pIterator || (m_pIterator->chain != m_pStart->chain))
614 if (m_pIterator->cip == INVALID_CIP)
619 IPluginContext *pContext = m_pIterator->ctx->context;
620 IPluginDebugInfo *pInfo = pContext->GetDebugInfo();
629 m_pIterator = m_pIterator->next;
633 if (pInfo->LookupFile(m_pIterator->cip, &(trace->filename)) != SP_ERROR_NONE)
635 trace->filename = NULL;
638 if (pInfo->LookupFunction(m_pIterator->cip, &(trace->function)) != SP_ERROR_NONE)
640 trace->function = NULL;
643 if (pInfo->LookupLine(m_pIterator->cip, &(trace->line)) != SP_ERROR_NONE)
648 m_pIterator = m_pIterator->next;
653 const char *CContextTrace::GetLastNative(uint32_t *index)
655 if (m_Native == INVALID_CIP)
661 if (m_pIterator->ctx->context->GetNativeByIndex(m_Native, &native) != SP_ERROR_NONE)