From 9db7de29fb4903afa734ad45abfc3a9d0b16e691 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 25 Jun 2016 08:16:15 +0300 Subject: [PATCH] Syscall analysis implemented --- Utilities/Thread.cpp | 3 +- Utilities/dynamic_library.cpp | 2 +- rpcs3/Emu/Cell/PPUFunction.cpp | 2 +- rpcs3/Emu/Cell/PPUFunction.h | 7 +- rpcs3/Emu/Cell/PPUModule.cpp | 54 +++++++----- rpcs3/Emu/Cell/PPUModule.h | 15 +--- rpcs3/Emu/Cell/PPUThread.cpp | 139 ++++++++++++++++++++----------- rpcs3/Emu/Cell/PPUThread.h | 1 + rpcs3/Emu/Cell/lv2/lv2.cpp | 38 ++++----- rpcs3/Emu/Cell/lv2/sys_timer.cpp | 2 + rpcs3/Emu/IdManager.cpp | 4 +- rpcs3/Emu/IdManager.h | 34 ++++---- rpcs3/Emu/PSP2/ARMv7Function.h | 7 +- rpcs3/Emu/PSP2/ARMv7Module.cpp | 33 ++++---- rpcs3/Emu/PSP2/ARMv7Thread.cpp | 47 +++++++---- rpcs3/Emu/PSP2/ARMv7Thread.h | 1 + 16 files changed, 234 insertions(+), 155 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index c44543d4fa..607bf03945 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -299,8 +299,9 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz switch (op2) { case 0x11: + case 0x29: { - if (!repe && !repne && !oso) // MOVUPS xmm/m, xmm + if (!repe && !repne) // MOVUPS/MOVAPS/MOVUPD/MOVAPD xmm/m, xmm { out_op = X64OP_STORE; out_reg = get_modRM_reg_xmm(code, rex); diff --git a/Utilities/dynamic_library.cpp b/Utilities/dynamic_library.cpp index 572edc42ea..68ec5066c4 100644 --- a/Utilities/dynamic_library.cpp +++ b/Utilities/dynamic_library.cpp @@ -42,7 +42,7 @@ namespace utils void *dynamic_library::get_impl(const std::string &name) const { #ifdef _WIN32 - return GetProcAddress((HMODULE)m_handle, name.c_str()); + return (void*)GetProcAddress((HMODULE)m_handle, name.c_str()); #else return dlsym(m_handle, (char *)name.c_str()); #endif diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp index dc1612bb68..692a83a589 100644 --- a/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -2363,7 +2363,7 @@ s32 ppu_error_code::report(s32 error, const char* text) { if (auto func = static_cast(thread)->last_function) { - LOG_ERROR(PPU, "Function '%s' failed with 0x%08x : %s", func, error, text); + LOG_ERROR(PPU, "'%s' failed with 0x%08x : %s", func, error, text); } else { diff --git a/rpcs3/Emu/Cell/PPUFunction.h b/rpcs3/Emu/Cell/PPUFunction.h index a6f066a40c..3b60580510 100644 --- a/rpcs3/Emu/Cell/PPUFunction.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -4,7 +4,12 @@ using ppu_function_t = void(*)(PPUThread&); -#define BIND_FUNC(func) [](PPUThread& ppu){ ppu.last_function = #func; ppu_func_detail::do_call(ppu, func); } +#define BIND_FUNC(func) static_cast([](PPUThread& ppu){\ + const auto old_f = ppu.last_function;\ + ppu.last_function = #func;\ + ppu_func_detail::do_call(ppu, func);\ + ppu.last_function = old_f;\ +}) struct ppu_va_args_t { diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 09920d6d32..49e02818eb 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -125,9 +125,22 @@ extern void ppu_initialize(const std::string& name, const std::vector g_ppu_function_cache; +// Function name cache in format %s.%s (module name, function name) +std::vector g_ppu_function_names; + // Function NID cache for autopause. Autopause tool should probably be rewritten. std::vector g_ppu_fnid_cache; +extern std::string ppu_get_module_function_name(u32 index) +{ + if (index < g_ppu_function_names.size()) + { + return g_ppu_function_names[index]; + } + + return fmt::format(".%u", index); +} + extern void ppu_execute_function(PPUThread& ppu, u32 index) { if (index < g_ppu_function_cache.size()) @@ -137,21 +150,8 @@ extern void ppu_execute_function(PPUThread& ppu, u32 index) if (const auto func = g_ppu_function_cache[index]) { - const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something, but only if it's equally fast - - try - { - func(ppu); - } - catch (...) - { - logs::HLE.format(Emu.IsStopped() ? logs::level::warning : logs::level::error, "Function '%s' aborted", ppu.last_function); - ppu.last_function = previous_function; - throw; - } - - LOG_TRACE(HLE, "Function '%s' finished, r3=0x%llx", ppu.last_function, ppu.GPR[3]); - ppu.last_function = previous_function; + func(ppu); + LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.GPR[3]); return; } } @@ -159,6 +159,16 @@ extern void ppu_execute_function(PPUThread& ppu, u32 index) throw fmt::exception("Function not registered (index %u)" HERE, index); } +extern ppu_function_t ppu_get_function(u32 index) +{ + if (index < g_ppu_function_cache.size()) + { + return g_ppu_function_cache[index]; + } + + return nullptr; +} + extern u32 ppu_generate_id(const char* name) { // Symbol name suffix @@ -312,7 +322,10 @@ static void ppu_initialize_modules() // Reinitialize function cache g_ppu_function_cache = ppu_function_manager::get(); - g_ppu_fnid_cache = std::vector(g_ppu_function_cache.size()); + g_ppu_function_names.clear(); + g_ppu_function_names.resize(g_ppu_function_cache.size()); + g_ppu_fnid_cache.clear(); + g_ppu_fnid_cache.resize(g_ppu_function_cache.size()); // "Use" all the modules for correct linkage for (auto& module : registered) @@ -322,6 +335,7 @@ static void ppu_initialize_modules() for (auto& function : module->functions) { LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + g_ppu_function_names.at(function.second.index) = fmt::format("%s.%s", module->name, function.second.name); g_ppu_fnid_cache.at(function.second.index) = function.first; } @@ -1531,10 +1545,12 @@ void ppu_exec_loader::load() const { // TODO const u32 index = ::size32(g_ppu_function_cache); + const std::string& fname = ppu_get_function_name(module.first, fnid); g_ppu_function_cache.emplace_back(); + g_ppu_function_names.emplace_back(fmt::format("%s.%s", module.first, fname)); g_ppu_fnid_cache.emplace_back(fnid); - LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", ppu_get_function_name(module.first, fnid), module.first, index); + LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", fname, module.first, index); for (auto& import : entry.second.second) { @@ -1544,11 +1560,11 @@ void ppu_exec_loader::load() const if (!ppu_patch_import_stub(stub, index)) { - LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", fname, module.first, stub); } else { - LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", fname, module.first, stub); } } diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index 957f8b6a38..274c0964e9 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -200,20 +200,7 @@ public: template> inline RT ppu_execute_function_or_callback(const char* name, PPUThread& ppu, Args&&... args) { - const auto previous_function = ppu.last_function; // TODO - - try - { - return Func(std::forward(args)...); - } - catch (...) - { - LOG_ERROR(PPU, "Function call '%s' aborted", ppu.last_function); - ppu.last_function = previous_function; - throw; - } - - ppu.last_function = previous_function; + return Func(std::forward(args)...); } #define CALL_FUNC(ppu, func, ...) ppu_execute_function_or_callback(#func, ppu, __VA_ARGS__) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index eb50c750c6..b46ac6ffb0 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -16,7 +16,7 @@ #include "llvm/IR/LLVMContext.h" //#include "llvm/IR/Dominators.h" #include "llvm/IR/Verifier.h" -//#include "llvm/IR/InstIterator.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/LegacyPassManager.h" //#include "llvm/IR/Module.h" //#include "llvm/IR/Function.h" @@ -27,6 +27,7 @@ //#include "llvm/Analysis/LoopInfo.h" //#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/Lint.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Vectorize.h" @@ -63,7 +64,7 @@ struct ppu_addr_hash } }; -static std::unordered_map s_ppu_compiled; +static std::unordered_map s_ppu_compiled; // TODO @@ -126,13 +127,11 @@ void PPUThread::cpu_task() { //SetHostRoundingMode(FPSCR_RN_NEAR); - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } + return custom_task ? custom_task(*this) : fast_call(pc, static_cast(GPR[2])); +} +void PPUThread::cpu_task_main() +{ if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm) { const auto found = s_ppu_compiled.find(pc); @@ -311,39 +310,54 @@ be_t* PPUThread::get_stack_arg(s32 i, u64 align) void PPUThread::fast_call(u32 addr, u32 rtoc) { - auto old_PC = pc; - auto old_stack = GPR[1]; - auto old_rtoc = GPR[2]; - auto old_LR = LR; - auto old_task = std::move(custom_task); + const auto old_PC = pc; + const auto old_stack = GPR[1]; + const auto old_rtoc = GPR[2]; + const auto old_LR = LR; + const auto old_task = std::move(custom_task); + const auto old_func = last_function; pc = addr; GPR[2] = rtoc; LR = Emu.GetCPUThreadStop(); custom_task = nullptr; + last_function = nullptr; try { - cpu_task(); + cpu_task_main(); + + if (GPR[1] != old_stack && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // GPR[1] shouldn't change + { + throw fmt::exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, GPR[1], old_stack); + } } catch (cpu_state _s) { state += _s; if (_s != cpu_state::ret) throw; } + catch (EmulationStopped) + { + if (last_function) LOG_WARNING(PPU, "'%s' aborted", last_function); + last_function = old_func; + throw; + } + catch (...) + { + if (last_function) LOG_ERROR(PPU, "'%s' aborted", last_function); + last_function = old_func; + throw; + } state -= cpu_state::ret; pc = old_PC; - - if (GPR[1] != old_stack) // GPR[1] shouldn't change - { - throw EXCEPTION("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, GPR[1], old_stack); - } - + GPR[1] = old_stack; GPR[2] = old_rtoc; LR = old_LR; custom_task = std::move(old_task); + last_function = old_func; //if (custom_task) //{ @@ -357,6 +371,10 @@ const ppu_decoder s_ppu_itype; extern u64 get_timebased_time(); extern void ppu_execute_syscall(PPUThread& ppu, u64 code); extern void ppu_execute_function(PPUThread& ppu, u32 index); +extern ppu_function_t ppu_get_syscall(u64 code); +extern std::string ppu_get_syscall_name(u64 code); +extern ppu_function_t ppu_get_function(u32 index); +extern std::string ppu_get_module_function_name(u32 index); extern __m128 sse_exp2_ps(__m128 A); extern __m128 sse_log2_ps(__m128 A); @@ -378,23 +396,6 @@ static void ppu_trace(u64 addr) LOG_NOTICE(PPU, "Trace: 0x%llx", addr); } -static void ppu_hlecall(PPUThread& ppu, u32 index) -{ - ppu_execute_function(ppu, index); - if (ppu.state.load() && ppu.check_status()) throw cpu_state::ret; // Temporarily -} - -static void ppu_syscall(PPUThread& ppu, u64 code) -{ - ppu_execute_syscall(ppu, code); - if (ppu.state.load() && ppu.check_status()) throw cpu_state::ret; // Temporarily -} - -static u32 ppu_tbl() -{ - return (u32)get_timebased_time(); -} - static void ppu_call(PPUThread& ppu, u32 addr) { const auto found = s_ppu_compiled.find(addr); @@ -410,7 +411,7 @@ static void ppu_call(PPUThread& ppu, u32 addr) // Allow HLE callbacks without compiling them if (itype == ppu_itype::HACK && vm::read32(addr + 4) == ppu_instructions::BLR()) { - return ppu_hlecall(ppu, op & 0x3ffffff); + return ppu_execute_function(ppu, op & 0x3ffffff); } ppu_trap(addr); @@ -506,9 +507,9 @@ extern void ppu_initialize(const std::string& name, const std::vectorTranslateToIR(info.first, info.first + info.second, vm::_ptr(info.first))); + const auto func = translator->TranslateToIR(info.first, info.first + info.second, vm::_ptr(info.first)); + + // Run optimization passes + pm.run(*func); + + const auto _syscall = module->getFunction("__syscall"); + const auto _hlecall = module->getFunction("__hlecall"); + + for (auto i = inst_begin(*func), end = inst_end(*func); i != end;) + { + const auto inst = &*i++; + + if (const auto ci = dyn_cast(inst)) + { + const auto cif = ci->getCalledFunction(); + const auto op1 = ci->getNumArgOperands() > 1 ? ci->getArgOperand(1) : nullptr; + + if (cif == _syscall && op1 && isa(op1)) + { + // Try to determine syscall using the value from r11 (requires constant propagation) + const u64 index = cast(op1)->getZExtValue(); + + if (const auto ptr = ppu_get_syscall(index)) + { + const auto n = ppu_get_syscall_name(index); + const auto f = cast(module->getOrInsertFunction(n, _func)); + link_table.emplace(n, reinterpret_cast(ptr)); + + // Call the syscall directly + ReplaceInstWithInst(ci, CallInst::Create(f, {ci->getArgOperand(0)})); + } + } + + if (cif == _hlecall && op1 && isa(op1)) + { + const u32 index = static_cast(cast(op1)->getZExtValue()); + + if (const auto ptr = ppu_get_function(index)) + { + const auto n = ppu_get_module_function_name(index); + const auto f = cast(module->getOrInsertFunction(n, _func)); + link_table.emplace(n, reinterpret_cast(ptr)); + + // Call the function directly + ReplaceInstWithInst(ci, CallInst::Create(f, {ci->getArgOperand(0)})); + } + } + } + } } } @@ -599,9 +647,6 @@ extern void ppu_initialize(const std::string& name, const std::vectorget(fmt::format("__sub_%x", info.first)); - s_ppu_compiled.emplace(info.first, (void(*)(PPUThread&))link); + s_ppu_compiled.emplace(info.first, (ppu_function_t)link); LOG_NOTICE(PPU, "** Function __sub_%x -> 0x%llx (addr=0x%x, size=0x%x)", info.first, link, info.first, info.second); } diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 6e3ae11888..1d95f8dd35 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -11,6 +11,7 @@ public: virtual std::string dump() const override; virtual void cpu_init() override; virtual void cpu_task() override; + virtual void cpu_task_main(); virtual bool handle_interrupt() override; virtual ~PPUThread() override; diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 0c4ae498c0..037a24cce7 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -910,40 +910,36 @@ std::array g_ppu_syscall_table extern void ppu_execute_syscall(PPUThread& ppu, u64 code) { - if (code >= g_ppu_syscall_table.size()) + if (code < g_ppu_syscall_table.size()) { - throw fmt::exception("Invalid syscall number (%llu)", code); - } + // If autopause occures, check_status() will hold the thread till unpaused. + if (debug::autopause::pause_syscall(code) && ppu.check_status()) throw cpu_state::ret; - // If autopause occures, check_status() will hold the thread till unpaused. - if (debug::autopause::pause_syscall(code) && ppu.check_status()) - { - throw cpu_state::ret; - } - - const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something - - try - { if (auto func = g_ppu_syscall_table[code]) { func(ppu); + LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]); } else { LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(code)); ppu.GPR[3] = 0; } - } - catch (...) - { - logs::PPU.format(Emu.IsStopped() ? logs::level::warning : logs::level::error, "Syscall '%s' (%llu) aborted", ppu_get_syscall_name(code), code); - ppu.last_function = previous_function; - throw; + + return; } - LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]); - ppu.last_function = previous_function; + throw fmt::exception("Invalid syscall number (%llu)", code); +} + +extern ppu_function_t ppu_get_syscall(u64 code) +{ + if (code < g_ppu_syscall_table.size()) + { + return g_ppu_syscall_table[code]; + } + + return nullptr; } DECLARE(lv2_lock_t::mutex); diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index d4edeea141..d0ccbf2c1c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -271,6 +271,7 @@ s32 sys_timer_sleep(u32 sleep_time) std::this_thread::sleep_for(std::chrono::microseconds(useconds - passed)); } + CHECK_EMU_STATUS; return CELL_OK; } @@ -294,5 +295,6 @@ s32 sys_timer_usleep(const u64 sleep_time) std::this_thread::sleep_for(std::chrono::microseconds(sleep_time - passed)); } + CHECK_EMU_STATUS; return CELL_OK; } diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index 639b3c7c0f..636eac6b34 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -89,9 +89,11 @@ void idm::clear() // Call recorded finalization functions for all IDs for (std::size_t i = 0; i < g_map.size(); i++) { + const auto on_stop = id_manager::typeinfo::get()[i].on_stop; + for (auto& id : g_map[i]) { - id_manager::typeinfo::get()[i].on_stop(id.second.get()); + on_stop(id.second.get()); } g_map[i].clear(); diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index bc9ac403fd..c78175fdc8 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -37,6 +37,8 @@ namespace id_manager { static inline void func(T*) { + // Forbid forward declarations + static constexpr auto size = sizeof(std::conditional_t::value, void*, T>); } }; @@ -45,7 +47,7 @@ namespace id_manager { static inline void func(T* ptr) { - ptr->on_init(); + if (ptr) ptr->on_init(); } }; @@ -55,6 +57,8 @@ namespace id_manager { static inline void func(T*) { + // Forbid forward declarations + static constexpr auto size = sizeof(std::conditional_t::value, void*, T>); } }; @@ -63,7 +67,7 @@ namespace id_manager { static inline void func(T* ptr) { - ptr->on_stop(); + if (ptr) ptr->on_stop(); } }; @@ -97,9 +101,6 @@ namespace id_manager template static inline void update() { - // Forbid forward declarations - static constexpr auto size = sizeof(std::conditional_t::value, void*, T>); - auto& info = access()[get_index()]; info.on_init = [](void* ptr) { return_ id_manager::on_init::func(static_cast(ptr)); }; @@ -111,12 +112,6 @@ namespace id_manager { return access(); } - - template - static inline auto get_stop() - { - return access()[get_index()].on_stop; - } }; template @@ -257,6 +252,7 @@ public: if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) { id_manager::on_init::func(static_cast(pair->second.get())); + id_manager::on_stop::func(nullptr); return{ pair->second, static_cast(pair->second.get()) }; } @@ -270,6 +266,7 @@ public: if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) { id_manager::on_init::func(static_cast(pair->second.get())); + id_manager::on_stop::func(nullptr); return pair->first; } @@ -283,6 +280,7 @@ public: if (auto pair = create_id(WRAP_EXPR(ptr))) { id_manager::on_init::func(static_cast(pair->second.get())); + id_manager::on_stop::func(nullptr); return pair->first; } @@ -296,6 +294,7 @@ public: if (auto pair = create_id(std::forward(provider))) { id_manager::on_init::func(static_cast(pair->second.get())); + id_manager::on_stop::func(nullptr); return { pair->second, static_cast(pair->second.get()) }; } @@ -389,7 +388,7 @@ public: if (LIKELY(ptr)) { - id_manager::typeinfo::get_stop()(static_cast(ptr.get())); + id_manager::on_stop::func(static_cast(ptr.get())); } return ptr.operator bool(); @@ -403,7 +402,7 @@ public: if (LIKELY(ptr)) { - id_manager::typeinfo::get_stop()(static_cast(ptr.get())); + id_manager::on_stop::func(static_cast(ptr.get())); } return{ ptr, static_cast(ptr.get()) }; @@ -429,7 +428,7 @@ public: g_map[get_type()].erase(id); } - id_manager::typeinfo::get_stop()(static_cast(ptr.get())); + id_manager::on_stop::func(static_cast(ptr.get())); return{ ptr, static_cast(ptr.get()) }; } @@ -479,6 +478,7 @@ public: if (ptr) { id_manager::on_init::func(ptr.get()); + id_manager::on_stop::func(nullptr); } return ptr; @@ -531,6 +531,7 @@ public: if (ptr) { id_manager::on_init::func(ptr.get()); + id_manager::on_stop::func(nullptr); } return ptr; @@ -585,6 +586,7 @@ public: } id_manager::on_init::func(ptr.get()); + id_manager::on_stop::func(nullptr); return ptr; } @@ -616,7 +618,7 @@ public: if (ptr) { - id_manager::typeinfo::get_stop()(static_cast(ptr.get())); + id_manager::on_stop::func(static_cast(ptr.get())); } return ptr.operator bool(); @@ -630,7 +632,7 @@ public: if (ptr) { - id_manager::typeinfo::get_stop()(static_cast(ptr.get())); + id_manager::on_stop::func(static_cast(ptr.get())); } return{ ptr, static_cast(ptr.get()) }; diff --git a/rpcs3/Emu/PSP2/ARMv7Function.h b/rpcs3/Emu/PSP2/ARMv7Function.h index 5d2f5d0e64..eb9e418cf7 100644 --- a/rpcs3/Emu/PSP2/ARMv7Function.h +++ b/rpcs3/Emu/PSP2/ARMv7Function.h @@ -4,7 +4,12 @@ using arm_function_t = void(*)(ARMv7Thread&); -#define BIND_FUNC(func) [](ARMv7Thread& cpu){ cpu.last_function = #func; arm_func_detail::do_call(cpu, func); } +#define BIND_FUNC(func) static_cast([](ARMv7Thread& cpu){\ + const auto old_f = cpu.last_function;\ + cpu.last_function = #func;\ + arm_func_detail::do_call(cpu, func);\ + cpu.last_function = old_f;\ +}) struct arm_va_args_t { diff --git a/rpcs3/Emu/PSP2/ARMv7Module.cpp b/rpcs3/Emu/PSP2/ARMv7Module.cpp index bf61a8fec4..7992b3b6f8 100644 --- a/rpcs3/Emu/PSP2/ARMv7Module.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Module.cpp @@ -79,27 +79,26 @@ extern std::string arm_get_variable_name(const std::string& module, u32 vnid); // Function lookup table. Not supposed to grow after emulation start. std::vector g_arm_function_cache; +std::vector g_arm_function_names; + +extern std::string arm_get_module_function_name(u32 index) +{ + if (index < g_arm_function_names.size()) + { + return g_arm_function_names[index]; + } + + return fmt::format(".%u", index); +} + extern void arm_execute_function(ARMv7Thread& cpu, u32 index) { if (index < g_arm_function_cache.size()) { if (const auto func = g_arm_function_cache[index]) { - const auto previous_function = cpu.last_function; // TODO: use gsl::finally or something - - try - { - func(cpu); - } - catch (...) - { - logs::ARMv7.format(Emu.IsStopped() ? logs::level::warning : logs::level::error, "Function '%s' aborted", cpu.last_function); - cpu.last_function = previous_function; - throw; - } - - LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", cpu.last_function, cpu.GPR[0]); - cpu.last_function = previous_function; + func(cpu); + LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", arm_get_module_function_name(index), cpu.GPR[0]); return; } } @@ -220,6 +219,8 @@ static void arm_initialize_modules() // Reinitialize function cache g_arm_function_cache = arm_function_manager::get(); + g_arm_function_names.clear(); + g_arm_function_names.resize(g_arm_function_cache.size()); // "Use" all the modules for correct linkage for (auto& module : registered) @@ -229,6 +230,7 @@ static void arm_initialize_modules() for (auto& function : module->functions) { LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + g_arm_function_names.at(function.second.index) = fmt::format("%s.%s", module->name, function.second.name); } for (auto& variable : module->variables) @@ -555,6 +557,7 @@ void arm_exec_loader::load() const // TODO index = ::size32(g_arm_function_cache); g_arm_function_cache.emplace_back(); + g_arm_function_names.emplace_back(fmt::format("%s.%s", module_name, fname)); LOG_ERROR(LOADER, "** Unknown function '%s' in module '%s' (*0x%x) -> index %u", fname, module_name, faddr, index); } diff --git a/rpcs3/Emu/PSP2/ARMv7Thread.cpp b/rpcs3/Emu/PSP2/ARMv7Thread.cpp index f491dff093..c0476525e3 100644 --- a/rpcs3/Emu/PSP2/ARMv7Thread.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Thread.cpp @@ -126,13 +126,11 @@ extern thread_local std::string(*g_tls_log_prefix)(); void ARMv7Thread::cpu_task() { - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } + return custom_task ? custom_task(*this) : fast_call(PC); +} +void ARMv7Thread::cpu_task_main() +{ g_tls_log_prefix = [] { const auto cpu = static_cast(get_current_cpu_thread()); @@ -191,34 +189,49 @@ ARMv7Thread::ARMv7Thread(const std::string& name) void ARMv7Thread::fast_call(u32 addr) { - auto old_PC = PC; - auto old_stack = SP; - auto old_LR = LR; - auto old_task = std::move(custom_task); + const auto old_PC = PC; + const auto old_SP = SP; + const auto old_LR = LR; + const auto old_task = std::move(custom_task); + const auto old_func = last_function; PC = addr; LR = Emu.GetCPUThreadStop(); custom_task = nullptr; + last_function = nullptr; try { - cpu_task(); + cpu_task_main(); + + if (SP != old_SP && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // SP shouldn't change + { + throw fmt::exception("Stack inconsistency (addr=0x%x, SP=0x%x, old=0x%x)", addr, SP, old_SP); + } } catch (cpu_state _s) { state += _s; if (_s != cpu_state::ret) throw; } + catch (EmulationStopped) + { + if (last_function) LOG_WARNING(ARMv7, "'%s' aborted", last_function); + last_function = old_func; + throw; + } + catch (...) + { + if (last_function) LOG_ERROR(ARMv7, "'%s' aborted", last_function); + last_function = old_func; + throw; + } state -= cpu_state::ret; PC = old_PC; - - if (SP != old_stack) // SP shouldn't change - { - throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%x, old=0x%x)", addr, SP, old_stack); - } - + SP = old_SP; LR = old_LR; custom_task = std::move(old_task); + last_function = old_func; } diff --git a/rpcs3/Emu/PSP2/ARMv7Thread.h b/rpcs3/Emu/PSP2/ARMv7Thread.h index 59b9c393a9..3f0aaa9231 100644 --- a/rpcs3/Emu/PSP2/ARMv7Thread.h +++ b/rpcs3/Emu/PSP2/ARMv7Thread.h @@ -18,6 +18,7 @@ public: virtual std::string dump() const override; virtual void cpu_init() override; virtual void cpu_task() override; + virtual void cpu_task_main(); virtual ~ARMv7Thread() override; ARMv7Thread(const std::string& name);