1.1 --- a/sourcepawn/include/sp_vm_api.h Sun Dec 31 03:02:40 2006 +0000
1.2 +++ b/sourcepawn/include/sp_vm_api.h Sun Dec 31 22:33:47 2006 +0000
1.3 @@ -314,6 +314,67 @@
1.4 virtual int Execute(uint32_t funcid, cell_t *result) =0;
1.5 };
1.6
1.7 + struct ErrorTraceInfo
1.8 + {
1.9 + const char *filename;
1.10 + unsigned int line;
1.11 + const char *function;
1.12 + };
1.13 +
1.14 + class IContextErrorInfo
1.15 + {
1.16 + /**
1.17 + * @brief Returns the integer error code.
1.18 + *
1.19 + * @return Integer error code.
1.20 + */
1.21 + virtual int GetErrorCode() =0;
1.22 +
1.23 + /**
1.24 + * @brief Returns a string describing the error.
1.25 + *
1.26 + * @return Error string.
1.27 + */
1.28 + virtual const char *GetErrorString() =0;
1.29 +
1.30 + /**
1.31 + * @brief Returns whether debug info is available.
1.32 + *
1.33 + * @return True if debug info is available, false otherwise.
1.34 + */
1.35 + virtual bool DebugInfoAvailable() =0;
1.36 +
1.37 + /**
1.38 + * @brief Returns a custom error message.
1.39 + *
1.40 + * @return A pointer to a custom error message, or NULL otherwise.
1.41 + */
1.42 + virtual const char *GetCustomErrorString() =0;
1.43 +
1.44 + /**
1.45 + * @brief Returns the number of calls in the call backtrace.
1.46 + * NOTE: Tracers are ordered from 0 to N-1, where 0 is the top of the trace.
1.47 + *
1.48 + * @return Number of calls in the trace.
1.49 + */
1.50 + virtual unsigned int TraceCallCount() =0;
1.51 +
1.52 + /**
1.53 + * @brief Returns trace info for a specific point in the backtrace.
1.54 + *
1.55 + * @param call The call trace index (from 0 to N-1).
1.56 + * @param trace An ErrorTraceInfo buffer to store information.
1.57 + * @return True if successful, false otherwise.
1.58 + */
1.59 + virtual bool GetTraceInfo(unsigned int call, ErrorTraceInfo *trace) =0;
1.60 + };
1.61 +
1.62 + class IDebugListener
1.63 + {
1.64 + public:
1.65 + virtual void OnContextExecuteError(IPluginContext *ctx, IContextErrorInfo *error) =0;
1.66 + };
1.67 +
1.68 /**
1.69 * @brief Contains helper functions used by VMs and the host app
1.70 */
1.71 @@ -321,17 +382,17 @@
1.72 {
1.73 public:
1.74 /**
1.75 - * Loads a named file from a file pointer.
1.76 - * Using this means base memory will be allocated by the VM.
1.77 - *
1.78 - * @param fp File pointer. May be at any offset. Not closed on return.
1.79 - * @param err Optional error code pointer.
1.80 - * @return A new plugin structure.
1.81 - */
1.82 + * @brief Loads a named file from a file pointer.
1.83 + * Note: Using this means the memory will be allocated by the VM.
1.84 + *
1.85 + * @param fp File pointer. May be at any offset. Not closed on return.
1.86 + * @param err Optional error code pointer.
1.87 + * @return A new plugin structure.
1.88 + */
1.89 virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0;
1.90
1.91 /**
1.92 - * Loads a file from a base memory address.
1.93 + * @brief Loads a file from a base memory address.
1.94 *
1.95 * @param base Base address of the plugin's memory region.
1.96 * @param plugin If NULL, a new plugin pointer is returned.
1.97 @@ -349,7 +410,7 @@
1.98 virtual int FreeFromMemory(sp_plugin_t *plugin) =0;
1.99
1.100 /**
1.101 - * Creates a new IContext from a context handle.
1.102 + * @brief Creates a new IContext from a context handle.
1.103 *
1.104 * @param ctx Context to use as a basis for the IPluginContext.
1.105 * @return New IPluginContext handle.
1.106 @@ -357,14 +418,14 @@
1.107 virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0;
1.108
1.109 /**
1.110 - * Frees a base context. Does not free the sp_context_t it holds.
1.111 + * @brief Frees a base context. Does not free the sp_context_t it holds.
1.112 *
1.113 * @param ctx Context pointer to free.
1.114 */
1.115 virtual void FreeBaseContext(IPluginContext *ctx) =0;
1.116
1.117 /**
1.118 - * Allocates large blocks of temporary memory.
1.119 + * @brief Allocates large blocks of temporary memory.
1.120 *
1.121 * @param size Size of memory to allocate.
1.122 * @return Pointer to memory, NULL if allocation failed.
1.123 @@ -372,14 +433,14 @@
1.124 virtual void *BaseAlloc(size_t size) =0;
1.125
1.126 /**
1.127 - * Frees memory allocated with BaseAlloc.
1.128 + * @brief Frees memory allocated with BaseAlloc.
1.129 *
1.130 * @param memory Memory address to free.
1.131 */
1.132 virtual void BaseFree(void *memory) =0;
1.133
1.134 /**
1.135 - * Allocates executable memory.
1.136 + * @brief Allocates executable memory.
1.137 *
1.138 * @param size Size of memory to allocate.
1.139 * @return Pointer to memory, NULL if allocation failed.
1.140 @@ -387,13 +448,50 @@
1.141 virtual void *ExecAlloc(size_t size) =0;
1.142
1.143 /**
1.144 - * Frees executable memory.
1.145 + * @brief Frees executable memory.
1.146 *
1.147 * @param address Address to free.
1.148 */
1.149 virtual void ExecFree(void *address) =0;
1.150 +
1.151 + /**
1.152 + * @brief Sets the debug listener.
1.153 + *
1.154 + * @param listener Pointer to an IDebugListener.
1.155 + * @return Old IDebugListener, or NULL if none.
1.156 + */
1.157 + virtual IDebugListener *SetDebugListener(IDebugListener *pListener) =0;
1.158 +
1.159 + /**
1.160 + * @brief Returns the number of plugins on the call stack.
1.161 + *
1.162 + * @return Number of contexts in the call stack.
1.163 + */
1.164 + virtual unsigned int GetContextCallCount() =0;
1.165 +
1.166 + /**
1.167 + * @brief Throws an error and halts any current execution.
1.168 + *
1.169 + * @param error The error number to set.
1.170 + * @param msg Custom error message format. NULL to use default.
1.171 + * @param ... Message format arguments, if any.
1.172 + */
1.173 + virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0;
1.174 +
1.175 + /**
1.176 + * @brief Throws a native error and halts any current execution.
1.177 + * NOTE: This is a wrapper around ThrowError() for convenience.
1.178 + *
1.179 + * @param msg Custom error message format. NULL to set no message.
1.180 + * @param ... Message format arguments, if any.
1.181 + * @return 0 for convenience.
1.182 + */
1.183 + virtual void ThrowNativeError(const char *msg, ...) =0;
1.184 };
1.185
1.186 + /**
1.187 + * @brief Dummy class for encapsulating private compilation data.
1.188 + */
1.189 class ICompilation
1.190 {
1.191 public:
2.1 --- a/sourcepawn/include/sp_vm_base.h Sun Dec 31 03:02:40 2006 +0000
2.2 +++ b/sourcepawn/include/sp_vm_base.h Sun Dec 31 22:33:47 2006 +0000
2.3 @@ -3,6 +3,8 @@
2.4
2.5 #include <sp_vm_api.h>
2.6
2.7 +/* :TODO: rename this to sp_vm_linkage.h */
2.8 +
2.9 #if defined WIN32
2.10 #define EXPORT_LINK extern "C" __declspec(dllexport)
2.11 #else if defined __GNUC__
3.1 --- a/sourcepawn/include/sp_vm_types.h Sun Dec 31 03:02:40 2006 +0000
3.2 +++ b/sourcepawn/include/sp_vm_types.h Sun Dec 31 22:33:47 2006 +0000
3.3 @@ -37,6 +37,7 @@
3.4 #define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */
3.5 #define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */
3.6 #define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */
3.7 +#define SP_ERROR_NATIVE 23 /* Error originates from a native */
3.8
3.9 /**********************************************
3.10 *** The following structures are reference structures.
3.11 @@ -204,7 +205,7 @@
3.12 * [1] - frm
3.13 * [2] - cip
3.14 */
3.15 -typedef int (*SPVM_DEBUGBREAK)(SourcePawn::IPluginContext *, uint32_t, uint32_t);
3.16 +typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t);
3.17
3.18 #define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */
3.19
3.20 @@ -234,8 +235,9 @@
3.21 cell_t hp; /* heap pointer */
3.22 cell_t sp; /* stack pointer */
3.23 cell_t frm; /* frame pointer */
3.24 - int32_t err; /* error code */
3.25 uint32_t pushcount; /* push count */
3.26 + int32_t n_err; /* error code set by a native */
3.27 + uint32_t n_idx; /* current native index being executed */
3.28 /* context rebased database */
3.29 sp_public_t *publics; /* public functions table */
3.30 sp_pubvar_t *pubvars; /* public variables table */
4.1 --- a/sourcepawn/jit/x86/jit_x86.cpp Sun Dec 31 03:02:40 2006 +0000
4.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp Sun Dec 31 22:33:47 2006 +0000
4.3 @@ -1631,7 +1631,7 @@
4.4 //cmp [ecx+err], 0
4.5 //jnz :error
4.6 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
4.7 - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0);
4.8 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
4.9 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
4.10
4.11 /* restore what we damaged */
4.12 @@ -1678,12 +1678,14 @@
4.13 IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker);
4.14
4.15 /* Check for errors */
4.16 - //pop eax
4.17 - //cmp [eax+err], 0
4.18 + //cmp eax, 0
4.19 //jnz :error
4.20 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0);
4.21 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
4.22 +
4.23 + /* Restore */
4.24 + //pop eax
4.25 IA32_Pop_Reg(jit, REG_EAX);
4.26 - IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
4.27 - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
4.28
4.29 /* Push the value into the stack and increment pCur */
4.30 //mov edx, [eax+vm[]]
4.31 @@ -1722,12 +1724,14 @@
4.32 IA32_Write_Jump32_Abs(jit, call, JIT_VerifyLowBoundTracker);
4.33
4.34 /* Check for errors */
4.35 - //pop eax
4.36 - //cmp [eax+err], 0
4.37 + //cmp eax, 0
4.38 //jnz :error
4.39 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0);
4.40 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
4.41 +
4.42 + /* Restore */
4.43 + //pop eax
4.44 IA32_Pop_Reg(jit, REG_EAX);
4.45 - IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
4.46 - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
4.47
4.48 /* Pop the value from the stack and decrease the heap by it*/
4.49 //mov edx, [eax+vm[]]
4.50 @@ -1768,11 +1772,13 @@
4.51 cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
4.52 {
4.53 sp_native_t *native = &ctx->natives[native_idx];
4.54 +
4.55 + ctx->n_idx = native_idx;
4.56
4.57 /* Technically both aren't needed, I guess */
4.58 if (native->status == SP_NATIVE_UNBOUND)
4.59 {
4.60 - ctx->err = SP_ERROR_INVALID_NATIVE;
4.61 + ctx->n_err = SP_ERROR_INVALID_NATIVE;
4.62 return 0;
4.63 }
4.64
4.65 @@ -1782,7 +1788,7 @@
4.66 static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
4.67 {
4.68 sp_context_t *ctx = pCtx->GetContext();
4.69 - ctx->err = SP_ERROR_INVALID_NATIVE;
4.70 + ctx->n_err = SP_ERROR_INVALID_NATIVE;
4.71
4.72 return 0;
4.73 }
4.74 @@ -1792,37 +1798,39 @@
4.75 cell_t save_sp = ctx->sp;
4.76 cell_t save_hp = ctx->hp;
4.77
4.78 + ctx->n_idx = native_idx;
4.79 +
4.80 if (ctx->hp < ctx->heap_base)
4.81 {
4.82 - ctx->err = SP_ERROR_HEAPMIN;
4.83 + ctx->n_err = SP_ERROR_HEAPMIN;
4.84 return 0;
4.85 }
4.86
4.87 if (ctx->hp + STACK_MARGIN > ctx->sp)
4.88 {
4.89 - ctx->err = SP_ERROR_STACKLOW;
4.90 + ctx->n_err = SP_ERROR_STACKLOW;
4.91 return 0;
4.92 }
4.93
4.94 if ((uint32_t)ctx->sp >= ctx->mem_size)
4.95 {
4.96 - ctx->err = SP_ERROR_STACKMIN;
4.97 + ctx->n_err = SP_ERROR_STACKMIN;
4.98 return 0;
4.99 }
4.100
4.101 cell_t result = NativeCallback(ctx, native_idx, params);
4.102
4.103 - if (ctx->err != SP_ERROR_NONE)
4.104 + if (ctx->n_err != SP_ERROR_NONE)
4.105 {
4.106 return result;
4.107 }
4.108
4.109 if (save_sp != ctx->sp)
4.110 {
4.111 - ctx->err = SP_ERROR_STACKLEAK;
4.112 + ctx->n_err = SP_ERROR_STACKLEAK;
4.113 return result;
4.114 } else if (save_hp != ctx->hp) {
4.115 - ctx->err = SP_ERROR_HEAPLEAK;
4.116 + ctx->n_err = SP_ERROR_HEAPLEAK;
4.117 return result;
4.118 }
4.119
5.1 --- a/sourcepawn/jit/x86/opcode_helpers.cpp Sun Dec 31 03:02:40 2006 +0000
5.2 +++ b/sourcepawn/jit/x86/opcode_helpers.cpp Sun Dec 31 22:33:47 2006 +0000
5.3 @@ -146,7 +146,7 @@
5.4 //add esp, 8
5.5 //popad
5.6 IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
5.7 - IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context));
5.8 + IA32_Push_Reg(jit, AMX_REG_TMP);
5.9 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
5.10 IA32_Call_Reg(jit, AMX_REG_TMP);
5.11 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
5.12 @@ -166,7 +166,7 @@
5.13 //mov eax, [eax+ctx.error]
5.14 //jmp [jit_return]
5.15 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
5.16 - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, err));
5.17 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
5.18 IA32_Jump_Imm32_Abs(jit, data->jit_return);
5.19 }
5.20
5.21 @@ -435,7 +435,7 @@
5.22 //cmp [ecx+err], 0
5.23 //jnz :error
5.24 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
5.25 - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0);
5.26 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
5.27 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
5.28
5.29 /* restore what we damaged */
5.30 @@ -662,7 +662,7 @@
5.31 //cmp [ecx+err], 0
5.32 //jnz :error
5.33 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
5.34 - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0);
5.35 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
5.36 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
5.37
5.38 /* restore what we damaged */
5.39 @@ -713,13 +713,15 @@
5.40 IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker);
5.41
5.42 /* Check for errors */
5.43 - //pop eax
5.44 - //cmp [eax+err], 0
5.45 + //cmp eax, 0
5.46 //jnz :error
5.47 - IA32_Pop_Reg(jit, REG_EAX);
5.48 - IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
5.49 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, 0);
5.50 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
5.51
5.52 + /* Restore */
5.53 + //pop eax
5.54 + IA32_Pop_Reg(jit, REG_EAX);
5.55 +
5.56 /* Push the register into the stack and increment pCur */
5.57 //mov edx, [eax+vm[]]
5.58 //mov eax, [edx+pcur]
5.59 @@ -742,14 +744,13 @@
5.60 IA32_Pop_Reg(jit, AMX_REG_PRI);
5.61 }
5.62
5.63 -void JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
5.64 +int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
5.65 {
5.66 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
5.67
5.68 if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
5.69 {
5.70 - ctx->err = SP_ERROR_TRACKER_BOUNDS;
5.71 - return;
5.72 + return SP_ERROR_TRACKER_BOUNDS;
5.73 }
5.74
5.75 if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
5.76 @@ -760,20 +761,23 @@
5.77
5.78 if (!trk->pBase)
5.79 {
5.80 - ctx->err = SP_ERROR_TRACKER_BOUNDS;
5.81 - return;
5.82 + return SP_ERROR_TRACKER_BOUNDS;
5.83 }
5.84
5.85 trk->pCur = trk->pBase + disp;
5.86 }
5.87 +
5.88 + return SP_ERROR_NONE;
5.89 }
5.90
5.91 -void JIT_VerifyLowBoundTracker(sp_context_t *ctx)
5.92 +int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
5.93 {
5.94 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
5.95
5.96 if (trk->pCur <= trk->pBase)
5.97 {
5.98 - ctx->err = SP_ERROR_TRACKER_BOUNDS;
5.99 + return SP_ERROR_TRACKER_BOUNDS;
5.100 }
5.101 -}
5.102 \ No newline at end of file
5.103 +
5.104 + return SP_ERROR_NONE;
5.105 +}
6.1 --- a/sourcepawn/jit/x86/opcode_helpers.h Sun Dec 31 03:02:40 2006 +0000
6.2 +++ b/sourcepawn/jit/x86/opcode_helpers.h Sun Dec 31 22:33:47 2006 +0000
6.3 @@ -69,8 +69,8 @@
6.4 /**
6.5 * Bound checking for the tracker stack,
6.6 */
6.7 -void JIT_VerifyLowBoundTracker(sp_context_t *ctx);
6.8 -void JIT_VerifyOrAllocateTracker(sp_context_t *ctx);
6.9 +int JIT_VerifyLowBoundTracker(sp_context_t *ctx);
6.10 +int JIT_VerifyOrAllocateTracker(sp_context_t *ctx);
6.11
6.12 /**
6.13 * Writes the push into tracker function.