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_JR_RA() (0x03e00008)
|
||||||
#define MIPS_MAKE_NOP() (0)
|
#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
|
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) {
|
static const char *DefaultFunctionName(char buffer[256], u32 startAddr) {
|
||||||
sprintf(buffer, "z_un_%08x", startAddr);
|
sprintf(buffer, "z_un_%08x", startAddr);
|
||||||
return buffer;
|
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) {
|
void ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols) {
|
||||||
AnalyzedFunction currentFunction = {startAddr};
|
AnalyzedFunction currentFunction = {startAddr};
|
||||||
|
|
||||||
|
@ -45,6 +204,8 @@ namespace MIPSAnalyst
|
||||||
bool end = false;
|
bool end = false;
|
||||||
bool isStraightLeaf = true;
|
bool isStraightLeaf = true;
|
||||||
|
|
||||||
|
functions.clear();
|
||||||
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
for (addr = startAddr; addr <= endAddr; addr += 4) {
|
for (addr = startAddr; addr <= endAddr; addr += 4) {
|
||||||
// Use pre-existing symbol map info if available. May be more reliable.
|
// Use pre-existing symbol map info if available. May be more reliable.
|
||||||
|
@ -64,8 +225,7 @@ namespace MIPSAnalyst
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 op = r5900Debug.read32(addr);
|
u32 op = r5900Debug.read32(addr);
|
||||||
/*
|
|
||||||
MIPSOpcode op = Memory::Read_Instruction(addr);
|
|
||||||
u32 target = GetBranchTargetNoRA(addr);
|
u32 target = GetBranchTargetNoRA(addr);
|
||||||
if (target != INVALIDTARGET) {
|
if (target != INVALIDTARGET) {
|
||||||
isStraightLeaf = false;
|
isStraightLeaf = false;
|
||||||
|
@ -97,7 +257,8 @@ namespace MIPSAnalyst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
if (op == MIPS_MAKE_JR_RA()) {
|
if (op == MIPS_MAKE_JR_RA()) {
|
||||||
// If a branch goes to the jr ra, it's still ending here.
|
// If a branch goes to the jr ra, it's still ending here.
|
||||||
if (furthestBranch > addr) {
|
if (furthestBranch > addr) {
|
||||||
|
@ -108,7 +269,7 @@ namespace MIPSAnalyst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (looking) {
|
if (looking) {
|
||||||
if (addr >= furthestBranch) {
|
if (addr >= furthestBranch) {
|
||||||
u32 sureTarget = GetSureBranchTarget(addr);
|
u32 sureTarget = GetSureBranchTarget(addr);
|
||||||
// Regular j only, jals are to new funcs.
|
// Regular j only, jals are to new funcs.
|
||||||
|
@ -129,11 +290,11 @@ namespace MIPSAnalyst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if (end) {
|
if (end) {
|
||||||
// most functions are aligned to 8 or 16 bytes
|
// most functions are aligned to 8 or 16 bytes
|
||||||
// add the padding to this one
|
// add the padding to this one
|
||||||
while (r5900Debug.read32(addr+8) == 0)
|
if (((addr+8) % 8) && r5900Debug.read32(addr+8) == 0)
|
||||||
addr += 4;
|
addr += 4;
|
||||||
|
|
||||||
currentFunction.end = addr + 4;
|
currentFunction.end = addr + 4;
|
||||||
|
@ -262,7 +423,7 @@ namespace MIPSAnalyst
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the accessed memory address
|
// extract the accessed memory address
|
||||||
info.isDataAccess = opcode.flags & IS_MEMORY;
|
info.isDataAccess = (opcode.flags & IS_MEMORY) != 0;
|
||||||
if (info.isDataAccess)
|
if (info.isDataAccess)
|
||||||
{
|
{
|
||||||
if (opcode.flags & IS_LEFT)
|
if (opcode.flags & IS_LEFT)
|
||||||
|
|
Loading…
Reference in New Issue