mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
The function list is from before the load, where other code (an overlay module) may have been. Hashing it again from the loaded memory keeps the hooks to code that actually matches. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
169 lines
4.7 KiB
C++
169 lines
4.7 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/File/Path.h"
|
|
#include "Core/Debugger/DebugInterface.h"
|
|
#include "Core/MIPS/MIPS.h"
|
|
|
|
namespace MIPSAnalyst {
|
|
const int MIPS_NUM_GPRS = 32;
|
|
|
|
struct RegisterAnalysisResults {
|
|
bool used;
|
|
int firstRead;
|
|
int lastRead;
|
|
int firstWrite;
|
|
int lastWrite;
|
|
int firstReadAsAddr;
|
|
int lastReadAsAddr;
|
|
|
|
int readCount;
|
|
int writeCount;
|
|
int readAsAddrCount;
|
|
|
|
int TotalReadCount() const { return readCount + readAsAddrCount; }
|
|
int FirstRead() const { return firstReadAsAddr < firstRead ? firstReadAsAddr : firstRead; }
|
|
int LastRead() const { return lastReadAsAddr > lastRead ? lastReadAsAddr : lastRead; }
|
|
|
|
void MarkRead(u32 addr) {
|
|
if (firstRead == -1)
|
|
firstRead = addr;
|
|
lastRead = addr;
|
|
readCount++;
|
|
used = true;
|
|
}
|
|
|
|
void MarkReadAsAddr(u32 addr) {
|
|
if (firstReadAsAddr == -1)
|
|
firstReadAsAddr = addr;
|
|
lastReadAsAddr = addr;
|
|
readAsAddrCount++;
|
|
used = true;
|
|
}
|
|
|
|
void MarkWrite(u32 addr) {
|
|
if (firstWrite == -1)
|
|
firstWrite = addr;
|
|
lastWrite = addr;
|
|
writeCount++;
|
|
used = true;
|
|
}
|
|
};
|
|
|
|
struct AnalysisResults {
|
|
RegisterAnalysisResults r[MIPS_NUM_GPRS];
|
|
};
|
|
|
|
AnalysisResults Analyze(u32 address);
|
|
|
|
// This tells us if the reg is used within intrs of addr (also includes likely delay slots.)
|
|
bool IsRegisterUsed(MIPSGPReg reg, u32 addr, int instrs);
|
|
// This tells us if the reg is clobbered within intrs of addr (e.g. it is surely not used.)
|
|
bool IsRegisterClobbered(MIPSGPReg reg, u32 addr, int instrs);
|
|
|
|
struct AnalyzedFunction {
|
|
u32 start = 0;
|
|
u32 end = 0;
|
|
u64 hash = 0;
|
|
u32 size = 0;
|
|
bool isStraightLeaf = false;
|
|
bool hasHash = false;
|
|
bool usesVFPU = false;
|
|
bool foundInSymbolMap = false;
|
|
char name[64] = {};
|
|
};
|
|
|
|
struct ReplacementTableEntry;
|
|
|
|
void Reset();
|
|
|
|
// This will not only create a database of "AnalyzedFunction" structs, it also
|
|
// will insert all the functions it finds into the symbol map, if insertSymbols is true.
|
|
|
|
// If we have loaded symbols from the elf, we'll register functions as they are touched
|
|
// so that we don't just dump them all in the cache.
|
|
void RegisterFunction(u32 startAddr, u32 size, const char *name);
|
|
// Returns new insertSymbols value for FinalizeScan().
|
|
bool ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols);
|
|
void FinalizeScan(bool insertSymbols);
|
|
void ForgetFunctions(u32 startAddr, u32 endAddr);
|
|
|
|
bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out);
|
|
|
|
void LoadBuiltinHashMap();
|
|
void LoadHashMap(const Path &filename);
|
|
void StoreHashMap(Path filename = Path());
|
|
|
|
const char *LookupHash(u64 hash, u32 funcSize);
|
|
// Hashes the known functions again, from what memory holds now (after a savestate load.)
|
|
void RehashFunctions();
|
|
void ReplaceFunctions();
|
|
|
|
void UpdateHashMap();
|
|
void ApplyHashMap();
|
|
|
|
std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op);
|
|
std::vector<MIPSGPReg> GetOutputRegs(MIPSOpcode op);
|
|
|
|
MIPSGPReg GetOutGPReg(MIPSOpcode op);
|
|
bool ReadsFromGPReg(MIPSOpcode op, MIPSGPReg reg);
|
|
bool IsDelaySlotNiceReg(MIPSOpcode branchOp, MIPSOpcode op, MIPSGPReg reg1, MIPSGPReg reg2 = MIPS_REG_ZERO);
|
|
bool IsDelaySlotNiceVFPU(MIPSOpcode branchOp, MIPSOpcode op);
|
|
bool IsDelaySlotNiceFPU(MIPSOpcode branchOp, MIPSOpcode op);
|
|
bool IsSyscall(MIPSOpcode op);
|
|
|
|
bool OpWouldChangeMemory(MIPSState *mips, u32 pc, u32 addr, u32 size);
|
|
int OpMemoryAccessSize(u32 pc);
|
|
bool IsOpMemoryWrite(u32 pc);
|
|
bool OpHasDelaySlot(u32 pc);
|
|
|
|
struct MipsOpcodeInfo {
|
|
DebugInterface *cpu;
|
|
u32 opcodeAddress;
|
|
MIPSOpcode encodedOpcode;
|
|
|
|
// shared between branches and conditional moves
|
|
bool isConditional;
|
|
bool conditionMet;
|
|
|
|
// branches
|
|
u32 branchTarget;
|
|
bool isBranch;
|
|
bool isLinkedBranch;
|
|
bool isLikelyBranch;
|
|
bool isBranchToRegister;
|
|
int branchRegisterNum;
|
|
|
|
// data access
|
|
bool isDataAccess;
|
|
int dataSize;
|
|
u32 dataAddress;
|
|
|
|
bool hasRelevantAddress;
|
|
u32 relevantAddress;
|
|
};
|
|
|
|
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address);
|
|
|
|
} // namespace MIPSAnalyst
|