Stub svcBreak with "bkpt 65535" so we can debug it

This commit is contained in:
TuxSH 2016-06-04 21:11:15 +02:00
parent bb230de72c
commit edff11be7b
7 changed files with 75 additions and 34 deletions

View File

@ -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[5] = 40 + REG_DUMP_SIZE + CODE_DUMP_SIZE + dump[8] + OTHER_DATA_SIZE; //Total size
//Dump code //Dump code
u16 *codedump = (u16 *)(regdump + dump[6] / 4); u8 *codedump = (u8 *)regdump + dump[6];
vu16 *instr = (vu16 *)pc - dump[7] / 2 + 1; 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] / 2; i++) for(u32 i = 0; i < dump[7]; i++)
codedump[i] = instr[i]; codedump[i] = instr[i];
//Dump stack in place //Dump stack in place

View File

@ -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[5] = 40 + REG_DUMP_SIZE + CODE_DUMP_SIZE + dump[8] + OTHER_DATA_SIZE; //Total size
//Dump code //Dump code
u16 *codedump = (u16 *)(regdump + dump[6] / 4); u8 *codedump = (u8 *)regdump + dump[6];
vu16 *instr = (vu16 *)pc - dump[7] / 2 + 1; 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] / 2; i++) for(u32 i = 0; i < dump[7]; i++)
codedump[i] = instr[i]; codedump[i] = instr[i];
//Dump stack //Dump stack

View File

