Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Show exception on misaligned jump #15880

Merged
merged 2 commits into from
Aug 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,16 +487,19 @@ void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) {
e.exec_type = type;
e.address = address;
e.pc = pc;
Core_EnableStepping(true, "cpu.exception", pc);
// This just records the closest value that could be useful as reference.
e.ra = currentMIPS->r[MIPS_REG_RA];
Core_EnableStepping(true, "cpu.exception", address);
}

void Core_Break() {
void Core_Break(u32 pc) {
ERROR_LOG(CPU, "BREAK!");

ExceptionInfo &e = g_exceptionInfo;
e = {};
e.type = ExceptionType::BREAK;
e.info = "";
e.pc = pc;

if (!g_Config.bIgnoreBadMemAccess) {
Core_EnableStepping(true, "cpu.breakInstruction", currentMIPS->pc);
Expand Down
3 changes: 2 additions & 1 deletion Core/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type);
void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std::string additionalInfo);

void Core_ExecException(u32 address, u32 pc, ExecExceptionType type);
void Core_Break();
void Core_Break(u32 pc);
// Call when loading save states, etc.
void Core_ResetException();

Expand All @@ -125,6 +125,7 @@ struct ExceptionInfo {
MemoryExceptionType memory_type;
uint32_t pc;
uint32_t address;
uint32_t ra = 0;

// Reuses pc and address from memory type, where address is the failed destination.
ExecExceptionType exec_type;
Expand Down
38 changes: 14 additions & 24 deletions Core/HLE/sceKernelThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,12 @@ void __KernelStartIdleThreads(SceUID moduleId)
}
}

void KernelValidateThreadTarget(uint32_t pc) {
if (!Memory::IsValidAddress(pc) || (pc & 3) != 0) {
Core_ExecException(pc, currentMIPS->pc, ExecExceptionType::THREAD);
}
}

bool __KernelSwitchOffThread(const char *reason)
{
if (!reason)
Expand Down Expand Up @@ -1141,9 +1147,7 @@ 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);
}
KernelValidateThreadTarget(t->context.pc);

__KernelSwitchContext(t, reason);
return true;
Expand Down Expand Up @@ -1471,9 +1475,7 @@ void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled) {
memcpy(currentMIPS->vfpuCtrl, ctx->vfpuCtrl, sizeof(ctx->vfpuCtrl));
}

if (!Memory::IsValidAddress(ctx->pc)) {
Core_ExecException(ctx->pc, currentMIPS->pc, ExecExceptionType::THREAD);
}
KernelValidateThreadTarget(ctx->pc);

memcpy(currentMIPS->other, ctx->other, sizeof(ctx->other));
// Not locking here, we assume the jit isn't switched during execution.
Expand Down Expand Up @@ -1924,9 +1926,7 @@ 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);
}
KernelValidateThreadTarget(thread->context.pc);

__KernelLoadContext(&thread->context, (attr & PSP_THREAD_ATTR_VFPU) != 0);
currentMIPS->r[MIPS_REG_A0] = args;
Expand Down Expand Up @@ -2057,9 +2057,7 @@ 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);
}
KernelValidateThreadTarget(startThread->context.pc);
__KernelChangeReadyState(cur, currentThread, true);
if (__InterruptsEnabled())
hleReSchedule("thread started");
Expand Down Expand Up @@ -2939,9 +2937,7 @@ 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);
}
KernelValidateThreadTarget(entryAddr);

currentMIPS->pc = entryAddr;
currentMIPS->r[MIPS_REG_A0] = entryParameter;
Expand Down Expand Up @@ -2975,9 +2971,7 @@ void __KernelReturnFromExtendStack()
return;
}

if (!Memory::IsValidAddress(restorePC)) {
Core_ExecException(restorePC, currentMIPS->pc, ExecExceptionType::THREAD);
}
KernelValidateThreadTarget(restorePC);

DEBUG_LOG(SCEKERNEL, "__KernelReturnFromExtendStack()");
currentMIPS->r[MIPS_REG_RA] = restoreRA;
Expand Down Expand Up @@ -3259,9 +3253,7 @@ 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);
}
KernelValidateThreadTarget(call->entryPoint);

// Set up the new state
currentMIPS->pc = call->entryPoint;
Expand Down Expand Up @@ -3312,9 +3304,7 @@ 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);
}
KernelValidateThreadTarget(call->savedPc);

