Finalized new debugging system

This commit is contained in:
David Anderson 2005-09-11 03:58:38 +00:00
parent 401ee3c97f
commit 760e29e531
8 changed files with 515 additions and 241 deletions

View File

@ -35,6 +35,7 @@
#include "CFile.h" #include "CFile.h"
#include "amx.h" #include "amx.h"
#include "natives.h" #include "natives.h"
#include "debugger.h"
extern const char *no_function; extern const char *no_function;
@ -220,6 +221,56 @@ CPluginMngr::CPlugin::~CPlugin( )
unload_amxscript( &amx, &code ); unload_amxscript( &amx, &code );
} }
int AMXAPI native_handler(AMX *amx, int index)
{
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
char name[sNAMEMAX+1];
amx_GetNative(amx, index, name);
return pHandler->HandleNative(name, index, 0);
}
static cell AMX_NATIVE_CALL invalid_native(AMX *amx, cell *params)
{
//A script has accidentally called an invalid native! give them a
// first chance to block the resulting error.
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
//this should never happen
if (!pHandler)
{
LogError(amx, AMX_ERR_INVNATIVE, "Invalid native attempt");
return 0;
}
//this should never happen because this native won't be called
// if the plugin isn't filtering.
if (!pHandler->IsNativeFiltering())
{
LogError(amx, AMX_ERR_INVNATIVE, "Invalid native attempt");
return 0;
}
char name[sNAMEMAX+1];
int native = amx->usertags[UT_NATIVE];
int err = amx_GetNative(amx, native, name);
if (err != AMX_ERR_NONE)
name[0] = '\0';
//1 - because we're trapping usage
if (!pHandler->HandleNative(name, native, 1))
{
LogError(amx, AMX_ERR_INVNATIVE, NULL);
return 0;
}
//Someday maybe allow native filters to write their own return value?
return 0;
}
void CPluginMngr::CPlugin::Finalize() void CPluginMngr::CPlugin::Finalize()
{ {
char buffer[128]; char buffer[128];
@ -228,11 +279,20 @@ void CPluginMngr::CPlugin::Finalize()
if (CheckModules(&amx, buffer)) if (CheckModules(&amx, buffer))
{ {
if ( amx_Register(&amx, core_Natives, -1) != AMX_ERR_NONE ) if ( amx_Register(&amx, core_Natives, -1) != AMX_ERR_NONE )
{
Handler *pHandler = (Handler *)amx.userdata[UD_HANDLER];
int res = 0;
if (pHandler->IsNativeFiltering())
res = amx_CheckNatives(&amx, native_handler);
if (!res)
{ {
status = ps_bad_load; status = ps_bad_load;
sprintf(buffer, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function); sprintf(buffer, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function);
errorMsg.assign(buffer); errorMsg.assign(buffer);
amx.error = AMX_ERR_NOTFOUND; amx.error = AMX_ERR_NOTFOUND;
} else {
amx_RegisterToAny(&amx, invalid_native);
}
} }
} else { } else {
status = ps_bad_load; status = ps_bad_load;

View File

@ -425,10 +425,7 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params)
AMX_FUNCSTUB *func; AMX_FUNCSTUB *func;
AMX_NATIVE f; AMX_NATIVE f;
assert(amx!=NULL);
hdr=(AMX_HEADER *)amx->base; hdr=(AMX_HEADER *)amx->base;
assert(hdr!=NULL);
assert(hdr->magic==AMX_MAGIC);
assert(hdr->natives<=hdr->libraries); assert(hdr->natives<=hdr->libraries);
#if defined AMX_NATIVETABLE #if defined AMX_NATIVETABLE
if (index<NULL) { if (index<NULL) {
@ -444,40 +441,10 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params)
#endif #endif
assert(f!=NULL); assert(f!=NULL);
/* Now that we have found the function, patch the program so that any /* As of AMX Mod X 1.56, we don't patch sysreq.c to sysreq.d anymore.
* subsequent call will call the function directly (bypassing this * Otherwise, we'd have no way of knowing the last native to be used.
* callback).
* This trick cannot work in the JIT, because the program would need to
* be re-JIT-compiled after patching a P-code instruction.
*/ */
#if !defined JIT amx->usertags[UT_NATIVE] = (long)index;
if (amx->sysreq_d != 0)
{
//if we're about to patch this, and we're debugging, don't patch!
//otherwise we won't be able to get back native names
if (amx->flags & AMX_FLAG_DEBUG)
{
amx->sysreq_d = 0;
} else {
/* at the point of the call, the CIP pseudo-register points directly
* behind the SYSREQ instruction and its parameter.
*/
unsigned char *code=amx->base+(int)hdr->cod+(int)amx->cip-4;
assert(amx->cip >= 4 && amx->cip < (hdr->dat - hdr->cod));
assert(sizeof(f)<=sizeof(cell)); /* function pointer must fit in a cell */
#if defined __GNUC__ || defined ASM32
if (*(cell*)code==index) {
#else
if (*(cell*)code!=OP_SYSREQ_PRI) {
assert(*(cell*)(code-sizeof(cell))==OP_SYSREQ_C);
assert(*(cell*)code==index);
#endif //defined __GNU__ || defined ASM32
*(cell*)(code-sizeof(cell))=amx->sysreq_d;
*(cell*)code=(cell)f;
} /* if */
} /* if */
} /* if */
#endif //!defined JIT
/* Note: /* Note:
* params[0] == number of bytes for the additional parameters passed to the native function * params[0] == number of bytes for the additional parameters passed to the native function
@ -486,7 +453,9 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params)
*/ */
amx->error=AMX_ERR_NONE; amx->error=AMX_ERR_NONE;
*result = f(amx,params); *result = f(amx,params);
return amx->error; return amx->error;
} }
#endif /* defined AMX_INIT */ #endif /* defined AMX_INIT */
@ -1571,6 +1540,61 @@ static AMX_NATIVE findfunction(const char *name, const AMX_NATIVE_INFO *list, in
} }
const char *no_function; const char *no_function;
int AMXAPI amx_CheckNatives(AMX *amx, AMX_NATIVE_FILTER nf)
{
AMX_FUNCSTUB *func;
AMX_HEADER *hdr;
int i,numnatives,res=0;
hdr=(AMX_HEADER *)amx->base;
assert(hdr!=NULL);
assert(hdr->magic==AMX_MAGIC);
assert(hdr->natives<=hdr->libraries);
numnatives=NUMENTRIES(hdr,natives,libraries);
func=GETENTRY(hdr,natives,0);
for (i=0; i<numnatives; i++) {
if (func->address==0) {
/* this function is not yet located */
res=nf(amx,i);
if (!res)
{
no_function = GETENTRYNAME(hdr,func);
return 0;
}
} /* if */
func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize);
} /* for */
return 1;
}
int AMXAPI amx_RegisterToAny(AMX *amx, AMX_NATIVE f)
{
AMX_FUNCSTUB *func;
AMX_HEADER *hdr;
int i,numnatives,err;
hdr=(AMX_HEADER *)amx->base;
assert(hdr!=NULL);
assert(hdr->magic==AMX_MAGIC);
assert(hdr->natives<=hdr->libraries);
numnatives=NUMENTRIES(hdr,natives,libraries);
err=AMX_ERR_NONE;
func=GETENTRY(hdr,natives,0);
for (i=0; i<numnatives; i++) {
if (func->address==0) {
/* this function is not yet located */
func->address=(ucell)f;
} /* if */
func=(AMX_FUNCSTUB*)((unsigned char*)func+hdr->defsize);
} /* for */
if (err==AMX_ERR_NONE)
amx->flags|=AMX_FLAG_NTVREG;
return err;
}
int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *list, int number) int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *list, int number)
{ {
AMX_FUNCSTUB *func; AMX_FUNCSTUB *func;

View File

@ -166,6 +166,7 @@ typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params);
typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index, typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index,
cell *result, cell *params); cell *result, cell *params);
typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
typedef int (AMXAPI *AMX_NATIVE_FILTER)(struct tagAMX *amx, int index);
#if !defined _FAR #if !defined _FAR
#define _FAR #define _FAR
#endif #endif
@ -301,6 +302,7 @@ enum {
AMX_ERR_DIVIDE, /* divide by zero */ AMX_ERR_DIVIDE, /* divide by zero */
AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
AMX_ERR_INVSTATE, /* invalid state for this access */ AMX_ERR_INVSTATE, /* invalid state for this access */
AMX_ERR_INVNATIVE, /* invalid native was used */
AMX_ERR_MEMORY = 16, /* out of memory */ AMX_ERR_MEMORY = 16, /* out of memory */
AMX_ERR_FORMAT, /* invalid file format */ AMX_ERR_FORMAT, /* invalid file format */
@ -340,6 +342,7 @@ enum {
#define UD_DEBUGGER 2 #define UD_DEBUGGER 2
#define UD_OPCODELIST 1 #define UD_OPCODELIST 1
#define UD_HANDLER 0 #define UD_HANDLER 0
#define UT_NATIVE 3
/* 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_
@ -373,6 +376,7 @@ uint32_t * AMXAPI amx_Align32(uint32_t *v);
#endif #endif
int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr); int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr);
int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params); int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params);
int AMXAPI amx_CheckNatives(AMX *amx, AMX_NATIVE_FILTER nf);
int AMXAPI amx_Cleanup(AMX *amx); int AMXAPI amx_Cleanup(AMX *amx);
int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index); int AMXAPI amx_Exec(AMX *amx, cell *retval, int index);
@ -402,6 +406,7 @@ int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell
int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar); int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar);
int AMXAPI amx_RaiseError(AMX *amx, int error); int AMXAPI amx_RaiseError(AMX *amx, int error);
int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number); int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number);
int AMXAPI amx_RegisterToAny(AMX *amx, AMX_NATIVE f);
int AMXAPI amx_Release(AMX *amx, cell amx_addr); int AMXAPI amx_Release(AMX *amx, cell amx_addr);
int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback);
int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug);

View File

@ -3012,174 +3012,198 @@ static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params)
return 1; return 1;
} }
AMX_NATIVE_INFO amxmod_Natives[] = { static cell AMX_NATIVE_CALL amx_abort(AMX *amx, cell *params)
{ "client_cmd", client_cmd }, {
{ "client_print", client_print }, int err = params[1];
{ "console_cmd", console_cmd },
{ "console_print", console_print }, int len;
{ "cvar_exists", cvar_exists }, char *fmt = format_amxstring(amx, params, 2, len);
{ "emit_sound", emit_sound },
{ "engclient_cmd", engclient_cmd }, if (fmt[0] == '\0')
{ "engclient_print", engclient_print }, fmt = NULL;
{ "find_player", find_player },
{ "find_plugin_byfile", find_plugin_byfile }, const char *filename = "";
{ "force_unmodified", force_unmodified }, CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx);
{ "format_time", format_time}, if (pPlugin)
{ "get_clcmd", get_clcmd}, filename = pPlugin->getName();
{ "get_clcmdsnum", get_clcmdsnum},
{ "get_concmd", get_concmd}, if (fmt)
{ "get_concmdsnum", get_concmdsnum}, LogError(amx, err, "[%s] %s", filename, fmt);
{ "get_cvar_flags", get_cvar_flags }, else
{ "get_cvar_float", get_cvar_float }, LogError(amx, err, NULL);
{ "get_cvar_num", get_cvar_num },
{ "get_cvar_string", get_cvar_string }, return 1;
{ "get_distance", get_distance }, }
{ "get_distance_f", get_distance_f },
{ "get_flags", get_flags }, AMX_NATIVE_INFO amxmodx_Natives[] = {
{ "get_gametime", get_gametime}, {"abort", amx_abort},
{ "get_localinfo", get_localinfo}, {"callfunc_begin", callfunc_begin},
{ "get_mapname", get_mapname}, {"callfunc_begin_i", callfunc_begin_i},
{ "get_maxplayers", get_maxplayers }, {"callfunc_end", callfunc_end},
{ "get_modname", get_modname}, {"callfunc_push_int", callfunc_push_byval},
{ "get_players", get_players }, {"callfunc_push_float", callfunc_push_byval},
{ "get_playersnum", get_playersnum }, {"callfunc_push_intrf", callfunc_push_byref},
{ "get_plugin", get_plugin }, {"callfunc_push_floatrf", callfunc_push_byref},
{ "get_pluginsnum", get_pluginsnum }, {"callfunc_push_str", callfunc_push_str},
{ "get_srvcmd", get_srvcmd }, {"client_cmd", client_cmd},
{ "get_srvcmdsnum", get_srvcmdsnum }, {"client_print", client_print},
{ "get_systime", get_systime}, {"console_cmd", console_cmd},
{ "get_time", get_time}, {"console_print", console_print},
{ "get_timeleft", get_timeleft}, {"cvar_exists", cvar_exists},
{ "get_user_aiming", get_user_aiming }, {"emit_sound", emit_sound},
{ "get_user_ammo", get_user_ammo}, {"engclient_cmd", engclient_cmd},
{ "get_user_armor", get_user_armor }, {"engclient_print", engclient_print},
{ "get_user_attacker",get_user_attacker }, {"find_player", find_player},
{ "get_user_authid", get_user_authid }, {"find_plugin_byfile", find_plugin_byfile},
{ "get_user_flags", get_user_flags }, {"force_unmodified", force_unmodified},
{ "get_user_frags", get_user_frags }, {"format_time", format_time},
{ "get_user_deaths", get_user_deaths }, {"get_clcmd", get_clcmd},
{ "get_user_health", get_user_health }, {"get_clcmdsnum", get_clcmdsnum},
{ "get_user_index", get_user_index }, {"get_concmd", get_concmd},
{ "get_user_info", get_user_info }, {"get_concmdsnum", get_concmdsnum},
{ "get_user_ip", get_user_ip }, {"get_cvar_flags", get_cvar_flags},
{ "get_user_menu", get_user_menu}, {"get_cvar_float", get_cvar_float},
{ "get_user_msgid", get_user_msgid}, {"get_cvar_num", get_cvar_num},
{ "get_user_msgname", get_user_msgname}, {"get_cvar_string", get_cvar_string},
{ "get_user_name", get_user_name }, {"get_distance", get_distance},
{ "get_user_origin", get_user_origin}, {"get_distance_f", get_distance_f},
{ "get_user_ping", get_user_ping }, {"get_flags", get_flags},
{ "get_user_team", get_user_team }, {"get_func_id", get_func_id},
{ "get_user_time", get_user_time }, {"get_gametime", get_gametime},
{ "get_user_userid", get_user_userid }, {"get_lang", get_lang},
{ "hcsardhnExsnu", register_byval }, {"get_langsnum", get_langsnum},
{ "user_has_weapon", user_has_weapon }, {"get_localinfo", get_localinfo},
{ "get_user_weapon", get_user_weapon}, {"get_mapname", get_mapname},
{ "get_user_weapons", get_user_weapons}, {"get_maxplayers", get_maxplayers},
{ "get_weaponname", get_weaponname}, {"get_modname", get_modname},
{ "get_xvar_float", get_xvar_num }, {"get_module", get_module},
{ "get_xvar_id", get_xvar_id }, {"get_modulesnum", get_modulesnum},
{ "get_xvar_num", get_xvar_num }, {"get_players", get_players},
{ "is_dedicated_server",is_dedicated_server }, {"get_playersnum", get_playersnum},
{ "is_linux_server", is_linux_server }, {"get_plugin", get_plugin},
{ "is_amd64_server", is_amd64_server }, {"get_pluginsnum", get_pluginsnum},
{ "is_jit_enabled", is_jit_enabled }, {"get_srvcmd", get_srvcmd},
{ "is_user_authorized", is_user_authorized }, {"get_srvcmdsnum", get_srvcmdsnum},
{ "is_map_valid", is_map_valid }, {"get_systime", get_systime},
{ "is_user_alive", is_user_alive }, {"get_time", get_time},
{ "is_user_bot", is_user_bot }, {"get_timeleft", get_timeleft},
{ "is_user_connected", is_user_connected }, {"get_user_aiming", get_user_aiming},
{ "is_user_connecting", is_user_connecting }, {"get_user_ammo", get_user_ammo},
{ "is_user_hltv", is_user_hltv }, {"get_user_armor", get_user_armor},
{ "log_message", log_message }, {"get_user_attacker", get_user_attacker},
{ "log_to_file", log_to_file }, {"get_user_authid", get_user_authid},
{ "num_to_word", num_to_word }, {"get_user_flags", get_user_flags},
{ "parse_loguser", parse_loguser }, {"get_user_frags", get_user_frags},
{ "parse_time", parse_time }, {"get_user_deaths", get_user_deaths},
{ "pause", pause }, {"get_user_health", get_user_health},
{ "precache_model", precache_model }, {"get_user_index", get_user_index},
{ "precache_sound", precache_sound }, {"get_user_info", get_user_info},
{ "random_float", random_float }, {"get_user_ip", get_user_ip},
{ "random_num", random_num }, {"get_user_menu", get_user_menu},
{ "read_argc", read_argc }, {"get_user_msgid", get_user_msgid},
{ "read_args", read_args }, {"get_user_msgname", get_user_msgname},
{ "read_argv", read_argv }, {"get_user_name", get_user_name},
{ "read_data", read_data }, {"get_user_origin", get_user_origin},
{ "read_datanum", read_datanum }, {"get_user_ping", get_user_ping},
{ "read_flags", read_flags }, {"get_user_team", get_user_team},
{ "read_logargc", read_logargc }, {"get_user_time", get_user_time},
{ "read_logargv", read_logargv }, {"get_user_userid", get_user_userid},
{ "read_logdata", read_logdata }, {"hcsardhnexsnu", register_byval},
{ "register_clcmd", register_clcmd }, {"user_has_weapon", user_has_weapon},
{ "register_concmd", register_concmd }, {"get_user_weapon", get_user_weapon},
{ "register_cvar", register_cvar }, {"get_user_weapons", get_user_weapons},
{ "register_event", register_event }, {"get_weaponname", get_weaponname},
{ "register_logevent",register_logevent}, {"get_xvar_float", get_xvar_num},
{ "register_menucmd", register_menucmd }, {"get_xvar_id", get_xvar_id},
{ "register_menuid", register_menuid }, {"get_xvar_num", get_xvar_num},
{ "require_module", require_module }, {"int3", int3},
{ "register_plugin", register_plugin }, {"is_amd64_server", is_amd64_server},
{ "register_srvcmd", register_srvcmd }, {"is_dedicated_server", is_dedicated_server},
{ "remove_cvar_flags", remove_cvar_flags }, {"is_jit_enabled", is_jit_enabled},
{ "remove_quotes", remove_quotes }, {"is_linux_server", is_linux_server},
{ "remove_task", remove_task }, {"is_map_valid", is_map_valid},
{ "change_task", change_task }, {"is_module_loaded", is_module_loaded},
{ "remove_user_flags", remove_user_flags }, {"is_plugin_loaded", is_plugin_loaded},
{ "server_cmd", server_cmd }, {"is_user_alive", is_user_alive},
{ "server_exec", server_exec }, {"is_user_authorized", is_user_authorized},
{ "server_print", server_print }, {"is_user_bot", is_user_bot},
{ "set_cvar_flags", set_cvar_flags }, {"is_user_connected", is_user_connected},
{ "set_cvar_float", set_cvar_float }, {"is_user_connecting", is_user_connecting},
{ "set_cvar_num", set_cvar_num }, {"is_user_hltv", is_user_hltv},
{ "set_cvar_string", set_cvar_string }, {"lang_exists", lang_exists},
{ "set_hudmessage", set_hudmessage }, {"lang_phrase", lang_phrase},
{ "set_localinfo", set_localinfo}, {"log_amx", log_amx},
{ "set_task", set_task }, {"log_message", log_message},
{ "set_user_flags", set_user_flags}, {"log_to_file", log_to_file},
{ "set_user_info", set_user_info }, {"md5", amx_md5},
{ "set_xvar_float", set_xvar_num }, {"md5_file", amx_md5_file},
{ "set_xvar_num", set_xvar_num }, {"message_begin", message_begin},
{ "show_hudmessage", show_hudmessage }, {"message_end", message_end},
{ "show_menu", show_menu }, {"mkdir", amx_mkdir},
{ "show_motd", show_motd }, {"num_to_word", num_to_word},
{ "task_exists", task_exists }, {"parse_loguser", parse_loguser},
{ "unpause", unpause }, {"parse_time", parse_time},
{ "user_kill", user_kill }, {"pause", pause},
{ "user_slap", user_slap }, {"plugin_flags", plugin_flags},
{ "xvar_exists", xvar_exists }, {"precache_model", precache_model},
{ "is_module_loaded", is_module_loaded }, {"precache_sound", precache_sound},
{ "is_plugin_loaded", is_plugin_loaded }, {"query_client_cvar", query_client_cvar},
{ "get_modulesnum", get_modulesnum }, {"random_float", random_float},
{ "get_module", get_module }, {"random_num", random_num},
{ "log_amx", log_amx }, {"read_argc", read_argc},
{ "get_func_id", get_func_id }, {"read_args", read_args},
{ "callfunc_begin", callfunc_begin }, {"read_argv", read_argv},
{ "callfunc_begin_i", callfunc_begin_i }, {"read_data", read_data},
{ "callfunc_end", callfunc_end }, {"read_datanum", read_datanum},
{ "callfunc_push_int", callfunc_push_byval }, {"read_flags", read_flags},
{ "callfunc_push_str", callfunc_push_str }, {"read_logargc", read_logargc},
{ "callfunc_push_float", callfunc_push_byval }, {"read_logargv", read_logargv},
{ "callfunc_push_intrf", callfunc_push_byref }, {"read_logdata", read_logdata},
{ "callfunc_push_floatrf", callfunc_push_byref }, {"register_clcmd", register_clcmd},
{ "message_begin", message_begin }, {"register_concmd", register_concmd},
{ "message_end", message_end }, {"register_cvar", register_cvar},
{ "write_angle", write_angle }, {"register_dictionary", register_dictionary},
{ "write_byte", write_byte }, {"register_event", register_event},
{ "write_char", write_char }, {"register_logevent", register_logevent},
{ "write_coord", write_coord }, {"register_menucmd", register_menucmd},
{ "write_entity", write_entity }, {"register_menuid", register_menuid},
{ "write_long", write_long }, {"register_plugin", register_plugin},
{ "write_short", write_short }, {"register_srvcmd", register_srvcmd},
{ "write_string", write_string }, {"require_module", require_module},
{ "get_langsnum", get_langsnum }, {"remove_cvar_flags", remove_cvar_flags},
{ "get_lang", get_lang }, {"remove_quotes", remove_quotes},
{ "register_dictionary", register_dictionary }, {"remove_task", remove_task},
{ "lang_exists", lang_exists }, {"change_task", change_task},
{ "md5", amx_md5 }, {"remove_user_flags", remove_user_flags},
{ "md5_file", amx_md5_file }, {"server_cmd", server_cmd},
{ "plugin_flags", plugin_flags}, {"server_exec", server_exec},
{ "lang_phrase", lang_phrase}, {"server_print", server_print},
{ "mkdir", amx_mkdir}, {"set_cvar_flags", set_cvar_flags},
{ "int3", int3}, {"set_cvar_float", set_cvar_float},
{ "query_client_cvar", query_client_cvar }, {"set_cvar_num", set_cvar_num},
{ NULL, NULL } {"set_cvar_string", set_cvar_string},
{"set_hudmessage", set_hudmessage},
{"set_localinfo", set_localinfo},
{"set_task", set_task},
{"set_user_flags", set_user_flags},
{"set_user_info", set_user_info},
{"set_xvar_float", set_xvar_num},
{"set_xvar_num", set_xvar_num},
{"show_hudmessage", show_hudmessage},
{"show_menu", show_menu},
{"show_motd", show_motd},
{"task_exists", task_exists},
{"unpause", unpause},
{"user_kill", user_kill},
{"user_slap", user_slap},
{"write_angle", write_angle},
{"write_byte", write_byte},
{"write_char", write_char},
{"write_coord", write_coord},
{"write_entity", write_entity},
{"write_long", write_long},
{"write_short", write_short},
{"write_string", write_string},
{"xvar_exists", xvar_exists},
{NULL, NULL}
}; };

View File

@ -74,7 +74,7 @@
extern AMX_NATIVE_INFO core_Natives[]; extern AMX_NATIVE_INFO core_Natives[];
extern AMX_NATIVE_INFO time_Natives[]; extern AMX_NATIVE_INFO time_Natives[];
extern AMX_NATIVE_INFO power_Natives[]; extern AMX_NATIVE_INFO power_Natives[];
extern AMX_NATIVE_INFO amxmod_Natives[]; extern AMX_NATIVE_INFO amxmodx_Natives[];
extern AMX_NATIVE_INFO file_Natives[]; extern AMX_NATIVE_INFO file_Natives[];
extern AMX_NATIVE_INFO float_Natives[]; extern AMX_NATIVE_INFO float_Natives[];
extern AMX_NATIVE_INFO string_Natives[]; extern AMX_NATIVE_INFO string_Natives[];

View File

@ -430,24 +430,25 @@ int Debugger::FormatError(char *buffer, size_t maxLength)
buffer += size; buffer += size;
maxLength -= size; maxLength -= size;
if (error == AMX_ERR_NATIVE) if (error == AMX_ERR_NATIVE || error == AMX_ERR_INVNATIVE)
{ {
char native_name[32]; char native_name[sNAMEMAX+1];
int num = 0; int num = 0;
//go two instructions back /*//go two instructions back
cip -= (sizeof(cell) * 2); cip -= (sizeof(cell) * 2);
int instr = _GetOpcodeFromCip(cip, p_cip); int instr = _GetOpcodeFromCip(cip, p_cip);
if (instr == OP_SYSREQ_C) if (instr == OP_SYSREQ_C)
{ {
num = (int)*p_cip; num = (int)*p_cip;
} else if (instr == OP_SYSREQ_PRI) { }*/
num = (int)m_pAmx->pri; //New code only requires this...
} num = m_pAmx->usertags[UT_NATIVE];
if (num) amx_err = amx_GetNative(m_pAmx, num, native_name);
/*if (num)
amx_err = amx_GetNative(m_pAmx, (int)*p_cip, native_name); amx_err = amx_GetNative(m_pAmx, (int)*p_cip, native_name);
else else
amx_err = AMX_ERR_NOTFOUND; amx_err = AMX_ERR_NOTFOUND;*/
if (!amx_err) //if (!amx_err)
size += _snprintf(buffer, maxLength, "(native \"%s\")", native_name); size += _snprintf(buffer, maxLength, "(native \"%s\")", native_name);
} else if (error == AMX_ERR_BOUNDS) { } else if (error == AMX_ERR_BOUNDS) {
tagAMX_DBG *pDbg = m_pAmxDbg; tagAMX_DBG *pDbg = m_pAmxDbg;
@ -731,7 +732,7 @@ const char *GenericError(int err)
"divide", "divide",
"sleep", "sleep",
"invalid access state", "invalid access state",
NULL, "native not found",
NULL, NULL,
"out of memory", //16 "out of memory", //16
"bad file format", "bad file format",
@ -760,6 +761,9 @@ int AMXAPI Debugger::DebugHook(AMX *amx)
if (!amx || !(amx->flags & AMX_FLAG_DEBUG)) if (!amx || !(amx->flags & AMX_FLAG_DEBUG))
return AMX_ERR_NONE; return AMX_ERR_NONE;
if (amx->flags & AMX_FLAG_PRENIT)
return AMX_ERR_NONE;
pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER]; pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER];
if (!pDebugger) if (!pDebugger)
@ -872,7 +876,7 @@ int Handler::SetErrorHandler(const char *function)
error = amx_FindPublic(m_pAmx, function, &m_iErrFunc); error = amx_FindPublic(m_pAmx, function, &m_iErrFunc);
if (error != AMX_ERR_NONE) if (error != AMX_ERR_NONE && m_iErrFunc < 1)
m_iErrFunc = -1; m_iErrFunc = -1;
return error; return error;
@ -884,7 +888,7 @@ int Handler::SetModuleFilter(const char *function)
error = amx_FindPublic(m_pAmx, function, &m_iModFunc); error = amx_FindPublic(m_pAmx, function, &m_iModFunc);
if (error != AMX_ERR_NONE) if (error != AMX_ERR_NONE && m_iModFunc < 1)
m_iModFunc = -1; m_iModFunc = -1;
return error; return error;
@ -896,7 +900,7 @@ int Handler::SetNativeFilter(const char *function)
error = amx_FindPublic(m_pAmx, function, &m_iNatFunc); error = amx_FindPublic(m_pAmx, function, &m_iNatFunc);
if (error != AMX_ERR_NONE) if (error != AMX_ERR_NONE && !IsNativeFiltering())
m_iNatFunc = -1; m_iNatFunc = -1;
return error; return error;
@ -918,6 +922,94 @@ const char *Handler::GetLastMsg()
return m_MsgCache.c_str(); return m_MsgCache.c_str();
} }
int Handler::HandleModule(const char *module)
{
if (m_iModFunc < 1)
return 0;
/**
* This is the most minimalistic handler of them all
*/
cell hea_addr, *phys_addr, retval;
//temporarily set prenit
m_pAmx->flags |= AMX_FLAG_PRENIT;
amx_PushString(m_pAmx, &hea_addr, &phys_addr, module, 0, 0);
int err = amx_Exec(m_pAmx, &retval, m_iModFunc);
amx_Release(m_pAmx, hea_addr);
m_pAmx->flags &= ~AMX_FLAG_PRENIT;
if (err != AMX_ERR_NONE)
return 0;
return (int)retval;
}
int Handler::HandleNative(const char *native, int index, int trap)
{
if (!IsNativeFiltering())
return 0;
/**
* Our handler here is a bit different from HandleError().
* For one, there is no current error in pDebugger, so we
* don't have to save some states.
*/
m_InNativeFilter = true;
Debugger *pDebugger = (Debugger *)m_pAmx->userdata[UD_DEBUGGER];
if (pDebugger && trap)
pDebugger->BeginExec();
cell hea_addr, *phys_addr, retval;
if (!trap)
m_pAmx->flags |= AMX_FLAG_PRENIT;
amx_Push(m_pAmx, trap);
amx_Push(m_pAmx, index);
amx_PushString(m_pAmx, &hea_addr, &phys_addr, native, 0, 0);
int err = amx_Exec(m_pAmx, &retval, m_iNatFunc);
if (err != AMX_ERR_NONE)
{
//LogError() took care of something for us.
if (err == -1)
{
m_InNativeFilter = false;
amx_Release(m_pAmx, hea_addr);
return 1;
}
if (!trap)
{
AMXXLOG_Log("[AMXX] Runtime failure %d occurred in native filter. Aborting plugin load.", err);
return 0;
}
//handle this manually.
//we need to push this through an error filter, same as executeForwards!
if (pDebugger && pDebugger->ErrorExists())
{
//don't display, it was already handled.
} else if (err != -1) {
LogError(m_pAmx, err, NULL);
}
AMXXLOG_Log("[AMXX] NOTE: Runtime failures in native filters are not good!");
retval = 0;
}
if (!trap)
m_pAmx->flags &= ~AMX_FLAG_PRENIT;
if (pDebugger && trap)
pDebugger->EndExec();
amx_Release(m_pAmx, hea_addr);
m_InNativeFilter = false;
return (int)retval;
}
int Handler::HandleError(const char *msg) int Handler::HandleError(const char *msg)
{ {
if (m_iErrFunc <= 0) if (m_iErrFunc <= 0)
@ -1073,11 +1165,63 @@ static cell AMX_NATIVE_CALL dbg_fmt_error(AMX *amx, cell *params)
return 1; return 1;
} }
static cell AMX_NATIVE_CALL set_native_filter(AMX *amx, cell *params)
{
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
if (!pHandler)
{
Debugger::GenericMessage(amx, AMX_ERR_NOTFOUND);
AMXXLOG_Log("[AMXX] Plugin not initialized correctly.");
return 0;
}
if (!pHandler->IsNativeFiltering())
{
//we can only initialize this during PRENIT
if (! (amx->flags & AMX_FLAG_PRENIT) )
return 0;
}
int len;
char *func = get_amxstring(amx, params[1], 0, len);
int err = pHandler->SetNativeFilter(func);
if (err != AMX_ERR_NONE)
{
Debugger::GenericMessage(amx, AMX_ERR_NOTFOUND);
AMXXLOG_Log("[AMXX] Function not found: %s", function);
return 0;
}
return 1;
}
static cell AMX_NATIVE_CALL set_module_filter(AMX *amx, cell *params)
{
if ( !(amx->flags & AMX_FLAG_PRENIT) )
return -1;
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
if (!pHandler)
return -2;
int len;
char *function = get_amxstring(amx, params[1], 0, len);
return pHandler->SetModuleFilter(function);
}
AMX_NATIVE_INFO g_DebugNatives[] = { AMX_NATIVE_INFO g_DebugNatives[] = {
{"set_error_filter", set_error_filter}, {"set_error_filter", set_error_filter},
{"dbg_trace_begin", dbg_trace_begin}, {"dbg_trace_begin", dbg_trace_begin},
{"dbg_trace_next", dbg_trace_next}, {"dbg_trace_next", dbg_trace_next},
{"dbg_trace_info", dbg_trace_info}, {"dbg_trace_info", dbg_trace_info},
{"dbg_fmt_error", dbg_fmt_error}, {"dbg_fmt_error", dbg_fmt_error},
{"set_native_filter", set_native_filter},
{"set_module_filter", set_module_filter},
{NULL, NULL}, {NULL, NULL},
}; };

