diff --git a/src/skel/wiiu/crashhandler.c b/src/skel/wiiu/crashhandler.c new file mode 100644 index 00000000..ef8687d7 --- /dev/null +++ b/src/skel/wiiu/crashhandler.c @@ -0,0 +1,281 @@ +// based on whbs crash handler + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_DISASSEMBLY_SIZE (4096) +#define LOG_STACK_TRACE_SIZE (4096) +#define LOG_REGISTER_SIZE (4096) + +#define THREAD_STACK_SIZE (4096) + +static const char * +sCrashType = NULL; + +static char +sDisassemblyBuffer[LOG_DISASSEMBLY_SIZE]; + +static uint32_t +sDisassemblyLength = 0; + +static char +sStackTraceBuffer[LOG_STACK_TRACE_SIZE]; + +static uint32_t +sStackTraceLength = 0; + +static char +sRegistersBuffer[LOG_REGISTER_SIZE]; + +static uint32_t +sRegistersLength = 0; + +static char +sFatalBuffer[LOG_REGISTER_SIZE + LOG_DISASSEMBLY_SIZE + LOG_STACK_TRACE_SIZE]; + +static uint8_t +sCrashThreadStack[THREAD_STACK_SIZE]; + +static OSThread __attribute__((aligned(8))) +sCrashThread; + +static int +crashReportThread(int argc, const char **argv) +{ + // Log crash dump +#ifdef _DEBUG_BUILD_ + WHBLogPrint(sRegistersBuffer); + WHBLogPrint(sDisassemblyBuffer); + WHBLogPrint(sStackTraceBuffer); +#endif + + sprintf(sFatalBuffer, "RE3 CRASH\nStackTrace:\n%s", sStackTraceBuffer); + OSFatal(sFatalBuffer); + return 0; +} + +static void +disassemblyPrintCallback(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + sDisassemblyLength += vsprintf(sDisassemblyBuffer + sDisassemblyLength, + fmt, args); + sDisassemblyBuffer[sDisassemblyLength] = 0; + va_end(args); +} + +static void +getDisassembly(OSContext *context) +{ + sDisassemblyLength = 0; + sDisassemblyBuffer[0] = 0; + + if (context->srr0 > 16) { + DisassemblePPCRange((void *)(context->srr0 - 16), + (void *)(context->srr0 + 16), + disassemblyPrintCallback, + OSGetSymbolName, + DISASSEMBLE_PPC_FLAGS_NONE); + } +} + +static void +getStackTrace(OSContext *context) +{ + int i; + uint32_t *stackPtr; + char name[256]; + + sStackTraceLength = 0; + sStackTraceBuffer[0] = 0; + stackPtr = (uint32_t *)context->gpr[1]; + + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, + "Address: Back Chain LR Save\n"); + + for (i = 0; i < 16; ++i) { + uint32_t addr; + + if (!stackPtr || + (uintptr_t)stackPtr == 0x1 || + (uintptr_t)stackPtr == 0xFFFFFFFF) { + break; + } + + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, + "0x%08x: 0x%08x 0x%08x", + (uintptr_t)stackPtr, + (uintptr_t)stackPtr[0], + (uintptr_t)stackPtr[1]); + + addr = OSGetSymbolName(stackPtr[1], name, sizeof(name)); + if (addr) { + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, + " %s+0x%x", name, + (uintptr_t)(stackPtr[1] - addr)); + } + + sStackTraceLength += sprintf(sStackTraceBuffer + sStackTraceLength, "\n"); + stackPtr = (uint32_t *)*stackPtr; + } + + sStackTraceBuffer[sStackTraceLength] = 0; +} + +static void +writeRegister(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + sRegistersLength += vsprintf(sRegistersBuffer + sRegistersLength, fmt, args); + sRegistersBuffer[sRegistersLength] = 0; + va_end(args); +} + +static void +getRegisters(OSContext *context) +{ + OSTime tbr = OSGetSystemTime(); + uint32_t addr; + char name[256]; + int i; + uint64_t *fpr, *psf; + + sRegistersLength = 0; + sRegistersBuffer[sRegistersLength] = 0; + + writeRegister("--Proc%d-Core%u--------- OSContext 0x%p --------------------\n\n", + OSGetUPID(), OSGetCoreId(), context); + writeRegister("tag1 = 0x%08X (expecting 0x%08X)\n", + (uint32_t)(context->tag >> 32), + (uint32_t)(OS_CONTEXT_TAG >> 32)); + writeRegister("tag2 = 0x%08X (expecting 0x%08X)\n", + (uint32_t)(context->tag & 0xFFFFFFFF), + (uint32_t)(OS_CONTEXT_TAG & 0xFFFFFFFF)); + writeRegister("TBR = 0x%08X_%08X\n", + (uint32_t)(tbr >> 32), (uint32_t)(tbr & 0xFFFFFFFF)); + writeRegister("CR = 0x%08X\n", context->cr); + writeRegister("CTR = 0x%08X\n", context->ctr); + + writeRegister("LR = 0x%08X", context->lr); + addr = OSGetSymbolName(context->lr, name, sizeof(name)); + if (addr) { + writeRegister(" %s+0x%X", name, context->lr - addr); + } + writeRegister("\n"); + + writeRegister("SRR0 = 0x%08X", context->srr0); + addr = OSGetSymbolName(context->srr0, name, sizeof(name)); + if (addr) { + writeRegister(" %s+0x%X", name, context->srr0 - addr); + } + writeRegister("\n"); + + writeRegister("SRR1 = 0x%08X\n", context->srr1); + writeRegister("state = 0x%04X\n", context->state); + + for (i = 0; i < 16; ++i) { + writeRegister("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", + i, context->gpr[i], context->gpr[i], + i + 16, context->gpr[i + 16], context->gpr[i + 16]); + } + + writeRegister("\n--GQRs----------\n"); + for (i = 0; i < 4; ++i) { + writeRegister("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", + i, context->gqr[i], context->gqr[i], + i + 4, context->gqr[i + 4], context->gqr[i + 4]); + } + + writeRegister("\n--Per-core OSContext runtime ----\n"); + for (i = 0; i < 3; ++i) { + writeRegister("coretime[%d] = 0x%016llX ticks, %lld second(s) elapsed\n", + i, context->coretime[i], + OSTicksToSeconds(context->coretime[i])); + } + + writeRegister("\n--FPRs----------\n"); + fpr = (uint64_t *)context->fpr; + for (i = 0; i < 16; ++i) { + writeRegister("fr%d \t= 0x%16.16llx \t fr%d \t= 0x%16.16llx\n", + i, fpr[i], + i + 16, fpr[i + 16]); + } + + writeRegister("\n\n--PSFs----------\n"); + psf = (uint64_t *)context->psf; + for (i = 0; i < 16; ++i) { + writeRegister("ps%d \t= 0x%16.16llx \t ps%d \t= 0x%16.16llx\n", + i, psf[i], + i + 16, psf[i + 16]); + } +} + +static BOOL +handleException(const char *type, + OSContext *context) +{ + sCrashType = type; + getDisassembly(context); + getStackTrace(context); + getRegisters(context); + + OSCreateThread(&sCrashThread, + crashReportThread, + 0, + NULL, + sCrashThreadStack + THREAD_STACK_SIZE, + THREAD_STACK_SIZE, + 16, + 0); + + OSResumeThread(&sCrashThread); + OSSuspendThread((OSThread *)context); + return TRUE; +} + +static BOOL +handleAlignment(OSContext *context) +{ + return handleException("ALIGNMENT", context); +} + +static BOOL +handleDSI(OSContext *context) +{ + return handleException("DSI", context); +} + +static BOOL +handleISI(OSContext *context) +{ + return handleException("ISI", context); +} + +static BOOL +handleProgram(OSContext *context) +{ + return handleException("PROGRAM", context); +} + +void +wiiu_init_crashhandler(void) +{ + OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL, + OS_EXCEPTION_TYPE_ALIGNMENT, handleAlignment); + OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL, + OS_EXCEPTION_TYPE_DSI, handleDSI); + OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL, + OS_EXCEPTION_TYPE_ISI, handleISI); + OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL, + OS_EXCEPTION_TYPE_PROGRAM, handleProgram); +} diff --git a/src/skel/wiiu/wiiu.cpp b/src/skel/wiiu/wiiu.cpp index 3e937e5f..ca52741e 100644 --- a/src/skel/wiiu/wiiu.cpp +++ b/src/skel/wiiu/wiiu.cpp @@ -2,9 +2,6 @@ #include "wiiu.h" #include -#include -#include - #include #include @@ -828,6 +825,8 @@ _InputTranslateShiftKeyUpDown(RsKeyCodes *rs) { RsKeyboardEventHandler(rshiftStatus ? rsKEYDOWN : rsKEYUP, &(*rs = rsRSHIFT)); } +extern "C" void wiiu_init_crashhandler(void); + /* ***************************************************************************** */ @@ -842,12 +841,13 @@ main(int argc, char *argv[]) #endif WHBProcInit(); - WHBInitCrashHandler(); - + #ifdef _DEBUG_BUILD_ WHBLogUdpInit(); #endif + wiiu_init_crashhandler(); + WHBLogPrintf("RE3 Wii U started"); #ifdef WIIU_CHANNEL