Files
PS2Recomp/ps2xAnalyzer/include/ps2recomp/elf_analyzer.h
Ranieri 7562ec14c9 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
2026-06-06 23:37:12 -03:00

155 lines
6.0 KiB
C++

#ifndef PS2RECOMP_ELF_ANALYZER_H
#define PS2RECOMP_ELF_ANALYZER_H
#include "ps2recomp/elf_analysis_context.h"
#include "ps2recomp/function_classifier.h"
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <map>
#include <set>
#include <functional>
#include <cstdint>
namespace ps2recomp
{
struct CFGNode;
struct Instruction;
struct FunctionCall;
struct JumpTable;
struct Relocation;
struct Section;
struct Symbol;
struct Function;
class R5900Decoder;
class ElfParser;
using CFG = std::unordered_map<uint32_t, CFGNode>;
class ElfAnalyzer
{
public:
explicit ElfAnalyzer(const std::string &elfPath);
~ElfAnalyzer();
public:
void setSceSymbolDatabasePath(const std::string &databasePath);
bool analyze();
bool generateToml(const std::string &outputPath);
bool importGhidraMap(const std::string &csvPath);
public:
const std::vector<Function> &getFunctions() const;
public:
bool isLibrarySymbolNameForHeuristics(const std::string &name) const;
static bool isReliableSymbolNameForHeuristics(const std::string &name);
public:
static int findEntryFunctionIndexForHeuristics(const std::vector<Function> &functions, uint32_t entryAddress);
static int findFallbackEntryFunctionIndexForHeuristics(const std::vector<Function> &functions);
public:
static bool hasHardwareIOSignalForHeuristics(const std::vector<Instruction> &instructions);
static bool hasLargeComplexMMISignalForHeuristics(const std::vector<Instruction> &instructions, size_t largeInstructionThreshold = 500);
static bool hasSelfModifyingSignalForHeuristics(const std::vector<Instruction> &instructions, const std::vector<Section> &sections);
public:
static std::vector<JumpTable> detectJumpTablesForHeuristics(const std::vector<Instruction> &instructions, const std::vector<Section> &sections, const std::function<bool(uint32_t, uint32_t &)> &readWord);
static std::unordered_set<std::string> findRecursiveFunctionsForHeuristics(const std::unordered_map<std::string, std::vector<std::string>> &callGraph);
private:
std::string m_elfPath;
std::unique_ptr<ElfParser> m_elfParser;
std::unique_ptr<R5900Decoder> m_decoder;
ElfAnalysisContext m_context;
std::unordered_set<std::string> m_libFunctions;
std::unordered_set<std::string> m_untrackedStubFunctions;
std::unordered_set<uint32_t> m_forceRecompileStarts;
std::unordered_set<std::string> m_sceSdkFunctionNames;
FunctionClassifier m_classifier;
std::unordered_map<std::string, std::set<std::string>> m_functionDataUsage;
std::unordered_map<uint32_t, std::string> m_commonDataAccess;
std::map<uint32_t, uint32_t> m_patches;
std::map<uint32_t, std::string> m_patchReasons;
std::unordered_map<uint32_t, CFG> m_functionCFGs;
std::vector<JumpTable> m_jumpTables;
std::unordered_map<uint32_t, std::vector<FunctionCall>> m_functionCalls;
std::map<uint32_t, std::string> m_performanceCriticalReasons;
std::unordered_map<uint32_t, uint32_t> m_mmioByInstructionAddress;
std::string m_sceSymbolDatabasePath;
bool loadElf();
void buildFunctionIndex();
void decodeAllFunctionsOnce();
void classifyFunctions();
void runDataUsagePass();
void runPatchDetectionPass();
void runControlFlowPass();
void runJumpTablePass();
void runPerformancePass();
void runSignaturePass() const;
void printAnalysisSummary() const;
void discoverSceSdkSymbols();
void analyzeEntryPoint();
void analyzeLibraryFunctions();
void analyzeDataUsage();
void identifyPotentialPatches();
bool tryPatchSelfModifyingStore(const Function &func,
const std::vector<Instruction> &instructions,
size_t index);
bool tryResolveBasePlusOffset(const std::vector<Instruction> &instructions,
size_t index,
uint32_t reg,
int16_t offset,
uint32_t &baseAddr) const;
bool tryResolveLuiBase(const std::vector<Instruction> &instructions,
size_t index,
uint32_t reg,
uint32_t &baseAddr) const;
bool isCodeAddress(uint32_t addr) const;
void analyzeControlFlow();
void detectJumpTables();
void analyzePerformanceCriticalPaths();
void identifyRecursiveFunctions();
void analyzeRegisterUsage() const;
void analyzeFunctionSignatures() const;
void optimizePatches();
bool identifyMemcpyPattern(const Function &func) const;
bool identifyMemsetPattern(const Function &func) const;
bool identifyStringOperationPattern(const Function &func) const;
bool identifyMathPattern(const Function &func) const;
bool isLibraryFunction(const std::string &name) const;
void clearDecodedInstructionCache();
const std::vector<Instruction> &getDecodedInstructions(const Function &function) const;
std::vector<Instruction> decodeFunction(const Function &function) const;
CFG buildCFG(const Function &function) const;
std::string formatAddress(uint32_t address) const;
bool hasMMIInstructions(const Function &function) const;
bool hasVUInstructions(const Function &function) const;
void identifyFunctionType(const Function &function) const;
void categorizeFunction(Function &function);
uint32_t getSuccessor(const Instruction &inst, uint32_t currentAddr);
bool isSelfModifyingCode(const Function &function) const;
bool isLoopHeavyFunction(const Function &function) const;
};
}
#endif // PS2RECOMP_ELF_ANALYZER_H