Crash: Show disassembly of the instruction causing the crash, and the symbol name.

This commit is contained in:
Henrik Rydgård 2020-07-15 12:38:05 +02:00
parent 626d173d10
commit 8c38d7305e
4 changed files with 76 additions and 8 deletions

View file

@ -436,6 +436,28 @@ void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) {
}
}
void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std::string additionalInfo) {
const char *desc = MemoryExceptionTypeAsString(type);
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) {
WARN_LOG(MEMMAP, "%s: Invalid address %08x. %s", desc, address, additionalInfo.c_str());
} else {
WARN_LOG(MEMMAP, "%s: Invalid address %08x PC %08x LR %08x %s", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA], additionalInfo.c_str());
}
if (!g_Config.bIgnoreBadMemAccess) {
ExceptionInfo &e = g_exceptionInfo;
e = {};
e.type = ExceptionType::MEMORY;
e.info = additionalInfo;
e.memory_type = type;
e.address = address;
e.pc = pc;
Core_EnableStepping(true);
host->SetDebugMode(true);
}
}
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]);

View file

@ -17,6 +17,8 @@
#pragma once
#include <string>
#include "Core/System.h"
#include "Core/CoreParameter.h"
@ -92,7 +94,11 @@ enum class ExecExceptionType {
THREAD,
};
// Separate one for without info, to avoid having to allocate a string
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();

View file

@ -21,6 +21,7 @@
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
#include "Common/x64Analyzer.h"
#elif PPSSPP_ARCH(ARM64)
#include "Core/Util/DisArm64.h"
#elif PPSSPP_ARCH(ARM)
@ -42,6 +43,29 @@ void MemFault_Init() {
#ifdef MACHINE_CONTEXT_SUPPORTED
static bool DisassembleNativeAt(const uint8_t *codePtr, int instructionSize, std::string *dest) {
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
auto lines = DisassembleX86(codePtr, instructionSize);
if (!lines.empty()) {
*dest = lines[0];
return true;
}
#elif PPSSPP_ARCH(ARM64)
auto lines = DisassembleArm64(codePtr, instructionSize);
if (!lines.empty()) {
*dest = lines[0];
return true;
}
#elif PPSSPP_ARCH(ARM)
auto lines = DisassembleArm2(codePtr, instructionSize);
if (!lines.empty()) {
*dest = lines[0];
return true;
}
#endif
return false;
}
bool HandleFault(uintptr_t hostAddress, void *ctx) {
SContext *context = (SContext *)ctx;
const uint8_t *codePtr = (uint8_t *)(context->CTX_PC);
@ -76,15 +100,23 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
MemoryExceptionType type = MemoryExceptionType::NONE;
std::string disassembly;
std::string infoString = "";
if (MIPSComp::jit) {
std::string desc;
if (MIPSComp::jit->DescribeCodePtr(codePtr, desc)) {
infoString += desc + "\n";
}
}
int instructionSize = 4;
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
// X86, X86-64. Variable instruction size so need to analyze the mov instruction in detail.
// To ignore the access, we need to disassemble the instruction and modify context->CTX_PC
LSInstructionInfo info;
success = X86AnalyzeMOV(codePtr, info);
instructionSize = info.instructionSize;
#elif PPSSPP_ARCH(ARM64)
uint32_t word;
memcpy(&word, codePtr, 4);
@ -98,6 +130,12 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
ArmLSInstructionInfo info;
success = ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info);
#endif
std::string disassembly;
if (DisassembleNativeAt(codePtr, instructionSize, &disassembly)) {
infoString += disassembly + "\n";
}
if (success) {
if (info.isMemoryWrite) {
type = MemoryExceptionType::WRITE_WORD;
@ -122,11 +160,11 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
} else {
// Either bIgnoreBadMemAccess is off, or we failed recovery analysis.
uint32_t approximatePC = currentMIPS->pc;
Core_MemoryException(guestAddress, currentMIPS->pc, type);
Core_MemoryExceptionInfo(guestAddress, approximatePC, type, infoString);
// Redirect execution to a crash handler that will exit the game.
// Redirect execution to a crash handler that will exit the game immediately.
context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler();
ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation.", guestAddress, (void *)hostAddress);
ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation. Info:\n%s", guestAddress, (void *)hostAddress, infoString.c_str());
}
return true;
}

View file

@ -1302,12 +1302,14 @@ ABI: %s
if (info.type == ExceptionType::MEMORY) {
snprintf(statbuf, sizeof(statbuf), R"(
Access: %s at %08x
PC: %08x)",
PC: %08x
%s)",
MemoryExceptionTypeAsString(info.memory_type),
info.address,
info.pc);
info.pc,
info.info.c_str());
draw2d->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);
y += 120;
y += 180;
} else if (info.type == ExceptionType::BAD_EXEC_ADDR) {
snprintf(statbuf, sizeof(statbuf), R"(
Destination: %s to %08x