diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 08adadcd3b..63e2c2d462 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -530,7 +530,7 @@ namespace ppu_patterns }; } -bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::basic_string& applied, std::function check_aborted) +bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::basic_string& applied, const std::vector& exported_funcs, std::function check_aborted) { if (segs.empty()) { @@ -931,6 +931,32 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b bool used_fallback = false; + if (func_queue.empty()) + { + for (u32 addr : exported_funcs) + { + const u32 faddr = get_ref(addr); + + if (addr < start || addr >= start + segs[0].size) + { + // TODO: Reverse engineer how it works (maybe some flag in exports) + + if (faddr < start || faddr >= start + segs[0].size) + { + ppu_log.notice("Export not usable at 0x%x / 0x%x (0x%x...0x%x)", addr, faddr, start, start + segs[0].size); + continue; + } + + addr = faddr; + } + + ppu_log.trace("Enqueued exported PPU function 0x%x for analysis", addr); + + add_func(addr, 0, 0); + used_fallback = true; + } + } + if (func_queue.empty() && segs[0].size >= 4u) { // Fallback, identify functions using callers (no jumptable detection, tail calls etc) diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index afb1fa82aa..c7e690cd1f 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -109,7 +109,7 @@ struct ppu_module addr_to_seg_index = info.addr_to_seg_index; } - bool analyse(u32 lib_toc, u32 entry, u32 end, const std::basic_string& applied, std::function check_aborted = {}); + bool analyse(u32 lib_toc, u32 entry, u32 end, const std::basic_string& applied, const std::vector& exported_funcs = std::vector{}, std::function check_aborted = {}); void validate(u32 reloc); template diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 52bac4586d..03ed64d515 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -682,7 +682,7 @@ extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib) } // Load and register exports; return special exports found (nameless module) -static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false, std::basic_string* loaded_flags = nullptr) +static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false, std::vector* funcs = nullptr, std::basic_string* loaded_flags = nullptr) { std::unordered_map result; @@ -714,6 +714,11 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, const u32 nid = _module.get_ref(lib.nids, i); const u32 addr = _module.get_ref(lib.addrs, i); + if (funcs) + { + funcs->emplace_back(addr); + } + if (i < lib.num_func) { ppu_loader.notice("** Special: [%s] at 0x%x [0x%x, 0x%x]", ppu_get_function_name({}, nid), addr, _module.get_ref(addr), _module.get_ref(addr + 4)); @@ -735,13 +740,6 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, continue; } - const bool is_dummy_load = Emu.IsReady() && g_fxo->get().segs.empty() && !Emu.DeserialManager(); - - if (!is_dummy_load && for_observing_callbacks) - { - continue; - } - const std::string module_name(&_module.get_ref(lib.name)); if (unload_exports) @@ -761,7 +759,7 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, ppu_loader.error("Unexpected num_tlsvar (%u)!", lib.num_tlsvar); } - const bool should_load = is_dummy_load || ppu_register_library_lock(module_name, true); + const bool should_load = for_observing_callbacks || ppu_register_library_lock(module_name, true); if (loaded_flags) { @@ -790,6 +788,16 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, const u32 faddr = _module.get_ref(faddrs, i); ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x [at:0x%x]", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, _module.get_ref(faddr)); + if (funcs) + { + funcs->emplace_back(faddr); + } + + if (for_observing_callbacks) + { + continue; + } + // Function linkage info auto& flink = mlink.functions[fnid]; @@ -850,6 +858,11 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, const u32 vaddr = _module.get_ref(vaddrs, i); ppu_loader.notice("**** %s export: &[%s] at 0x%x", module_name, ppu_get_variable_name(module_name, vnid), vaddr); + if (for_observing_callbacks) + { + continue; + } + // Variable linkage info auto& vlink = mlink.variables[vnid]; @@ -979,7 +992,7 @@ void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 ex vm_all_fake_module.segs.emplace_back(ppu_segment{0x10000, 0 - 0x10000u, 1 /*LOAD*/, 0, 0 - 0x1000u, vm::base(0x10000)}); vm_all_fake_module.addr_to_seg_index.emplace(0x10000, 0); - ppu_load_exports(vm_all_fake_module, &link, exports_start, exports_start + exports_size, false, &loaded_flags); + ppu_load_exports(vm_all_fake_module, &link, exports_start, exports_start + exports_size, false, nullptr, &loaded_flags); if (!imports_size) { @@ -1731,6 +1744,8 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo } } + std::vector exported_funcs; + if (!elf.progs.empty() && elf.progs[0].p_paddr) { struct ppu_prx_library_info @@ -1774,7 +1789,7 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo ppu_linkage_info dummy{}; - prx->specials = ppu_load_exports(*prx, virtual_load ? &dummy : &link, prx->exports_start, prx->exports_end, true); + prx->specials = ppu_load_exports(*prx, virtual_load ? &dummy : &link, prx->exports_start, prx->exports_end, true, &exported_funcs); prx->imports = ppu_load_imports(*prx, prx->relocs, virtual_load ? &dummy : &link, lib_info->imports_start, lib_info->imports_end); if (virtual_load) @@ -1883,7 +1898,7 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo ppu_check_patch_spu_images(*prx, seg); } - prx->analyse(toc, 0, end, applied); + prx->analyse(toc, 0, end, applied, exported_funcs); if (!ar && !virtual_load) { @@ -3014,7 +3029,7 @@ std::pair, CellError> ppu_load_overlay(const ppu_ex const auto cpu = cpu_thread::get_current(); // Analyse executable (TODO) - if (!ovlm->analyse(0, ovlm->entry, end, ovlm->applied_patches, !cpu ? std::function() : [cpu]() + if (!ovlm->analyse(0, ovlm->entry, end, ovlm->applied_patches, std::vector{}, !cpu ? std::function() : [cpu]() { return !!(cpu->state & cpu_flag::exit); })) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 9fdc3662c9..bd55a780fb 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -4148,7 +4148,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vectorget().sem); !ovlm->analyse(0, ovlm->entry, ovlm->seg0_code_end, ovlm->applied_patches, []() + if (std::lock_guard lock(g_fxo->get().sem); !ovlm->analyse(0, ovlm->entry, ovlm->seg0_code_end, ovlm->applied_patches, std::vector{}, []() { return Emu.IsStopped(); })) @@ -4256,7 +4256,7 @@ extern void ppu_precompile(std::vector& dir_queue, std::vector{}, [](){ return Emu.IsStopped(); })) { g_fxo->get() = std::move(current_cache); break; @@ -4308,7 +4308,7 @@ extern void ppu_initialize() std::optional progr(std::in_place, "Analyzing PPU Executable..."); // Analyse executable - if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_patches, [](){ return Emu.IsStopped(); })) + if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_patches, std::vector{}, [](){ return Emu.IsStopped(); })) { return; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index be2465d6e3..e66a642ae2 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1681,7 +1681,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, { if (auto& _main = *ensure(g_fxo->try_get()); !_main.path.empty()) { - if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_patches, [](){ return Emu.IsStopped(); })) + if (!_main.analyse(0, _main.elf_entry, _main.seg0_code_end, _main.applied_patches, std::vector{}, [](){ return Emu.IsStopped(); })) { return; }