From c7d93bd470e2d5d966c33ec1c1d12b59da9c5797 Mon Sep 17 00:00:00 2001 From: Eladash <18193363+elad335@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:42:11 +0300 Subject: [PATCH] PPU Analyzer: Look for functions using callers (fallback) --- rpcs3/Emu/Cell/PPUAnalyser.cpp | 36 ++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 9e6ae11906..c8390b6075 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -696,7 +696,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b const vm::cptr seg_end = vm::cast(seg.addr + seg.size - 4); auto ptr = get_ptr(_ptr); - for (vm::cptr _ptr = vm::cast(seg.addr); _ptr <= seg_end; advance(_ptr, ptr, 1)) + for (; _ptr <= seg_end; advance(_ptr, ptr, 1)) { const u32 value = *ptr; @@ -929,6 +929,38 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b } } + if (func_queue.empty() && segs[0].size >= 4u) + { + // Fallback, identify functions using callers (no jumptable detection, tail calls etc) + ppu_log.warning("Looking for PPU functions using callers. ('%s')", name); + + vm::cptr _ptr = vm::cast(start); + const vm::cptr seg_end = vm::cast(end - 4); + + for (auto ptr = get_ptr(_ptr); _ptr <= seg_end; advance(_ptr, ptr, 1)) + { + const u32 iaddr = _ptr.addr(); + + const ppu_opcode_t op{*ptr}; + const ppu_itype::type type = s_ppu_itype.decode(op.opcode); + + if (type == ppu_itype::B && op.lk && !op.aa) + { + const u32 target = iaddr + op.bt24; + + if (target >= start && target < end && target != iaddr && target != iaddr + 4) + { + // TODO: Check full executability + if (s_ppu_itype.decode(get_ref(target)) != ppu_itype::UNK) + { + ppu_log.trace("Enqueued PPU function 0x%x using a caller at 0x%x", target, iaddr); + add_func(target, 0, 0); + } + } + } + } + } + // Main loop (func_queue may grow) for (usz i = 0; i < func_queue.size(); i++) { @@ -1631,7 +1663,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b } } - ppu_log.notice("Function analysis: %zu functions (%zu enqueued)", fmap.size(), func_queue.size()); + (fmap.empty() ? ppu_log.error : ppu_log.notice)("Function analysis: %zu functions (%zu enqueued)", fmap.size(), func_queue.size()); // Decompose functions to basic blocks if (!entry && !sec_end)