From 760e29e53112dddddf11e9346c2800372e92e384 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 11 Sep 2005 03:58:38 +0000 Subject: [PATCH] Finalized new debugging system --- amxmodx/CPlugin.cpp | 68 +++++++- amxmodx/amx.cpp | 96 +++++++----- amxmodx/amx.h | 5 + amxmodx/amxmodx.cpp | 364 +++++++++++++++++++++++-------------------- amxmodx/amxmodx.h | 10 +- amxmodx/debugger.cpp | 170 ++++++++++++++++++-- amxmodx/debugger.h | 6 +- amxmodx/modules.cpp | 37 +++-- 8 files changed, 515 insertions(+), 241 deletions(-) diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp index 9876c964..2acbb670 100755 --- a/amxmodx/CPlugin.cpp +++ b/amxmodx/CPlugin.cpp @@ -35,6 +35,7 @@ #include "CFile.h" #include "amx.h" #include "natives.h" +#include "debugger.h" extern const char *no_function; @@ -220,6 +221,56 @@ CPluginMngr::CPlugin::~CPlugin( ) 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() { char buffer[128]; @@ -229,10 +280,19 @@ void CPluginMngr::CPlugin::Finalize() { if ( amx_Register(&amx, core_Natives, -1) != AMX_ERR_NONE ) { - status = ps_bad_load; - sprintf(buffer, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function); - errorMsg.assign(buffer); - amx.error = AMX_ERR_NOTFOUND; + 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; + sprintf(buffer, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function); + errorMsg.assign(buffer); + amx.error = AMX_ERR_NOTFOUND; + } else { + amx_RegisterToAny(&amx, invalid_native); + } } } else { status = ps_bad_load; diff --git a/amxmodx/amx.cpp b/amxmodx/amx.cpp index 77d8e5e0..391452cc 100755 --- a/amxmodx/amx.cpp +++ b/amxmodx/amx.cpp @@ -425,10 +425,7 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) AMX_FUNCSTUB *func; AMX_NATIVE f; - assert(amx!=NULL); hdr=(AMX_HEADER *)amx->base; - assert(hdr!=NULL); - assert(hdr->magic==AMX_MAGIC); assert(hdr->natives<=hdr->libraries); #if defined AMX_NATIVETABLE if (indexsysreq_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 + amx->usertags[UT_NATIVE] = (long)index; /* Note: * 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; + *result = f(amx,params); + return amx->error; } #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; + +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; iaddress==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; iaddress==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) { AMX_FUNCSTUB *func; diff --git a/amxmodx/amx.h b/amxmodx/amx.h index c882048b..7ecbf48e 100755 --- a/amxmodx/amx.h +++ b/amxmodx/amx.h @@ -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, cell *result, cell *params); typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); +typedef int (AMXAPI *AMX_NATIVE_FILTER)(struct tagAMX *amx, int index); #if !defined _FAR #define _FAR #endif @@ -301,6 +302,7 @@ enum { AMX_ERR_DIVIDE, /* divide by zero */ AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ AMX_ERR_INVSTATE, /* invalid state for this access */ + AMX_ERR_INVNATIVE, /* invalid native was used */ AMX_ERR_MEMORY = 16, /* out of memory */ AMX_ERR_FORMAT, /* invalid file format */ @@ -340,6 +342,7 @@ enum { #define UD_DEBUGGER 2 #define UD_OPCODELIST 1 #define UD_HANDLER 0 +#define UT_NATIVE 3 /* for native functions that use floating point parameters, the following * 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 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_CheckNatives(AMX *amx, AMX_NATIVE_FILTER nf); int AMXAPI amx_Cleanup(AMX *amx); int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); 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_RaiseError(AMX *amx, int error); 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_SetCallback(AMX *amx, AMX_CALLBACK callback); int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 1aae983b..79e7b73a 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -3012,174 +3012,198 @@ static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params) return 1; } -AMX_NATIVE_INFO amxmod_Natives[] = { - { "client_cmd", client_cmd }, - { "client_print", client_print }, - { "console_cmd", console_cmd }, - { "console_print", console_print }, - { "cvar_exists", cvar_exists }, - { "emit_sound", emit_sound }, - { "engclient_cmd", engclient_cmd }, - { "engclient_print", engclient_print }, - { "find_player", find_player }, - { "find_plugin_byfile", find_plugin_byfile }, - { "force_unmodified", force_unmodified }, - { "format_time", format_time}, - { "get_clcmd", get_clcmd}, - { "get_clcmdsnum", get_clcmdsnum}, - { "get_concmd", get_concmd}, - { "get_concmdsnum", get_concmdsnum}, - { "get_cvar_flags", get_cvar_flags }, - { "get_cvar_float", get_cvar_float }, - { "get_cvar_num", get_cvar_num }, - { "get_cvar_string", get_cvar_string }, - { "get_distance", get_distance }, - { "get_distance_f", get_distance_f }, - { "get_flags", get_flags }, - { "get_gametime", get_gametime}, - { "get_localinfo", get_localinfo}, - { "get_mapname", get_mapname}, - { "get_maxplayers", get_maxplayers }, - { "get_modname", get_modname}, - { "get_players", get_players }, - { "get_playersnum", get_playersnum }, - { "get_plugin", get_plugin }, - { "get_pluginsnum", get_pluginsnum }, - { "get_srvcmd", get_srvcmd }, - { "get_srvcmdsnum", get_srvcmdsnum }, - { "get_systime", get_systime}, - { "get_time", get_time}, - { "get_timeleft", get_timeleft}, - { "get_user_aiming", get_user_aiming }, - { "get_user_ammo", get_user_ammo}, - { "get_user_armor", get_user_armor }, - { "get_user_attacker",get_user_attacker }, - { "get_user_authid", get_user_authid }, - { "get_user_flags", get_user_flags }, - { "get_user_frags", get_user_frags }, - { "get_user_deaths", get_user_deaths }, - { "get_user_health", get_user_health }, - { "get_user_index", get_user_index }, - { "get_user_info", get_user_info }, - { "get_user_ip", get_user_ip }, - { "get_user_menu", get_user_menu}, - { "get_user_msgid", get_user_msgid}, - { "get_user_msgname", get_user_msgname}, - { "get_user_name", get_user_name }, - { "get_user_origin", get_user_origin}, - { "get_user_ping", get_user_ping }, - { "get_user_team", get_user_team }, - { "get_user_time", get_user_time }, - { "get_user_userid", get_user_userid }, - { "hcsardhnExsnu", register_byval }, - { "user_has_weapon", user_has_weapon }, - { "get_user_weapon", get_user_weapon}, - { "get_user_weapons", get_user_weapons}, - { "get_weaponname", get_weaponname}, - { "get_xvar_float", get_xvar_num }, - { "get_xvar_id", get_xvar_id }, - { "get_xvar_num", get_xvar_num }, - { "is_dedicated_server",is_dedicated_server }, - { "is_linux_server", is_linux_server }, - { "is_amd64_server", is_amd64_server }, - { "is_jit_enabled", is_jit_enabled }, - { "is_user_authorized", is_user_authorized }, - { "is_map_valid", is_map_valid }, - { "is_user_alive", is_user_alive }, - { "is_user_bot", is_user_bot }, - { "is_user_connected", is_user_connected }, - { "is_user_connecting", is_user_connecting }, - { "is_user_hltv", is_user_hltv }, - { "log_message", log_message }, - { "log_to_file", log_to_file }, - { "num_to_word", num_to_word }, - { "parse_loguser", parse_loguser }, - { "parse_time", parse_time }, - { "pause", pause }, - { "precache_model", precache_model }, - { "precache_sound", precache_sound }, - { "random_float", random_float }, - { "random_num", random_num }, - { "read_argc", read_argc }, - { "read_args", read_args }, - { "read_argv", read_argv }, - { "read_data", read_data }, - { "read_datanum", read_datanum }, - { "read_flags", read_flags }, - { "read_logargc", read_logargc }, - { "read_logargv", read_logargv }, - { "read_logdata", read_logdata }, - { "register_clcmd", register_clcmd }, - { "register_concmd", register_concmd }, - { "register_cvar", register_cvar }, - { "register_event", register_event }, - { "register_logevent",register_logevent}, - { "register_menucmd", register_menucmd }, - { "register_menuid", register_menuid }, - { "require_module", require_module }, - { "register_plugin", register_plugin }, - { "register_srvcmd", register_srvcmd }, - { "remove_cvar_flags", remove_cvar_flags }, - { "remove_quotes", remove_quotes }, - { "remove_task", remove_task }, - { "change_task", change_task }, - { "remove_user_flags", remove_user_flags }, - { "server_cmd", server_cmd }, - { "server_exec", server_exec }, - { "server_print", server_print }, - { "set_cvar_flags", set_cvar_flags }, - { "set_cvar_float", set_cvar_float }, - { "set_cvar_num", set_cvar_num }, - { "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 }, - { "xvar_exists", xvar_exists }, - { "is_module_loaded", is_module_loaded }, - { "is_plugin_loaded", is_plugin_loaded }, - { "get_modulesnum", get_modulesnum }, - { "get_module", get_module }, - { "log_amx", log_amx }, - { "get_func_id", get_func_id }, - { "callfunc_begin", callfunc_begin }, - { "callfunc_begin_i", callfunc_begin_i }, - { "callfunc_end", callfunc_end }, - { "callfunc_push_int", callfunc_push_byval }, - { "callfunc_push_str", callfunc_push_str }, - { "callfunc_push_float", callfunc_push_byval }, - { "callfunc_push_intrf", callfunc_push_byref }, - { "callfunc_push_floatrf", callfunc_push_byref }, - { "message_begin", message_begin }, - { "message_end", message_end }, - { "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 }, - { "get_langsnum", get_langsnum }, - { "get_lang", get_lang }, - { "register_dictionary", register_dictionary }, - { "lang_exists", lang_exists }, - { "md5", amx_md5 }, - { "md5_file", amx_md5_file }, - { "plugin_flags", plugin_flags}, - { "lang_phrase", lang_phrase}, - { "mkdir", amx_mkdir}, - { "int3", int3}, - { "query_client_cvar", query_client_cvar }, - { NULL, NULL } +static cell AMX_NATIVE_CALL amx_abort(AMX *amx, cell *params) +{ + int err = params[1]; + + int len; + char *fmt = format_amxstring(amx, params, 2, len); + + if (fmt[0] == '\0') + fmt = NULL; + + const char *filename = ""; + CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx); + if (pPlugin) + filename = pPlugin->getName(); + + if (fmt) + LogError(amx, err, "[%s] %s", filename, fmt); + else + LogError(amx, err, NULL); + + return 1; +} + +AMX_NATIVE_INFO amxmodx_Natives[] = { + {"abort", amx_abort}, + {"callfunc_begin", callfunc_begin}, + {"callfunc_begin_i", callfunc_begin_i}, + {"callfunc_end", callfunc_end}, + {"callfunc_push_int", callfunc_push_byval}, + {"callfunc_push_float", callfunc_push_byval}, + {"callfunc_push_intrf", callfunc_push_byref}, + {"callfunc_push_floatrf", callfunc_push_byref}, + {"callfunc_push_str", callfunc_push_str}, + {"client_cmd", client_cmd}, + {"client_print", client_print}, + {"console_cmd", console_cmd}, + {"console_print", console_print}, + {"cvar_exists", cvar_exists}, + {"emit_sound", emit_sound}, + {"engclient_cmd", engclient_cmd}, + {"engclient_print", engclient_print}, + {"find_player", find_player}, + {"find_plugin_byfile", find_plugin_byfile}, + {"force_unmodified", force_unmodified}, + {"format_time", format_time}, + {"get_clcmd", get_clcmd}, + {"get_clcmdsnum", get_clcmdsnum}, + {"get_concmd", get_concmd}, + {"get_concmdsnum", get_concmdsnum}, + {"get_cvar_flags", get_cvar_flags}, + {"get_cvar_float", get_cvar_float}, + {"get_cvar_num", get_cvar_num}, + {"get_cvar_string", get_cvar_string}, + {"get_distance", get_distance}, + {"get_distance_f", get_distance_f}, + {"get_flags", get_flags}, + {"get_func_id", get_func_id}, + {"get_gametime", get_gametime}, + {"get_lang", get_lang}, + {"get_langsnum", get_langsnum}, + {"get_localinfo", get_localinfo}, + {"get_mapname", get_mapname}, + {"get_maxplayers", get_maxplayers}, + {"get_modname", get_modname}, + {"get_module", get_module}, + {"get_modulesnum", get_modulesnum}, + {"get_players", get_players}, + {"get_playersnum", get_playersnum}, + {"get_plugin", get_plugin}, + {"get_pluginsnum", get_pluginsnum}, + {"get_srvcmd", get_srvcmd}, + {"get_srvcmdsnum", get_srvcmdsnum}, + {"get_systime", get_systime}, + {"get_time", get_time}, + {"get_timeleft", get_timeleft}, + {"get_user_aiming", get_user_aiming}, + {"get_user_ammo", get_user_ammo}, + {"get_user_armor", get_user_armor}, + {"get_user_attacker", get_user_attacker}, + {"get_user_authid", get_user_authid}, + {"get_user_flags", get_user_flags}, + {"get_user_frags", get_user_frags}, + {"get_user_deaths", get_user_deaths}, + {"get_user_health", get_user_health}, + {"get_user_index", get_user_index}, + {"get_user_info", get_user_info}, + {"get_user_ip", get_user_ip}, + {"get_user_menu", get_user_menu}, + {"get_user_msgid", get_user_msgid}, + {"get_user_msgname", get_user_msgname}, + {"get_user_name", get_user_name}, + {"get_user_origin", get_user_origin}, + {"get_user_ping", get_user_ping}, + {"get_user_team", get_user_team}, + {"get_user_time", get_user_time}, + {"get_user_userid", get_user_userid}, + {"hcsardhnexsnu", register_byval}, + {"user_has_weapon", user_has_weapon}, + {"get_user_weapon", get_user_weapon}, + {"get_user_weapons", get_user_weapons}, + {"get_weaponname", get_weaponname}, + {"get_xvar_float", get_xvar_num}, + {"get_xvar_id", get_xvar_id}, + {"get_xvar_num", get_xvar_num}, + {"int3", int3}, + {"is_amd64_server", is_amd64_server}, + {"is_dedicated_server", is_dedicated_server}, + {"is_jit_enabled", is_jit_enabled}, + {"is_linux_server", is_linux_server}, + {"is_map_valid", is_map_valid}, + {"is_module_loaded", is_module_loaded}, + {"is_plugin_loaded", is_plugin_loaded}, + {"is_user_alive", is_user_alive}, + {"is_user_authorized", is_user_authorized}, + {"is_user_bot", is_user_bot}, + {"is_user_connected", is_user_connected}, + {"is_user_connecting", is_user_connecting}, + {"is_user_hltv", is_user_hltv}, + {"lang_exists", lang_exists}, + {"lang_phrase", lang_phrase}, + {"log_amx", log_amx}, + {"log_message", log_message}, + {"log_to_file", log_to_file}, + {"md5", amx_md5}, + {"md5_file", amx_md5_file}, + {"message_begin", message_begin}, + {"message_end", message_end}, + {"mkdir", amx_mkdir}, + {"num_to_word", num_to_word}, + {"parse_loguser", parse_loguser}, + {"parse_time", parse_time}, + {"pause", pause}, + {"plugin_flags", plugin_flags}, + {"precache_model", precache_model}, + {"precache_sound", precache_sound}, + {"query_client_cvar", query_client_cvar}, + {"random_float", random_float}, + {"random_num", random_num}, + {"read_argc", read_argc}, + {"read_args", read_args}, + {"read_argv", read_argv}, + {"read_data", read_data}, + {"read_datanum", read_datanum}, + {"read_flags", read_flags}, + {"read_logargc", read_logargc}, + {"read_logargv", read_logargv}, + {"read_logdata", read_logdata}, + {"register_clcmd", register_clcmd}, + {"register_concmd", register_concmd}, + {"register_cvar", register_cvar}, + {"register_dictionary", register_dictionary}, + {"register_event", register_event}, + {"register_logevent", register_logevent}, + {"register_menucmd", register_menucmd}, + {"register_menuid", register_menuid}, + {"register_plugin", register_plugin}, + {"register_srvcmd", register_srvcmd}, + {"require_module", require_module}, + {"remove_cvar_flags", remove_cvar_flags}, + {"remove_quotes", remove_quotes}, + {"remove_task", remove_task}, + {"change_task", change_task}, + {"remove_user_flags", remove_user_flags}, + {"server_cmd", server_cmd}, + {"server_exec", server_exec}, + {"server_print", server_print}, + {"set_cvar_flags", set_cvar_flags}, + {"set_cvar_float", set_cvar_float}, + {"set_cvar_num", set_cvar_num}, + {"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} }; diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 7ead8e80..e7f25d7d 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -74,11 +74,11 @@ extern AMX_NATIVE_INFO core_Natives[]; extern AMX_NATIVE_INFO time_Natives[]; extern AMX_NATIVE_INFO power_Natives[]; -extern AMX_NATIVE_INFO amxmod_Natives[]; -extern AMX_NATIVE_INFO file_Natives[]; -extern AMX_NATIVE_INFO float_Natives[]; -extern AMX_NATIVE_INFO string_Natives[]; -extern AMX_NATIVE_INFO vault_Natives[]; +extern AMX_NATIVE_INFO amxmodx_Natives[]; +extern AMX_NATIVE_INFO file_Natives[]; +extern AMX_NATIVE_INFO float_Natives[]; +extern AMX_NATIVE_INFO string_Natives[]; +extern AMX_NATIVE_INFO vault_Natives[]; #ifndef __linux__ #define DLLOAD(path) (DLHANDLE)LoadLibrary(path) diff --git a/amxmodx/debugger.cpp b/amxmodx/debugger.cpp index d1f78759..e719a867 100755 --- a/amxmodx/debugger.cpp +++ b/amxmodx/debugger.cpp @@ -430,24 +430,25 @@ int Debugger::FormatError(char *buffer, size_t maxLength) buffer += 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; - //go two instructions back + /*//go two instructions back cip -= (sizeof(cell) * 2); int instr = _GetOpcodeFromCip(cip, p_cip); if (instr == OP_SYSREQ_C) { num = (int)*p_cip; - } else if (instr == OP_SYSREQ_PRI) { - num = (int)m_pAmx->pri; - } - if (num) + }*/ + //New code only requires this... + num = m_pAmx->usertags[UT_NATIVE]; + amx_err = amx_GetNative(m_pAmx, num, native_name); + /*if (num) amx_err = amx_GetNative(m_pAmx, (int)*p_cip, native_name); else - amx_err = AMX_ERR_NOTFOUND; - if (!amx_err) + amx_err = AMX_ERR_NOTFOUND;*/ + //if (!amx_err) size += _snprintf(buffer, maxLength, "(native \"%s\")", native_name); } else if (error == AMX_ERR_BOUNDS) { tagAMX_DBG *pDbg = m_pAmxDbg; @@ -731,7 +732,7 @@ const char *GenericError(int err) "divide", "sleep", "invalid access state", - NULL, + "native not found", NULL, "out of memory", //16 "bad file format", @@ -760,6 +761,9 @@ int AMXAPI Debugger::DebugHook(AMX *amx) if (!amx || !(amx->flags & AMX_FLAG_DEBUG)) return AMX_ERR_NONE; + if (amx->flags & AMX_FLAG_PRENIT) + return AMX_ERR_NONE; + pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER]; if (!pDebugger) @@ -872,7 +876,7 @@ int Handler::SetErrorHandler(const char *function) error = amx_FindPublic(m_pAmx, function, &m_iErrFunc); - if (error != AMX_ERR_NONE) + if (error != AMX_ERR_NONE && m_iErrFunc < 1) m_iErrFunc = -1; return error; @@ -884,7 +888,7 @@ int Handler::SetModuleFilter(const char *function) error = amx_FindPublic(m_pAmx, function, &m_iModFunc); - if (error != AMX_ERR_NONE) + if (error != AMX_ERR_NONE && m_iModFunc < 1) m_iModFunc = -1; return error; @@ -896,7 +900,7 @@ int Handler::SetNativeFilter(const char *function) error = amx_FindPublic(m_pAmx, function, &m_iNatFunc); - if (error != AMX_ERR_NONE) + if (error != AMX_ERR_NONE && !IsNativeFiltering()) m_iNatFunc = -1; return error; @@ -918,6 +922,94 @@ const char *Handler::GetLastMsg() 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) { if (m_iErrFunc <= 0) @@ -1073,11 +1165,63 @@ static cell AMX_NATIVE_CALL dbg_fmt_error(AMX *amx, cell *params) 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[] = { {"set_error_filter", set_error_filter}, {"dbg_trace_begin", dbg_trace_begin}, {"dbg_trace_next", dbg_trace_next}, {"dbg_trace_info", dbg_trace_info}, {"dbg_fmt_error", dbg_fmt_error}, + {"set_native_filter", set_native_filter}, + {"set_module_filter", set_module_filter}, {NULL, NULL}, }; diff --git a/amxmodx/debugger.h b/amxmodx/debugger.h index fdb60e49..b8d4c376 100755 --- a/amxmodx/debugger.h +++ b/amxmodx/debugger.h @@ -159,7 +159,7 @@ public: int SetModuleFilter(const char *function); public: int HandleError(const char *msg); - int HandleNative(const char *native); + int HandleNative(const char *native, int index, int trap); int HandleModule(const char *module); public: bool IsHandling() const { return m_Handling; } @@ -167,12 +167,16 @@ public: const char *GetLastMsg(); trace_info_t *GetTrace() const { return m_pTrace; } const char *GetFmtCache() { return m_FmtCache.c_str(); } + bool IsNativeFiltering() { return (m_iNatFunc > 0); } + bool InNativeFilter() { return m_InNativeFilter; } private: AMX *m_pAmx; int m_iErrFunc; int m_iModFunc; int m_iNatFunc; bool m_Handling; + //in the future, make this a stack! + bool m_InNativeFilter; String m_MsgCache; String m_FmtCache; trace_info_t *m_pTrace; diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index 4258e144..706139fd 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -344,6 +344,7 @@ int CheckModules(AMX *amx, char error[128]) bool isdbi = false; CList::iterator a; const amxx_module_info_s *info; + Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER]; for (int i=0; iHandleModule(buffer)) + found = true; + } + if (!found) { sprintf(error, "Module \"%s\" required for plugin. Check modules.ini.", buffer); return 0; @@ -406,7 +412,7 @@ int set_amxnatives(AMX* amx,char error[128]) amx_Register(amx, string_Natives, -1); amx_Register(amx, float_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, time_Natives, -1); amx_Register(amx, vault_Natives, -1); @@ -1306,19 +1312,26 @@ void LogError(AMX *amx, int err, const char *fmt, ...) //give the plugin first chance to handle any sort of error Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER]; - if (pHandler) + + if (pHandler->InNativeFilter()) { - if (pHandler->IsHandling()) + if (pDebugger) + pDebugger->EndExec(); + } else { + if (pHandler) { - 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 (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; + } } }