currentMIPS->pc = call->savedPc;
// This is how we set the return value.
Expand Down
2 changes: 1 addition & 1 deletion Core/MIPS/ARM/ArmCompBranch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ void ArmJit::Comp_Jump(MIPSOpcode op) {
u32 targetAddr = (GetCompilerPC() & 0xF0000000) | off;

// Might be a stubbed address or something?
if (!Memory::IsValidAddress(targetAddr)) {
if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) {
if (js.nextExit == 0) {
ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x", targetAddr);
} else {
Expand Down
2 changes: 1 addition & 1 deletion Core/MIPS/ARM64/Arm64CompBranch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ void Arm64Jit::Comp_Jump(MIPSOpcode op) {
u32 targetAddr = (GetCompilerPC() & 0xF0000000) | off;

// Might be a stubbed address or something?
if (!Memory::IsValidAddress(targetAddr)) {
if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) {
if (js.nextExit == 0) {
ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x", targetAddr);
} else {
Expand Down
2 changes: 1 addition & 1 deletion Core/MIPS/IR/IRInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
}

case IROp::Break:
Core_Break();
Core_Break(mips->pc);
return mips->pc + 4;

case IROp::SetCtrlVFPU:
Expand Down
5 changes: 3 additions & 2 deletions Core/MIPS/IR/IRJit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,10 @@ void IRJit::RunLoopUntil(u64 globalticks) {
if (opcode == MIPS_EMUHACK_OPCODE) {
u32 data = inst & 0xFFFFFF;
IRBlock *block = blocks_.GetBlock(data);
u32 startPC = mips_->pc;
mips_->pc = IRInterpret(mips_, block->GetInstructions(), block->GetNumInstructions());
if (!Memory::IsValidAddress(mips_->pc)) {
Core_ExecException(mips_->pc, mips_->pc, ExecExceptionType::JUMP);
if (!Memory::IsValidAddress(mips_->pc) || (mips_->pc & 3) != 0) {
Core_ExecException(mips_->pc, startPC, ExecExceptionType::JUMP);
break;
}
} else {
Expand Down
5 changes: 2 additions & 3 deletions Core/MIPS/MIPSInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@

static inline void DelayBranchTo(u32 where)
{
if (!Memory::IsValidAddress(where)) {
// TODO: What about misaligned?
if (!Memory::IsValidAddress(where) || (where & 3) != 0) {
Core_ExecException(where, PC, ExecExceptionType::JUMP);
}
PC += 4;
Expand Down Expand Up @@ -158,7 +157,7 @@ namespace MIPSInt
void Int_Break(MIPSOpcode op)
{
Reporting::ReportMessage("BREAK instruction hit");
Core_Break();
Core_Break(PC);
PC += 4;
}

Expand Down
2 changes: 1 addition & 1 deletion Core/MIPS/x86/CompBranch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ void Jit::Comp_Jump(MIPSOpcode op) {
u32 targetAddr = (GetCompilerPC() & 0xF0000000) | off;

// Might be a stubbed address or something?
if (!Memory::IsValidAddress(targetAddr)) {
if (!Memory::IsValidAddress(targetAddr) || (targetAddr & 3) != 0) {
if (js.nextExit == 0) {
ERROR_LOG_REPORT(JIT, "Jump to invalid address: %08x PC %08x LR %08x", targetAddr, GetCompilerPC(), currentMIPS->r[MIPS_REG_RA]);
} else {
Expand Down
12 changes: 9 additions & 3 deletions Core/MIPS/x86/Jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ void Jit::Compile(u32 em_address) {
ClearCache();
}

if (!Memory::IsValidAddress(em_address)) {
if (!Memory::IsValidAddress(em_address) || (em_address & 3) != 0) {
Core_ExecException(em_address, em_address, ExecExceptionType::JUMP);
return;
}
Expand Down Expand Up @@ -672,7 +672,7 @@ static void HitInvalidBranch(uint32_t dest) {
void Jit::WriteExit(u32 destination, int exit_num) {
_dbg_assert_msg_(exit_num < MAX_JIT_BLOCK_EXITS, "Expected a valid exit_num");

if (!Memory::IsValidAddress(destination)) {
if (!Memory::IsValidAddress(destination) || (destination & 3) != 0) {
ERROR_LOG_REPORT(JIT, "Trying to write block exit to illegal destination %08x: pc = %08x", destination, currentMIPS->pc);
MOV(32, MIPSSTATE_VAR(pc), Imm32(GetCompilerPC()));
ABI_CallFunctionC(&HitInvalidBranch, destination);
Expand Down Expand Up @@ -721,6 +721,12 @@ void Jit::WriteExit(u32 destination, int exit_num) {
}
}

static u32 IsValidJumpTarget(uint32_t addr) {
if (Memory::IsValidAddress(addr) && (addr & 3) == 0)
return 1;
return 0;
}

static void HitInvalidJumpReg(uint32_t source) {
Core_ExecException(currentMIPS->pc, source, ExecExceptionType::JUMP);
currentMIPS->pc = source + 8;
Expand Down Expand Up @@ -762,7 +768,7 @@ void Jit::WriteExitDestInReg(X64Reg reg) {
SetJumpTarget(tooLow);
SetJumpTarget(tooHigh);

ABI_CallFunctionA((const void *)&Memory::IsValidAddress, R(reg));
ABI_CallFunctionA((const void *)&IsValidJumpTarget, R(reg));

// If we're ignoring, coreState didn't trip - so trip it now.
CMP(32, R(EAX), Imm32(0));
Expand Down
17 changes: 13 additions & 4 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,16 +1209,25 @@ PC: %08x
} else if (info.type == ExceptionType::BAD_EXEC_ADDR) {
snprintf(statbuf, sizeof(statbuf), R"(
Destination: %s to %08x
PC: %08x)",
PC: %08x
RA: %08x)",
ExecExceptionTypeAsString(info.exec_type),
info.address,
info.pc);
info.pc,
info.ra);
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
y += 180;
} else {
} else if (info.type == ExceptionType::BREAK) {
snprintf(statbuf, sizeof(statbuf), R"(
BREAK
)");
PC: %08x
)", info.pc);
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
y += 180;
} else {
snprintf(statbuf, sizeof(statbuf), R"(
Invalid / Unknown (%d)
)", (int)info.type);
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
y += 180;
}
Expand Down