From edff11be7b87eba518ac0aa8ab1988d2695ddaf9 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Sat, 4 Jun 2016 21:11:15 +0200 Subject: [PATCH] Stub svcBreak with "bkpt 65535" so we can debug it --- exceptions/arm11/source/mainHandler.c | 6 +-- exceptions/arm9/source/mainHandler.c | 6 +-- exceptions/exception_dump_parser.py | 18 ++++++--- source/exceptions.c | 12 +++--- source/firm.c | 8 +++- source/patches.c | 57 +++++++++++++++++++-------- source/patches.h | 2 + 7 files changed, 75 insertions(+), 34 deletions(-) diff --git a/exceptions/arm11/source/mainHandler.c b/exceptions/arm11/source/mainHandler.c index 9704266..71ca073 100644 --- a/exceptions/arm11/source/mainHandler.c +++ b/exceptions/arm11/source/mainHandler.c @@ -51,9 +51,9 @@ void __attribute__((noreturn)) mainHandler(u32 regs[18], u32 type, u32 cpuId, u3 dump[5] = 40 + REG_DUMP_SIZE + CODE_DUMP_SIZE + dump[8] + OTHER_DATA_SIZE; //Total size //Dump code - u16 *codedump = (u16 *)(regdump + dump[6] / 4); - vu16 *instr = (vu16 *)pc - dump[7] / 2 + 1; - for(u32 i = 0; i < dump[7] / 2; i++) + u8 *codedump = (u8 *)regdump + dump[6]; + vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dump[7]; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem + for(u32 i = 0; i < dump[7]; i++) codedump[i] = instr[i]; //Dump stack in place diff --git a/exceptions/arm9/source/mainHandler.c b/exceptions/arm9/source/mainHandler.c index 2e07225..d6e35ad 100644 --- a/exceptions/arm9/source/mainHandler.c +++ b/exceptions/arm9/source/mainHandler.c @@ -49,9 +49,9 @@ void __attribute__((noreturn)) mainHandler(u32 regs[17], u32 type) dump[5] = 40 + REG_DUMP_SIZE + CODE_DUMP_SIZE + dump[8] + OTHER_DATA_SIZE; //Total size //Dump code - u16 *codedump = (u16 *)(regdump + dump[6] / 4); - vu16 *instr = (vu16 *)pc - dump[7] / 2 + 1; - for(u32 i = 0; i < dump[7] / 2; i++) + u8 *codedump = (u8 *)regdump + dump[6]; + vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dump[7]; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem + for(u32 i = 0; i < dump[7]; i++) codedump[i] = instr[i]; //Dump stack diff --git a/exceptions/exception_dump_parser.py b/exceptions/exception_dump_parser.py index e2f7c65..1fb91b2 100644 --- a/exceptions/exception_dump_parser.py +++ b/exceptions/exception_dump_parser.py @@ -68,6 +68,7 @@ def makeRegisterLine(A, rA, B, rB): handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort") registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr", "fpexc") +svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)") if __name__ == "__main__": parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps") @@ -81,23 +82,28 @@ if __name__ == "__main__": processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize = unpack_from("<6I", data, 12) nbRegisters //= 4 + registers = unpack_from("<{0}I".format(nbRegisters), data, 40) + codeDump = data[40 + 4 * nbRegisters : 40 + 4 * nbRegisters + codeDumpSize] + stackOffset = 40 + 4 * nbRegisters + codeDumpSize + stackDump = data[stackOffset : stackOffset + stackDumpSize] + if processor == 9: print("Processor: ARM9") else: print("Processor: ARM11 (core {0})".format(processor >> 16)) - print("Exception type: {0}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType])) + svcBreakStr = "" + if exceptionType == 2 and (registers[16] & 0x20) == 0 and unpack_from("= len(handledExceptionNames) else handledExceptionNames[exceptionType], svcBreakStr)) - registers = unpack_from("<{0}I".format(nbRegisters), data, 40) print("\nRegister dump:\n") for i in range(0, nbRegisters - (nbRegisters % 2), 2): print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1])) if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[-2], "{0:08x}".format(registers[-1]))) - codeDump = data[40 + 4 * nbRegisters : 40 + 4 * nbRegisters + codeDumpSize] print("\nCode dump:\n") - print(hexdump(registers[15] - codeDumpSize + 2, codeDump)) + print(hexdump(registers[15] - codeDumpSize + (4 if (registers[16] & 0x20 == 0) else 2), codeDump)) - stackOffset = 40 + 4*nbRegisters + codeDumpSize - stackDump = data[stackOffset : stackOffset + stackDumpSize] print("\nStack dump:\n") print(hexdump(registers[13], stackDump)) \ No newline at end of file diff --git a/source/exceptions.c b/source/exceptions.c index 2cfb5f7..bd7322c 100644 --- a/source/exceptions.c +++ b/source/exceptions.c @@ -98,13 +98,14 @@ void detectAndProcessExceptionDumps(void) char path9[41] = "/luma/dumps/arm9"; char path11[42] = "/luma/dumps/arm11"; char fileName[] = "crash_dump_00000000.dmp"; + u32 size = dump[5]; if(dump[3] == 9) { findDumpFile(path9, fileName); path9[16] = '/'; memcpy(&path9[17], fileName, sizeof(fileName)); - fileWrite((void *)dump, path9, dump[5]); + fileWrite((void *)dump, path9, size); } else @@ -125,7 +126,9 @@ void detectAndProcessExceptionDumps(void) int posY = drawString(((dump[3] & 0xFFFF) == 11) ? arm11Str : "Processor: ARM9", 10, 30, COLOR_WHITE) + SPACING_Y; posY = drawString("Exception type: ", 10, posY, COLOR_WHITE); posY = drawString(handledExceptionNames[dump[4]], 10 + 16 * SPACING_X, posY, COLOR_WHITE); - + if(dump[4] == 2 && dump[7] >= 4 && (dump[10 + 16] & 0x20) == 0 && *(vu32 *)((vu8 *)dump + 40 + dump[6] + dump[7] - 4) == 0xE12FFF7F) + posY = drawString("(svcBreak)", 10 + 31 * SPACING_X, posY, COLOR_WHITE); + posY += 3 * SPACING_Y; for(u32 i = 0; i < 17; i += 2) { @@ -145,7 +148,7 @@ void detectAndProcessExceptionDumps(void) posY += 2 * SPACING_Y; - u32 mode = dump[40 + 16] & 0xF; + u32 mode = dump[10 + 16] & 0xF; if(dump[4] == 3 && (mode == 7 || mode == 11)) posY = drawString("Incorrect dump: failed to dump code and/or stack", 10, posY, 0x00FFFF) + 2 * SPACING_Y; //in yellow @@ -155,8 +158,7 @@ void detectAndProcessExceptionDumps(void) waitInput(); - *(vu32 *)0x25000000 = 0; //Make sure we won't detect a corrupted exception dump after we've rebooted. It doesn't seem to be sufficient though - *(vu32 *)0x25000004 = 0; + for(u32 i = 0; i < size / 4; i++) dump[i] = 0; clearScreens(); diff --git a/source/firm.c b/source/firm.c index 3405af1..cbd3079 100755 --- a/source/firm.c +++ b/source/firm.c @@ -216,7 +216,9 @@ void main(void) { u32 arm9SectionNum = 0; for(; (u32)(section[arm9SectionNum].address) >> 24 != 0x08 && arm9SectionNum < 4; arm9SectionNum++); + patchExceptionHandlersInstall((u8 *)firm + section[arm9SectionNum].offset, section[arm9SectionNum].size); + patchSvcBreak9((u8 *)firm + section[arm9SectionNum].offset, section[arm9SectionNum].size, (u32)(section[arm9SectionNum].address)); } switch(firmType) @@ -337,6 +339,9 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode) u32 *exceptionsPage = getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &stackAddress); installArm11Handlers(exceptionsPage, stackAddress); + //Stub svcBreak11 with "bkpt 255" + patchSvcBreak11(arm11Section1, section[1].size); + //Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size); } @@ -351,7 +356,8 @@ static inline void patchLegacyFirm(u32 firmType) firm->arm9Entry = (u8 *)0x801301C; } - applyLegacyFirmPatches((u8 *)firm, firmType, console);} + applyLegacyFirmPatches((u8 *)firm, firmType, console); +} static inline void patchSafeFirm(void) { diff --git a/source/patches.c b/source/patches.c index 734a2fe..651e59c 100644 --- a/source/patches.c +++ b/source/patches.c @@ -7,7 +7,21 @@ #include "config.h" #include "../build/rebootpatch.h" -static u32 *exceptionsPage = NULL; +static u32 *arm11ExceptionsPage = NULL; +static u32 *arm11SvcTable = NULL; + +static void findArm11ExceptionsPageAndSvcTable(u8 *pos, u32 size) +{ + const u8 arm11ExceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5}; + + if(arm11ExceptionsPage == NULL) arm11ExceptionsPage = (u32 *)memsearch(pos, arm11ExceptionsPagePattern, size, 4) - 0xB; + if(arm11SvcTable == NULL && arm11ExceptionsPage != NULL) + { + u32 svcOffset = (-((arm11ExceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch + arm11SvcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address + while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) + } +} u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) { @@ -25,13 +39,11 @@ u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr) //This function has to succeed. Crash if it doesn't (we'll get an exception dump of it anyways) const u8 callExceptionDispatcherPattern[] = {0x0F, 0x00, 0xBD, 0xE8, 0x13, 0x00, 0x02, 0xF1}; - const u8 exceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5}; - + *stackAddr = *((u32 *)memsearch(pos, callExceptionDispatcherPattern, size, 8) + 3); - if(exceptionsPage == NULL) exceptionsPage = (u32 *)memsearch(pos, exceptionsPagePattern, size, 4) - 0xB; - - return exceptionsPage; + findArm11ExceptionsPageAndSvcTable(pos, size); + return arm11ExceptionsPage; } void patchSignatureChecks(u8 *pos, u32 size) @@ -131,6 +143,25 @@ void patchExceptionHandlersInstall(u8 *pos, u32 size) } } +void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr) +{ + //Stub svcBreak with "bkpt 65535" so we can debug the panic. + //Thanks @yellows8 and others for mentioning this idea on #3dsdev. + const u8 svcHandlerPattern[] = {0x08, 0xE0, 0x0D, 0xE5, 0x00, 0xE0, 0x4F, 0xE1}; //str lr, [sp]; mrs lr, spsr + + u32 *arm9SvcTable = (u32 *)memsearch(pos, svcHandlerPattern, size, 8); + while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL) + *(u32 *)(pos + arm9SvcTable[0x3C] - k9addr) = 0xE12FFF7F; +} + +void patchSvcBreak11(u8 *pos, u32 size) +{ + //Same as above, for NFIRM arm11 + + findArm11ExceptionsPageAndSvcTable(pos, size); + *(u32 *)(pos + arm11SvcTable[0x3C] - 0xFFF00000) = 0xE12FFF7F; +} + void patchUnitInfoValueSet(u8 *pos, u32 size) { //Look for UNITINFO value being set @@ -166,22 +197,16 @@ void reimplementSvcBackdoor(u8 *pos, u32 size) 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x11, 0xFF, 0x2F, 0xE1}; //bx r1 - const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif - - if(exceptionsPage == NULL) exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB; + findArm11ExceptionsPageAndSvcTable(pos, size); - u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch - u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address - while(*svcTable) svcTable++; //Look for SVC0 (NULL) - - if(!svcTable[0x7B]) + if(!arm11SvcTable[0x7B]) { u32 *freeSpace; - for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); + for(freeSpace = arm11ExceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); memcpy(freeSpace, svcBackdoor, 40); - svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage); + arm11SvcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)arm11ExceptionsPage); } } diff --git a/source/patches.h b/source/patches.h index b698249..3b57645 100644 --- a/source/patches.h +++ b/source/patches.h @@ -23,6 +23,8 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); void patchFirmWrites(u8 *pos, u32 size); void patchFirmWriteSafe(u8 *pos, u32 size); void patchExceptionHandlersInstall(u8 *pos, u32 size); +void patchSvcBreak9(u8 *pos, u32 size, u32 k9addr); +void patchSvcBreak11(u8 *pos, u32 size); void patchUnitInfoValueSet(u8 *pos, u32 size); void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size); void reimplementSvcBackdoor(u8 *pos, u32 size);