PPU Analyzer: Look for functions using callers (fallback)

This commit is contained in:
Eladash 2024-04-18 15:42:11 +03:00 committed by Elad Ashkenazi
parent 7bf8917c08
commit c7d93bd470
1 changed files with 34 additions and 2 deletions

View File

@ -696,7 +696,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
const vm::cptr<void> seg_end = vm::cast(seg.addr + seg.size - 4);
auto ptr = get_ptr<u32>(_ptr);
for (vm::cptr<u32> _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<u32> _ptr = vm::cast(start);
const vm::cptr<void> seg_end = vm::cast(end - 4);
for (auto ptr = get_ptr<u32>(_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<u32>(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)