PPU Analyser fix

This commit is contained in:
Nekotekina 2016-07-13 02:54:34 +03:00
parent 94da0dbd4d
commit 0a5b518aea
2 changed files with 44 additions and 18 deletions

View File

@ -367,14 +367,15 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
} }
}; };
// Get next function address // Get next reliable function address
auto get_limit = [&](u32 addr) -> u32 auto get_limit = [&](u32 addr) -> u32
{ {
const auto found = funcs.lower_bound(addr); for (auto it = funcs.lower_bound(addr), end = funcs.end(); it != end; it++)
if (found != funcs.end())
{ {
return found->first; if (it->second.attr & ppu_attr::known_addr)
{
return it->first;
}
} }
return end; return end;
@ -396,6 +397,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
TOCs.emplace(toc); TOCs.emplace(toc);
auto& func = add_func(addr, toc, ptr.addr()); auto& func = add_func(addr, toc, ptr.addr());
func.attr += ppu_attr::known_addr;
} }
break; break;
@ -469,14 +471,15 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
u32 addr = 0; u32 addr = 0;
u32 size = 0; u32 size = 0;
if ((ptr[2] == -1 || ptr[2] == 0) && ptr[4] == 0) if (ptr[2] == 0 && ptr[3] == 0)
{
size = ptr[5];
}
else if ((ptr[2] == -1 || ptr[2] == 0) && ptr[4] == 0)
{ {
addr = ptr[3] + ptr.addr() + 8; addr = ptr[3] + ptr.addr() + 8;
size = ptr[5]; size = ptr[5];
} }
else if (ptr[2] == 0 && ptr[3] == 0)
{
}
else if (ptr[2] != -1 && ptr[4]) else if (ptr[2] != -1 && ptr[4])
{ {
addr = ptr[2]; addr = ptr[2];
@ -499,6 +502,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
} }
auto& func = add_func(addr, 0, ptr.addr()); auto& func = add_func(addr, 0, ptr.addr());
func.attr += ppu_attr::known_addr;
func.attr += ppu_attr::known_size; func.attr += ppu_attr::known_size;
func.size = size; func.size = size;
} }
@ -565,6 +569,8 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// The most used simple import stub // The most used simple import stub
func.size = 0x20; func.size = 0x20;
func.blocks.emplace(func.addr, func.size); func.blocks.emplace(func.addr, func.size);
func.attr += ppu_attr::known_addr;
func.attr += ppu_attr::known_size;
continue; continue;
} }
@ -592,12 +598,20 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
func.blocks.emplace(vm::cast(func.addr), 0); func.blocks.emplace(vm::cast(func.addr), 0);
} }
// Get function limit
const u32 func_end = get_limit(func.addr + 1);
// Block analysis workload // Block analysis workload
std::vector<std::reference_wrapper<std::pair<const u32, u32>>> block_queue; std::vector<std::reference_wrapper<std::pair<const u32, u32>>> block_queue;
// Add new block for analysis // Add new block for analysis
auto add_block = [&](u32 addr) -> bool auto add_block = [&](u32 addr) -> bool
{ {
if (addr < func.addr || addr >= func_end)
{
return false;
}
const auto _pair = func.blocks.emplace(addr, 0); const auto _pair = func.blocks.emplace(addr, 0);
if (_pair.second) if (_pair.second)
@ -611,7 +625,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
for (auto& block : func.blocks) for (auto& block : func.blocks)
{ {
if (!block.second) if (!block.second && block.first < func_end)
{ {
block_queue.emplace_back(block); block_queue.emplace_back(block);
} }
@ -620,7 +634,11 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
// TODO: lower priority? // TODO: lower priority?
if (func.attr & ppu_attr::no_size) if (func.attr & ppu_attr::no_size)
{ {
const u32 next = get_limit(func.blocks.crbegin()->first + 1); // Get next function
const auto _next = funcs.lower_bound(func.blocks.crbegin()->first + 1);
// Get limit
const u32 func_end2 = _next == funcs.end() ? func_end : std::min<u32>(_next->first, func_end);
// Find more block entries // Find more block entries
for (const auto& seg : segs) for (const auto& seg : segs)
@ -629,7 +647,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{ {
const u32 value = *ptr; const u32 value = *ptr;
if (value % 4 == 0 && value >= func.addr && value < next) if (value % 4 == 0 && value >= func.addr && value < func_end2)
{ {
add_block(value); add_block(value);
} }
@ -644,7 +662,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{ {
auto& block = block_queue[j].get(); auto& block = block_queue[j].get();
for (vm::cptr<u32> _ptr = vm::cast(block.first); _ptr.addr() < end;) for (vm::cptr<u32> _ptr = vm::cast(block.first); _ptr.addr() < func_end;)
{ {
const u32 iaddr = _ptr.addr(); const u32 iaddr = _ptr.addr();
const ppu_opcode_t op{*_ptr++}; const ppu_opcode_t op{*_ptr++};
@ -685,7 +703,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{ {
// Nothing // Nothing
} }
else if (is_call || target < func.addr/* || target >= get_limit(_ptr.addr())*/) else if (is_call || target < func.addr || target >= func_end)
{ {
// Add function call (including obvious tail call) // Add function call (including obvious tail call)
add_func(target, 0, func.addr); add_func(target, 0, func.addr);
@ -719,7 +737,7 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
{ {
// Analyse jumptable (TODO) // Analyse jumptable (TODO)
const u32 jt_addr = _ptr.addr(); const u32 jt_addr = _ptr.addr();
const u32 jt_end = end; const u32 jt_end = func_end;
for (; _ptr.addr() < jt_end; _ptr++) for (; _ptr.addr() < jt_end; _ptr++)
{ {
@ -771,6 +789,11 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
continue; continue;
} }
// Just set the max
func.size = std::max<u32>(func.size, block.first + block.second - func.addr);
continue;
// Disabled (TODO)
if (expected == block.first) if (expected == block.first)
{ {
func.size += block.second; func.size += block.second;
@ -869,13 +892,15 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
} }
} }
// Function shrinkage (TODO: it's potentially dangerous but improvable) // Function shrinkage, disabled (TODO: it's potentially dangerous but improvable)
for (auto& _pair : funcs) for (auto& _pair : funcs)
{ {
auto& func = _pair.second; auto& func = _pair.second;
// Next function start // Get next function addr
const u32 next = get_limit(_pair.first + 1); const auto _next = funcs.lower_bound(_pair.first + 1);
const u32 next = _next == funcs.end() ? end : _next->first;
// Just ensure that functions don't overlap // Just ensure that functions don't overlap
if (func.addr + func.size > next) if (func.addr + func.size > next)

View File

@ -8,6 +8,7 @@
// PPU Function Attributes // PPU Function Attributes
enum class ppu_attr : u32 enum class ppu_attr : u32
{ {
known_addr,
known_size, known_size,
no_return, no_return,
no_size, no_size,