Stub svcBreak with "bkpt 65535" so we can debug it
This commit is contained in:
parent
bb230de72c
commit
edff11be7b
@ -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
|
||||
|
@ -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
|
||||
|
@ -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("<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")
|
||||
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))
|
||||
|
@ -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,6 +126,8 @@ 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();
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user