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[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
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
|
@ -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,6 +126,8 @@ 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();
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
if(!arm11SvcTable[0x7B])
|
||||||
|
|
||||||
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])
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user