| 176 | } |
| 177 | |
| 178 | void ScanForFunctions(ccc::SymbolDatabase& database, MemoryInterface& reader, u32 startAddr, u32 endAddr, bool generateHashes) { |
| 179 | std::vector<MIPSAnalyst::AnalyzedFunction> functions; |
| 180 | AnalyzedFunction currentFunction = {startAddr}; |
| 181 | |
| 182 | u32 furthestBranch = 0; |
| 183 | bool looking = false; |
| 184 | bool end = false; |
| 185 | bool isStraightLeaf = true; |
| 186 | bool suspectedNoReturn = false; |
| 187 | |
| 188 | u32 addr; |
| 189 | for (addr = startAddr; addr < endAddr; addr += 4) { |
| 190 | // Use pre-existing symbol map info if available. May be more reliable. |
| 191 | ccc::FunctionHandle existing_symbol_handle = database.functions.first_handle_from_starting_address(addr); |
| 192 | const ccc::Function* existing_symbol = database.functions.symbol_from_handle(existing_symbol_handle); |
| 193 | |
| 194 | if (existing_symbol && existing_symbol->address().valid() && existing_symbol->size() > 0) { |
| 195 | addr = existing_symbol->address().value + existing_symbol->size() - 4; |
| 196 | currentFunction.start = addr + 4; |
| 197 | furthestBranch = 0; |
| 198 | looking = false; |
| 199 | end = false; |
| 200 | continue; |
| 201 | } |
| 202 | |
| 203 | u32 op = reader.Read32(addr); |
| 204 | |
| 205 | u32 target = GetBranchTargetNoRA(addr, reader); |
| 206 | if (target != INVALIDTARGET) { |
| 207 | isStraightLeaf = false; |
| 208 | if (target > furthestBranch) { |
| 209 | furthestBranch = target; |
| 210 | } |
| 211 | |
| 212 | // beq $zero, $zero, xyz |
| 213 | if ((op >> 16) == 0x1000) |
| 214 | { |
| 215 | // If it's backwards, and there's no other branch passing it, treat as noreturn |
| 216 | if(target < addr && furthestBranch < addr) |
| 217 | { |
| 218 | end = suspectedNoReturn = true; |
| 219 | } |
| 220 | } |
| 221 | } else if ((op & 0xFC000000) == 0x08000000) { |
| 222 | u32 sureTarget = GetJumpTarget(addr, reader); |
| 223 | // Check for a tail call. Might not even have a jr ra. |
| 224 | if (sureTarget != INVALIDTARGET && sureTarget < currentFunction.start) { |
| 225 | if (furthestBranch > addr) { |
| 226 | looking = true; |
| 227 | addr += 4; |
| 228 | } else { |
| 229 | end = true; |
| 230 | } |
| 231 | } else if (sureTarget != INVALIDTARGET && sureTarget > addr && sureTarget > furthestBranch) { |
| 232 | // A jump later. Probably tail, but let's check if it jumps back. |
| 233 | u32 knownEnd = furthestBranch == 0 ? addr : furthestBranch; |
| 234 | u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd, reader); |
| 235 | if (jumpback != INVALIDTARGET && jumpback > addr && jumpback > knownEnd) { |
no test coverage detected