Finalized new debugging system
This commit is contained in:
parent
401ee3c97f
commit
760e29e531
@ -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;
|
||||
|
@ -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 (index<NULL) {
|
||||
@ -444,40 +441,10 @@ int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params)
|
||||
#endif
|
||||
assert(f!=NULL);
|
||||
|
||||
/* Now that we have found the function, patch the program so that any
|
||||
* subsequent call will call the function directly (bypassing this
|
||||
* callback).
|
||||
* This trick cannot work in the JIT, because the program would need to
|
||||
* be re-JIT-compiled after patching a P-code instruction.
|
||||
/* As of AMX Mod X 1.56, we don't patch sysreq.c to sysreq.d anymore.
|
||||
* Otherwise, we'd have no way of knowing the last native to be used.
|
||||
*/
|
||||
#if !defined JIT
|
||||
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
|
||||
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; 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)
|
||||
{
|
||||
AMX_FUNCSTUB *func;
|
||||
|
@ -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);
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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},
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -344,6 +344,7 @@ int CheckModules(AMX *amx, char error[128])
|
||||
bool isdbi = false;
|
||||
CList<CModule,const char *>::iterator a;
|
||||
const amxx_module_info_s *info;
|
||||
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
|
||||
|
||||
for (int i=0; i<numLibraries; i++)
|
||||
{
|
||||
@ -385,6 +386,11 @@ int CheckModules(AMX *amx, char error[128])
|
||||
if (!found)
|
||||
found = LibraryExists(buffer);
|
||||
if (!found)
|
||||
{
|
||||
if (pHandler->HandleModule(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user