diff --git a/core/CTextParsers.h b/core/CTextParsers.h index aeaf40da..49cadb1c 100644 --- a/core/CTextParsers.h +++ b/core/CTextParsers.h @@ -1,7 +1,7 @@ #ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ #define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_ -#include "interfaces/ITextParsers.h" +#include using namespace SourceMod; diff --git a/core/sm_globals.h b/core/sm_globals.h index 90114c35..00024b62 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -8,7 +8,7 @@ #include #include #include "sm_platform.h" -#include "interfaces/IShareSys.h" +#include using namespace SourcePawn; using namespace SourceMod; diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index 507801e7..3d307e15 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -50,7 +50,7 @@ void RootConsoleMenu::ConsolePrint(const char *fmt, ...) size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); - if (len >= sizeof(buffer)) + if (len >= sizeof(buffer) - 1) { buffer[510] = '\n'; buffer[511] = '\0'; diff --git a/core/systems/ExtensionSys.cpp b/core/systems/ExtensionSys.cpp index acb28046..b95e46e7 100644 --- a/core/systems/ExtensionSys.cpp +++ b/core/systems/ExtensionSys.cpp @@ -564,6 +564,12 @@ void CExtensionManager::MarkAllLoaded() } } +void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload) +{ + /* :TODO: implement */ + return; +} + void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount) { if (argcount >= 3) diff --git a/core/systems/ExtensionSys.h b/core/systems/ExtensionSys.h index f3afc978..91352ceb 100644 --- a/core/systems/ExtensionSys.h +++ b/core/systems/ExtensionSys.h @@ -80,6 +80,7 @@ public: void AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives); void BindAllNativesToPlugin(IPlugin *pPlugin); void MarkAllLoaded(); + void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload); private: CExtension *FindByOrder(unsigned int num); private: diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 5d7bb335..e05a0abf 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -194,3 +194,9 @@ void ShareSystem::RemoveInterfaces(IExtension *pExtension) } } } + +void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload) +{ + g_Extensions.AddDependency(myself, filename, require, autoload); +} + diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index be249e5c..21a09468 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -42,6 +42,7 @@ public: //IShareSys IdentityToken_t *CreateIdentity(IdentityType_t type); void DestroyIdentType(IdentityType_t type); void DestroyIdentity(IdentityToken_t *identity); + void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload); public: //SMGlobalClass /* Pre-empt in case anything tries to register idents early */ void OnSourceModStartup(bool late); diff --git a/core/interfaces/IExtensionSys.h b/public/IExtensionSys.h similarity index 100% rename from core/interfaces/IExtensionSys.h rename to public/IExtensionSys.h diff --git a/core/interfaces/IForwardSys.h b/public/IForwardSys.h similarity index 100% rename from core/interfaces/IForwardSys.h rename to public/IForwardSys.h diff --git a/core/interfaces/IHandleSys.h b/public/IHandleSys.h similarity index 100% rename from core/interfaces/IHandleSys.h rename to public/IHandleSys.h diff --git a/core/interfaces/ILibrarySys.h b/public/ILibrarySys.h similarity index 100% rename from core/interfaces/ILibrarySys.h rename to public/ILibrarySys.h diff --git a/core/interfaces/IPluginFunction.h b/public/IPluginFunction.h similarity index 100% rename from core/interfaces/IPluginFunction.h rename to public/IPluginFunction.h diff --git a/core/interfaces/IPluginSys.h b/public/IPluginSys.h similarity index 100% rename from core/interfaces/IPluginSys.h rename to public/IPluginSys.h diff --git a/core/interfaces/IRootConsoleMenu.h b/public/IRootConsoleMenu.h similarity index 100% rename from core/interfaces/IRootConsoleMenu.h rename to public/IRootConsoleMenu.h diff --git a/core/interfaces/IShareSys.h b/public/IShareSys.h similarity index 100% rename from core/interfaces/IShareSys.h rename to public/IShareSys.h diff --git a/core/interfaces/ISourceMod.h b/public/ISourceMod.h similarity index 100% rename from core/interfaces/ISourceMod.h rename to public/ISourceMod.h diff --git a/core/interfaces/ITextParsers.h b/public/ITextParsers.h similarity index 100% rename from core/interfaces/ITextParsers.h rename to public/ITextParsers.h diff --git a/extensions/sdk/extension.cpp b/public/sample_ext/extension.cpp similarity index 100% rename from extensions/sdk/extension.cpp rename to public/sample_ext/extension.cpp diff --git a/extensions/sdk/extension.h b/public/sample_ext/extension.h similarity index 100% rename from extensions/sdk/extension.h rename to public/sample_ext/extension.h diff --git a/extensions/sdk/sdk.sln b/public/sample_ext/sdk.sln similarity index 100% rename from extensions/sdk/sdk.sln rename to public/sample_ext/sdk.sln diff --git a/extensions/sdk/sdk.vcproj b/public/sample_ext/sdk.vcproj similarity index 100% rename from extensions/sdk/sdk.vcproj rename to public/sample_ext/sdk.vcproj diff --git a/extensions/sdk/smsdk_config.h b/public/sample_ext/smsdk_config.h similarity index 100% rename from extensions/sdk/smsdk_config.h rename to public/sample_ext/smsdk_config.h diff --git a/extensions/sdk/smsdk_ext.cpp b/public/sample_ext/smsdk_ext.cpp similarity index 100% rename from extensions/sdk/smsdk_ext.cpp rename to public/sample_ext/smsdk_ext.cpp diff --git a/extensions/sdk/smsdk_ext.h b/public/sample_ext/smsdk_ext.h similarity index 100% rename from extensions/sdk/smsdk_ext.h rename to public/sample_ext/smsdk_ext.h diff --git a/public/sm_platform.h b/public/sm_platform.h new file mode 100644 index 00000000..05171cd8 --- /dev/null +++ b/public/sm_platform.h @@ -0,0 +1,39 @@ +#ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_ +#define _INCLUDE_SOURCEMOD_PLATFORM_H_ + +/** + * @file Contains platform-specific macros for abstraction. + */ + +#if defined WIN32 || defined WIN64 +#define PLATFORM_WINDOWS +#if !defined WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#if !defined snprintf +#define snprintf _snprintf +#endif +#if !defined stat +#define stat _stat +#endif +#define strcasecmp strcmpi +#include +#include +#define PLATFORM_LIB_EXT "dll" +#define PLATFORM_MAX_PATH MAX_PATH +#define PLATFORM_SEP_CHAR '\\' +#define PLATFORM_SEP_ALTCHAR '/' +#define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) +#else if defined __linux__ +#define PLATFORM_LINUX +#define PLATFORM_POSIX +#include +#include +#define PLATFORM_MAX_PATH PATH_MAX +#define PLATFORM_LIB_EXT "so" +#define PLATFORM_SEP_CHAR '/' +#define PLATFORM_SEP_ALTCHAR '\\' +#define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) +#endif + +#endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ diff --git a/public/sourcepawn/sp_file_headers.h b/public/sourcepawn/sp_file_headers.h new file mode 100644 index 00000000..d3f41e7e --- /dev/null +++ b/public/sourcepawn/sp_file_headers.h @@ -0,0 +1,163 @@ +#ifndef _INCLUDE_SPFILE_HEADERS_H +#define _INCLUDE_SPFILE_HEADERS_H + +#include +#if defined __GNUC__ || defined HAVE_STDINT_ +#include +#else + #if !defined HAVE_STDINT_H + typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; + typedef unsigned __int16 uint16_t; + typedef __int16 int16_t; + typedef unsigned __int8 uint8_t; + typedef __int8 int8_t; + #define HAVE_STDINT_H + #endif +#endif + +#define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */ +//#define SPFILE_VERSION 0x0100 +#define SPFILE_VERSION 0x0101 /* Uncompressed bytecode */ + +//:TODO: better compiler/nix support +#if defined __linux__ + #pragma pack(1) /* structures must be packed (byte-aligned) */ +#else + #pragma pack(push) + #pragma pack(1) /* structures must be packed (byte-aligned) */ +#endif + +#define SPFILE_COMPRESSION_NONE 0 +#define SPFILE_COMPRESSION_GZ 1 + +typedef struct sp_file_section_s +{ + uint32_t nameoffs; /* rel offset into global string table */ + uint32_t dataoffs; + uint32_t size; +} sp_file_section_t; + +/** + * If compression is 0, then + * disksize may be 0 to mean that + * only the imagesize is needed. + */ +typedef struct sp_file_hdr_s +{ + uint32_t magic; /* magic number */ + uint16_t version; /* version code */ + uint8_t compression;/* compression algorithm */ + uint32_t disksize; /* size on disk */ + uint32_t imagesize; /* size in memory */ + uint8_t sections; /* number of sections */ + uint32_t stringtab; /* offset to string table */ + uint32_t dataoffs; /* offset to file proper (any compression starts here) */ +} sp_file_hdr_t; + +#define SP_FLAG_DEBUG (1<<0) + +/* section is ".code" */ +typedef struct sp_file_code_s +{ + uint32_t codesize; /* codesize in bytes */ + uint8_t cellsize; /* cellsize in bytes */ + uint8_t codeversion; /* version of opcodes supported */ + uint16_t flags; /* flags */ + uint32_t main; /* address to "main" if any */ + uint32_t code; /* rel offset to code */ +} sp_file_code_t; + +/* section is .data */ +typedef struct sp_file_data_s +{ + uint32_t datasize; /* size of data section in memory */ + uint32_t memsize; /* total mem required (includes data) */ + uint32_t data; /* file offset to data (helper) */ +} sp_file_data_t; + +/* section is .publics */ +typedef struct sp_file_publics_s +{ + uint32_t address; /* address rel to code section */ + uint32_t name; /* index into nametable */ +} sp_file_publics_t; + +/* section is .natives */ +typedef struct sp_file_natives_s +{ + uint32_t name; /* name of native at index */ +} sp_file_natives_t; + +/* section is .libraries */ +typedef struct sp_file_libraries_s +{ + uint32_t name; /* index into nametable */ +} sp_file_libraries_t; + +/* section is .pubvars */ +typedef struct sp_file_pubvars_s +{ + uint32_t address; /* address rel to dat section */ + uint32_t name; /* index into nametable */ +} sp_file_pubvars_t; + +#if defined __linux__ + #pragma pack() /* reset default packing */ +#else + #pragma pack(pop) /* reset previous packing */ +#endif + +typedef struct sp_fdbg_info_s +{ + uint32_t num_files; /* number of files */ + uint32_t num_lines; /* number of lines */ + uint32_t num_syms; /* number of symbols */ + uint32_t num_arrays; /* number of symbols which are arrays */ +} sp_fdbg_info_t; + +/** + * Debug information structures + */ +typedef struct sp_fdbg_file_s +{ + uint32_t addr; /* address into code */ + uint32_t name; /* offset into debug nametable */ +} sp_fdbg_file_t; + +typedef struct sp_fdbg_line_s +{ + uint32_t addr; /* address into code */ + uint32_t line; /* line number */ +} sp_fdbg_line_t; + +#define SP_SYM_VARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */ +#define SP_SYM_REFERENCE 2 /* VARIABLE, but must be dereferenced */ +#define SP_SYM_ARRAY 3 +#define SP_SYM_REFARRAY 4 /* an array passed by reference (i.e. a pointer) */ +#define SP_SYM_FUNCTION 9 + +typedef struct sp_fdbg_symbol_s +{ + int32_t addr; /* address rel to DAT or stack frame */ + int16_t tagid; /* tag id */ + uint32_t codestart; /* start scope validity in code */ + uint32_t codeend; /* end scope validity in code */ + uint8_t ident; /* variable type */ + uint8_t vclass; /* scope class (local vs global) */ + uint16_t dimcount; /* dimension count (for arrays) */ + uint32_t name; /* offset into debug nametable */ +} sp_fdbg_symbol_t; + +typedef struct sp_fdbg_arraydim_s +{ + int16_t tagid; /* tag id */ + uint32_t size; /* size of dimension */ +} sp_fdbg_arraydim_t; + +/* section is .names */ +typedef char * sp_file_nametab_t; + +#endif //_INCLUDE_SPFILE_HEADERS_H diff --git a/public/sourcepawn/sp_typeutil.h b/public/sourcepawn/sp_typeutil.h new file mode 100644 index 00000000..921f9f74 --- /dev/null +++ b/public/sourcepawn/sp_typeutil.h @@ -0,0 +1,15 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ +#define _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ + +#include "sp_vm_types.h" + +inline cell_t sp_ftoc(float val) +{ + return *(cell_t *)&val; +} +inline float sp_ctof(cell_t val) +{ + return *(float *)&val; +} + +#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_ \ No newline at end of file diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h new file mode 100644 index 00000000..cb904105 --- /dev/null +++ b/public/sourcepawn/sp_vm_api.h @@ -0,0 +1,631 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_API_H_ +#define _INCLUDE_SOURCEPAWN_VM_API_H_ + +#include +#include "sp_vm_types.h" + +#define SOURCEPAWN_VM_API_VERSION 1 + +#if defined SOURCEMOD_BUILD +namespace SourceMod +{ + struct IdentityToken_t; +}; +#endif + +namespace SourcePawn +{ + class IVirtualMachine; + + /** + * @brief Interface to managing a debug context at runtime. + */ + class IPluginDebugInfo + { + public: + /** + * @brief Given a code pointer, finds the file it is associated with. + * + * @param addr Code address offset. + * @param filename Pointer to store filename pointer in. + */ + virtual int LookupFile(ucell_t addr, const char **filename) =0; + + /** + * @brief Given a code pointer, finds the function it is associated with. + * + * @param addr Code address offset. + * @param name Pointer to store function name pointer in. + */ + virtual int LookupFunction(ucell_t addr, const char **name) =0; + + /** + * @brief Given a code pointer, finds the line it is associated with. + * + * @param addr Code address offset. + * @param line Pointer to store line number in. + */ + virtual int LookupLine(ucell_t addr, uint32_t *line) =0; + }; + + /** + * @brief Interface to managing a context at runtime. + */ + class IPluginContext + { + public: + virtual ~IPluginContext() { }; + public: + /** + * @brief Returns the parent IVirtualMachine. + * + * @return Parent virtual machine pointer. + */ + virtual IVirtualMachine *GetVirtualMachine() =0; + + /** + * @brief Returns the child sp_context_t structure. + * + * @return Child sp_context_t structure. + */ + virtual sp_context_t *GetContext() =0; + + /** + * @brief Returns true if the plugin is in debug mode. + * + * @return True if in debug mode, false otherwise. + */ + virtual bool IsDebugging() =0; + + /** + * @brief Installs a debug break and returns the old one, if any. + * This will fail if the plugin is not debugging. + * + * @param newpfn New function pointer. + * @param oldpfn Pointer to retrieve old function pointer. + */ + virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0; + + /** + * @brief Returns debug info. + * + * @return IPluginDebugInfo, or NULL if no debug info found. + */ + virtual IPluginDebugInfo *GetDebugInfo() =0; + + /** + * @brief Allocs memory on the secondary stack of a plugin. + * Note that although called a heap, it is in fact a stack. + * + * @param cells Number of cells to allocate. + * @param local_addr Will be filled with data offset to heap. + * @param phys_addr Physical address to heap memory. + */ + virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * @brief Pops a heap address off the heap stack. Use this to free memory allocated with + * SP_HeapAlloc(). + * Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations + * with this native should be performed in precisely the REVERSE order. + * + * @param local_addr Local address to free. + */ + virtual int HeapPop(cell_t local_addr) =0; + + /** + * @brief Releases a heap address using a different method than SP_HeapPop(). + * This allows you to release in any order. However, if you allocate N + * objects, release only some of them, then begin allocating again, + * you cannot go back and starting freeing the originals. + * In other words, for each chain of allocations, if you start deallocating, + * then allocating more in a chain, you must only deallocate from the current + * allocation chain. This is basically HeapPop() except on a larger scale. + * + * @param local_addr Local address to free. + */ + virtual int HeapRelease(cell_t local_addr) =0; + + /** + * @brief Finds a native by name. + * + * @param name Name of native. + * @param index Optionally filled with native index number. + */ + virtual int FindNativeByName(const char *name, uint32_t *index) =0; + + /** + * @brief Gets native info by index. + * + * @param index Index number of native. + * @param native Optionally filled with pointer to native structure. + */ + virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0; + + /** + * @brief Gets the number of natives. + * + * @return Filled with the number of natives. + */ + virtual uint32_t GetNativesNum() =0; + + /** + * @brief Finds a public function by name. + * + * @param name Name of public + * @param index Optionally filled with public index number. + */ + virtual int FindPublicByName(const char *name, uint32_t *index) =0; + + /** + * @brief Gets public function info by index. + * + * @param index Public function index number. + * @param publicptr Optionally filled with pointer to public structure. + */ + virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0; + + /** + * @brief Gets the number of public functions. + * + * @return Filled with the number of public functions. + */ + virtual uint32_t GetPublicsNum() =0; + + /** + * @brief Gets public variable info by index. + * + * @param index Public variable index number. + * @param pubvar Optionally filled with pointer to pubvar structure. + */ + virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0; + + /** + * @brief Finds a public variable by name. + * + * @param name Name of pubvar + * @param index Optionally filled with pubvar index number. + */ + virtual int FindPubvarByName(const char *name, uint32_t *index) =0; + + /** + * @brief Gets the addresses of a public variable. + * + * @param index Index of public variable. + * @param local_addr Address to store local address in. + * @param phys_addr Address to store physically relocated in. + */ + virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0; + + /** + * @brief Returns the number of public variables. + * + * @return Number of public variables. + */ + virtual uint32_t GetPubVarsNum() =0; + + /** + * @brief Round-about method of converting a plugin reference to a physical address + * + * @param local_addr Local address in plugin. + * @param phys_addr Optionally filled with relocated physical address. + */ + virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0; + + /** + * @brief Converts a local address to a physical string. + * + * @param local_addr Local address in plugin. + * @param addr Destination output pointer. + */ + virtual int LocalToString(cell_t local_addr, char **addr) =0; + + /** + * @brief Converts a physical string to a local address. + * + * @param local_addr Local address in plugin. + * @param bytes Number of chars to write, including NULL terminator. + * @param source Source string to copy. + */ + virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0; + + /** + * @brief Converts a physical UTF-8 string to a local address. + * This function is the same as the ANSI version, except it will copy the maximum number of characters possible + * without accidentally chopping a multi-byte character. + * + * @param local_addr Local address in plugin. + * @param maxbytes Number of bytes to write, including NULL terminator. + * @param source Source string to copy. + * @param wrtnbytes Optionally set to the number of actual bytes written. + */ + virtual int StringToLocalUTF8(cell_t local_addr, + size_t maxbytes, + const char *source, + size_t *wrtnbytes) =0; + + /** + * @brief Pushes a cell onto the stack. Increases the parameter count by one. + * + * @param value Cell value. + */ + virtual int PushCell(cell_t value) =0; + + /** + * @brief Pushes an array of cells onto the stack. Increases the parameter count by one. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param array Cell array to copy. + * @param numcells Number of cells in the array to copy. + */ + virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; + + /** + * @brief Pushes a string onto the stack (by reference) and increases the parameter count by one. + * Note that this does not release the heap, so you should release it after + * calling Execute(). + * + * @param local_addr Filled with local address to release. + * @param phys_addr Optionally filled with physical address of new array. + * @param string Source string to push. + */ + virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; + + /** + * @brief Individually pushes each cell of an array of cells onto the stack. Increases the + * parameter count by the number of cells pushed. + * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * + * @param array Array of cells to read from. + * @param numcells Number of cells to read. + */ + virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; + + /** + * @brief Binds a list of native names and their function pointers to a context. + * If num is 0, the list is read until an entry with a NULL name is reached. + * If overwrite is non-zero, already registered natives will be overwritten. + * + * @param natives Array of natives. + * @param num Number of natives in array. + * @param overwrite Toggles overwrite. + */ + virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; + + /** + * @brief Binds a single native. Overwrites any existing bind. + * If the context does not contain the native that will be binded the function will return + * with a SP_ERROR_NOT_FOUND error. + * + * @param native Pointer to native. + */ + virtual int BindNative(const sp_nativeinfo_t *native) =0; + + /** + * @brief Binds a single native to any non-registered native. + * + * @param native Native to bind. + */ + virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; + + /** + * @brief Executes a function ID located in this context. + * + * @param funcid Function id to execute. + * @param result Pointer to store the return value (required). + * @return Error code (if any) from the VM. + */ + virtual int Execute(uint32_t funcid, cell_t *result) =0; + + + /** + * @brief Throws a error and halts any current execution. + * + * @param error The error number to set. + * @param msg Custom error message format. NULL to use default. + * @param ... Message format arguments, if any. + */ + virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0; + + /** + * @brief Throws a generic native error and halts any current execution. + * + * @param msg Custom error message format. NULL to set no message. + * @param ... Message format arguments, if any. + * @return 0 for convenience. + */ + virtual cell_t ThrowNativeError(const char *msg, ...) =0; + +#if defined SOURCEMOD_BUILD + /** + * @brief Returns the identity token for this context. + * Note: This is a helper function for native calls and the Handle System. + * + * @return Identity token. + */ + virtual SourceMod::IdentityToken_t *GetIdentity() =0; +#endif + }; + + + /** + * @brief Information about a position in a call stack. + */ + struct CallStackInfo + { + const char *filename; /* NULL if not found */ + unsigned int line; /* 0 if not found */ + const char *function; /* NULL if not found */ + }; + + /** + * @brief Retrieves error information from a debug hook. + */ + class IContextTrace + { + public: + /** + * @brief Returns the integer error code. + * + * @return Integer error code. + */ + virtual int GetErrorCode() =0; + + /** + * @brief Returns a string describing the error. + * + * @return Error string. + */ + virtual const char *GetErrorString() =0; + + /** + * @brief Returns whether debug info is available. + * + * @return True if debug info is available, false otherwise. + */ + virtual bool DebugInfoAvailable() =0; + + /** + * @brief Returns a custom error message. + * + * @return A pointer to a custom error message, or NULL otherwise. + */ + virtual const char *GetCustomErrorString() =0; + + /** + * @brief Returns trace info for a specific point in the backtrace, if any. + * The next subsequent call to GetTraceInfo() will return the next item in the call stack. + * Calls are retrieved in descending order (i.e. the first item is at the top of the stack/call sequence). + * + * @param trace An ErrorTraceInfo buffer to store information (NULL to ignore). + * @return True if successful, false if there are no more traces. + */ + virtual bool GetTraceInfo(CallStackInfo *trace) =0; + + /** + * @brief Resets the trace to its original position (the call on the top of the stack). + */ + virtual void ResetTrace() =0; + + /** + * @brief Retrieves the name of the last native called. + * Returns NULL if there was no native that caused the error. + * + * @param index Optional pointer to store index. + * @return Native name, or NULL if none. + */ + virtual const char *GetLastNative(uint32_t *index) =0; + }; + + + /** + * @brief Provides callbacks for debug information. + */ + class IDebugListener + { + public: + virtual void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) =0; + }; + + + /** + * @brief Contains helper functions used by VMs and the host app + */ + class ISourcePawnEngine + { + public: + /** + * @brief Loads a named file from a file pointer. + * Note: Using this means the memory will be allocated by the VM. + * + * @param fp File pointer. May be at any offset. Not closed on return. + * @param err Optional error code pointer. + * @return A new plugin structure. + */ + virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0; + + /** + * @brief Loads a file from a base memory address. + * + * @param base Base address of the plugin's memory region. + * @param plugin If NULL, a new plugin pointer is returned. + * Otherwise, the passed pointer is used. + * @param err Optional error code pointer. + * @return The resulting plugin pointer. + */ + virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0; + + /** + * Frees all of the memory associated with a plugin file. + * If allocated using SP_LoadFromMemory, the base and plugin pointer + * itself are not freed (so this may end up doing nothing). + */ + virtual int FreeFromMemory(sp_plugin_t *plugin) =0; + + /** + * @brief Allocates large blocks of temporary memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *BaseAlloc(size_t size) =0; + + /** + * @brief Frees memory allocated with BaseAlloc. + * + * @param memory Memory address to free. + */ + virtual void BaseFree(void *memory) =0; + + /** + * @brief Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *ExecAlloc(size_t size) =0; + + /** + * @brief Frees executable memory. + * + * @param address Address to free. + */ + virtual void ExecFree(void *address) =0; + + /** + * @brief Sets the debug listener. This should only be called once. + * If called successively (using manual chaining), only the last function should + * attempt to call back into the same plugin. Otherwise, globally cached states + * can be accidentally overwritten. + * + * @param listener Pointer to an IDebugListener. + * @return Old IDebugListener, or NULL if none. + */ + virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0; + + /** + * @brief Returns the number of plugins on the call stack. + * + * @return Number of contexts in the call stack. + */ + virtual unsigned int GetContextCallCount() =0; + }; + + + /** + * @brief Dummy class for encapsulating private compilation data. + */ + class ICompilation + { + public: + virtual ~ICompilation() { }; + }; + + + /** + * @brief Outlines the interface a Virtual Machine (JIT) must expose + */ + class IVirtualMachine + { + public: + /** + * @brief Returns the current API version. + */ + virtual unsigned int GetAPIVersion() =0; + + /** + * @brief Returns the string name of a VM implementation. + */ + virtual const char *GetVMName() =0; + + /** + * @brief Begins a new compilation + * + * @param plugin Pointer to a plugin structure. + * @return New compilation pointer. + */ + virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0; + + /** + * @brief Sets a compilation option. + * + * @param co Pointer to a compilation. + * @param key Option key name. + * @param val Option value string. + * @return True if option could be set, false otherwise. + */ + virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; + + /** + * @brief Finalizes a compilation into a new sp_context_t. + * Note: This will free the ICompilation pointer. + * + * @param co Compilation pointer. + * @param err Filled with error code on exit. + * @return New plugin context. + */ + virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0; + + /** + * @brief Aborts a compilation and frees the ICompilation pointer. + * + * @param co Compilation pointer. + */ + virtual void AbortCompilation(ICompilation *co) =0; + + /** + * @brief Frees any internal variable usage on a context. + * + * @param ctx Context structure pointer. + */ + virtual void FreeContext(sp_context_t *ctx) =0; + + /** + * @brief Calls the "execute" function on a context. + * + * @param ctx Executes a function in a context. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. + * @return Error code (if any). + */ + virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0; + + /** + * @brief Given a context and a code address, returns the index of the function. + * + * @param ctx Context to search. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. + * @return True if code index is valid, false otherwise. + */ + virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; + + /** + * @brief Returns the number of functions defined in the context. + * + * @param ctx Context to search. + * @return Number of functions. + */ + virtual unsigned int FunctionCount(const sp_context_t *ctx) =0; + + /** + * @brief Returns a version string. + * + * @return Versioning string. + */ + virtual const char *GetVersionString() =0; + + /** + * @brief Returns a string describing optimizations. + * + * @return String describing CPU specific optimizations. + */ + virtual const char *GetCPUOptimizations() =0; + }; +}; + +#endif //_INCLUDE_SOURCEPAWN_VM_API_H_ diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h new file mode 100644 index 00000000..4fff0f4c --- /dev/null +++ b/public/sourcepawn/sp_vm_base.h @@ -0,0 +1,16 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_BASE_H_ +#define _INCLUDE_SOURCEPAWN_VM_BASE_H_ + +#include + +/* :TODO: rename this to sp_vm_linkage.h */ + +#if defined WIN32 +#define EXPORT_LINK extern "C" __declspec(dllexport) +#else if defined __GNUC__ +#define EXPORT_LINK extern "C" __attribute__((visibility("default"))) +#endif + +typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); + +#endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h new file mode 100644 index 00000000..2436144d --- /dev/null +++ b/public/sourcepawn/sp_vm_types.h @@ -0,0 +1,251 @@ +#ifndef _INCLUDE_SOURCEPAWN_VM_TYPES_H +#define _INCLUDE_SOURCEPAWN_VM_TYPES_H + +#include "sp_file_headers.h" + +typedef uint32_t ucell_t; +typedef int32_t cell_t; +typedef uint32_t funcid_t; + +#include "sp_typeutil.h" + +#define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */ + +/** + * Error codes + * NOTE: Be sure to update the error string table when changing these + */ +#define SP_ERROR_NONE 0 +#define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */ +#define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */ +#define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */ +#define SP_ERROR_PARAM 4 /* Invalid parameter or parameter type */ +#define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */ +#define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */ +#define SP_ERROR_INDEX 7 /* Invalid index parameter */ +#define SP_ERROR_STACKLOW 8 /* Nnot enough space left on the stack */ +#define SP_ERROR_NOTDEBUGGING 9 /* Debug mode was not on or debug section not found */ +#define SP_ERROR_INVALID_INSTRUCTION 10 /* Invalid instruction was encountered */ +#define SP_ERROR_MEMACCESS 11 /* Invalid memory access */ +#define SP_ERROR_STACKMIN 12 /* Stack went beyond its minimum value */ +#define SP_ERROR_HEAPMIN 13 /* Heap went beyond its minimum value */ +#define SP_ERROR_DIVIDE_BY_ZERO 14 /* Division by zero */ +#define SP_ERROR_ARRAY_BOUNDS 15 /* Array index is out of bounds */ +#define SP_ERROR_INSTRUCTION_PARAM 16 /* Instruction had an invalid parameter */ +#define SP_ERROR_STACKLEAK 17 /* A native leaked an item on the stack */ +#define SP_ERROR_HEAPLEAK 18 /* A native leaked an item on the heap */ +#define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */ +#define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ +#define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ +#define SP_ERROR_NATIVE 23 /* Error originates from a native */ + +/********************************************** + *** The following structures are reference structures. + *** They are not essential to the API, but are used + *** to hold the back end database format of the plugin + *** binary. + **********************************************/ + +/** + * Information about the core plugin tables. + * These may or may not be present! + */ +typedef struct sp_plugin_infotab_s +{ + const char *stringbase; /* base of string table */ + uint32_t publics_num; /* number of publics */ + sp_file_publics_t *publics; /* public table */ + uint32_t natives_num; /* number of natives */ + sp_file_natives_t *natives; /* native table */ + uint32_t pubvars_num; /* number of pubvars */ + sp_file_pubvars_t *pubvars; /* pubvars table */ + uint32_t libraries_num; /* number of libraries */ + sp_file_libraries_t *lib; /* library table */ +} sp_plugin_infotab_t; + +/** + * Information about the plugin's debug tables. + * These are all present if one is present. + */ +typedef struct sp_plugin_debug_s +{ + const char *stringbase; /* base of string table */ + uint32_t files_num; /* number of files */ + sp_fdbg_file_t *files; /* files table */ + uint32_t lines_num; /* number of lines */ + sp_fdbg_line_t *lines; /* lines table */ + uint32_t syms_num; /* number of symbols */ + sp_fdbg_symbol_t *symbols; /* symbol table */ +} sp_plugin_debug_t; + +#define SP_FA_SELF_EXTERNAL (1<<0) +#define SP_FA_BASE_EXTERNAL (1<<1) + +/** + * The rebased, in-memory format of a plugin. + * This differs from the on-disk structure to ensure + * that the format is properly read. + */ +typedef struct sp_plugin_s +{ + uint8_t *base; /* base of memory */ + uint8_t *pcode; /* p-code */ + uint32_t pcode_size; /* size of p-code */ + uint8_t *data; /* data size */ + uint32_t data_size; /* size of data */ + uint32_t memory; /* required memory */ + uint16_t flags; /* code flags */ + uint32_t allocflags; /* allocation flags */ + sp_plugin_infotab_t info; /* base info table */ + sp_plugin_debug_t debug; /* debug info table */ +} sp_plugin_t; + +/** Forward declarations */ + +namespace SourcePawn +{ + class IPluginContext; + class IVirtualMachine; +}; + +struct sp_context_s; + +typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *); + +/********************************************** + *** The following structures are bound to the VM/JIT. + *** Changing them will result in necessary recompilation. + **********************************************/ + +/** + * Offsets and names to a public function. + * By default, these point back to the string table + * in the sp_plugin_infotab_t structure. + */ +typedef struct sp_public_s +{ + funcid_t funcid; /* encoded function id */ + uint32_t code_offs; /* code offset */ + const char *name; /* name */ +} sp_public_t; + +/** + * Offsets and names to public variables. + * The offset is relocated and the name by default + * points back to the sp_plugin_infotab_t structure. + */ +typedef struct sp_pubvar_s +{ + cell_t *offs; /* pointer to data */ + const char *name; /* name */ +} sp_pubvar_t; + +#define SP_NATIVE_UNBOUND (0) /* Native is undefined */ +#define SP_NATIVE_BOUND (1) /* Native is bound */ + +/** + * Native lookup table, by default names + * point back to the sp_plugin_infotab_t structure. + * A native is NULL if unit + */ +typedef struct sp_native_s +{ + SPVM_NATIVE_FUNC pfn; /* function pointer */ + const char * name; /* name of function */ + uint32_t status; /* status flags */ +} sp_native_t; + +/** + * Used for setting natives from modules/host apps. + */ +typedef struct sp_nativeinfo_s +{ + const char *name; + SPVM_NATIVE_FUNC func; +} sp_nativeinfo_t; + +/** + * Debug file table + */ +typedef struct sp_debug_file_s +{ + uint32_t addr; /* address into code */ + const char * name; /* name of file */ +} sp_debug_file_t; + +/** + * Note that line is missing. It is not necessary since + * this can be retrieved from the base plugin info. + */ +typedef struct sp_debug_line_s +{ + uint32_t addr; /* address into code */ + uint32_t line; /* line no. */ +} sp_debug_line_t; + +typedef sp_fdbg_arraydim_t sp_debug_arraydim_t; + +/** + * The majority of this struct is already located in the parent + * block. Thus, only the relocated portions are required. + */ +typedef struct sp_debug_symbol_s +{ + uint32_t codestart; /* relocated code address */ + uint32_t codeend; /* relocated code end address */ + const char * name; /* relocated name */ + sp_debug_arraydim_t *dims; /* relocated dimension struct, if any */ + sp_fdbg_symbol_t *sym; /* pointer to original symbol */ +} sp_debug_symbol_t; + +/** + * Breaks into a debugger + * Params: + * [0] - plugin context + * [1] - frm + * [2] - cip + */ +typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t); + +#define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */ + +/** + * This is the heart of the VM. It contains all of the runtime + * information about a plugin context. + * Note that user[0..3] can be used for any user based pointers. + * vm[0..3] should not be touched, as it is reserved for the VM. + */ +typedef struct sp_context_s +{ + /* general/parent information */ + void *codebase; /* base of generated code and memory */ + sp_plugin_t *plugin; /* pointer back to parent information */ + SourcePawn::IPluginContext *context; /* pointer to IPluginContext */ + SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */ + void *user[4]; /* user specific pointers */ + void *vm[4]; /* VM specific pointers */ + uint32_t flags; /* compilation flags */ + SPVM_DEBUGBREAK dbreak; /* debug break function */ + /* context runtime information */ + uint8_t *memory; /* data chunk */ + ucell_t mem_size; /* total memory size; */ + cell_t data_size; /* data chunk size, always starts at 0 */ + cell_t heap_base; /* where the heap starts */ + /* execution specific data */ + cell_t hp; /* heap pointer */ + cell_t sp; /* stack pointer */ + cell_t frm; /* frame pointer */ + uint32_t pushcount; /* push count */ + int32_t n_err; /* error code set by a native */ + uint32_t n_idx; /* current native index being executed */ + /* context rebased database */ + sp_public_t *publics; /* public functions table */ + sp_pubvar_t *pubvars; /* public variables table */ + sp_native_t *natives; /* natives table */ + sp_debug_file_t *files; /* files */ + sp_debug_line_t *lines; /* lines */ + sp_debug_symbol_t *symbols; /* symbols */ +} sp_context_t; + +#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H