initial import of new debugger API
authorDavid Anderson <dvander@alliedmods.net>
Mon Jan 01 01:09:53 2007 +0000 (2007-01-01)
changeset 2401360e8aa47d7
parent 239 cd48418120ba
child 241 5444b56b5ba6
initial import of new debugger API
core/interfaces/IHandleSys.h
core/msvc8/sourcemod_mm.vcproj
core/vm/sp_vm_basecontext.cpp
core/vm/sp_vm_basecontext.h
core/vm/sp_vm_engine.cpp
core/vm/sp_vm_engine.h
     1.1 --- a/core/interfaces/IHandleSys.h	Mon Jan 01 01:08:36 2007 +0000
     1.2 +++ b/core/interfaces/IHandleSys.h	Mon Jan 01 01:09:53 2007 +0000
     1.3 @@ -100,7 +100,7 @@
     1.4  		 *
     1.5  		 * @param name		Name of handle type (NULL or "" to be anonymous)
     1.6  		 * @param dispatch	Pointer to a valid IHandleTypeDispatch object.
     1.7 -		 * @return			A new HandleType_t unique ID.
     1.8 +		 * @return			A new HandleType_t unique ID, or 0 on failure.
     1.9  		 */
    1.10  		virtual HandleType_t CreateType(const char *name, 
    1.11  										IHandleTypeDispatch *dispatch) =0;
    1.12 @@ -116,7 +116,7 @@
    1.13  		 * @param security	Pointer to a temporary HandleSecurity object, NULL to use default 
    1.14  		 *					or inherited permissions.
    1.15  		 * @param ident		Security token for any permissions.
    1.16 -		 * @return			A new HandleType_t unique ID.
    1.17 +		 * @return			A new HandleType_t unique ID, or 0 on failure.
    1.18  		 */
    1.19  		virtual HandleType_t CreateTypeEx(const char *name,
    1.20  										  IHandleTypeDispatch *dispatch,
     2.1 --- a/core/msvc8/sourcemod_mm.vcproj	Mon Jan 01 01:08:36 2007 +0000
     2.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Mon Jan 01 01:09:53 2007 +0000
     2.3 @@ -488,10 +488,6 @@
     2.4  				Name="Header Files"
     2.5  				>
     2.6  				<File
     2.7 -					RelativePath="..\..\sourcepawn\include\sp_typeutil.h"
     2.8 -					>
     2.9 -				</File>
    2.10 -				<File
    2.11  					RelativePath="..\vm\sp_vm_basecontext.h"
    2.12  					>
    2.13  				</File>
    2.14 @@ -520,6 +516,10 @@
    2.15  					>
    2.16  				</File>
    2.17  				<File
    2.18 +					RelativePath="..\..\sourcepawn\include\sp_typeutil.h"
    2.19 +					>
    2.20 +				</File>
    2.21 +				<File
    2.22  					RelativePath="..\..\sourcepawn\include\sp_vm_api.h"
    2.23  					>
    2.24  				</File>
    2.25 @@ -531,10 +531,6 @@
    2.26  					RelativePath="..\..\sourcepawn\include\sp_vm_types.h"
    2.27  					>
    2.28  				</File>
    2.29 -				<File
    2.30 -					RelativePath="..\..\sourcepawn\include\sp_vm_typeutil.h"
    2.31 -					>
    2.32 -				</File>
    2.33  			</Filter>
    2.34  		</Filter>
    2.35  	</Files>
     3.1 --- a/core/vm/sp_vm_basecontext.cpp	Mon Jan 01 01:08:36 2007 +0000
     3.2 +++ b/core/vm/sp_vm_basecontext.cpp	Mon Jan 01 01:09:53 2007 +0000
     3.3 @@ -1,18 +1,32 @@
     3.4  #include <string.h>
     3.5 +#include <stdarg.h>
     3.6  #include <assert.h>
     3.7  #include <limits.h>
     3.8  #include "sp_vm_api.h"
     3.9  #include "sp_vm_basecontext.h"
    3.10 +#include "sp_vm_engine.h"
    3.11  
    3.12  using namespace SourcePawn;
    3.13  
    3.14 +extern SourcePawnEngine g_SourcePawn;
    3.15 +
    3.16  #define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
    3.17  #define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
    3.18  
    3.19 +int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
    3.20 +{
    3.21 +	g_SourcePawn.RunTracer(ctx, frm, cip);
    3.22 +
    3.23 +	return SP_ERROR_NONE;
    3.24 +}
    3.25 +
    3.26  BaseContext::BaseContext(sp_context_t *_ctx)
    3.27  {
    3.28  	ctx = _ctx;
    3.29  	ctx->context = this;
    3.30 +	ctx->dbreak = GlobalDebugBreak;
    3.31 +	m_InExec = false;
    3.32 +	m_CustomMsg = false;
    3.33  }
    3.34  
    3.35  IVirtualMachine *BaseContext::GetVirtualMachine()
    3.36 @@ -74,11 +88,26 @@
    3.37  	cell_t save_sp = ctx->sp;
    3.38  	cell_t save_hp = ctx->hp;
    3.39  
    3.40 +	bool wasExec = m_InExec;
    3.41 +
    3.42 +	/* Clear the error state, if any */
    3.43 +	ctx->n_err = SP_ERROR_NONE;
    3.44 +	ctx->n_idx = 0;
    3.45 +	m_InExec = true;
    3.46 +	m_MsgCache[0] = '\0';
    3.47 +	m_CustomMsg = false;
    3.48 +
    3.49 +	g_SourcePawn.PushTracer(ctx);
    3.50 +
    3.51  	err = vm->ContextExecute(ctx, code_addr, result);
    3.52 -	
    3.53 +
    3.54 +	m_InExec = wasExec;
    3.55 +
    3.56  	/**
    3.57 -	 * :TODO: turn this into an error check
    3.58 +	 * :TODO: Calling from a plugin in here will erase the cached message...
    3.59 +	 * Should that be documented?
    3.60  	 */
    3.61 +	g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
    3.62  
    3.63  #if defined _DEBUG
    3.64  	if (err == SP_ERROR_NONE)
    3.65 @@ -96,6 +125,51 @@
    3.66  	return err;
    3.67  }
    3.68  
    3.69 +void BaseContext::SetErrorMessage(const char *msg, va_list ap)
    3.70 +{
    3.71 +	m_CustomMsg = true;
    3.72 +
    3.73 +	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
    3.74 +}
    3.75 +
    3.76 +void BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
    3.77 +{
    3.78 +	if (!m_InExec)
    3.79 +	{
    3.80 +		return;
    3.81 +	}
    3.82 +
    3.83 +	ctx->n_err = error;
    3.84 +	
    3.85 +	if (msg)
    3.86 +	{
    3.87 +		va_list ap;
    3.88 +		va_start(ap, msg);
    3.89 +		SetErrorMessage(msg, ap);
    3.90 +		va_end(ap);
    3.91 +	}
    3.92 +}
    3.93 +
    3.94 +cell_t BaseContext::ThrowNativeError(const char *msg, ...)
    3.95 +{
    3.96 +	if (!m_InExec)
    3.97 +	{
    3.98 +		return 0;
    3.99 +	}
   3.100 +
   3.101 +	ctx->n_err = SP_ERROR_NATIVE;
   3.102 +
   3.103 +	if (msg)
   3.104 +	{
   3.105 +		va_list ap;
   3.106 +		va_start(ap, msg);
   3.107 +		SetErrorMessage(msg, ap);
   3.108 +		va_end(ap);
   3.109 +	}
   3.110 +
   3.111 +	return 0;
   3.112 +}
   3.113 +
   3.114  int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
   3.115  {
   3.116  	cell_t *addr;
     4.1 --- a/core/vm/sp_vm_basecontext.h	Mon Jan 01 01:08:36 2007 +0000
     4.2 +++ b/core/vm/sp_vm_basecontext.h	Mon Jan 01 01:09:53 2007 +0000
     4.3 @@ -42,12 +42,19 @@
     4.4  		virtual int BindNative(sp_nativeinfo_t *native);
     4.5  		virtual int BindNativeToAny(SPVM_NATIVE_FUNC native);
     4.6  		virtual int Execute(funcid_t funcid, cell_t *result);
     4.7 +		virtual void ThrowNativeErrorEx(int error, const char *msg, ...);
     4.8 +		virtual cell_t ThrowNativeError(const char *msg, ...);
     4.9  	public: //IPluginDebugInfo
    4.10  		virtual int LookupFile(ucell_t addr, const char **filename);
    4.11  		virtual int LookupFunction(ucell_t addr, const char **name);
    4.12  		virtual int LookupLine(ucell_t addr, uint32_t *line);
    4.13  	private:
    4.14 +		void SetErrorMessage(const char *msg, va_list ap);
    4.15 +	private:
    4.16  		sp_context_t *ctx;
    4.17 +		char m_MsgCache[1024];
    4.18 +		bool m_CustomMsg;
    4.19 +		bool m_InExec;
    4.20  	};
    4.21  };
    4.22  
     5.1 --- a/core/vm/sp_vm_engine.cpp	Mon Jan 01 01:08:36 2007 +0000
     5.2 +++ b/core/vm/sp_vm_engine.cpp	Mon Jan 01 01:09:53 2007 +0000
     5.3 @@ -1,5 +1,6 @@
     5.4  #include <malloc.h>
     5.5  #include <string.h>
     5.6 +#include <assert.h>
     5.7  #include "sp_file_headers.h"
     5.8  #include "sp_vm_types.h"
     5.9  #include "sp_vm_engine.h"
    5.10 @@ -13,8 +14,60 @@
    5.11   #include <sys/mman.h>
    5.12  #endif
    5.13  
    5.14 +#define INVALID_CIP			0xFFFFFFFF
    5.15 +
    5.16  using namespace SourcePawn;
    5.17  
    5.18 +#define ERROR_MESSAGE_MAX		23
    5.19 +static const char *g_ErrorMsgTable[] = 
    5.20 +{
    5.21 +	NULL,
    5.22 +	"Unrecognizable file format",
    5.23 +	"Decompressor was not found",
    5.24 +	"Not enough space on the heap",
    5.25 +	"Invalid parameter or parameter type",
    5.26 +	"Invalid plugin address",
    5.27 +	"Object or index not found",
    5.28 +	"Invalid index or index not found",
    5.29 +	"Not enough space on the stack",
    5.30 +	"Debug section not found or debug not enabled",
    5.31 +	"Invalid instruction",
    5.32 +	"Invalid memory access",
    5.33 +	"Stack went below stack boundary",
    5.34 +	"Heap went below heap boundary",
    5.35 +	"Divide by zero",
    5.36 +	"Array index is out of bounds",
    5.37 +	"Instruction contained invalid parameter",
    5.38 +	"Stack memory leaked by native",
    5.39 +	"Heap memory leaked by native",
    5.40 +	"Dynamic array is too big",
    5.41 +	"Tracker stack is out of bounds",
    5.42 +	"Native was never bound",
    5.43 +	"Maximum number of parameters reached",
    5.44 +	"Native detected error",
    5.45 +};
    5.46 +
    5.47 +SourcePawnEngine::SourcePawnEngine()
    5.48 +{
    5.49 +	m_pDebugHook = NULL;
    5.50 +	m_CallStack = NULL;
    5.51 +	m_FreedCalls = NULL;
    5.52 +	m_CurChain = 0;
    5.53 +}
    5.54 +
    5.55 +SourcePawnEngine::~SourcePawnEngine()
    5.56 +{
    5.57 +	assert(m_CallStack == NULL);
    5.58 +
    5.59 +	TracedCall *pTemp;
    5.60 +	while (m_FreedCalls)
    5.61 +	{
    5.62 +		pTemp = m_FreedCalls->next;
    5.63 +		delete pTemp;
    5.64 +		m_FreedCalls = pTemp;
    5.65 +	}
    5.66 +}
    5.67 +
    5.68  void *SourcePawnEngine::ExecAlloc(size_t size)
    5.69  {
    5.70  #if defined WIN32
    5.71 @@ -302,3 +355,224 @@
    5.72  
    5.73  	return SP_ERROR_NONE;
    5.74  }
    5.75 +
    5.76 +IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
    5.77 +{
    5.78 +	IDebugListener *old = m_pDebugHook;
    5.79 +
    5.80 +	m_pDebugHook = pListener;
    5.81 +
    5.82 +	return old;
    5.83 +}
    5.84 +
    5.85 +unsigned int SourcePawnEngine::GetContextCallCount()
    5.86 +{
    5.87 +	if (!m_CallStack)
    5.88 +	{
    5.89 +		return 0;
    5.90 +	}
    5.91 +
    5.92 +	return m_CallStack->chain;
    5.93 +}
    5.94 +
    5.95 +TracedCall *SourcePawnEngine::MakeTracedCall(bool new_chain)
    5.96 +{
    5.97 +	TracedCall *pCall;
    5.98 +
    5.99 +	if (!m_FreedCalls)
   5.100 +	{
   5.101 +		pCall = new TracedCall;
   5.102 +	} else {
   5.103 +		/* Unlink the head node from the free list */
   5.104 +		pCall = m_FreedCalls;
   5.105 +		m_FreedCalls = m_FreedCalls->next;
   5.106 +		if (m_FreedCalls)
   5.107 +		{
   5.108 +			m_FreedCalls->prev = NULL;
   5.109 +		}
   5.110 +	}
   5.111 +
   5.112 +	/* Link as the head node into the call stack */
   5.113 +	pCall->next = m_CallStack;
   5.114 +	pCall->prev = NULL;
   5.115 +
   5.116 +	if (new_chain)
   5.117 +	{
   5.118 +		pCall->chain = ++m_CurChain;
   5.119 +	} else {
   5.120 +		pCall->chain = m_CurChain;
   5.121 +	}
   5.122 +
   5.123 +	if (m_CallStack)
   5.124 +	{
   5.125 +		m_CallStack->prev = pCall;
   5.126 +	}
   5.127 +	m_CallStack = pCall;
   5.128 +
   5.129 +	return pCall;
   5.130 +}
   5.131 +
   5.132 +void SourcePawnEngine::FreeTracedCall(TracedCall *pCall)
   5.133 +{
   5.134 +	/* Check if this is the top of the call stack */
   5.135 +	if (pCall == m_CallStack)
   5.136 +	{
   5.137 +		m_CallStack = m_CallStack->next;
   5.138 +		if (m_CallStack)
   5.139 +		{
   5.140 +			m_CallStack->prev = NULL;
   5.141 +		}
   5.142 +	}
   5.143 +
   5.144 +	/* Add this to our linked list of freed calls */
   5.145 +	if (!m_FreedCalls)
   5.146 +	{
   5.147 +		m_FreedCalls = pCall;
   5.148 +		m_FreedCalls->next = NULL;
   5.149 +		m_FreedCalls->prev = NULL;
   5.150 +	} else {
   5.151 +		pCall->next = m_FreedCalls;
   5.152 +		pCall->prev = NULL;
   5.153 +		m_FreedCalls->prev = pCall;
   5.154 +		m_FreedCalls = pCall;
   5.155 +	}
   5.156 +}
   5.157 +
   5.158 +void SourcePawnEngine::PushTracer(sp_context_t *ctx)
   5.159 +{
   5.160 +	TracedCall *pCall = MakeTracedCall(true);
   5.161 +
   5.162 +	pCall->cip = INVALID_CIP;
   5.163 +	pCall->ctx = ctx;
   5.164 +	pCall->frm = INVALID_CIP;
   5.165 +}
   5.166 +
   5.167 +void SourcePawnEngine::RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip)
   5.168 +{
   5.169 +	assert(m_CallStack != NULL);
   5.170 +	assert(m_CallStack->ctx == ctx);
   5.171 +	assert(m_CallStack->chain == m_CurChain);
   5.172 +
   5.173 +	if (m_CallStack->cip == INVALID_CIP)
   5.174 +	{
   5.175 +		/* We aren't logging anything yet, so begin the trace */
   5.176 +		m_CallStack->cip = codeip;
   5.177 +		m_CallStack->frm = frame;
   5.178 +	} else {
   5.179 +		if (m_CallStack->frm > frame)
   5.180 +		{
   5.181 +			/* The last frame has moved down the stack, 
   5.182 +			 * so we have to push a new call onto our list.
   5.183 +			 */
   5.184 +			TracedCall *pCall = MakeTracedCall(false);
   5.185 +			pCall->frm = frame;
   5.186 +		} else if (m_CallStack->frm < frame) {
   5.187 +			/* The last frame has moved up the stack,
   5.188 +			 * so we have to pop the call from our list.
   5.189 +			 */
   5.190 +			FreeTracedCall(m_CallStack);
   5.191 +		}
   5.192 +		/* no matter where we are, update the cip */
   5.193 +		m_CallStack->cip = codeip;
   5.194 +	}
   5.195 +}
   5.196 +
   5.197 +void SourcePawnEngine::PopTracer(int error, const char *msg)
   5.198 +{
   5.199 +	assert(m_CallStack != NULL);
   5.200 +
   5.201 +	if (error != SP_ERROR_NONE && m_pDebugHook)
   5.202 +	{
   5.203 +		CContextTrace trace(m_CallStack, error, msg);
   5.204 +		m_pDebugHook->OnContextExecuteError(m_CallStack->ctx->context, &trace);
   5.205 +	}
   5.206 +
   5.207 +	/* Now pop the error chain  */
   5.208 +	while (m_CallStack && m_CallStack->chain == m_CurChain)
   5.209 +	{
   5.210 +		FreeTracedCall(m_CallStack);
   5.211 +	}
   5.212 +
   5.213 +	m_CurChain--;
   5.214 +}
   5.215 +
   5.216 +CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg) : 
   5.217 + m_Error(error), m_pMsg(msg), m_pStart(pStart), m_pIterator(pStart)
   5.218 +{
   5.219 +}
   5.220 +
   5.221 +bool CContextTrace::DebugInfoAvailable()
   5.222 +{
   5.223 +	return ((m_pStart->ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
   5.224 +}
   5.225 +
   5.226 +const char *CContextTrace::GetCustomErrorString()
   5.227 +{
   5.228 +	return m_pMsg;
   5.229 +}
   5.230 +
   5.231 +int CContextTrace::GetErrorCode()
   5.232 +{
   5.233 +	return m_Error;
   5.234 +}
   5.235 +
   5.236 +const char *CContextTrace::GetErrorString()
   5.237 +{
   5.238 +	if (m_Error > ERROR_MESSAGE_MAX || 
   5.239 +		m_Error < 1)
   5.240 +	{
   5.241 +		return "Invalid error code";
   5.242 +	} else {
   5.243 +		return g_ErrorMsgTable[m_Error];
   5.244 +	}
   5.245 +}
   5.246 +
   5.247 +void CContextTrace::ResetTrace()
   5.248 +{
   5.249 +	m_pIterator = m_pStart;
   5.250 +}
   5.251 +
   5.252 +bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
   5.253 +{
   5.254 +	if (m_pIterator->chain != m_pStart->chain)
   5.255 +	{
   5.256 +		return false;
   5.257 +	}
   5.258 +
   5.259 +	if (m_pIterator->cip == INVALID_CIP)
   5.260 +	{
   5.261 +		return false;
   5.262 +	}
   5.263 +
   5.264 +	IPluginContext *pContext = m_pIterator->ctx->context;
   5.265 +	IPluginDebugInfo *pInfo = pContext->GetDebugInfo();
   5.266 +
   5.267 +	m_pIterator = m_pIterator->next;
   5.268 +
   5.269 +	if (!pInfo)
   5.270 +	{
   5.271 +		return false;
   5.272 +	}
   5.273 +
   5.274 +	if (!trace)
   5.275 +	{
   5.276 +		return true;
   5.277 +	}
   5.278 +
   5.279 +	if (pInfo->LookupFile(m_pIterator->cip, &(trace->filename)) != SP_ERROR_NONE)
   5.280 +	{
   5.281 +		trace->filename = NULL;
   5.282 +	}
   5.283 +
   5.284 +	if (pInfo->LookupFunction(m_pIterator->cip, &(trace->function)) != SP_ERROR_NONE)
   5.285 +	{
   5.286 +		trace->function = NULL;
   5.287 +	}
   5.288 +
   5.289 +	if (pInfo->LookupLine(m_pIterator->cip, &(trace->line)) != SP_ERROR_NONE)
   5.290 +	{
   5.291 +		trace->line = 0;
   5.292 +	}
   5.293 +
   5.294 +	return true;
   5.295 +}
     6.1 --- a/core/vm/sp_vm_engine.h	Mon Jan 01 01:08:36 2007 +0000
     6.2 +++ b/core/vm/sp_vm_engine.h	Mon Jan 01 01:09:53 2007 +0000
     6.3 @@ -5,83 +5,78 @@
     6.4  
     6.5  namespace SourcePawn
     6.6  {
     6.7 +	struct TracedCall
     6.8 +	{
     6.9 +		uint32_t cip;
    6.10 +		uint32_t frm;
    6.11 +		sp_context_t *ctx;
    6.12 +		TracedCall *next;
    6.13 +		TracedCall *prev;
    6.14 +		unsigned int chain;
    6.15 +	};
    6.16 +
    6.17 +
    6.18 +	class CContextTrace : public IContextTrace
    6.19 +	{
    6.20 +	public:
    6.21 +		CContextTrace(TracedCall *pStart, int error, const char *msg);
    6.22 +	public:
    6.23 +		virtual int GetErrorCode();
    6.24 +		virtual const char *GetErrorString();
    6.25 +		virtual bool DebugInfoAvailable();
    6.26 +		virtual const char *GetCustomErrorString();
    6.27 +		virtual bool GetTraceInfo(CallStackInfo *trace);
    6.28 +		virtual void ResetTrace();
    6.29 +	private:
    6.30 +		TracedCall *m_pStart;
    6.31 +		TracedCall *m_pIterator;
    6.32 +		const char *m_pMsg;
    6.33 +		int m_Error;
    6.34 +	};
    6.35 +
    6.36 +
    6.37  	class SourcePawnEngine : public ISourcePawnEngine
    6.38  	{
    6.39  	public:
    6.40 -		/**
    6.41 -		 * Loads a named file from a file pointer.  
    6.42 -		 * Using this means base memory will be allocated by the VM.
    6.43 -		 * Note: The file handle position may be undefined on entry, and is
    6.44 -		 *  always undefined on conclusion.
    6.45 -		 * 
    6.46 -		 * @param fp		File pointer.  May be at any offset.  Not closed on return.
    6.47 -		 * @param err		Optional error code pointer.
    6.48 -		 * @return			A new plugin structure.
    6.49 -		 */	
    6.50 +		SourcePawnEngine();
    6.51 +		~SourcePawnEngine();
    6.52 +	public: //ISourcePawnEngine
    6.53  		sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err);
    6.54 -
    6.55 +		sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
    6.56 +		int FreeFromMemory(sp_plugin_t *plugin);
    6.57 +		IPluginContext *CreateBaseContext(sp_context_t *ctx);
    6.58 +		void FreeBaseContext(IPluginContext *ctx);
    6.59 +		void *BaseAlloc(size_t size);
    6.60 +		void BaseFree(void *memory);
    6.61 +		void *ExecAlloc(size_t size);
    6.62 +		void ExecFree(void *address);
    6.63 +		IDebugListener *SetDebugListener(IDebugListener *pListener);
    6.64 +		unsigned int GetContextCallCount();
    6.65 +	public: //Debugger Stuff
    6.66  		/**
    6.67 -		 * Loads a file from a base memory address.
    6.68 -		 *	
    6.69 -		 * @param base		Base address of the plugin's memory region.
    6.70 -		 * @param plugin	If NULL, a new plugin pointer is returned.
    6.71 -		 *                  Otherwise, the passed pointer is used.
    6.72 -		 * @param err		Optional error code pointer.
    6.73 -		 * @return			The resulting plugin pointer.
    6.74 +		 * @brief Pushes a context onto the top of the call tracer.
    6.75 +		 * 
    6.76 +		 * @param ctx		Plugin context.
    6.77  		 */
    6.78 -		sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
    6.79 -
    6.80 -		/**
    6.81 -		 * Frees all of the memory associated with a plugin file.
    6.82 -		 * If allocated using SP_LoadFromMemory, the base and plugin pointer 
    6.83 -		 *  itself are not freed (so this may end up doing nothing).
    6.84 -		 */
    6.85 -		int FreeFromMemory(sp_plugin_t *plugin);
    6.86 +		void PushTracer(sp_context_t *ctx);
    6.87  
    6.88  		/**
    6.89 -		 * Creates a new IContext from a context handle.
    6.90 -		 *
    6.91 -		 * @param ctx		Context to use as a basis for the IPluginContext.
    6.92 -		 * @return			New IPluginContext handle.
    6.93 +		 * @brief Pops a plugin off the call tracer.
    6.94  		 */
    6.95 -		IPluginContext *CreateBaseContext(sp_context_t *ctx);
    6.96 -
    6.97 -		/** 
    6.98 -		 * Frees a context.
    6.99 -		 *
   6.100 -		 * @param ctx		Context pointer to free.
   6.101 -		 */
   6.102 -		void FreeBaseContext(IPluginContext *ctx);
   6.103 +		void PopTracer(int error, const char *msg);
   6.104  
   6.105  		/**
   6.106 -		 * Allocates memory.
   6.107 -		 * 
   6.108 -		 * @param size		Size of memory to allocate.
   6.109 -		 * @return			Pointer to memory, NULL if allocation failed.
   6.110 -		 */
   6.111 -		void *BaseAlloc(size_t size);
   6.112 -
   6.113 -		/**
   6.114 -		 * Frees memory allocated with BaseAlloc.
   6.115 -		 *
   6.116 -		 * @param memory	Memory address to free.
   6.117 +		 * @brief Runs tracer from a debug break.
   6.118  		 */
   6.119 -		void BaseFree(void *memory);
   6.120 -
   6.121 -		/**
   6.122 -		 * Allocates executable memory.
   6.123 -		 *
   6.124 -		 * @param size		Size of memory to allocate.
   6.125 -		 * @return			Pointer to memory, NULL if allocation failed.
   6.126 -		 */
   6.127 -		void *ExecAlloc(size_t size);
   6.128 -
   6.129 -		/**
   6.130 -		 * Frees executable memory.
   6.131 -		 *
   6.132 -		 * @param address	Address to free.
   6.133 -		 */
   6.134 -		void ExecFree(void *address);
   6.135 +		void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip);
   6.136 +	private:
   6.137 +		TracedCall *MakeTracedCall(bool new_chain);
   6.138 +		void FreeTracedCall(TracedCall *pCall);
   6.139 +	private:
   6.140 +		IDebugListener *m_pDebugHook;
   6.141 +		TracedCall *m_FreedCalls;
   6.142 +		TracedCall *m_CallStack;
   6.143 +		unsigned int m_CurChain;
   6.144  	};
   6.145  };
   6.146