mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-26 06:45:37 +03:00
Reworked code to support error handling, LogError() is separate from DisplayTrace() implementation
This commit is contained in:
parent
4738c92b8e
commit
f8aac5e88d
@ -38,7 +38,8 @@
|
||||
|
||||
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);
|
||||
|
@ -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_
|
||||
|
@ -149,6 +149,7 @@ extern CList<ForceObject> g_forcemodels;
|
||||
extern CList<ForceObject> g_forcesounds;
|
||||
extern CList<ForceObject> g_forcegeneric;
|
||||
extern CList<CModule,const char *> g_modules;
|
||||
extern CList<CScript,AMX*> g_loadedscripts;
|
||||
extern CList<CPlayer*> g_auth;
|
||||
extern EventsMngr g_events;
|
||||
extern Grenades g_grenades;
|
||||
|
@ -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<CScript,AMX*>::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;
|
||||
}
|
||||
|
@ -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<Tracer *> 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_
|
||||
|
@ -1289,6 +1289,29 @@ void LogError(AMX *amx, int err, const char *fmt, ...)
|
||||
Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER];
|
||||
|
||||
amx->error = err;
|
||||
|
||||
char msg_buffer[2048];
|
||||
|
||||
msg_buffer[0] = '\0';
|
||||
if (fmt != NULL)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
_vsnprintf(msg_buffer, sizeof(msg_buffer)-1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
//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 = "";
|
||||
@ -1300,53 +1323,17 @@ void LogError(AMX *amx, int err, const char *fmt, ...)
|
||||
if (a)
|
||||
filename = (*a).getName();
|
||||
}
|
||||
|
||||
static char msg_buffer[4096];
|
||||
if (fmt != NULL)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
_vsnprintf(msg_buffer, sizeof(msg_buffer)-1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
if (fmt != NULL)
|
||||
AMXXLOG_Log("%s", msg_buffer);
|
||||
|
||||
if (!pDebugger)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
} else {
|
||||
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);
|
||||
//we can display error now
|
||||
pDebugger->DisplayTrace(fmt ? msg_buffer : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user