mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Core: Track exception on bad jumps.
This commit is contained in:
@@ -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!");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user