mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-10-01 18:31:21 -04:00
better analyzer and integrating sce-symbol-scanner (#130)
* feat: modularize elf analyzer feat: added experimental sce symbol scanner feat: change analyzer order feat: small optimizations on analyzer * feat: remove example_config.toml because its causing confusion on some people * feat: embed sce symbol but leave optional import path feat: killed skip function on analyzer but leave it so you can skip manual if you want * feat: pin elfio tag * feat: manually create string view with size * feat: update ghidra script
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
#include "MiniTest.h"
|
||||
#include "ps2recomp/elf_analyzer.h"
|
||||
#include "ps2recomp/function_classifier.h"
|
||||
#include "ps2recomp/instructions.h"
|
||||
#include "ps2recomp/types.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using namespace ps2recomp;
|
||||
@@ -47,9 +47,24 @@ void register_elf_analyzer_tests()
|
||||
|
||||
t.IsFalse(analyzer.isLibrarySymbolNameForHeuristics("bhEne13_Brain"),
|
||||
"named game function should not be classified as library");
|
||||
t.IsFalse(analyzer.isLibrarySymbolNameForHeuristics("ScenePrerender"),
|
||||
"game functions beginning with Scene should not be classified as sce SDK APIs");
|
||||
t.IsFalse(analyzer.isLibrarySymbolNameForHeuristics("sub_00100C00"),
|
||||
"unreliable auto-generated names should not be classified as library"); });
|
||||
|
||||
tc.Run("runtime handler filter keeps unsupported SDK names informational", [](TestCase &t)
|
||||
{
|
||||
t.IsTrue(FunctionClassifier::hasRuntimeHandler("sceCdRead"),
|
||||
"sceCdRead should resolve to a known runtime stub handler");
|
||||
t.IsTrue(FunctionClassifier::hasRuntimeHandler("_printf"),
|
||||
"runtime handler resolution should accept leading underscore aliases");
|
||||
t.IsTrue(FunctionClassifier::hasRuntimeHandler("__ieee754_rem_pio2f"),
|
||||
"double-underscore libm helpers should be active stubs only when the runtime knows them");
|
||||
t.IsTrue(FunctionClassifier::hasRuntimeHandler("__kernel_cosf"),
|
||||
"runtime-known libm kernel helpers should resolve exactly");
|
||||
t.IsFalse(FunctionClassifier::hasRuntimeHandler("scePP1_Kick"),
|
||||
"SDK functions without runtime handlers should not be active stubs"); });
|
||||
|
||||
tc.Run("reliable-symbol heuristic filters autogenerated names", [](TestCase &t)
|
||||
{
|
||||
t.IsTrue(ElfAnalyzer::isReliableSymbolNameForHeuristics("bhEne13_Brain"),
|
||||
@@ -70,37 +85,6 @@ void register_elf_analyzer_tests()
|
||||
t.IsFalse(ElfAnalyzer::isReliableSymbolNameForHeuristics("0x00100ABC"),
|
||||
"pure hex-style symbol should be treated as unreliable"); });
|
||||
|
||||
tc.Run("system-symbol heuristic is strict to system patterns", [](TestCase &t)
|
||||
{
|
||||
t.IsTrue(ElfAnalyzer::isSystemSymbolNameForHeuristics("__main"),
|
||||
"__main should be classified as system");
|
||||
t.IsTrue(ElfAnalyzer::isSystemSymbolNameForHeuristics("_start"),
|
||||
"_start should be classified as system");
|
||||
t.IsTrue(ElfAnalyzer::isSystemSymbolNameForHeuristics(".text.startup"),
|
||||
".text.* should be classified as system");
|
||||
|
||||
t.IsFalse(ElfAnalyzer::isSystemSymbolNameForHeuristics("bhObj001"),
|
||||
"game symbol should not be classified as system");
|
||||
t.IsFalse(ElfAnalyzer::isSystemSymbolNameForHeuristics("SetupSoundDriver"),
|
||||
"engine/game symbol should not be classified as system");
|
||||
t.IsFalse(ElfAnalyzer::isSystemSymbolNameForHeuristics("sub_00100C00"),
|
||||
"unreliable names should not be considered system by this classifier"); });
|
||||
|
||||
tc.Run("system skip keeps forced entry names recompiled", [](TestCase &t)
|
||||
{
|
||||
std::unordered_set<std::string> forcedNames{"_start", "_init"};
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipSystemSymbolForHeuristics("_start", forcedNames),
|
||||
"forced entry name _start should not be skipped");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipSystemSymbolForHeuristics("_init", forcedNames),
|
||||
"forced entry name _init should not be skipped");
|
||||
|
||||
t.IsTrue(ElfAnalyzer::shouldSkipSystemSymbolForHeuristics("__main", forcedNames),
|
||||
"system symbol not marked as forced should still be skipped");
|
||||
t.IsTrue(ElfAnalyzer::shouldSkipSystemSymbolForHeuristics("__divdi3", {}),
|
||||
"compiler helper __divdi3 should be skippable as system/runtime");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipSystemSymbolForHeuristics("ps2___divdi3", {}),
|
||||
"generated ps2_ wrapper names should not be treated as system"); });
|
||||
|
||||
tc.Run("entry-point mapping handles exact inside and fallback", [](TestCase &t)
|
||||
{
|
||||
Function f1;
|
||||
@@ -138,7 +122,7 @@ void register_elf_analyzer_tests()
|
||||
t.Equals(ElfAnalyzer::findFallbackEntryFunctionIndexForHeuristics(fallbackOnly), 0,
|
||||
"fallback should also accept 0x80100000"); });
|
||||
|
||||
tc.Run("signal-based skip heuristics keep reliable names and skip unreliable/system", [](TestCase &t)
|
||||
tc.Run("risk signal detection reports hardware io mmi and self modifying code", [](TestCase &t)
|
||||
{
|
||||
// Hardware I/O signal via LUI upper address in I/O region.
|
||||
Instruction hw = makeInstruction(0x1000, OPCODE_LUI);
|
||||
@@ -173,30 +157,9 @@ void register_elf_analyzer_tests()
|
||||
const bool hasSelfModifying = ElfAnalyzer::hasSelfModifyingSignalForHeuristics(smcInst, sections);
|
||||
t.IsTrue(hasSelfModifying, "self-modifying signal should be detected");
|
||||
|
||||
// Decision behavior by name reliability/system-ness.
|
||||
t.IsFalse(hasHardwareIO && ElfAnalyzer::shouldAutoSkipNameForHeuristics("bhEne13_Brain"),
|
||||
"reliable game symbol should not auto-skip from hardware signal alone");
|
||||
t.IsTrue(hasHardwareIO && ElfAnalyzer::shouldAutoSkipNameForHeuristics("sub_00100C00"),
|
||||
"unreliable symbol should auto-skip when risky signals exist");
|
||||
t.IsTrue(hasLargeComplexMMI && ElfAnalyzer::shouldAutoSkipNameForHeuristics("__main"),
|
||||
"system symbol should auto-skip when risky signals exist");
|
||||
t.IsFalse(hasSelfModifying && ElfAnalyzer::shouldAutoSkipNameForHeuristics("topThread"),
|
||||
"do-not-skip list should override auto-skip"); });
|
||||
|
||||
tc.Run("patch-density threshold behavior", [](TestCase &t)
|
||||
{
|
||||
t.IsTrue(ElfAnalyzer::shouldSkipForPatchDensityForHeuristics("sub_00100C00", 100, 6, false),
|
||||
"high-density patches on unreliable names should skip");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipForPatchDensityForHeuristics("sub_00100C00", 200, 6, false),
|
||||
"density below threshold should not skip");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipForPatchDensityForHeuristics("sub_00100C00", 100, 5, false),
|
||||
"patch count <= 5 should not skip");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipForPatchDensityForHeuristics("printf", 100, 6, true),
|
||||
"library functions should not be auto-skipped by patch density");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipForPatchDensityForHeuristics("bhEne13_Brain", 100, 6, false),
|
||||
"reliable game function should not be auto-skipped by patch density");
|
||||
t.IsFalse(ElfAnalyzer::shouldSkipForPatchDensityForHeuristics("topThread", 100, 6, false),
|
||||
"do-not-skip names should never be auto-skipped"); });
|
||||
(void)hasHardwareIO;
|
||||
(void)hasLargeComplexMMI;
|
||||
(void)hasSelfModifying; });
|
||||
|
||||
tc.Run("jump-table detection finds canonical sltiu/bne/lw/jr pattern", [](TestCase &t)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user