@ -68,6 +68,7 @@ def makeRegisterLine(A, rA, B, rB):
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort") handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr", "fpexc") 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__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps") 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) processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize = unpack_from("<6I", data, 12)
nbRegisters //= 4 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") if processor == 9: print("Processor: ARM9")
else: print("Processor: ARM11 (core {0})".format(processor >> 16)) 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("<I", codeDump[-4:])[0] == 0xe12fff7f:
svcBreakStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], svcBreakStr))
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
print("\nRegister dump:\n") print("\nRegister dump:\n")
for i in range(0, nbRegisters - (nbRegisters % 2), 2): for i in range(0, nbRegisters - (nbRegisters % 2), 2):
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1])) 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]))) 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("\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("\nStack dump:\n")
print(hexdump(registers[13], stackDump)) print(hexdump(registers[13], stackDump))

View File

@ -98,13 +98,14 @@ void detectAndProcessExceptionDumps(void)
char path9[41] = "/luma/dumps/arm9"; char path9[41] = "/luma/dumps/arm9";
char path11[42] = "/luma/dumps/arm11"; char path11[42] = "/luma/dumps/arm11";
char fileName[] = "crash_dump_00000000.dmp"; char fileName[] = "crash_dump_00000000.dmp";
u32 size = dump[5];
if(dump[3] == 9) if(dump[3] == 9)
{ {
findDumpFile(path9, fileName); findDumpFile(path9, fileName);
path9[16] = '/'; path9[16] = '/';
memcpy(&path9[17], fileName, sizeof(fileName)); memcpy(&path9[17], fileName, sizeof(fileName));
fileWrite((void *)dump, path9, dump[5]); fileWrite((void *)dump, path9, size);
} }
else else
@ -125,7 +126,9 @@ void detectAndProcessExceptionDumps(void)
int posY = drawString(((dump[3] & 0xFFFF) == 11) ? arm11Str : "Processor: ARM9", 10, 30, COLOR_WHITE) + SPACING_Y; 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("Exception type: ", 10, posY, COLOR_WHITE);
posY = drawString(handledExceptionNames[dump[4]], 10 + 16 * SPACING_X, 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; posY += 3 * SPACING_Y;
for(u32 i = 0; i < 17; i += 2) for(u32 i = 0; i < 17; i += 2)
{ {
@ -145,7 +148,7 @@ void detectAndProcessExceptionDumps(void)
posY += 2 * SPACING_Y; posY += 2 * SPACING_Y;
u32 mode = dump[40 + 16] & 0xF; u32 mode = dump[10 + 16] & 0xF;
if(dump[4] == 3 && (mode == 7 || mode == 11)) 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 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(); 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 for(u32 i = 0; i < size / 4; i++) dump[i] = 0;
*(vu32 *)0x25000004 = 0;
clearScreens(); clearScreens();

View File

@ -216,7 +216,9 @@ void main(void)
{ {
u32 arm9SectionNum = 0; u32 arm9SectionNum = 0;
for(; (u32)(section[arm9SectionNum].address) >> 24 != 0x08 && arm9SectionNum < 4; arm9SectionNum++); for(; (u32)(section[arm9SectionNum].address) >> 24 != 0x08 && arm9SectionNum < 4; arm9SectionNum++);
patchExceptionHandlersInstall((u8 *)firm + section[arm9SectionNum].offset, section[arm9SectionNum].size); patchExceptionHandlersInstall((u8 *)firm + section[arm9SectionNum].offset, section[arm9SectionNum].size);
patchSvcBreak9((u8 *)firm + section[arm9SectionNum].offset, section[arm9SectionNum].size, (u32)(section[arm9SectionNum].address));
} }
switch(firmType) switch(firmType)
@ -337,6 +339,9 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
u32 *exceptionsPage = getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &stackAddress); u32 *exceptionsPage = getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &stackAddress);
installArm11Handlers(exceptionsPage, 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 //Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size); patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size);
} }
@ -351,7 +356,8 @@ static inline void patchLegacyFirm(u32 firmType)
firm->arm9Entry = (u8 *)0x801301C; firm->arm9Entry = (u8 *)0x801301C;
} }
applyLegacyFirmPatches((u8 *)firm, firmType, console);} applyLegacyFirmPatches((u8 *)firm, firmType, console);
}
static inline void patchSafeFirm(void) static inline void patchSafeFirm(void)
{ {

View File

@ -7,7 +7,21 @@
#include "config.h" #include "config.h"
#include "../build/rebootpatch.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) 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) //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 callExceptionDispatcherPattern[] = {0x0F, 0x00, 0xBD, 0xE8, 0x13, 0x00, 0x02, 0xF1};
const u8 exceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5};
*stackAddr = *((u32 *)memsearch(pos, callExceptionDispatcherPattern, size, 8) + 3); *stackAddr = *((u32 *)memsearch(pos, callExceptionDispatcherPattern, size, 8) + 3);
if(exceptionsPage == NULL) exceptionsPage = (u32 *)memsearch(pos, exceptionsPagePattern, size, 4) - 0xB; findArm11ExceptionsPageAndSvcTable(pos, size);
return arm11ExceptionsPage;
return exceptionsPage;
} }
void patchSignatureChecks(u8 *pos, u32 size) 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) void patchUnitInfoValueSet(u8 *pos, u32 size)
{ {
//Look for UNITINFO value being set //Look for UNITINFO value being set
@ -166,22 +197,16 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
0x11, 0xFF, 0x2F, 0xE1}; //bx r1 0x11, 0xFF, 0x2F, 0xE1}; //bx r1
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif findArm11ExceptionsPageAndSvcTable(pos, size);
if(exceptionsPage == NULL) exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch if(!arm11SvcTable[0x7B])
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
if(!svcTable[0x7B])
{ {
u32 *freeSpace; u32 *freeSpace;
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); for(freeSpace = arm11ExceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
memcpy(freeSpace, svcBackdoor, 40); memcpy(freeSpace, svcBackdoor, 40);
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage); arm11SvcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)arm11ExceptionsPage);
} }
} }

View File

@ -23,6 +23,8 @@ void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
void patchFirmWrites(u8 *pos, u32 size); void patchFirmWrites(u8 *pos, u32 size);
void patchFirmWriteSafe(u8 *pos, u32 size); void patchFirmWriteSafe(u8 *pos, u32 size);
void patchExceptionHandlersInstall(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 patchUnitInfoValueSet(u8 *pos, u32 size);
void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size); void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 size); void reimplementSvcBackdoor(u8 *pos, u32 size);