Merge pull request #272 from Kingcom/Scanning

Complete function scanning
This commit is contained in:
ramapcsx2 2014-09-06 00:32:51 +02:00
commit 08dc8b40e4
1 changed files with 168 additions and 7 deletions

View File

@ -29,14 +29,173 @@ static std::vector<MIPSAnalyst::AnalyzedFunction> 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)