diff --git a/src/game/crash_screen.c b/src/game/crash_screen.c index 7fafecf3..cbc7b62e 100644 --- a/src/game/crash_screen.c +++ b/src/game/crash_screen.c @@ -18,6 +18,7 @@ enum crashPages { PAGE_CONTEXT, PAGE_LOG, PAGE_STACKTRACE, + PAGE_DISASM, PAGE_COUNT }; @@ -193,19 +194,16 @@ void draw_crash_context(OSThread *thread, s32 cause) { __OSThreadContext *tc = &thread->context; - crash_screen_draw_rect(25, 20, 270, 25); - crash_screen_print(30, 25, "THREAD:%d (%s)", thread->id, gCauseDesc[cause]); - crash_screen_print(30, 35, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr); + crash_screen_draw_rect(15, 20, 270, 210); + crash_screen_print(30, 20, "THREAD:%d (%s)", thread->id, gCauseDesc[cause]); + crash_screen_print(30, 30, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr); osWritebackDCacheAll(); - crash_screen_draw_rect(25, 45, 270, 185); - if ((u32)parse_map == 0x80345678) { - crash_screen_print(30, 50, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0, - (u32) tc->v1); - } else { + crash_screen_draw_rect(15, 45, 270, 185); + if ((u32)parse_map != 0x80345678) { char *fname = parse_map(tc->pc); - crash_screen_print(30, 50, "CRASH AT: %s", fname == NULL ? "UNKNOWN" : fname); + crash_screen_print(30, 40, "CRASH AT: %s", fname == NULL ? "UNKNOWN" : fname); } - // crash_screen_print(30, 50, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0, (u32) tc->v1); + crash_screen_print(30, 50, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0, (u32) tc->v1); crash_screen_print(30, 60, "A0:%08XH A1:%08XH A2:%08XH", (u32) tc->a0, (u32) tc->a1, (u32) tc->a2); crash_screen_print(30, 70, "A3:%08XH T0:%08XH T1:%08XH", (u32) tc->a3, (u32) tc->t0, (u32) tc->t1); crash_screen_print(30, 80, "T2:%08XH T3:%08XH T4:%08XH", (u32) tc->t2, (u32) tc->t3, (u32) tc->t4); @@ -263,7 +261,7 @@ void draw_stacktrace(OSThread *thread, UNUSED s32 cause) { __OSThreadContext *tc = &thread->context; u32 temp_sp = tc->sp + 0x14; - crash_screen_draw_rect(25, 20, 270, 25); + crash_screen_draw_rect(25, 20, 270, 210); crash_screen_print(30, 25, "STACK TRACE FROM %08X:", temp_sp); if ((u32) parse_map == 0x80345678) { crash_screen_print(30, 35, "CURRFUNC: NONE"); @@ -290,8 +288,31 @@ void draw_stacktrace(OSThread *thread, UNUSED s32 cause) { } } } +} + +static u32 sProgramPosition = 0; +void draw_disasm(OSThread *thread) { + __OSThreadContext *tc = &thread->context; + // u32 insn = *(u32*)tc->pc; + + crash_screen_draw_rect(25, 20, 270, 210); + if (sProgramPosition == 0) { + sProgramPosition = tc->pc - 36; + } + crash_screen_print(30, 25, "DISASM %08X", sProgramPosition); + osWritebackDCacheAll(); + for (int i = 0; i < 19; i++) { + u32 addr = sProgramPosition + (i * 4); + u32 toDisasm = *(u32*)(addr); + + + + crash_screen_print(30, 35 + (i * 10), "%s", insn_disasm(toDisasm, addr == tc->pc)); + } + + osWritebackDCacheAll(); } @@ -321,6 +342,14 @@ void draw_crash_screen(OSThread *thread) crashPage--; updateBuffer = TRUE; } + if (gPlayer1Controller->buttonDown & D_CBUTTONS) { + sProgramPosition += 4; + updateBuffer = TRUE; + } + if (gPlayer1Controller->buttonDown & U_CBUTTONS) { + sProgramPosition -= 4; + updateBuffer = TRUE; + } if (crashPage >= PAGE_COUNT && crashPage != 255) crashPage = 0; @@ -336,6 +365,7 @@ void draw_crash_screen(OSThread *thread) case PAGE_CONTEXT: draw_crash_context(thread, cause); break; case PAGE_LOG: draw_crash_log(); break; case PAGE_STACKTRACE: draw_stacktrace(thread, cause); break; + case PAGE_DISASM: draw_disasm(thread); break; } osWritebackDCacheAll(); diff --git a/src/game/insn_disasm.c b/src/game/insn_disasm.c new file mode 100644 index 00000000..bb5fb286 --- /dev/null +++ b/src/game/insn_disasm.c @@ -0,0 +1,168 @@ +#include +#include "macros.h" +#include "farcall.h" + +enum InsnTypes { + R_TYPE, + I_TYPE, + J_TYPE, +}; + +enum ParamTypes { + PARAM_NONE, + PARAM_SWAP_RS_IMM, + PARAM_JAL, + PARAM_JR, + PARAM_LUI, +}; + +extern far char *parse_map(u32); +static char insn_as_string[100]; + +typedef struct __attribute__((packed)) { + u8 rd : 5; + u8 shift_amt : 5; + u8 function : 6; +} RTypeData; + +typedef struct __attribute__((packed)) { + u8 opcode : 6; + u8 rs : 5; + u8 rt : 5; + union { + RTypeData rdata; + u16 immediate; + }; +} Insn; + +typedef union { + Insn i; + u32 d; +} InsnData; + +typedef struct __attribute__((packed)) { + u32 type; + u32 arbitraryParam; + u8 opcode : 6; + u8 function : 6; + u8 name[10]; +} InsnTemplate; + + +InsnTemplate insn_db[] = { + {R_TYPE, PARAM_NONE, 0, 0b100000, "ADD"}, + {R_TYPE, PARAM_NONE, 0, 0b100001, "ADDU"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b001001, 0, "ADDIU"}, + {R_TYPE, PARAM_NONE, 0, 0b100100, "AND"}, + {R_TYPE, PARAM_NONE, 0, 0b011010, "DIV"}, + {R_TYPE, PARAM_NONE, 0, 0b011011, "DIVU"}, + {R_TYPE, PARAM_NONE, 0, 0b001000, "JR"}, + + {I_TYPE, PARAM_NONE, 0b101000, 0, "SB"}, + {I_TYPE, PARAM_NONE, 0b100000, 0, "LB"}, + {I_TYPE, PARAM_NONE, 0b100100, 0, "LBU"}, + {I_TYPE, PARAM_NONE, 0b101001, 0, "SH"}, + {I_TYPE, PARAM_NONE, 0b100001, 0, "LH"}, + {I_TYPE, PARAM_NONE, 0b100101, 0, "LHU"}, + {I_TYPE, PARAM_NONE, 0b101011, 0, "SW"}, + {I_TYPE, PARAM_NONE, 0b100011, 0, "LW"}, + {I_TYPE, PARAM_LUI, 0b001111, 0, "LUI"}, + + // branches + {I_TYPE, PARAM_SWAP_RS_IMM, 0b000100, 0, "BEQ"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b000101, 0, "BNE"}, + {R_TYPE, PARAM_NONE, 0, 0b110100, "TEQ"}, + {R_TYPE, PARAM_NONE, 0, 0b001001, "JALR"}, + + // jal (special) + {J_TYPE, PARAM_JAL, 0b000011, 0, "JAL"} +}; + + +char registerMaps[][4] = { + "$R0", + "$AT", + "$V0", "$V1", + "$A0", "$A1", "$A2", "$A3", + "$T0", "$T1", "$T2", "$T3", "$T4", "$T5", "$T6", "$T7", + "$S0", "$S1", "$S2", "$S3", "$S4", "$S5", "$S6", "$S7", + "$T8", "$T9", + "$K0", "$K1", + "$GP", "$SP", "$FP", "$RA", +}; + +char *insn_disasm(InsnData insn, u32 isPC) { + char *strp = &insn_as_string[0]; + int successful_print = 0; + + if (insn.d == 0) { // trivial case + if (isPC) + return "NOP <-- CRASH"; + else + return "NOP"; + } + + for (int i = 0; i < ARRAY_COUNT(insn_as_string); i++) insn_as_string[i] = 0; + + + for (int i = 0; i < ARRAY_COUNT(insn_db); i++) { + if (insn.i.opcode != 0 && insn.i.opcode == insn_db[i].opcode) { + switch (insn_db[i].arbitraryParam) { + case PARAM_SWAP_RS_IMM: + strp += sprintf(strp, "%-8s %s %s %04X", insn_db[i].name, + registerMaps[insn.i.rt], + registerMaps[insn.i.rs], + insn.i.immediate + ); break; + case PARAM_LUI: + strp += sprintf(strp, "%-8s %s %04X", insn_db[i].name, + registerMaps[insn.i.rt], + insn.i.immediate + ); break; + break; + case PARAM_JAL: + u32 target = 0x80000000 | ((insn.d & 0x1FFFFFF) * 4); + if ((u32)parse_map != 0x80345678) { + strp += sprintf(strp, "%-8s %s", insn_db[i].name, + parse_map(target) + ); + } else { + strp += sprintf(strp, "%-8s %08X", insn_db[i].name, + target + ); + } + break; + case PARAM_NONE: + strp += sprintf(strp, "%-8s %s %04X (%s)", insn_db[i].name, + registerMaps[insn.i.rt], + insn.i.immediate, + registerMaps[insn.i.rs] + ); break; + + } + successful_print = 1; + break; + } + else if (insn.i.rdata.function != 0 && insn.i.rdata.function == insn_db[i].function) { + strp += sprintf(strp, "%-8s %s %s %s", insn_db[i].name, + registerMaps[insn.i.rdata.rd], + registerMaps[insn.i.rs], + registerMaps[insn.i.rt] + ); + successful_print = 1; + break; + } + } + if (successful_print == 0) { + strp += sprintf(strp, "unimpl %08X", insn.d); + } + + if (isPC) { + sprintf(strp, " <-- CRASH"); + } + + return insn_as_string; +} + + +