Core: Track exception on bad jumps.

This commit is contained in:
Unknown W. Brackets
2020-07-12 21:59:08 -07:00
parent b071db9ec2
commit 940066db68
6 changed files with 83 additions and 1 deletions
+26
View File
@@ -404,6 +404,15 @@ const char *MemoryExceptionTypeAsString(MemoryExceptionType type) {
}
}
const char *ExecExceptionTypeAsString(ExecExceptionType type) {
switch (type) {
case ExecExceptionType::JUMP: return "CPU Jump";
case ExecExceptionType::THREAD: return "Thread switch";
default:
return "N/A";
}
}
void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) {
const char *desc = MemoryExceptionTypeAsString(type);
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
@@ -426,6 +435,23 @@ void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) {
}
}
void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) {
const char *desc = ExecExceptionTypeAsString(type);
WARN_LOG(MEMMAP, "%s: Invalid destination %08x PC %08x LR %08x", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
if (!g_Config.bIgnoreBadMemAccess) {
ExceptionInfo &e = g_exceptionInfo;
e = {};
e.type = ExceptionType::BAD_EXEC_ADDR;
e.info = "";
e.exec_type = type;
e.address = address;
e.pc = pc;
Core_EnableStepping(true);
host->SetDebugMode(true);
}
}
void Core_Break() {
ERROR_LOG(CPU, "BREAK!");
+9
View File
@@ -85,8 +85,13 @@ enum class MemoryExceptionType {
READ_BLOCK,
WRITE_BLOCK,
};
enum class ExecExceptionType {
JUMP,
THREAD,
};
void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type);
void Core_ExecException(u32 address, u32 pc, ExecExceptionType type);
void Core_Break();
enum class ExceptionType {
@@ -104,9 +109,13 @@ struct ExceptionInfo {
MemoryExceptionType memory_type;
uint32_t pc;
uint32_t address;
// Reuses pc and address from memory type, where address is the failed destination.
ExecExceptionType exec_type;
};
const ExceptionInfo &Core_GetExceptionInfo();
const char *ExceptionTypeAsString(ExceptionType type);
const char *MemoryExceptionTypeAsString(MemoryExceptionType type);
const char *ExecExceptionTypeAsString(ExecExceptionType type);
+34
View File
@@ -31,6 +31,7 @@
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/MemMapHelpers.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
@@ -1142,6 +1143,10 @@ bool __KernelSwitchToThread(SceUID threadID, const char *reason)
if (current && current->isRunning())
__KernelChangeReadyState(current, currentThread, true);
if (!Memory::IsValidAddress(t->context.pc)) {
Core_ExecException(t->context.pc, currentMIPS->pc, ExecExceptionType::THREAD);
}
__KernelSwitchContext(t, reason);
return true;
}
@@ -1463,6 +1468,12 @@ void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled) {
memcpy(currentMIPS->vfpuCtrl, ctx->vfpuCtrl, sizeof(ctx->vfpuCtrl));
}
#ifdef _DEBUG
if (!Memory::IsValidAddress(ctx->pc)) {
Core_ExecException(ctx->pc, currentMIPS->pc, ExecExceptionType::THREAD);
}
#endif
memcpy(currentMIPS->other, ctx->other, sizeof(ctx->other));
if (MIPSComp::jit) {
// When thread switching, we must update the rounding mode if cached in the jit.
@@ -1912,6 +1923,10 @@ SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int
strcpy(thread->nt.name, "root");
if (!Memory::IsValidAddress(thread->context.pc)) {
Core_ExecException(thread->context.pc, currentMIPS->pc, ExecExceptionType::THREAD);
}
__KernelLoadContext(&thread->context, (attr & PSP_THREAD_ATTR_VFPU) != 0);
currentMIPS->r[MIPS_REG_A0] = args;
currentMIPS->r[MIPS_REG_SP] -= (args + 0xf) & ~0xf;
@@ -2041,6 +2056,9 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo
// Smaller is better for priority. Only switch if the new thread is better.
if (cur && cur->nt.currentPriority > startThread->nt.currentPriority) {
if (!Memory::IsValidAddress(startThread->context.pc)) {
Core_ExecException(startThread->context.pc, currentMIPS->pc, ExecExceptionType::THREAD);
}
__KernelChangeReadyState(cur, currentThread, true);
hleReSchedule("thread started");
}
@@ -2903,6 +2921,10 @@ u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter)
Memory::Write_U32(currentMIPS->r[MIPS_REG_SP], thread->currentStack.end - 8);
Memory::Write_U32(currentMIPS->pc, thread->currentStack.end - 12);
if (!Memory::IsValidAddress(entryAddr)) {
Core_ExecException(entryAddr, currentMIPS->pc, ExecExceptionType::THREAD);
}
currentMIPS->pc = entryAddr;
currentMIPS->r[MIPS_REG_A0] = entryParameter;
currentMIPS->r[MIPS_REG_RA] = extendReturnHackAddr;
@@ -2935,6 +2957,10 @@ void __KernelReturnFromExtendStack()
return;
}
if (!Memory::IsValidAddress(restorePC)) {
Core_ExecException(restorePC, currentMIPS->pc, ExecExceptionType::THREAD);
}
DEBUG_LOG(SCEKERNEL, "__KernelReturnFromExtendStack()");
currentMIPS->r[MIPS_REG_RA] = restoreRA;
currentMIPS->r[MIPS_REG_SP] = restoreSP;
@@ -3215,6 +3241,10 @@ bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter)
call->savedId = cur->currentMipscallId;
call->reschedAfter = reschedAfter;
if (!Memory::IsValidAddress(call->entryPoint)) {
Core_ExecException(call->entryPoint, currentMIPS->pc, ExecExceptionType::THREAD);
}
// Set up the new state
currentMIPS->pc = call->entryPoint;
currentMIPS->r[MIPS_REG_RA] = __KernelCallbackReturnAddress();
@@ -3264,6 +3294,10 @@ void __KernelReturnFromMipsCall()
currentMIPS->r[MIPS_REG_RA] = Memory::Read_U32(sp + MIPS_REG_RA * 4);
sp += 32 * 4;
if (!Memory::IsValidAddress(call->savedPc)) {
Core_ExecException(call->savedPc, currentMIPS->pc, ExecExceptionType::THREAD);
}
currentMIPS->pc = call->savedPc;
// This is how we set the return value.
currentMIPS->r[MIPS_REG_V0] = call->savedV0;
+3
View File
@@ -54,6 +54,9 @@
static inline void DelayBranchTo(u32 where)
{
if (!Memory::IsValidAddress(where)) {
Core_ExecException(where, PC, ExecExceptionType::JUMP);
}
PC += 4;
mipsr4k.nextPC = where;
mipsr4k.inDelaySlot = true;
+2 -1
View File
@@ -1019,13 +1019,14 @@ int MIPSInterpret_RunUntil(u64 globalTicks)
if (curMips->inDelaySlot)
{
curMips->downcount -= 1;
// The reason we have to check this is the delay slot hack in Int_Syscall.
if (wasInDelaySlot)
{
curMips->pc = curMips->nextPC;
curMips->inDelaySlot = false;
continue;
}
curMips->downcount -= 1;
goto again;
}
}
+9
View File
@@ -1305,6 +1305,15 @@ PC: %08x)",
info.pc);
draw2d->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
y += 120;
} else if (info.type == ExceptionType::BAD_EXEC_ADDR) {
snprintf(statbuf, sizeof(statbuf), R"(
Destination: %s to %08x
PC: %08x)",
ExecExceptionTypeAsString(info.exec_type),
info.address,
info.pc);
draw2d->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
y += 120;
}
std::string kernelState = __KernelStateSummary();