2015-02-23 22:40:01 +01:00
|
|
|
// vim: set sts=2 ts=8 sw=2 tw=99 et:
|
|
|
|
//
|
|
|
|
// Copyright (C) 2006-2015 AlliedModders LLC
|
|
|
|
//
|
|
|
|
// This file is part of SourcePawn. SourcePawn is free software: you can
|
|
|
|
// redistribute it and/or modify it under the terms of the GNU General Public
|
|
|
|
// License as published by the Free Software Foundation, either version 3 of
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License along with
|
|
|
|
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
|
|
|
//
|
2008-07-11 10:18:43 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
2015-02-24 21:55:00 +01:00
|
|
|
#include <sp_vm_api.h>
|
|
|
|
#include "plugin-context.h"
|
2013-08-15 08:54:25 +02:00
|
|
|
#include "watchdog_timer.h"
|
2008-07-11 10:18:43 +02:00
|
|
|
#include "x86/jit_x86.h"
|
2015-02-24 03:19:33 +01:00
|
|
|
#include "environment.h"
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
#include "compiled-function.h"
|
2008-07-11 10:18:43 +02:00
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
using namespace sp;
|
2008-07-11 10:18:43 +02:00
|
|
|
using namespace SourcePawn;
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
|
|
|
|
#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
|
2008-07-11 10:18:43 +02:00
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
static const size_t kMinHeapSize = 16384;
|
|
|
|
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::PluginContext(PluginRuntime *pRuntime)
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
: m_pRuntime(pRuntime),
|
|
|
|
memory_(nullptr),
|
|
|
|
data_size_(m_pRuntime->data().length),
|
|
|
|
mem_size_(m_pRuntime->image()->HeapSize()),
|
|
|
|
m_pNullVec(nullptr),
|
|
|
|
m_pNullString(nullptr),
|
|
|
|
m_CustomMsg(false),
|
|
|
|
m_InExec(false)
|
|
|
|
{
|
|
|
|
// Compute and align a minimum memory amount.
|
|
|
|
if (mem_size_ < data_size_)
|
|
|
|
mem_size_ = data_size_;
|
|
|
|
mem_size_ = ke::Align(mem_size_, sizeof(cell_t));
|
|
|
|
|
|
|
|
// Add a minimum heap size if needed.
|
|
|
|
if (mem_size_ < data_size_ + kMinHeapSize)
|
|
|
|
mem_size_ = data_size_ + kMinHeapSize;
|
|
|
|
assert(ke::IsAligned(mem_size_, sizeof(cell_t)));
|
|
|
|
|
|
|
|
hp_ = data_size_;
|
|
|
|
sp_ = mem_size_ - sizeof(cell_t);
|
|
|
|
frm_ = sp_;
|
|
|
|
rp_ = 0;
|
|
|
|
last_native_ = -1;
|
|
|
|
native_error_ = SP_ERROR_NONE;
|
|
|
|
|
|
|
|
tracker_.pBase = (ucell_t *)malloc(1024);
|
|
|
|
tracker_.pCur = tracker_.pBase;
|
|
|
|
tracker_.size = 1024 / sizeof(cell_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
PluginContext::~PluginContext()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
free(tracker_.pBase);
|
|
|
|
delete[] memory_;
|
|
|
|
}
|
2015-02-23 22:40:01 +01:00
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
bool
|
|
|
|
PluginContext::Initialize()
|
|
|
|
{
|
|
|
|
memory_ = new uint8_t[mem_size_];
|
|
|
|
if (!memory_)
|
|
|
|
return false;
|
|
|
|
memset(memory_ + data_size_, 0, mem_size_ - data_size_);
|
|
|
|
memcpy(memory_, m_pRuntime->data().bytes, data_size_);
|
2015-02-23 22:40:01 +01:00
|
|
|
|
|
|
|
/* Initialize the null references */
|
|
|
|
uint32_t index;
|
|
|
|
if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE) {
|
|
|
|
sp_pubvar_t *pubvar;
|
|
|
|
GetPubvarByIndex(index, &pubvar);
|
|
|
|
m_pNullVec = pubvar->offs;
|
|
|
|
} else {
|
|
|
|
m_pNullVec = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE) {
|
|
|
|
sp_pubvar_t *pubvar;
|
|
|
|
GetPubvarByIndex(index, &pubvar);
|
|
|
|
m_pNullString = pubvar->offs;
|
|
|
|
} else {
|
|
|
|
m_pNullString = NULL;
|
|
|
|
}
|
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
return true;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
IVirtualMachine *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetVirtualMachine()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return NULL;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
sp_context_t *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetContext()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
bool
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::IsDebugging()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return true;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::SetDebugBreak(void *newpfn, void *oldpfn)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
IPluginDebugInfo *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetDebugInfo()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return NULL;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::Execute(uint32_t code_addr, cell_t *result)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
void
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::SetErrorMessage(const char *msg, va_list ap)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
m_CustomMsg = true;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
void
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::_SetErrorMessage(const char *msg, ...)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
|
|
SetErrorMessage(msg, ap);
|
|
|
|
va_end(ap);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::ThrowNativeErrorEx(int error, const char *msg, ...)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
if (!m_InExec)
|
|
|
|
return 0;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = error;
|
2015-02-23 22:40:01 +01:00
|
|
|
|
|
|
|
if (msg) {
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
|
|
SetErrorMessage(msg, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return 0;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::ThrowNativeError(const char *msg, ...)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
if (!m_InExec)
|
|
|
|
return 0;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_NATIVE;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (msg) {
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
|
|
SetErrorMessage(msg, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return 0;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t *addr;
|
|
|
|
ucell_t realmem;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
|
|
|
#if 0
|
2015-02-23 22:40:01 +01:00
|
|
|
if (cells > CELLBOUNDMAX)
|
|
|
|
{
|
|
|
|
return SP_ERROR_ARAM;
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
#else
|
2015-02-23 22:40:01 +01:00
|
|
|
assert(cells < CELLBOUNDMAX);
|
2008-07-11 10:18:43 +02:00
|
|
|
#endif
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
realmem = cells * sizeof(cell_t);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/**
|
|
|
|
* Check if the space between the heap and stack is sufficient.
|
|
|
|
*/
|
2015-02-25 06:18:34 +01:00
|
|
|
if ((cell_t)(sp_ - hp_ - realmem) < STACKMARGIN)
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_HEAPLOW;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
addr = (cell_t *)(memory_ + hp_);
|
2015-02-23 22:40:01 +01:00
|
|
|
/* store size of allocation in cells */
|
|
|
|
*addr = (cell_t)cells;
|
|
|
|
addr++;
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_ += sizeof(cell_t);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
*local_addr = hp_;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (phys_addr)
|
|
|
|
*phys_addr = addr;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_ += realmem;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::HeapPop(cell_t local_addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t cellcount;
|
|
|
|
cell_t *addr;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/* check the bounds of this address */
|
|
|
|
local_addr -= sizeof(cell_t);
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
if (local_addr < (cell_t)data_size_ || local_addr >= sp_)
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
addr = (cell_t *)(memory_ + local_addr);
|
2015-02-23 22:40:01 +01:00
|
|
|
cellcount = (*addr) * sizeof(cell_t);
|
|
|
|
/* check if this memory count looks valid */
|
2015-02-25 06:18:34 +01:00
|
|
|
if ((signed)(hp_ - cellcount - sizeof(cell_t)) != local_addr)
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_ = local_addr;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::HeapRelease(cell_t local_addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
if (local_addr < (cell_t)data_size_)
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_ = local_addr - sizeof(cell_t);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::FindNativeByName(const char *name, uint32_t *index)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->FindNativeByName(name, index);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetNativeByIndex(index, native);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
uint32_t
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetNativesNum()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetNativesNum();
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::FindPublicByName(const char *name, uint32_t *index)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->FindPublicByName(name, index);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetPublicByIndex(index, pblic);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
uint32_t
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetPublicsNum()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetPublicsNum();
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetPubvarByIndex(index, pubvar);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::FindPubvarByName(const char *name, uint32_t *index)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->FindPubvarByName(name, index);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
uint32_t
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetPubVarsNum()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetPubVarsNum();
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::BindNative(const sp_nativeinfo_t *native)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-25 06:18:34 +01:00
|
|
|
if (((local_addr >= hp_) && (local_addr < sp_)) ||
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
(local_addr < 0) || ((ucell_t)local_addr >= mem_size_))
|
2015-02-23 22:40:01 +01:00
|
|
|
{
|
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (phys_addr)
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
*phys_addr = (cell_t *)(memory_ + local_addr);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::PushCell(cell_t value)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::LocalToString(cell_t local_addr, char **addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-25 06:18:34 +01:00
|
|
|
if (((local_addr >= hp_) && (local_addr < sp_)) ||
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
(local_addr < 0) || ((ucell_t)local_addr >= mem_size_))
|
2015-02-23 22:40:01 +01:00
|
|
|
{
|
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
|
|
|
}
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
*addr = (char *)(memory_ + local_addr);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_ABORTED;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
char *dest;
|
|
|
|
size_t len;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
if (((local_addr >= hp_) && (local_addr < sp_)) ||
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
(local_addr < 0) || ((ucell_t)local_addr >= mem_size_))
|
2015-02-23 22:40:01 +01:00
|
|
|
{
|
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (bytes == 0)
|
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
len = strlen(source);
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
dest = (char *)(memory_ + local_addr);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (len >= bytes)
|
|
|
|
len = bytes - 1;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
memmove(dest, source, len);
|
|
|
|
dest[len] = '\0';
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
static inline int
|
|
|
|
__CheckValidChar(char *c)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
int count;
|
|
|
|
int bytecount = 0;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
for (count=1; (*c & 0xC0) == 0x80; count++)
|
|
|
|
c--;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
switch (*c & 0xF0)
|
|
|
|
{
|
|
|
|
case 0xC0:
|
|
|
|
case 0xD0:
|
|
|
|
{
|
|
|
|
bytecount = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0xE0:
|
|
|
|
{
|
|
|
|
bytecount = 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0xF0:
|
|
|
|
{
|
|
|
|
bytecount = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (bytecount != count)
|
|
|
|
return count;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return 0;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
char *dest;
|
|
|
|
size_t len;
|
|
|
|
bool needtocheck = false;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
if (((local_addr >= hp_) && (local_addr < sp_)) ||
|
2015-02-23 22:40:01 +01:00
|
|
|
(local_addr < 0) ||
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
((ucell_t)local_addr >= mem_size_))
|
2015-02-23 22:40:01 +01:00
|
|
|
{
|
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maxbytes == 0)
|
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
len = strlen(source);
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
dest = (char *)(memory_ + local_addr);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if ((size_t)len >= maxbytes) {
|
|
|
|
len = maxbytes - 1;
|
|
|
|
needtocheck = true;
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
memmove(dest, source, len);
|
|
|
|
if ((dest[len-1] & 1<<7) && needtocheck)
|
|
|
|
len -= __CheckValidChar(dest+len-1);
|
|
|
|
dest[len] = '\0';
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (wrtnbytes)
|
|
|
|
*wrtnbytes = len;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
IPluginFunction *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetFunctionById(funcid_t func_id)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetFunctionById(func_id);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
IPluginFunction *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetFunctionByName(const char *public_name)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_pRuntime->GetFunctionByName(public_name);
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::LocalToStringNULL(cell_t local_addr, char **addr)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
int err;
|
|
|
|
if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
|
|
|
|
return err;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if ((cell_t *)*addr == m_pNullString)
|
|
|
|
*addr = NULL;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_NONE;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
SourceMod::IdentityToken_t *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetIdentity()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
SourceMod::IdentityToken_t *tok;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (GetKey(1, (void **)&tok))
|
|
|
|
return tok;
|
|
|
|
return NULL;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetNullRef(SP_NULL_TYPE type)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
if (type == SP_NULL_VECTOR)
|
|
|
|
return m_pNullVec;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
return NULL;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
bool
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::IsInExec()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
return m_InExec;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
int ir;
|
|
|
|
int serial;
|
|
|
|
cell_t *sp;
|
2015-02-24 01:27:57 +01:00
|
|
|
CompiledFunction *fn;
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t _ignore_result;
|
|
|
|
|
|
|
|
EnterProfileScope profileScope("SourcePawn", "EnterJIT");
|
|
|
|
|
2015-02-24 07:47:08 +01:00
|
|
|
if (!Environment::get()->watchdog()->HandleInterrupt())
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_TIMEOUT;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
funcid_t fnid = function->GetFunctionID();
|
|
|
|
if (!(fnid & 1))
|
|
|
|
return SP_ERROR_INVALID_ADDRESS;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
unsigned public_id = fnid >> 1;
|
2015-02-24 00:47:47 +01:00
|
|
|
ScriptedInvoker *cfun = m_pRuntime->GetPublicFunction(public_id);
|
2015-02-23 22:40:01 +01:00
|
|
|
if (!cfun)
|
|
|
|
return SP_ERROR_NOT_FOUND;
|
2013-08-15 08:54:25 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (m_pRuntime->IsPaused())
|
|
|
|
return SP_ERROR_NOT_RUNNABLE;
|
2014-06-24 10:04:13 +02:00
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
if ((cell_t)(hp_ + 16*sizeof(cell_t)) > (cell_t)(sp_ - (sizeof(cell_t) * (num_params + 1))))
|
2015-02-23 22:40:01 +01:00
|
|
|
return SP_ERROR_STACKLOW;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
if (result == NULL)
|
|
|
|
result = &_ignore_result;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/* We got this far. It's time to start profiling. */
|
|
|
|
EnterProfileScope scriptScope("SourcePawn", cfun->FullName());
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/* See if we have to compile the callee. */
|
2015-02-25 08:37:23 +01:00
|
|
|
if (Environment::get()->IsJitEnabled()) {
|
2015-02-23 22:40:01 +01:00
|
|
|
/* We might not have to - check pcode offset. */
|
2015-02-25 08:37:23 +01:00
|
|
|
if ((fn = cfun->cachedCompiledFunction()) == nullptr) {
|
|
|
|
fn = m_pRuntime->GetJittedFunctionByOffset(cfun->Public()->code_offs);
|
|
|
|
if (!fn) {
|
|
|
|
if ((fn = CompileFunction(m_pRuntime, cfun->Public()->code_offs, &ir)) == NULL)
|
|
|
|
return ir;
|
|
|
|
}
|
|
|
|
cfun->setCachedCompiledFunction(fn);
|
2015-02-23 22:40:01 +01:00
|
|
|
}
|
|
|
|
}
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/* Save our previous state. */
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
bool save_exec;
|
|
|
|
uint32_t save_n_idx;
|
|
|
|
cell_t save_sp, save_hp, save_rp, save_cip;
|
2008-08-15 07:22:26 +02:00
|
|
|
|
2015-02-25 06:06:06 +01:00
|
|
|
save_sp = sp_;
|
2015-02-25 06:18:34 +01:00
|
|
|
save_hp = hp_;
|
2015-02-23 22:40:01 +01:00
|
|
|
save_exec = m_InExec;
|
2015-02-25 04:59:45 +01:00
|
|
|
save_n_idx = last_native_;
|
2015-02-25 00:20:00 +01:00
|
|
|
save_rp = rp_;
|
2015-02-25 05:53:44 +01:00
|
|
|
save_cip = cip_;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/* Push parameters */
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-25 06:06:06 +01:00
|
|
|
sp_ -= sizeof(cell_t) * (num_params + 1);
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
sp = (cell_t *)(memory_ + sp_);
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
sp[0] = num_params;
|
|
|
|
for (unsigned int i = 0; i < num_params; i++)
|
|
|
|
sp[i + 1] = params[i];
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
/* Clear internal state */
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_NONE;
|
2015-02-25 04:59:45 +01:00
|
|
|
last_native_ = -1;
|
2015-02-23 22:40:01 +01:00
|
|
|
m_MsgCache[0] = '\0';
|
|
|
|
m_CustomMsg = false;
|
|
|
|
m_InExec = true;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-24 10:12:23 +01:00
|
|
|
// Enter the execution engine.
|
|
|
|
Environment *env = Environment::get();
|
2015-02-25 08:57:08 +01:00
|
|
|
ir = env->Invoke(m_pRuntime, fn, result);
|
2015-02-23 22:40:01 +01:00
|
|
|
|
|
|
|
/* Restore some states, stop the frame tracer */
|
|
|
|
|
|
|
|
m_InExec = save_exec;
|
|
|
|
|
|
|
|
if (ir == SP_ERROR_NONE) {
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_NONE;
|
2015-02-25 06:06:06 +01:00
|
|
|
if (sp_ != save_sp) {
|
2015-02-23 22:40:01 +01:00
|
|
|
ir = SP_ERROR_STACKLEAK;
|
|
|
|
_SetErrorMessage("Stack leak detected: sp:%d should be %d!",
|
2015-02-25 06:06:06 +01:00
|
|
|
sp_,
|
2015-02-23 22:40:01 +01:00
|
|
|
save_sp);
|
|
|
|
}
|
2015-02-25 06:18:34 +01:00
|
|
|
if (hp_ != save_hp) {
|
2015-02-23 22:40:01 +01:00
|
|
|
ir = SP_ERROR_HEAPLEAK;
|
|
|
|
_SetErrorMessage("Heap leak detected: hp:%d should be %d!",
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_,
|
2015-02-23 22:40:01 +01:00
|
|
|
save_hp);
|
|
|
|
}
|
2015-02-25 00:20:00 +01:00
|
|
|
if (rp_ != save_rp) {
|
2015-02-23 22:40:01 +01:00
|
|
|
ir = SP_ERROR_STACKLEAK;
|
|
|
|
_SetErrorMessage("Return stack leak detected: rp:%d should be %d!",
|
2015-02-25 00:20:00 +01:00
|
|
|
rp_,
|
2015-02-23 22:40:01 +01:00
|
|
|
save_rp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ir == SP_ERROR_TIMEOUT)
|
2015-02-24 07:47:08 +01:00
|
|
|
Environment::get()->watchdog()->NotifyTimeoutReceived();
|
2015-02-23 22:40:01 +01:00
|
|
|
|
|
|
|
if (ir != SP_ERROR_NONE)
|
2015-02-24 03:19:33 +01:00
|
|
|
Environment::get()->ReportError(m_pRuntime, ir, m_MsgCache, save_rp);
|
2015-02-23 22:40:01 +01:00
|
|
|
|
2015-02-25 06:06:06 +01:00
|
|
|
sp_ = save_sp;
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_ = save_hp;
|
2015-02-25 00:20:00 +01:00
|
|
|
rp_ = save_rp;
|
2015-02-23 22:40:01 +01:00
|
|
|
|
2015-02-25 05:53:44 +01:00
|
|
|
cip_ = save_cip;
|
2015-02-25 04:59:45 +01:00
|
|
|
last_native_ = save_n_idx;
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_NONE;
|
2015-02-23 22:40:01 +01:00
|
|
|
m_MsgCache[0] = '\0';
|
|
|
|
m_CustomMsg = false;
|
|
|
|
|
|
|
|
return ir;
|
|
|
|
}
|
|
|
|
|
|
|
|
IPluginRuntime *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetRuntime()
|
2015-02-23 22:40:01 +01:00
|
|
|
{
|
|
|
|
return m_pRuntime;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
int
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetLastNativeError()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-25 05:16:13 +01:00
|
|
|
return native_error_;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
cell_t *
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetLocalParams()
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
return (cell_t *)(memory_ + frm_ + (2 * sizeof(cell_t)));
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
void
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::SetKey(int k, void *value)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
if (k < 1 || k > 4)
|
|
|
|
return;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
m_keys[k - 1] = value;
|
|
|
|
m_keys_set[k - 1] = true;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
bool
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::GetKey(int k, void **value)
|
2008-07-11 10:18:43 +02:00
|
|
|
{
|
2015-02-23 22:40:01 +01:00
|
|
|
if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
|
|
|
|
return false;
|
2008-07-11 10:18:43 +02:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
*value = m_keys[k - 1];
|
|
|
|
return true;
|
2008-07-11 10:18:43 +02:00
|
|
|
}
|
2009-02-01 08:03:03 +01:00
|
|
|
|
2015-02-23 22:40:01 +01:00
|
|
|
void
|
2015-02-24 21:50:09 +01:00
|
|
|
PluginContext::ClearLastNativeError()
|
2009-02-01 08:03:03 +01:00
|
|
|
{
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_NONE;
|
2009-02-01 08:03:03 +01:00
|
|
|
}
|
2015-02-25 00:43:41 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
PluginContext::popTrackerAndSetHeap()
|
|
|
|
{
|
|
|
|
assert(tracker_.pCur > tracker_.pBase);
|
|
|
|
|
|
|
|
tracker_.pCur--;
|
|
|
|
if (tracker_.pCur < tracker_.pBase)
|
|
|
|
return SP_ERROR_TRACKER_BOUNDS;
|
|
|
|
|
|
|
|
ucell_t amt = *tracker_.pCur;
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
if (amt > (hp_ - data_size_))
|
2015-02-25 00:43:41 +01:00
|
|
|
return SP_ERROR_HEAPMIN;
|
|
|
|
|
2015-02-25 06:18:34 +01:00
|
|
|
hp_ -= amt;
|
2015-02-25 00:43:41 +01:00
|
|
|
return SP_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
PluginContext::pushTracker(uint32_t amount)
|
|
|
|
{
|
|
|
|
if ((size_t)(tracker_.pCur - tracker_.pBase) >= tracker_.size)
|
|
|
|
return SP_ERROR_TRACKER_BOUNDS;
|
|
|
|
|
|
|
|
if (tracker_.pCur + 1 - (tracker_.pBase + tracker_.size) == 0) {
|
|
|
|
size_t disp = tracker_.size - 1;
|
|
|
|
tracker_.size *= 2;
|
|
|
|
tracker_.pBase = (ucell_t *)realloc(tracker_.pBase, tracker_.size * sizeof(cell_t));
|
|
|
|
|
|
|
|
if (!tracker_.pBase)
|
|
|
|
return SP_ERROR_TRACKER_BOUNDS;
|
|
|
|
|
|
|
|
tracker_.pCur = tracker_.pBase + disp;
|
|
|
|
}
|
|
|
|
|
|
|
|
*tracker_.pCur++ = amount;
|
|
|
|
return SP_ERROR_NONE;
|
|
|
|
}
|
2015-02-25 04:59:45 +01:00
|
|
|
|
|
|
|
cell_t
|
|
|
|
PluginContext::invokeNative(ucell_t native_idx, cell_t *params)
|
|
|
|
{
|
2015-02-25 06:06:06 +01:00
|
|
|
cell_t save_sp = sp_;
|
2015-02-25 06:18:34 +01:00
|
|
|
cell_t save_hp = hp_;
|
2015-02-25 04:59:45 +01:00
|
|
|
|
|
|
|
// Note: Invoke() saves the last native, so we don't need to here.
|
|
|
|
last_native_ = native_idx;
|
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
const sp_native_t *native = m_pRuntime->GetNative(native_idx);
|
2015-02-25 04:59:45 +01:00
|
|
|
|
|
|
|
if (native->status == SP_NATIVE_UNBOUND) {
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_INVALID_NATIVE;
|
2015-02-25 04:59:45 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-25 06:19:29 +01:00
|
|
|
cell_t result = native->pfn(this, params);
|
2015-02-25 04:59:45 +01:00
|
|
|
|
2015-02-25 05:16:13 +01:00
|
|
|
if (native_error_ != SP_ERROR_NONE)
|
2015-02-25 04:59:45 +01:00
|
|
|
return result;
|
|
|
|
|
2015-02-25 06:06:06 +01:00
|
|
|
if (save_sp != sp_) {
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_STACKLEAK;
|
2015-02-25 04:59:45 +01:00
|
|
|
return result;
|
|
|
|
}
|
2015-02-25 06:18:34 +01:00
|
|
|
if (save_hp != hp_) {
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_HEAPLEAK;
|
2015-02-25 04:59:45 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell_t
|
|
|
|
PluginContext::invokeBoundNative(SPVM_NATIVE_FUNC pfn, cell_t *params)
|
|
|
|
{
|
2015-02-25 06:06:06 +01:00
|
|
|
cell_t save_sp = sp_;
|
2015-02-25 06:18:34 +01:00
|
|
|
cell_t save_hp = hp_;
|
2015-02-25 04:59:45 +01:00
|
|
|
|
|
|
|
cell_t result = pfn(this, params);
|
|
|
|
|
2015-02-25 05:16:13 +01:00
|
|
|
if (native_error_ != SP_ERROR_NONE)
|
2015-02-25 04:59:45 +01:00
|
|
|
return result;
|
|
|
|
|
2015-02-25 06:06:06 +01:00
|
|
|
if (save_sp != sp_) {
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_STACKLEAK;
|
2015-02-25 04:59:45 +01:00
|
|
|
return result;
|
|
|
|
}
|
2015-02-25 06:18:34 +01:00
|
|
|
if (save_hp != hp_) {
|
2015-02-25 05:16:13 +01:00
|
|
|
native_error_ = SP_ERROR_HEAPLEAK;
|
2015-02-25 04:59:45 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2015-02-25 06:18:34 +01:00
|
|
|
|
|
|
|
struct array_creation_t
|
|
|
|
{
|
|
|
|
const cell_t *dim_list; /* Dimension sizes */
|
|
|
|
cell_t dim_count; /* Number of dimensions */
|
|
|
|
cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
|
|
|
|
cell_t *base; /* array base */
|
|
|
|
};
|
|
|
|
|
|
|
|
static cell_t
|
|
|
|
GenerateInnerArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
|
|
|
|
{
|
|
|
|
cell_t write_offs = cur_offs;
|
|
|
|
cell_t *data_offs = ar->data_offs;
|
|
|
|
|
|
|
|
cur_offs += ar->dim_list[dim];
|
|
|
|
|
|
|
|
// Dimension n-x where x > 2 will have sub-vectors.
|
|
|
|
// Otherwise, we just need to reference the data section.
|
|
|
|
if (ar->dim_count > 2 && dim < ar->dim_count - 2) {
|
|
|
|
// For each index at this dimension, write offstes to our sub-vectors.
|
|
|
|
// After we write one sub-vector, we generate its sub-vectors recursively.
|
|
|
|
// At the end, we're given the next offset we can use.
|
|
|
|
for (int i = 0; i < ar->dim_list[dim]; i++) {
|
|
|
|
ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
|
|
|
|
write_offs++;
|
|
|
|
cur_offs = GenerateInnerArrayIndirectionVectors(ar, dim + 1, cur_offs);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// In this section, there are no sub-vectors, we need to write offsets
|
|
|
|
// to the data. This is separate so the data stays in one big chunk.
|
|
|
|
// The data offset will increment by the size of the last dimension,
|
|
|
|
// because that is where the data is finally computed as.
|
|
|
|
for (int i = 0; i < ar->dim_list[dim]; i++) {
|
|
|
|
ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
|
|
|
|
write_offs++;
|
|
|
|
*data_offs = *data_offs + ar->dim_list[dim + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cur_offs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static cell_t
|
|
|
|
calc_indirection(const array_creation_t *ar, cell_t dim)
|
|
|
|
{
|
|
|
|
cell_t size = ar->dim_list[dim];
|
|
|
|
if (dim < ar->dim_count - 2)
|
|
|
|
size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static cell_t
|
|
|
|
GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
|
|
|
|
{
|
|
|
|
array_creation_t ar;
|
|
|
|
cell_t data_offs;
|
|
|
|
|
|
|
|
/* Reverse the dimensions */
|
|
|
|
cell_t dim_list[sDIMEN_MAX];
|
|
|
|
int cur_dim = 0;
|
|
|
|
for (int i = _dimcount - 1; i >= 0; i--)
|
|
|
|
dim_list[cur_dim++] = dims[i];
|
|
|
|
|
|
|
|
ar.base = arraybase;
|
|
|
|
ar.dim_list = dim_list;
|
|
|
|
ar.dim_count = _dimcount;
|
|
|
|
ar.data_offs = &data_offs;
|
|
|
|
|
|
|
|
data_offs = calc_indirection(&ar, 0);
|
|
|
|
GenerateInnerArrayIndirectionVectors(&ar, 0, 0);
|
|
|
|
return data_offs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
PluginContext::generateFullArray(uint32_t argc, cell_t *argv, int autozero)
|
|
|
|
{
|
|
|
|
// Calculate how many cells are needed.
|
|
|
|
if (argv[0] <= 0)
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
|
|
|
|
uint32_t cells = argv[0];
|
|
|
|
|
|
|
|
for (uint32_t dim = 1; dim < argc; dim++) {
|
|
|
|
cell_t dimsize = argv[dim];
|
|
|
|
if (dimsize <= 0)
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
if (!ke::IsUint32MultiplySafe(cells, dimsize))
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
cells *= uint32_t(dimsize);
|
|
|
|
if (!ke::IsUint32AddSafe(cells, dimsize))
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
cells += uint32_t(dimsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ke::IsUint32MultiplySafe(cells, 4))
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
|
|
|
|
uint32_t bytes = cells * 4;
|
|
|
|
if (!ke::IsUint32AddSafe(hp_, bytes))
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
|
|
|
|
uint32_t new_hp = hp_ + bytes;
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
cell_t *dat_hp = reinterpret_cast<cell_t *>(memory_ + new_hp);
|
2015-02-25 06:18:34 +01:00
|
|
|
|
|
|
|
// argv, coincidentally, is STK.
|
|
|
|
if (dat_hp >= argv - STACK_MARGIN)
|
|
|
|
return SP_ERROR_HEAPLOW;
|
|
|
|
|
|
|
|
if (int err = pushTracker(bytes))
|
|
|
|
return err;
|
|
|
|
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
cell_t *base = reinterpret_cast<cell_t *>(memory_ + hp_);
|
2015-02-25 06:18:34 +01:00
|
|
|
cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, !!autozero);
|
|
|
|
assert(size_t(offs) == cells);
|
|
|
|
|
|
|
|
argv[argc - 1] = hp_;
|
|
|
|
hp_ = new_hp;
|
|
|
|
return SP_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
PluginContext::generateArray(cell_t dims, cell_t *stk, bool autozero)
|
|
|
|
{
|
|
|
|
if (dims == 1) {
|
|
|
|
uint32_t size = *stk;
|
|
|
|
if (size == 0 || !ke::IsUint32MultiplySafe(size, 4))
|
|
|
|
return SP_ERROR_ARRAY_TOO_BIG;
|
|
|
|
*stk = hp_;
|
|
|
|
|
|
|
|
uint32_t bytes = size * 4;
|
|
|
|
|
|
|
|
hp_ += bytes;
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
if (uintptr_t(memory_ + hp_) >= uintptr_t(stk))
|
2015-02-25 06:18:34 +01:00
|
|
|
return SP_ERROR_HEAPLOW;
|
|
|
|
|
|
|
|
if (int err = pushTracker(bytes))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (autozero)
|
Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.
The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.
Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.
PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.
Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 11:19:38 +01:00
|
|
|
memset(memory_ + hp_, 0, bytes);
|
2015-02-25 06:18:34 +01:00
|
|
|
|
|
|
|
return SP_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (int err = generateFullArray(dims, stk, autozero))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return SP_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|