mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 18:53:32 +00:00
Fix: Recover from null pointer execution crashes
Add proper recovery mechanism for null pointer execution (PC < 0x1000) by returning from invalid function calls using the Link Register instead of blindly continuing execution. Fixes infinite crash loop in games like Little Nightmares III. Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -13,6 +13,17 @@ void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
|||||||
Kernel::Svc::ThreadContext ctx;
|
Kernel::Svc::ThreadContext ctx;
|
||||||
this->GetContext(ctx);
|
this->GetContext(ctx);
|
||||||
|
|
||||||
|
// Check if this is a null pointer execution (PC in very low memory)
|
||||||
|
bool is_null_pointer_execution = ctx.pc < 0x1000;
|
||||||
|
|
||||||
|
// Only show detailed backtrace for the first occurrence or non-null-pointer crashes
|
||||||
|
if (is_null_pointer_execution) {
|
||||||
|
LOG_WARNING(Core_ARM, "Null pointer execution at pc={:016X}, sp={:016X}, lr={:016X}",
|
||||||
|
ctx.pc, ctx.sp, ctx.lr);
|
||||||
|
LOG_WARNING(Core_ARM, "Will attempt recovery by returning from function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", ctx.sp, ctx.pc);
|
LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", ctx.sp, ctx.pc);
|
||||||
LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address",
|
LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address",
|
||||||
"Offset", "Symbol");
|
"Offset", "Symbol");
|
||||||
|
|||||||
@@ -125,11 +125,39 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
|||||||
if (prefetch_abort) {
|
if (prefetch_abort) {
|
||||||
LOG_WARNING(Core_ARM, "Prefetch abort detected - checking if recoverable...");
|
LOG_WARNING(Core_ARM, "Prefetch abort detected - checking if recoverable...");
|
||||||
|
|
||||||
// For Nintendo SDK crashes, try to continue execution
|
// Get the current PC to check if we're in a null pointer execution loop
|
||||||
|
Kernel::Svc::ThreadContext ctx;
|
||||||
|
interface->GetContext(ctx);
|
||||||
|
u64 current_pc = ctx.pc;
|
||||||
|
|
||||||
|
// Detect null pointer execution loop (PC in very low memory addresses)
|
||||||
|
if (current_pc < 0x1000) {
|
||||||
|
LOG_WARNING(Core_ARM, "Null pointer execution detected at PC={:016X}", current_pc);
|
||||||
|
LOG_WARNING(Core_ARM, "Attempting to recover by returning from invalid function call");
|
||||||
|
|
||||||
|
// Try to recover by returning from the function using LR (X30)
|
||||||
|
// This simulates a function return
|
||||||
|
u64 return_address = ctx.lr;
|
||||||
|
|
||||||
|
if (return_address != 0 && return_address >= 0x1000) {
|
||||||
|
LOG_INFO(Core_ARM, "Recovering: Setting PC to return address {:016X}", return_address);
|
||||||
|
ctx.pc = return_address;
|
||||||
|
// Set return value to 0 in X0
|
||||||
|
ctx.r[0] = 0;
|
||||||
|
interface->SetContext(ctx);
|
||||||
|
should_continue = true;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Core_ARM, "Cannot recover: Invalid return address {:016X}", return_address);
|
||||||
|
LOG_ERROR(Core_ARM, "Thread will be suspended due to unrecoverable crash");
|
||||||
|
should_continue = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For Nintendo SDK crashes at valid addresses, try to continue execution
|
||||||
// This is especially important for games like Phoenix Switch
|
// This is especially important for games like Phoenix Switch
|
||||||
should_continue = true;
|
should_continue = true;
|
||||||
LOG_INFO(Core_ARM, "Attempting to continue execution after Nintendo SDK crash");
|
LOG_INFO(Core_ARM, "Attempting to continue execution after Nintendo SDK crash");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
system.GetDebugger().NotifyThreadStopped(thread);
|
system.GetDebugger().NotifyThreadStopped(thread);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user