New debugging engine

This commit is contained in:
David Anderson 2004-09-15 21:21:46 +00:00
parent 0c2dbdbc47
commit d3751054da
6 changed files with 273 additions and 7 deletions

View File

@ -110,7 +110,8 @@ cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays)
int err = amx_Execv(iter->pPlugin->getAMX(), &retVal, iter->func, m_NumParams, realParams);
// log runtime error, if any
if (err != AMX_ERR_NONE)
AMXXLOG_Log("[AMXX] Run time error %d on line %ld (plugin \"%s\")", err, iter->pPlugin->getAMX()->curline, iter->pPlugin->getName());
LogError(iter->pPlugin->getAMX(), err, "");
// AMXXLOG_Log("[AMXX] Run time error %d on line %ld (plugin \"%s\")", err, iter->pPlugin->getAMX()->curline, iter->pPlugin->getName());
// cleanup strings & arrays
for (i = 0; i < m_NumParams; ++i)

View File

@ -39,11 +39,13 @@
# endif
#endif
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h> /* for wchar_t */
#include <string.h>
#include <malloc.h>
#include "osdefs.h"
#if defined LINUX
#include <sclinux.h>
@ -479,6 +481,62 @@ int AMXAPI amx_Debug(AMX *amx)
return AMX_ERR_DEBUG;
}
//Here is the actual debugger that AMX Mod X uses
int AMXAPI amx_DebugCall(AMX *amx, int mode)
{
//right away, check for debugging
AMX_HEADER *hdr;
AMX_DBG *p = 0;
AMX_TRACE *t = 0;
hdr = (AMX_HEADER *)amx->base;
if ( !(amx->flags & AMX_FLAG_DEBUG) || !(amx->flags & AMX_FLAG_LINEOPS))
return AMX_ERR_NONE;
p = (AMX_DBG *)(amx->userdata[0]);
if ( !p )
return AMX_ERR_NONE;
if (mode == 2)
{
//mode - push onto the stack
t = (AMX_TRACE *)malloc(sizeof(AMX_TRACE));
memset(t, 0, sizeof(AMX_TRACE));
if (!p->head)
{
p->head = t;
t->prev = NULL;
} else {
t->prev = p->tail;
p->tail->next = t;
}
p->tail = t;
t->line = amx->curline;
t->file = amx->curfile;
} else if (mode == 1) {
//mode <0 - pop from the stack
t = p->tail;
if (t)
{
p->tail = t->prev;
free(t);
}
if (p->tail == NULL)
p->head = NULL;
} else if (mode == 0) {
AMX_TRACE *m;
//mode == 0 - clear stack
t = p->head;
while (t)
{
m = t->next;
free(t);
t = m;
}
p->head = 0;
p->tail = 0;
}
return AMX_ERR_NONE;
}
#if defined JIT
#if defined WIN32 || defined __cplusplus
extern "C" int AMXAPI getMaxCodeSize(void);
@ -536,6 +594,20 @@ static int amx_BrowseRelocate(AMX *amx)
amx->flags=AMX_FLAG_BROWSE;
/* check the debug hook */
if ((hdr->flags & AMX_FLAG_LINEOPS) && !(hdr->flags & AMX_FLAG_TRACED))
{
amx->userdata[0] = (AMX_DBG *)malloc(sizeof(AMX_DBG));
amx->userdata[1] = (void *)amx_DebugCall;
memset(amx->userdata[0], 0, sizeof(AMX_DBG));
amx->flags |= AMX_FLAG_LINEOPS;
amx->flags |= AMX_FLAG_TRACED;
amx->flags |= AMX_FLAG_DEBUG;
} else {
amx->userdata[0] = 0;
amx->userdata[1] = 0;
}
#if defined __GNUC__ || defined ASM32 || defined JIT && !defined __64BIT__
amx_Exec(amx, (cell*)&opcode_list, 0, 0);
#if !defined JIT
@ -715,6 +787,20 @@ static int amx_BrowseRelocate(AMX *amx)
DBGPARAM(amx->curfile);
amx->dbgname=(char *)(code+(int)cip);
cip+=num - sizeof(cell);
if (!(hdr->flags & AMX_FLAG_TRACED) && amx->userdata[0] != NULL)
{
AMX_DBG *pDbg = (AMX_DBG *)(amx->userdata[0]);
if (pDbg->numFiles == 0)
{
pDbg->numFiles++;
pDbg->files = (char **)malloc(sizeof(char *) * 1);
} else {
pDbg->numFiles++;
pDbg->files = (char **)realloc(pDbg->files, pDbg->numFiles * sizeof(char*));
}
pDbg->files[pDbg->numFiles-1] = (char *)malloc((sizeof(char) * strlen(amx->dbgname)) + 1);
strcpy(pDbg->files[pDbg->numFiles-1], amx->dbgname);
} /* if */
break;
} /* case */
case OP_LINE:
@ -765,6 +851,7 @@ static int amx_BrowseRelocate(AMX *amx)
amx->flags &= ~AMX_FLAG_BROWSE;
amx->flags |= AMX_FLAG_RELOC;
amx->flags |= AMX_FLAG_TRACED;
return AMX_ERR_NONE;
}
@ -1721,6 +1808,8 @@ static void *amx_opcodelist_nodebug[] = {
ucell codesize;
int num,i;
va_list ap;
AMX_DEBUGCALL tracer = 0;
AMX_DBG *pdbg = 0;
/* HACK: return label table (for amx_BrowseRelocate) if amx structure
* has the AMX_FLAG_BROWSE flag set.
@ -1824,6 +1913,20 @@ static void *amx_opcodelist_nodebug[] = {
/* check stack/heap before starting to run */
CHKMARGIN();
if ((amx->flags & AMX_FLAG_DEBUG) && (amx->flags & AMX_FLAG_LINEOPS))
{
if (amx->userdata[0])
{
tracer = (AMX_DEBUGCALL)amx->userdata[1];
pdbg = (AMX_DBG *)(amx->userdata[0]);
if (tracer)
{
//as a precaution, clear the call stack
(tracer)(amx, 0);
}
}
}
/* start running */
NEXT(cip);
@ -2108,6 +2211,10 @@ static void *amx_opcodelist_nodebug[] = {
CHKMARGIN();
NEXT(cip);
op_ret:
if (tracer)
{
(tracer)(amx, 1);
}
POP(frm);
POP(offs);
/* verify the return address */
@ -2116,6 +2223,10 @@ static void *amx_opcodelist_nodebug[] = {
cip=(cell *)(code+(int)offs);
NEXT(cip);
op_ret_nodebug:
if (tracer)
{
(tracer)(amx, 1);
}
POP(frm);
POP(offs);
/* verify the return address */
@ -2124,6 +2235,10 @@ static void *amx_opcodelist_nodebug[] = {
cip=(cell *)(code+(int)offs);
NEXT(cip);
op_retn:
if (tracer)
{
(tracer)(amx, 1);
}
POP(frm);
POP(offs);
/* verify the return address */
@ -2133,6 +2248,10 @@ static void *amx_opcodelist_nodebug[] = {
stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */
NEXT(cip);
op_retn_nodebug:
if (tracer)
{
(tracer)(amx, 1);
}
POP(frm);
POP(offs);
/* verify the return address */
@ -2142,18 +2261,34 @@ static void *amx_opcodelist_nodebug[] = {
stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */
NEXT(cip);
op_call:
if (tracer)
{
(tracer)(amx, 2);
}
PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */
cip=JUMPABS(code, cip); /* jump to the address */
NEXT(cip);
op_call_nodebug:
if (tracer)
{
(tracer)(amx, 2);
}
PUSH(((unsigned char *)cip-code)+sizeof(cell));/* push address behind instruction */
cip=JUMPABS(code, cip); /* jump to the address */
NEXT(cip);
op_call_pri:
if (tracer)
{
(tracer)(amx, 2);
}
PUSH((unsigned char *)cip-code);
cip=(cell *)(code+(int)pri);
NEXT(cip);
op_call_pri_nodebug:
if (tracer)
{
(tracer)(amx, 2);
}
PUSH((unsigned char *)cip-code);
cip=(cell *)(code+(int)pri);
NEXT(cip);
@ -2697,6 +2832,8 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...)
cell offs;
int num;
#endif
AMX_DEBUGCALL tracer = 0;
AMX_DBG *pdbg = 0;
#if defined ASM32 || defined JIT
/* HACK: return label table (for amx_BrowseRelocate) if amx structure
@ -2718,6 +2855,16 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...)
} /* if */
#endif
if ((amx->flags & AMX_FLAG_DEBUG) && (amx->flags & AMX_FLAG_LINEOPS))
{
if (amx->userdata[0])
{
tracer = (AMX_DEBUGCALL)amx->userdata[1];
pdbg = (AMX_DBG *)(amx->userdata[0]);
}
}
if (amx->callback==NULL)
return AMX_ERR_CALLBACK;
i=amx_Register(amx,NULL,0); /* verify that all natives are registered */
@ -3134,10 +3281,18 @@ int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...)
cip=(cell *)(code+(int)offs);
stk+= *(cell *)(data+(int)stk) + sizeof(cell); /* remove parameters from the stack */
amx->stk=stk;
if (tracer)
{
(tracer)(amx, 1);
}
break;
case OP_CALL:
PUSH(((unsigned char *)cip-code)+sizeof(cell));/* skip address */
cip=JUMPABS(code, cip); /* jump to the address */
if (tracer)
{
(tracer)(amx, 2);
}
break;
case OP_CALL_PRI:
PUSH((unsigned char *)cip-code);

View File

@ -255,6 +255,7 @@ void free_amxmemory(void **ptr);
// get_localinfo
const char* get_localinfo( const char* name , const char* def );
cell AMX_NATIVE_CALL require_module(AMX *amx, cell *params);
void LogError(AMX *amx, int err, const char *fmt, ...);
enum ModuleCallReason
{

View File

@ -106,7 +106,7 @@ int g_srvindex;
cvar_t init_amxmodx_version = {"amxmodx_version", "", FCVAR_SERVER | FCVAR_SPONLY};
cvar_t init_amxmodx_modules = {"amxmodx_modules", "", FCVAR_SPONLY};
cvar_t init_amxmodx_debug = {"amx_debug", "", FCVAR_SPONLY};
cvar_t init_amxmodx_debug = {"amx_debug", "1", FCVAR_SPONLY};
cvar_t* amxmodx_version = NULL;
cvar_t* amxmodx_modules = NULL;
cvar_t* hostname = NULL;

View File

@ -153,7 +153,6 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64
//automatic debug mode
hdr->flags |= AMX_FLAG_LINEOPS;
hdr->flags |= AMX_FLAG_DEBUG;
printf("init flags:= %d\n", hdr->flags);
}
int err;
@ -1110,6 +1109,117 @@ void MNF_Log(const char *fmt, ...)
AMXXLOG_Log("%s", msg);
}
//by BAILOPAN
// generic error printing routine
void GenericError(AMX *amx, int err, int line, char buf[], const char *file)
{
static const char *amx_errs[] =
{
NULL,
"forced exit",
"assertion failed",
"stack error",
"index out of bounds",
"memory access",
"invalid instruction",
"stack low",
"heap low",
"callback",
"native",
"divide",
"sleep",
NULL,
NULL,
NULL,
"out of memory", //16
"bad file format",
"bad file version",
"function not found",
"invalid entry point",
"debugger cannot run",
"plugin un or re-initialized",
"userdata table full",
"JIT failed to initialize",
"parameter error",
"domain error",
};
//does this plugin have line ops?
const char *geterr = NULL;
if (err > 26 || err < 0)
geterr = NULL;
else
geterr = amx_errs[err];
if (!(amx->flags & AMX_FLAG_LINEOPS))
{
if (geterr == NULL)
{
sprintf(buf, "Run time error %d (plugin \"%s\" - debug not enabled).", err, g_plugins.findPluginFast(amx)->getName());
} else {
sprintf(buf, "Run time error %d (%s) (plugin \"%s\") - debug not enabled.", err, geterr, g_plugins.findPluginFast(amx)->getName());
}
} else {
if (geterr == NULL)
{
sprintf(buf, "Run time error %d on line %d (%s \"%s\").", err, line, (file?"file":"plugin"), (file?file:g_plugins.findPluginFast(amx)->getName()));
} else {
sprintf(buf, "Run time error %d (%s) on line %d (%s \"%s\").", err, geterr, line, (file?"file":"plugin"), (file?file:g_plugins.findPluginFast(amx)->getName()));
}
}
}
//by BAILOPAN
// debugger engine front end
void LogError(AMX *amx, int err, const char *fmt, ...)
{
//does this plugin have debug info?
va_list arg;
AMX_DBG *dbg = (AMX_DBG *)(amx->userdata[0]);
static char buf[1024];
static char vbuf[1024];
*buf = 0;
*vbuf = 0;
va_start(arg, fmt);
vsprintf(vbuf, fmt, arg);
va_end(arg);
if (!dbg || !(dbg->tail))
{
GenericError(amx, err, amx->curline, buf, NULL);
AMXXLOG_Log("[AMXX] %s %s", buf, vbuf);
} else {
AMX_TRACE *t = dbg->tail;
AMX_DEBUGCALL tracer = (AMX_DEBUGCALL)(amx->userdata[1]);
//actuall
cell line = amx->curline;
cell file = amx->curfile;
int i = 0;
if (file >= dbg->numFiles || file < 0)
{
GenericError(amx, err, line, buf, NULL);
} else {
GenericError(amx, err, line, buf, dbg->files[file]);
}
AMXXLOG_Log("[AMXX] %s %s", buf, vbuf);
AMXXLOG_Log("[AMXX] Debug Trace =>");
//log the error right away
while (t != NULL)
{
line = t->line;
file = t->file;
if (file >= dbg->numFiles)
{
AMXXLOG_Log("[AMXX] [%d] Line %d, Plugin \"%s\"", i++, line, g_plugins.findPluginFast(amx)->getName());
} else {
AMXXLOG_Log("[AMXX] [%d] Line %d, Plugin \"%s\"", i++, line, dbg->files[file]);
}
if (tracer)
(tracer)(amx, 1); //pop
t = dbg->tail;
}
}
}
void MNF_MergeDefinitionFile(const char *file)
{
g_langMngr.MergeDefinitionFile(file);

View File

@ -283,10 +283,9 @@ void plugin_srvcmd()
if ((err = amx_Exec( (*a).getPlugin()->getAMX(), &ret , (*a).getFunction()
, 3 , g_srvindex , (*a).getFlags() , (*a).getId() )) != AMX_ERR_NONE)
AMXXLOG_Log("[AMXX] Run time error %d on line %ld (plugin \"%s\")",
err,(*a).getPlugin()->getAMX()->curline,(*a).getPlugin()->getName());
{
LogError((*a).getPlugin()->getAMX(), err, "");
}
if ( ret ) break;
}