View File

@ -159,7 +159,7 @@ public:
int SetModuleFilter(const char *function); int SetModuleFilter(const char *function);
public: public:
int HandleError(const char *msg); int HandleError(const char *msg);
int HandleNative(const char *native); int HandleNative(const char *native, int index, int trap);
int HandleModule(const char *module); int HandleModule(const char *module);
public: public:
bool IsHandling() const { return m_Handling; } bool IsHandling() const { return m_Handling; }
@ -167,12 +167,16 @@ public:
const char *GetLastMsg(); const char *GetLastMsg();
trace_info_t *GetTrace() const { return m_pTrace; } trace_info_t *GetTrace() const { return m_pTrace; }
const char *GetFmtCache() { return m_FmtCache.c_str(); } const char *GetFmtCache() { return m_FmtCache.c_str(); }
bool IsNativeFiltering() { return (m_iNatFunc > 0); }
bool InNativeFilter() { return m_InNativeFilter; }
private: private:
AMX *m_pAmx; AMX *m_pAmx;
int m_iErrFunc; int m_iErrFunc;
int m_iModFunc; int m_iModFunc;
int m_iNatFunc; int m_iNatFunc;
bool m_Handling; bool m_Handling;
//in the future, make this a stack!
bool m_InNativeFilter;
String m_MsgCache; String m_MsgCache;
String m_FmtCache; String m_FmtCache;
trace_info_t *m_pTrace; trace_info_t *m_pTrace;

