| 116 | } |
| 117 | |
| 118 | static u32 ScanAheadForJumpback(u32 fromAddr, u32 knownStart, u32 knownEnd, MemoryInterface& reader) { |
| 119 | static const u32 MAX_AHEAD_SCAN = 0x1000; |
| 120 | // Maybe a bit high... just to make sure we don't get confused by recursive tail recursion. |
| 121 | static const u32 MAX_FUNC_SIZE = 0x20000; |
| 122 | |
| 123 | if (fromAddr > knownEnd + MAX_FUNC_SIZE) { |
| 124 | return INVALIDTARGET; |
| 125 | } |
| 126 | |
| 127 | // Code might jump halfway up to before fromAddr, but after knownEnd. |
| 128 | // In that area, there could be another jump up to the valid range. |
| 129 | // So we track that for a second scan. |
| 130 | u32 closestJumpbackAddr = INVALIDTARGET; |
| 131 | u32 closestJumpbackTarget = fromAddr; |
| 132 | |
| 133 | // We assume the furthest jumpback is within the func. |
| 134 | u32 furthestJumpbackAddr = INVALIDTARGET; |
| 135 | |
| 136 | for (u32 ahead = fromAddr; ahead < fromAddr + MAX_AHEAD_SCAN; ahead += 4) { |
| 137 | u32 aheadOp = reader.Read32(ahead); |
| 138 | u32 target = GetBranchTargetNoRA(ahead, reader); |
| 139 | if (target == INVALIDTARGET && ((aheadOp & 0xFC000000) == 0x08000000)) { |
| 140 | target = GetJumpTarget(ahead, reader); |
| 141 | } |
| 142 | |
| 143 | if (target != INVALIDTARGET) { |
| 144 | // Only if it comes back up to known code within this func. |
| 145 | if (target >= knownStart && target <= knownEnd) { |
| 146 | furthestJumpbackAddr = ahead; |
| 147 | } |
| 148 | // But if it jumps above fromAddr, we should scan that area too... |
| 149 | if (target < closestJumpbackTarget && target < fromAddr && target > knownEnd) { |
| 150 | closestJumpbackAddr = ahead; |
| 151 | closestJumpbackTarget = target; |
| 152 | } |
| 153 | } |
| 154 | if (aheadOp == MIPS_MAKE_JR_RA()) { |
| 155 | break; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | if (closestJumpbackAddr != INVALIDTARGET && furthestJumpbackAddr == INVALIDTARGET) { |
| 160 | for (u32 behind = closestJumpbackTarget; behind < fromAddr; behind += 4) { |
| 161 | u32 behindOp = reader.Read32(behind); |
| 162 | u32 target = GetBranchTargetNoRA(behind, reader); |
| 163 | if (target == INVALIDTARGET && ((behindOp & 0xFC000000) == 0x08000000)) { |
| 164 | target = GetJumpTarget(behind, reader); |
| 165 | } |
| 166 | |
| 167 | if (target != INVALIDTARGET) { |
| 168 | if (target >= knownStart && target <= knownEnd) { |
| 169 | furthestJumpbackAddr = closestJumpbackAddr; |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | return furthestJumpbackAddr; |
no test coverage detected