mirror of https://github.com/PCSX2/pcsx2.git
Merge pull request #272 from Kingcom/Scanning
Complete function scanning
This commit is contained in:
commit
08dc8b40e4
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue