mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-19 01:10:39 +02:00
WriteMMIO_U32 was missing the return after the kernel-mode check, so a user-mode write raised the exception and then went through anyway. The other five MMIO accessors already return here; this one lost it when the GPIO/syscon branches were added. Int_Vrot scanned all four entries of dregs, but GetVectorRegs only fills the first n - so a vrot with vs == 0 (S000) matched a lane that isn't there and took the cosine from it. The IR backend gets this right via IsOverlapSafe, so the two disagreed. The breakpoint checks in MIPSInterpret and RunUntilDowncountZeroWithChecks read instr->flags without checking for null, which MIPSGetInstruction returns for the eight primary opcodes (and many subops) that don't decode. With a memcheck or register breakpoint active, landing on one of those crashed instead of raising ILLEGAL. Also: GetVectorOverlap decoded the second vector with size1 (no callers today), and RegisterFunction left most of its AnalyzedFunction uninitialized, including the size that ends up in knownfuncs.ini. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
167 lines
4.6 KiB
C++
167 lines
4.6 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);
|
|
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
|