From 769cb6a3699ba6568e367645766ae20c3ec53d14 Mon Sep 17 00:00:00 2001 From: Kingcom Date: Sun, 17 Aug 2014 14:57:30 +0200 Subject: [PATCH] Port the rest of the function scanning over from PPSSPP --- pcsx2/DebugTools/MIPSAnalyst.cpp | 175 +++++++++++++++++++++++++++++-- 1 file changed, 168 insertions(+), 7 deletions(-) diff --git a/pcsx2/DebugTools/MIPSAnalyst.cpp b/pcsx2/DebugTools/MIPSAnalyst.cpp index 2a715f80a4..4c708bd6e3 100644 --- a/pcsx2/DebugTools/MIPSAnalyst.cpp +++ b/pcsx2/DebugTools/MIPSAnalyst.cpp @@ -29,14 +29,173 @@ static std::vector functions; #define MIPS_MAKE_JR_RA() (0x03e00008) #define MIPS_MAKE_NOP() (0) +#define INVALIDTARGET 0xFFFFFFFF + +#define FULLOP_JR_RA 0x03e00008 +#define OP_SYSCALL 0x0000000c +#define OP_SYSCALL_MASK 0xFC00003F +#define _RS ((op>>21) & 0x1F) +#define _RT ((op>>16) & 0x1F) + namespace MIPSAnalyst { + u32 GetJumpTarget(u32 addr) + { + u32 op = r5900Debug.read32(addr); + const R5900::OPCODE& opcode = R5900::GetInstruction(op); + + if ((opcode.flags & IS_BRANCH) && (opcode.flags & BRANCHTYPE_MASK) == BRANCHTYPE_JUMP) + { + u32 target = (addr & 0xF0000000) | ((op&0x03FFFFFF) << 2); + return target; + } + else + return INVALIDTARGET; + } + + u32 GetBranchTarget(u32 addr) + { + u32 op = r5900Debug.read32(addr); + const R5900::OPCODE& opcode = R5900::GetInstruction(op); + + int branchType = (opcode.flags & BRANCHTYPE_MASK); + if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1)) + return addr + 4 + ((signed short)(op&0xFFFF)<<2); + else + return INVALIDTARGET; + } + u32 GetBranchTargetNoRA(u32 addr) + { + u32 op = r5900Debug.read32(addr); + const R5900::OPCODE& opcode = R5900::GetInstruction(op); + + int branchType = (opcode.flags & BRANCHTYPE_MASK); + if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1)) + { + if (!(opcode.flags & IS_LINKED)) + return addr + 4 + ((signed short)(op&0xFFFF)<<2); + else + return INVALIDTARGET; + } + else + return INVALIDTARGET; + } + + u32 GetSureBranchTarget(u32 addr) + { + u32 op = r5900Debug.read32(addr); + const R5900::OPCODE& opcode = R5900::GetInstruction(op); + + if ((opcode.flags & IS_BRANCH) && (opcode.flags & BRANCHTYPE_MASK) == BRANCHTYPE_BRANCH) + { + bool sure; + bool takeBranch; + switch (opcode.flags & CONDTYPE_MASK) + { + case CONDTYPE_EQ: + sure = _RS == _RT; + takeBranch = true; + break; + + case CONDTYPE_NE: + sure = _RS == _RT; + takeBranch = false; + break; + + case CONDTYPE_LEZ: + case CONDTYPE_GEZ: + sure = _RS == 0; + takeBranch = true; + break; + + case CONDTYPE_LTZ: + case CONDTYPE_GTZ: + sure = _RS == 0; + takeBranch = false; + break; + + default: + sure = false; + } + + if (sure && takeBranch) + return addr + 4 + ((signed short)(op&0xFFFF)<<2); + else if (sure && !takeBranch) + return addr + 8; + else + return INVALIDTARGET; + } + else + return INVALIDTARGET; + } + static const char *DefaultFunctionName(char buffer[256], u32 startAddr) { sprintf(buffer, "z_un_%08x", startAddr); return buffer; } + + static u32 ScanAheadForJumpback(u32 fromAddr, u32 knownStart, u32 knownEnd) { + static const u32 MAX_AHEAD_SCAN = 0x1000; + // Maybe a bit high... just to make sure we don't get confused by recursive tail recursion. + static const u32 MAX_FUNC_SIZE = 0x20000; + + if (fromAddr > knownEnd + MAX_FUNC_SIZE) { + return INVALIDTARGET; + } + + // Code might jump halfway up to before fromAddr, but after knownEnd. + // In that area, there could be another jump up to the valid range. + // So we track that for a second scan. + u32 closestJumpbackAddr = INVALIDTARGET; + u32 closestJumpbackTarget = fromAddr; + + // We assume the furthest jumpback is within the func. + u32 furthestJumpbackAddr = INVALIDTARGET; + + for (u32 ahead = fromAddr; ahead < fromAddr + MAX_AHEAD_SCAN; ahead += 4) { + u32 aheadOp = r5900Debug.read32(ahead); + u32 target = GetBranchTargetNoRA(ahead); + if (target == INVALIDTARGET && ((aheadOp & 0xFC000000) == 0x08000000)) { + target = GetJumpTarget(ahead); + } + + if (target != INVALIDTARGET) { + // Only if it comes back up to known code within this func. + if (target >= knownStart && target <= knownEnd) { + furthestJumpbackAddr = ahead; + } + // But if it jumps above fromAddr, we should scan that area too... + if (target < closestJumpbackTarget && target < fromAddr && target > knownEnd) { + closestJumpbackAddr = ahead; + closestJumpbackTarget = target; + } + } + if (aheadOp == MIPS_MAKE_JR_RA()) { + break; + } + } + + if (closestJumpbackAddr != INVALIDTARGET && furthestJumpbackAddr == INVALIDTARGET) { + for (u32 behind = closestJumpbackTarget; behind < fromAddr; behind += 4) { + u32 behindOp = r5900Debug.read32(behind); + u32 target = GetBranchTargetNoRA(behind); + if (target == INVALIDTARGET && ((behindOp & 0xFC000000) == 0x08000000)) { + target = GetJumpTarget(behind); + } + + if (target != INVALIDTARGET) { + if (target >= knownStart && target <= knownEnd) { + furthestJumpbackAddr = closestJumpbackAddr; + } + } + } + } + + return furthestJumpbackAddr; + } + void ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols) { AnalyzedFunction currentFunction = {startAddr}; @@ -45,6 +204,8 @@ namespace MIPSAnalyst bool end = false; bool isStraightLeaf = true; + functions.clear(); + u32 addr; for (addr = startAddr; addr <= endAddr; addr += 4) { // Use pre-existing symbol map info if available. May be more reliable. @@ -64,8 +225,7 @@ namespace MIPSAnalyst } u32 op = r5900Debug.read32(addr); -/* - MIPSOpcode op = Memory::Read_Instruction(addr); + u32 target = GetBranchTargetNoRA(addr); if (target != INVALIDTARGET) { isStraightLeaf = false; @@ -97,7 +257,8 @@ namespace MIPSAnalyst } } } - }*/ + } + if (op == MIPS_MAKE_JR_RA()) { // If a branch goes to the jr ra, it's still ending here. if (furthestBranch > addr) { @@ -108,7 +269,7 @@ namespace MIPSAnalyst } } - /* if (looking) { + if (looking) { if (addr >= furthestBranch) { u32 sureTarget = GetSureBranchTarget(addr); // Regular j only, jals are to new funcs. @@ -129,11 +290,11 @@ namespace MIPSAnalyst } } } - */ + if (end) { // most functions are aligned to 8 or 16 bytes // add the padding to this one - while (r5900Debug.read32(addr+8) == 0) + if (((addr+8) % 8) && r5900Debug.read32(addr+8) == 0) addr += 4; currentFunction.end = addr + 4; @@ -262,7 +423,7 @@ namespace MIPSAnalyst } // extract the accessed memory address - info.isDataAccess = opcode.flags & IS_MEMORY; + info.isDataAccess = (opcode.flags & IS_MEMORY) != 0; if (info.isDataAccess) { if (opcode.flags & IS_LEFT)