Longjmp fixes

Co-Authored-By: Edo <edoardo.sanguineti222@gmail.com>
This commit is contained in:
Federico Cecchetto 2022-08-29 03:05:32 +02:00
parent f8247a8f3b
commit c505c29bea
3 changed files with 122 additions and 84 deletions

View File

@ -41,7 +41,7 @@ namespace gsc
std::unordered_map<std::string, unsigned int> main_handles; std::unordered_map<std::string, unsigned int> main_handles;
std::unordered_map<std::string, unsigned int> init_handles; std::unordered_map<std::string, unsigned int> init_handles;
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts; std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
std::unordered_map<unsigned int, scripting::script_function> functions; std::unordered_map<scripting::script_function, unsigned int> functions;
std::optional<std::string> gsc_error; std::optional<std::string> gsc_error;
char* allocate_buffer(size_t size) char* allocate_buffer(size_t size)
@ -185,21 +185,6 @@ namespace gsc
loaded_scripts.clear(); loaded_scripts.clear();
} }
void gscr_print_stub()
{
const auto num = game::Scr_GetNumParam();
std::string buffer{};
for (auto i = 0; i < num; i++)
{
const auto str = game::Scr_GetString(i);
buffer.append(str);
buffer.append("\t");
}
printf("%s\n", buffer.data());
}
void load_gametype_script_stub(void* a1, void* a2) void load_gametype_script_stub(void* a1, void* a2)
{ {
utils::hook::invoke<void>(0x1404E1400, a1, a2); utils::hook::invoke<void>(0x1404E1400, a1, a2);
@ -318,13 +303,11 @@ namespace gsc
bool force_error_print = false; bool force_error_print = false;
void* vm_error_stub(void* a1) void* vm_error_stub(void* a1)
{ {
if (!developer_script->current.enabled || force_error_print) if (!developer_script->current.enabled && !force_error_print)
{ {
return utils::hook::invoke<void*>(0x140614670, a1); return utils::hook::invoke<void*>(0x140614670, a1);
} }
force_error_print = false;
console::warn("*********** script runtime error *************\n"); console::warn("*********** script runtime error *************\n");
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x14BAA93E8); const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x14BAA93E8);
@ -343,6 +326,9 @@ namespace gsc
opcode_id, error_str.data()); opcode_id, error_str.data());
} }
force_error_print = false;
gsc_error = {};
print_callstack(); print_callstack();
console::warn("**********************************************\n"); console::warn("**********************************************\n");
return utils::hook::invoke<void*>(0x140614670, a1); return utils::hook::invoke<void*>(0x140614670, a1);
@ -359,7 +345,7 @@ namespace gsc
utils::hook::invoke<void>(0x140509F20, a1, a2); utils::hook::invoke<void>(0x140509F20, a1, a2);
for (const auto& func : functions) for (const auto& func : functions)
{ {
game::Scr_RegisterFunction(func.second, 0, func.first); game::Scr_RegisterFunction(func.first, 0, func.second);
} }
} }
@ -378,33 +364,54 @@ namespace gsc
auto function_id_start = 0x320; auto function_id_start = 0x320;
void add_function(const std::string& name, scripting::script_function function) void add_function(const std::string& name, scripting::script_function function)
{ {
const auto id = ++function_id_start; if (scripting::function_map.find(name) != scripting::function_map.end())
scripting::function_map[name] = id;
functions[id] = function;
}
void set_gsc_error(const std::string& error)
{
force_error_print = true;
gsc_error = error;
game::Scr_ErrorInternal();
}
void assert_cmd()
{
const auto expr = get_argument(0).as<int>();
if (!expr)
{ {
set_gsc_error("assert fail"); const auto id = scripting::function_map[name];
functions[function] = id;
}
else
{
const auto id = ++function_id_start;
scripting::function_map[name] = id;
functions[function] = id;
} }
} }
void assertex_cmd() void execute_custom_function(scripting::script_function function)
{ {
const auto expr = get_argument(0).as<int>(); bool error = false;
if (!expr)
try
{ {
set_gsc_error(get_argument(1).as<std::string>()); function({});
}
catch (const std::exception& e)
{
error = true;
force_error_print = true;
gsc_error = e.what();
}
if (error)
{
game::Scr_ErrorInternal();
}
}
void vm_call_builtin_stub(scripting::script_function function)
{
bool custom = false;
{
custom = functions.find(function) != functions.end();
}
if (!custom)
{
function({});
}
else
{
execute_custom_function(function);
} }
} }
} }
@ -466,13 +473,6 @@ namespace gsc
utils::hook::call(0x1404C8F71, g_load_structs_stub); utils::hook::call(0x1404C8F71, g_load_structs_stub);
utils::hook::call(0x1404C8F80, scr_load_level_stub); utils::hook::call(0x1404C8F80, scr_load_level_stub);
// replace builtin print function
utils::hook::jump(0x1404EC640, gscr_print_stub);
// restore assert
utils::hook::jump(0x1404EC890, assert_cmd);
utils::hook::jump(0x1404EC920, assertex_cmd);
utils::hook::call(0x1405CB94F, vm_error_stub); utils::hook::call(0x1405CB94F, vm_error_stub);
utils::hook::call(0x1405BC583, unknown_function_stub); utils::hook::call(0x1405BC583, unknown_function_stub);
@ -487,31 +487,59 @@ namespace gsc
utils::hook::inject(0x1405BCB78 + 3, &func_table); utils::hook::inject(0x1405BCB78 + 3, &func_table);
utils::hook::set<uint32_t>(0x1405CA678 + 4, RVA(&func_table)); utils::hook::set<uint32_t>(0x1405CA678 + 4, RVA(&func_table));
utils::hook::nop(0x1405CA683, 8);
utils::hook::call(0x1405CA683, vm_call_builtin_stub);
add_function("print", [](const game::scr_entref_t ref)
{
const auto num = game::Scr_GetNumParam();
std::string buffer{};
for (auto i = 0; i < num; i++)
{
const auto str = game::Scr_GetString(i);
buffer.append(str);
buffer.append("\t");
}
printf("%s\n", buffer.data());
});
add_function("assert", [](const game::scr_entref_t ref)
{
const auto expr = get_argument(0).as<int>();
if (!expr)
{
throw std::runtime_error("assert fail");
}
});
add_function("assertex", [](const game::scr_entref_t ref)
{
const auto expr = get_argument(0).as<int>();
if (!expr)
{
const auto error = get_argument(1).as<std::string>();
throw std::runtime_error(error);
}
});
add_function("replacefunc", [](const game::scr_entref_t ref) add_function("replacefunc", [](const game::scr_entref_t ref)
{ {
try const auto what = get_argument(0).get_raw();
const auto with = get_argument(1).get_raw();
if (what.type != game::SCRIPT_FUNCTION)
{ {
const auto what = get_argument(0).get_raw(); throw std::runtime_error("replaceFunc: parameter 1 must be a function");
const auto with = get_argument(1).get_raw();
if (what.type != game::SCRIPT_FUNCTION)
{
set_gsc_error("replaceFunc: parameter 0 must be a function");
return;
}
if (with.type != game::SCRIPT_FUNCTION)
{
set_gsc_error("replaceFunc: parameter 1 must be a function");
return;
}
notifies::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
} }
catch (const std::exception& e)
if (with.type != game::SCRIPT_FUNCTION)
{ {
set_gsc_error(utils::string::va("replaceFunc: %s", e.what())); throw std::runtime_error("replaceFunc: parameter 2 must be a function");
} }
notifies::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
}); });
scripting::on_shutdown([](int free_scripts) scripting::on_shutdown([](int free_scripts)

View File

@ -152,7 +152,7 @@ namespace notifies
} }
void scr_entity_damage_stub(game::gentity_s* self, game::gentity_s* inflictor, game::gentity_s* attacker, const float* vDir, const float* vPoint, void scr_entity_damage_stub(game::gentity_s* self, game::gentity_s* inflictor, game::gentity_s* attacker, const float* vDir, const float* vPoint,
int damage, int dflags, const unsigned int hitLoc, const unsigned int weapon, bool isAlternate, unsigned int a11, const int meansOfDeath, unsigned int a13, unsigned int a14) int damage, int dflags, const unsigned int meansOfDeath, const unsigned int weapon, bool isAlternate, unsigned int a11, const int hitLoc, unsigned int a13, unsigned int a14)
{ {
{ {
const std::string _hitLoc = reinterpret_cast<const char**>(0x140BF4AA0)[hitLoc]; const std::string _hitLoc = reinterpret_cast<const char**>(0x140BF4AA0)[hitLoc];
@ -187,7 +187,8 @@ namespace notifies
} }
} }
scr_entity_damage_hook.invoke<void>(self, inflictor, attacker, vDir, vPoint, damage, dflags, hitLoc, weapon, isAlternate, a11, meansOfDeath, a13, a14); scr_entity_damage_hook.invoke<void>(self,inflictor, attacker, vDir, vPoint, damage, dflags,
meansOfDeath, weapon, isAlternate, a11, hitLoc, a13, a14);
} }
} }

View File

@ -444,25 +444,28 @@ namespace ui_scripting
reader_data, chunk_name); reader_data, chunk_name);
} }
} }
std::string current_error;
int main_handler(game::hks::lua_State* state) int main_handler(game::hks::lua_State* state)
{ {
const auto value = state->m_apistack.base[-1]; bool error = false;
if (value.t != game::hks::TCFUNCTION)
{
return 0;
}
const auto closure = value.v.cClosure;
if (converted_functions.find(closure) == converted_functions.end())
{
return 0;
}
const auto& function = converted_functions[closure];
try try
{ {
const auto value = state->m_apistack.base[-1];
if (value.t != game::hks::TCFUNCTION)
{
return 0;
}
const auto closure = value.v.cClosure;
if (converted_functions.find(closure) == converted_functions.end())
{
return 0;
}
const auto& function = converted_functions[closure];
const auto args = get_return_values(); const auto args = get_return_values();
const auto results = function(args); const auto results = function(args);
@ -475,7 +478,13 @@ namespace ui_scripting
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
game::hks::hksi_luaL_error(state, e.what()); current_error = e.what();
error = true;
}
if (error)
{
game::hks::hksi_luaL_error(state, current_error.data());
} }
return 0; return 0;