View File

@ -344,6 +344,7 @@ int CheckModules(AMX *amx, char error[128])
bool isdbi = false; bool isdbi = false;
CList<CModule,const char *>::iterator a; CList<CModule,const char *>::iterator a;
const amxx_module_info_s *info; const amxx_module_info_s *info;
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
for (int i=0; i<numLibraries; i++) for (int i=0; i<numLibraries; i++)
{ {
@ -385,6 +386,11 @@ int CheckModules(AMX *amx, char error[128])
if (!found) if (!found)
found = LibraryExists(buffer); found = LibraryExists(buffer);
if (!found) if (!found)
{
if (pHandler->HandleModule(buffer))
found = true;
}
if (!found)
{ {
sprintf(error, "Module \"%s\" required for plugin. Check modules.ini.", buffer); sprintf(error, "Module \"%s\" required for plugin. Check modules.ini.", buffer);
return 0; return 0;
@ -406,7 +412,7 @@ int set_amxnatives(AMX* amx,char error[128])
amx_Register(amx, string_Natives, -1); amx_Register(amx, string_Natives, -1);
amx_Register(amx, float_Natives, -1); amx_Register(amx, float_Natives, -1);
amx_Register(amx, file_Natives, -1); amx_Register(amx, file_Natives, -1);
amx_Register(amx, amxmod_Natives, -1); amx_Register(amx, amxmodx_Natives, -1);
amx_Register(amx, power_Natives, -1); amx_Register(amx, power_Natives, -1);
amx_Register(amx, time_Natives, -1); amx_Register(amx, time_Natives, -1);
amx_Register(amx, vault_Natives, -1); amx_Register(amx, vault_Natives, -1);
@ -1306,6 +1312,12 @@ void LogError(AMX *amx, int err, const char *fmt, ...)
//give the plugin first chance to handle any sort of error //give the plugin first chance to handle any sort of error
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER]; Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
if (pHandler->InNativeFilter())
{
if (pDebugger)
pDebugger->EndExec();
} else {
if (pHandler) if (pHandler)
{ {
if (pHandler->IsHandling()) if (pHandler->IsHandling())
@ -1321,6 +1333,7 @@ void LogError(AMX *amx, int err, const char *fmt, ...)
return; return;
} }
} }
}
if (!pDebugger) if (!pDebugger)
{ {