diff --git a/amxmodx/debugger.cpp b/amxmodx/debugger.cpp index 0ece5bcd..b1813632 100755 --- a/amxmodx/debugger.cpp +++ b/amxmodx/debugger.cpp @@ -830,6 +830,27 @@ const char *Debugger::_GetFilename() return m_FileName.c_str(); } +void Debugger::GenericMessage(AMX *amx, int err) +{ + CPluginMngr::CPlugin *pl = g_plugins.findPluginFast(amx); + const char *filename = ""; + + CList::iterator a = g_loadedscripts.find(amx); + if (a) + filename = (*a).getName(); + size_t len = strlen(filename); + for (size_t i=len-1; i>=0; i--) + { + if (filename[i] == '/' || filename[i] == '\\' && i != len - 1) + { + filename = &(filename[i+1]); + break; + } + } + + AMXXLOG_Log("[AMXX] Run time error %d (plugin \"%s\") - debug not enabled!", err, filename); +} + Debugger::~Debugger() { Clear(); @@ -871,7 +892,98 @@ int Handler::SetNativeFilter(const char *function) return error; } +void Handler::SetErrorMsg(const char *msg) +{ + if (!msg) + m_MsgCache.clear(); + else + m_MsgCache.assign(msg); +} + +const char *Handler::GetLastMsg() +{ + if (m_MsgCache.size() < 1) + return NULL; + + return m_MsgCache.c_str(); +} + int Handler::HandleError(const char *msg) { - return 0; + if (m_iErrFunc <= 0) + return 0; + + m_Handling = true; + + Debugger *pDebugger = (Debugger *)m_pAmx->userdata[UD_DEBUGGER]; + + int error = m_pAmx->error; + + if (pDebugger) + pDebugger->BeginExec(); + + SetErrorMsg(msg); + + cell hea_addr, *phys_addr, result; + + amx_PushString(m_pAmx, &hea_addr, &phys_addr, msg, 0, 0); + amx_Push(m_pAmx, pDebugger ? 1 : 0); + amx_Push(m_pAmx, error); + int err = amx_Exec(m_pAmx, &result, m_iErrFunc); + if (err != AMX_ERR_NONE) + { + //handle this manually. + if (pDebugger) + { + pDebugger->SetTracedError(err); + pDebugger->DisplayTrace(msg); + } else { + if (GetLastMsg()) + AMXXLOG_Log("%s", GetLastMsg()); + Debugger::GenericMessage(m_pAmx, err); + } + AMXXLOG_Log("[AMXX] NOTE: Runtime failures in an error filter are not good!"); + } + + if (pDebugger) + pDebugger->EndExec(); + + amx_Release(m_pAmx, hea_addr); + + m_Handling = false; + + if (err != AMX_ERR_NONE || !result) + return 0; + + return result; } + +static cell AMX_NATIVE_CALL set_error_filter(AMX *amx, cell *params) +{ + int len; + char *function = get_amxstring(amx, params[1], 0, len); + + Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER]; + + if (!pHandler) + { + Debugger::GenericMessage(amx, AMX_ERR_NOTFOUND); + AMXXLOG_Log("[AMXX] Plugin not initialized correctly."); + return 0; + } + + int err = pHandler->SetErrorHandler(function); + if (err != AMX_ERR_NONE) + { + Debugger::GenericMessage(amx, AMX_ERR_NOTFOUND); + AMXXLOG_Log("[AMXX] Function not found: %s", function); + return 0; + } + + return 1; +} + +AMX_NATIVE_INFO g_DebugNatives[] = { + {"set_error_filter", set_error_filter}, + {NULL, NULL}, +}; diff --git a/amxmodx/debugger.h b/amxmodx/debugger.h index 68bd7b4e..38cd6cc8 100755 --- a/amxmodx/debugger.h +++ b/amxmodx/debugger.h @@ -123,6 +123,7 @@ public: public: //generic static opcode breaker static int AMXAPI DebugHook(AMX *amx); + static void GenericMessage(AMX *amx, int error); private: void _CacheAmxOpcodeList(); int _GetOpcodeFromCip(cell cip, cell *&addr); @@ -146,8 +147,9 @@ typedef Debugger::Tracer::trace_info trace_info_t; class Handler { public: - Handler(AMX *pAmx) : m_pAmx(pAmx), - m_iErrFunc(-1), m_iModFunc(-1), m_iNatFunc(-1) + Handler(AMX *pAmx) : m_pAmx(pAmx), + m_iErrFunc(-1), m_iModFunc(-1), m_iNatFunc(-1), + m_Handling(false) { }; ~Handler() { }; public: @@ -158,11 +160,19 @@ public: int HandleError(const char *msg); int HandleNative(const char *native); int HandleModule(const char *module); +public: + bool IsHandling() const { return m_Handling; } + void SetErrorMsg(const char *msg); + const char *GetLastMsg(); public: AMX *m_pAmx; int m_iErrFunc; int m_iModFunc; int m_iNatFunc; + bool m_Handling; + String m_MsgCache; }; +extern AMX_NATIVE_INFO g_DebugNatives[]; + #endif //_INCLUDE_DEBUGGER_H_ diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index 05da5bcf..4258e144 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -209,6 +209,9 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64 return (amx->error = AMX_ERR_INIT); } + Handler *pHandler = new Handler(amx); + amx->userdata[UD_HANDLER] = (void *)pHandler; + if (will_be_debugged) { amx->flags |= AMX_FLAG_DEBUG; @@ -409,17 +412,19 @@ int set_amxnatives(AMX* amx,char error[128]) amx_Register(amx, vault_Natives, -1); amx_Register(amx, g_NewMenuNatives, -1); amx_Register(amx, g_NativeNatives, -1); + amx_Register(amx, g_DebugNatives, -1); //we're not actually gonna check these here anymore amx->flags |= AMX_FLAG_PRENIT; - int idx; + int idx, err; cell retval; if (amx_FindPublic(amx, "plugin_natives", &idx)==AMX_ERR_NONE) { - if (amx_Exec(amx, &retval, idx)!=AMX_ERR_NONE) + if ( (err=amx_Exec(amx, &retval, idx))!=AMX_ERR_NONE ) { - //someday clear libraries that this added + Debugger::GenericMessage(amx, err); + AMXXLOG_Log("An error occurred in plugins_native. This is dangerous!"); } } @@ -434,6 +439,9 @@ int unload_amxscript(AMX* amx, void** program) Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER]; if (pDebugger) delete pDebugger; + Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER]; + if (pHandler) + delete pHandler; CList::iterator a = g_loadedscripts.find( amx ); if ( a ) a.remove(); char *prg = (char *)*program; @@ -1256,11 +1264,6 @@ float MNF_GetPlayerHealth(int id) return (GET_PLAYER_POINTER_I(id)->pEdict->v.health); } -void MNF_HiddenStuff() -{ - // :TODO: -} - cell MNF_RealToCell(REAL x) { return *(cell*)&x; @@ -1305,36 +1308,34 @@ void LogError(AMX *amx, int err, const char *fmt, ...) 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) + if (pHandler->IsHandling()) + { + if (fmt != NULL) + pHandler->SetErrorMsg(msg_buffer); return; + } + //give the user a first-chance at blocking the error from displaying + if (pHandler->HandleError(fmt ? msg_buffer : NULL) != 0) + { + amx->error = -1; + 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) + if (fmt) 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); + Debugger::GenericMessage(amx, err); 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; } else { pDebugger->SetTracedError(err); //we can display error now pDebugger->DisplayTrace(fmt ? msg_buffer : NULL); } + + amx->error = -1; } void MNF_MergeDefinitionFile(const char *file) @@ -1516,8 +1517,6 @@ void Module_CacheFunctions() REGISTER_FUNC("Deallocator", MNF_Deallocator) REGISTER_FUNC("Reallocator", MNF_Reallocator) #endif // MEMORY_TEST - - REGISTER_FUNC("Haha_HiddenStuff", MNF_HiddenStuff) } void *Module_ReqFnptr(const char *funcName)