diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp index c1f36fcd..9876c964 100755 --- a/amxmodx/CPlugin.cpp +++ b/amxmodx/CPlugin.cpp @@ -38,10 +38,11 @@ extern const char *no_function; -CPluginMngr::CPlugin* CPluginMngr::loadPlugin(const char* path, const char* name, char* error, int debug) { +CPluginMngr::CPlugin* CPluginMngr::loadPlugin(const char* path, const char* name, char* error, int debug) +{ CPlugin** a = &head; while( *a ) a = &(*a)->next; - *a = new CPlugin( pCounter++ ,path,name,error, debug); + *a = new CPlugin(pCounter++, path, name, error, debug); return (*a); } diff --git a/amxmodx/amx.h b/amxmodx/amx.h index 9009fb46..c882048b 100755 --- a/amxmodx/amx.h +++ b/amxmodx/amx.h @@ -339,6 +339,7 @@ enum { #define UD_FINDPLUGIN 3 #define UD_DEBUGGER 2 #define UD_OPCODELIST 1 +#define UD_HANDLER 0 /* for native functions that use floating point parameters, the following * two macros are convenient for casting a "cell" into a "float" type _without_ diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index ad262165..7ead8e80 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -149,6 +149,7 @@ extern CList g_forcemodels; extern CList g_forcesounds; extern CList g_forcegeneric; extern CList g_modules; +extern CList g_loadedscripts; extern CList g_auth; extern EventsMngr g_events; extern Grenades g_grenades; diff --git a/amxmodx/debugger.cpp b/amxmodx/debugger.cpp index 3f9cdb86..0ece5bcd 100755 --- a/amxmodx/debugger.cpp +++ b/amxmodx/debugger.cpp @@ -778,7 +778,100 @@ void Debugger::Clear() m_pCalls.clear(); } +void Debugger::DisplayTrace(const char *message) +{ + if (message != NULL) + AMXXLOG_Log("%s", message); + + char buffer[512]; + FormatError(buffer, sizeof(buffer)-1); + + const char *filename = _GetFilename(); + + AMXXLOG_Log("[AMXX] Displaying debug trace (plugin \"%s\")", filename); + AMXXLOG_Log("[AMXX] %s", buffer); + + int count = 0; + long lLine; + const char *file, *function; + trace_info_t *pTrace = GetTraceStart(); + while (pTrace) + { + GetTraceInfo(pTrace, lLine, function, file); + AMXXLOG_Log( + "[AMXX] [%d] %s::%s (line %d)", + count, + file, + function, + (int)(lLine + 1) + ); + count++; + pTrace = GetNextTrace(pTrace); + } +} + +const char *Debugger::_GetFilename() +{ + if (m_FileName.size() < 1) + { + const char *filename = ""; + CPluginMngr::CPlugin *pl = g_plugins.findPluginFast(m_pAmx); + if (pl) + { + filename = pl->getName(); + } else { + CList::iterator a = g_loadedscripts.find(m_pAmx); + if (a) + filename = (*a).getName(); + } + m_FileName.assign(filename); + } + + return m_FileName.c_str(); +} + Debugger::~Debugger() { Clear(); } + +int Handler::SetErrorHandler(const char *function) +{ + int error; + + error = amx_FindPublic(m_pAmx, function, &m_iErrFunc); + + if (error != AMX_ERR_NONE) + m_iErrFunc = -1; + + return error; +} + +int Handler::SetModuleFilter(const char *function) +{ + int error; + + error = amx_FindPublic(m_pAmx, function, &m_iModFunc); + + if (error != AMX_ERR_NONE) + m_iModFunc = -1; + + return error; +} + +int Handler::SetNativeFilter(const char *function) +{ + int error; + + error = amx_FindPublic(m_pAmx, function, &m_iNatFunc); + + if (error != AMX_ERR_NONE) + m_iNatFunc = -1; + + return error; +} + +int Handler::HandleError(const char *msg) +{ + return 0; +} diff --git a/amxmodx/debugger.h b/amxmodx/debugger.h index 0f632fed..68bd7b4e 100755 --- a/amxmodx/debugger.h +++ b/amxmodx/debugger.h @@ -116,6 +116,10 @@ public: //Destroy internal states for shutdown void Clear(); + + void DisplayTrace(const char *message); + + AMX *GetAMX() const { return m_pAmx; } public: //generic static opcode breaker static int AMXAPI DebugHook(AMX *amx); @@ -123,14 +127,42 @@ private: void _CacheAmxOpcodeList(); int _GetOpcodeFromCip(cell cip, cell *&addr); cell _CipAsVa(cell cip); + const char *_GetFilename(); public: AMX *m_pAmx; AMX_DBG *m_pAmxDbg; int m_Top; cell *m_pOpcodeList; + String m_FileName; CVector m_pCalls; }; typedef Debugger::Tracer::trace_info trace_info_t; +/** + * Error handler for plugins + */ + +class Handler +{ +public: + Handler(AMX *pAmx) : m_pAmx(pAmx), + m_iErrFunc(-1), m_iModFunc(-1), m_iNatFunc(-1) + { }; + ~Handler() { }; +public: + int SetErrorHandler(const char *function); + int SetNativeFilter(const char *function); + int SetModuleFilter(const char *function); +public: + int HandleError(const char *msg); + int HandleNative(const char *native); + int HandleModule(const char *module); +public: + AMX *m_pAmx; + int m_iErrFunc; + int m_iModFunc; + int m_iNatFunc; +}; + #endif //_INCLUDE_DEBUGGER_H_ diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index 8a10644f..05da5bcf 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -1289,19 +1289,10 @@ void LogError(AMX *amx, int err, const char *fmt, ...) Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER]; amx->error = err; - CPluginMngr::CPlugin *pl = g_plugins.findPluginFast(amx); - const char *filename = ""; - if (pl) - { - filename = pl->getName(); - } else { - CList::iterator a = g_loadedscripts.find(amx); - if (a) - filename = (*a).getName(); - } + char msg_buffer[2048]; - static char msg_buffer[4096]; + msg_buffer[0] = '\0'; if (fmt != NULL) { va_list ap; @@ -1310,43 +1301,39 @@ void LogError(AMX *amx, int err, const char *fmt, ...) va_end(ap); } - if (fmt != NULL) - AMXXLOG_Log("%s", msg_buffer); + //give the plugin first chance to handle any sort of error + Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER]; + if (pHandler) + { + //give the user a first-chance at blocking the error from displaying + if (pHandler->HandleError(msg_buffer) != 0) + return; + } if (!pDebugger) { + CPluginMngr::CPlugin *pl = g_plugins.findPluginFast(amx); + + const char *filename = ""; + if (pl) + { + filename = pl->getName(); + } else { + CList::iterator a = g_loadedscripts.find(amx); + if (a) + filename = (*a).getName(); + } + if (fmt != NULL) + AMXXLOG_Log("%s", msg_buffer); //give the module's error first. makes the report look nicer. AMXXLOG_Log("[AMXX] Run time error %d (plugin \"%s\") - debug not enabled!", err, filename); AMXXLOG_Log("[AMXX] To enable debug mode, add \"debug\" after the plugin name in plugins.ini (without quotes)."); //destroy original error code so the original is not displayed again amx->error = -1; - return; - } - - pDebugger->SetTracedError(err); - - char buffer[512]; - pDebugger->FormatError(buffer, sizeof(buffer)-1); - - AMXXLOG_Log("[AMXX] Displaying debug trace (plugin \"%s\")", filename); - AMXXLOG_Log("[AMXX] %s", buffer); - - int count = 0; - long lLine; - const char *file, *function; - trace_info_t *pTrace = pDebugger->GetTraceStart(); - while (pTrace) - { - pDebugger->GetTraceInfo(pTrace, lLine, function, file); - AMXXLOG_Log( - "[AMXX] [%d] %s::%s (line %d)", - count, - file, - function, - (int)(lLine + 1) - ); - count++; - pTrace = pDebugger->GetNextTrace(pTrace); + } else { + pDebugger->SetTracedError(err); + //we can display error now + pDebugger->DisplayTrace(fmt ? msg_buffer : NULL); } }