Reworked code to support error handling, LogError() is separate from DisplayTrace() implementation

This commit is contained in:
David Anderson 2005-09-09 16:04:44 +00:00
parent 4738c92b8e
commit f8aac5e88d
6 changed files with 157 additions and 42 deletions

View File

@ -38,10 +38,11 @@
extern const char *no_function; 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; CPlugin** a = &head;
while( *a ) a = &(*a)->next; while( *a ) a = &(*a)->next;
*a = new CPlugin( pCounter++ ,path,name,error, debug); *a = new CPlugin(pCounter++, path, name, error, debug);
return (*a); return (*a);
} }

View File

@ -339,6 +339,7 @@ enum {
#define UD_FINDPLUGIN 3 #define UD_FINDPLUGIN 3
#define UD_DEBUGGER 2 #define UD_DEBUGGER 2
#define UD_OPCODELIST 1 #define UD_OPCODELIST 1
#define UD_HANDLER 0
/* for native functions that use floating point parameters, the following /* for native functions that use floating point parameters, the following
* two macros are convenient for casting a "cell" into a "float" type _without_ * two macros are convenient for casting a "cell" into a "float" type _without_

View File

@ -149,6 +149,7 @@ extern CList<ForceObject> g_forcemodels;
extern CList<ForceObject> g_forcesounds; extern CList<ForceObject> g_forcesounds;
extern CList<ForceObject> g_forcegeneric; extern CList<ForceObject> g_forcegeneric;
extern CList<CModule,const char *> g_modules; extern CList<CModule,const char *> g_modules;
extern CList<CScript,AMX*> g_loadedscripts;
extern CList<CPlayer*> g_auth; extern CList<CPlayer*> g_auth;
extern EventsMngr g_events; extern EventsMngr g_events;
extern Grenades g_grenades; extern Grenades g_grenades;

View File

@ -778,7 +778,100 @@ void Debugger::Clear()
m_pCalls.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() Debugger::~Debugger()
{ {
Clear(); 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;
}

View File

@ -116,6 +116,10 @@ public:
//Destroy internal states for shutdown //Destroy internal states for shutdown
void Clear(); void Clear();
void DisplayTrace(const char *message);
AMX *GetAMX() const { return m_pAmx; }
public: public:
//generic static opcode breaker //generic static opcode breaker
static int AMXAPI DebugHook(AMX *amx); static int AMXAPI DebugHook(AMX *amx);
@ -123,14 +127,42 @@ private:
void _CacheAmxOpcodeList(); void _CacheAmxOpcodeList();
int _GetOpcodeFromCip(cell cip, cell *&addr); int _GetOpcodeFromCip(cell cip, cell *&addr);
cell _CipAsVa(cell cip); cell _CipAsVa(cell cip);
const char *_GetFilename();
public: public:
AMX *m_pAmx; AMX *m_pAmx;
AMX_DBG *m_pAmxDbg; AMX_DBG *m_pAmxDbg;
int m_Top; int m_Top;
cell *m_pOpcodeList; cell *m_pOpcodeList;
String m_FileName;
CVector<Tracer *> m_pCalls; CVector<Tracer *> m_pCalls;
}; };
typedef Debugger::Tracer::trace_info trace_info_t; 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_ #endif //_INCLUDE_DEBUGGER_H_

View File

@ -1289,6 +1289,29 @@ void LogError(AMX *amx, int err, const char *fmt, ...)
Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER]; Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER];
amx->error = err; 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); CPluginMngr::CPlugin *pl = g_plugins.findPluginFast(amx);
const char *filename = ""; const char *filename = "";
@ -1300,53 +1323,17 @@ void LogError(AMX *amx, int err, const char *fmt, ...)
if (a) if (a)
filename = (*a).getName(); 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) if (fmt != NULL)
AMXXLOG_Log("%s", msg_buffer); AMXXLOG_Log("%s", msg_buffer);
if (!pDebugger)
{
//give the module's error first. makes the report look nicer. //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] 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)."); 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 //destroy original error code so the original is not displayed again
amx->error = -1; amx->error = -1;
return; } else {
}
pDebugger->SetTracedError(err); pDebugger->SetTracedError(err);
//we can display error now
char buffer[512]; pDebugger->DisplayTrace(fmt ? msg_buffer : NULL);
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);
} }
} }