mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
PPU Analyzer: Utilize exported functions
This commit is contained in:
parent
6d280c5f3c
commit
6fff22391c
5 changed files with 60 additions and 19 deletions
|
@ -530,7 +530,7 @@ namespace ppu_patterns
|
|||
};
|
||||
}
|
||||
|
||||
bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::basic_string<u32>& applied, std::function<bool()> check_aborted)
|
||||
bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::basic_string<u32>& applied, const std::vector<u32>& exported_funcs, std::function<bool()> 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<u32>(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)
|
||||
|
|
|
@ -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<u32>& applied, std::function<bool()> check_aborted = {});
|
||||
bool analyse(u32 lib_toc, u32 entry, u32 end, const std::basic_string<u32>& applied, const std::vector<u32>& exported_funcs = std::vector<u32>{}, std::function<bool()> check_aborted = {});
|
||||
void validate(u32 reloc);
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -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<bool>* 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<u32>* funcs = nullptr, std::basic_string<bool>* loaded_flags = nullptr)
|
||||
{
|
||||
std::unordered_map<u32, u32> result;
|
||||
|
||||
|
@ -714,6 +714,11 @@ static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link,
|
|||
const u32 nid = _module.get_ref<u32>(lib.nids, i);
|
||||
const u32 addr = _module.get_ref<u32>(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<u32>(addr), _module.get_ref<u32>(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<main_ppu_module>().segs.empty() && !Emu.DeserialManager();
|
||||
|
||||
if (!is_dummy_load && for_observing_callbacks)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string module_name(&_module.get_ref<const char>(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<u32>(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<u32>(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<u32>(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<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<u32> exported_funcs;
|
||||
|
||||
if (!elf.progs.empty() && elf.progs[0].p_paddr)
|
||||
{
|
||||
struct ppu_prx_library_info
|
||||
|
@ -1774,7 +1789,7 @@ std::shared_ptr<lv2_prx> 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<lv2_prx> 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<std::shared_ptr<lv2_overlay>, 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<bool()>() : [cpu]()
|
||||
if (!ovlm->analyse(0, ovlm->entry, end, ovlm->applied_patches, std::vector<u32>{}, !cpu ? std::function<bool()>() : [cpu]()
|
||||
{
|
||||
return !!(cpu->state & cpu_flag::exit);
|
||||
}))
|
||||
|
|
|
@ -4148,7 +4148,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
|||
}
|
||||
|
||||
// Participate in thread execution limitation (takes a long time)
|
||||
if (std::lock_guard lock(g_fxo->get<jit_core_allocator>().sem); !ovlm->analyse(0, ovlm->entry, ovlm->seg0_code_end, ovlm->applied_patches, []()
|
||||
if (std::lock_guard lock(g_fxo->get<jit_core_allocator>().sem); !ovlm->analyse(0, ovlm->entry, ovlm->seg0_code_end, ovlm->applied_patches, std::vector<u32>{}, []()
|
||||
{
|
||||
return Emu.IsStopped();
|
||||
}))
|
||||
|
@ -4256,7 +4256,7 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
|
|||
break;
|
||||
}
|
||||
|
||||
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<u32>{}, [](){ return Emu.IsStopped(); }))
|
||||
{
|
||||
g_fxo->get<spu_cache>() = std::move(current_cache);
|
||||
break;
|
||||
|
@ -4308,7 +4308,7 @@ extern void ppu_initialize()
|
|||
std::optional<scoped_progress_dialog> 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<u32>{}, [](){ return Emu.IsStopped(); }))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -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_ppu_module>()); !_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<u32>{}, [](){ return Emu.IsStopped(); }))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue