From 9b107af8d741111eb50bd7820bbdf59e69100f49 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Mon, 15 Sep 2025 21:04:53 -0400 Subject: [PATCH 1/6] start integrating crash screen code --- include/PR/os.h | 2 + src/fault/assert.h | 74 +++++ src/fault/crash_screen.c | 579 +++++++++++++++++++++++++++++++++++++++ src/fault/crash_screen.h | 6 + src/fault/disasm.c | 394 ++++++++++++++++++++++++++ src/fault/disasm.h | 88 ++++++ src/fault/map_parser.c | 83 ++++++ src/fault/map_parser.h | 14 + src/fault/stacktrace.c | 121 ++++++++ src/fault/stacktrace.h | 21 ++ src/fault/symtable.c | 191 +++++++++++++ src/fault/symtable.h | 76 +++++ 12 files changed, 1649 insertions(+) create mode 100644 src/fault/assert.h create mode 100644 src/fault/crash_screen.c create mode 100644 src/fault/crash_screen.h create mode 100644 src/fault/disasm.c create mode 100644 src/fault/disasm.h create mode 100644 src/fault/map_parser.c create mode 100644 src/fault/map_parser.h create mode 100644 src/fault/stacktrace.c create mode 100644 src/fault/stacktrace.h create mode 100644 src/fault/symtable.c create mode 100644 src/fault/symtable.h diff --git a/include/PR/os.h b/include/PR/os.h index 2ce02f99..8fa825d3 100644 --- a/include/PR/os.h +++ b/include/PR/os.h @@ -63,6 +63,8 @@ extern "C" { #endif +#define PACKED __attribute__((packed)) + #include /************************************************************************** diff --git a/src/fault/assert.h b/src/fault/assert.h new file mode 100644 index 00000000..c466c48f --- /dev/null +++ b/src/fault/assert.h @@ -0,0 +1,74 @@ +#pragma once + +#define ASSERT_MESGBUF_SIZE 256 + + +#ifndef __ASSEMBLER__ + +extern char *__n64Assert_Filename; +extern u32 __n64Assert_LineNum; +extern char *__n64Assert_Condition; +extern char __n64Assert_MessageBuf[ASSERT_MESGBUF_SIZE + 1]; +extern void __n64Assert(char *fileName, u32 lineNum, char *cond); + +/** + * Will always cause a crash with your message of choice + */ +#define errorf(message, ...) { \ + sprintf(__n64Assert_MessageBuf, message ## __VA_ARGS__); \ + __n64Assert(__FILE__, __LINE__, " errorf() "); \ +} +#define error(message) { \ + sprintf(__n64Assert_MessageBuf, message); \ + __n64Assert(__FILE__, __LINE__, " error() "); \ +} + +/** + * Wrapper for assert/aggress + */ +#define __assert_wrapper(cond) __n64Assert(__FILE__, __LINE__, (cond)) + +/** + * `aggress` and `aggressf` will always cause a crash if `cond` is not true (handle with care) + */ +#define aggressf(cond, ...) do {\ + if ((cond) == FALSE) { \ + sprintf(__n64Assert_MessageBuf, __VA_ARGS__); \ + __assert_wrapper(#cond); \ + } \ +} while (0); +#define aggress(cond) do {\ + if ((cond) == FALSE) { \ + __n64Assert_MessageBuf[0] = 0; \ + __assert_wrapper(#cond); \ + } \ +} while (0); + +/** + * Will cause a crash if cond is not true, and DEBUG is defined. + * If disabled, `!cond` is marked as unreachable, which should + * improve codegen on release builds + */ +#ifdef DEBUG_ASSERTIONS +#define assertf(cond, ...) do {\ + if ((cond) == FALSE) { \ + sprintf(__n64Assert_MessageBuf, __VA_ARGS__); \ + __assert_wrapper(#cond); \ + } \ +} while (0); +#else +#define assertf(cond, ...) +#endif + +#ifdef DEBUG_ASSERTIONS +#define assert(cond) do {\ + if ((cond) == FALSE) { \ + __n64Assert_MessageBuf[0] = 0; \ + __assert_wrapper(#cond); \ + } \ +} while (0); +#else +#define assert(cond) +#endif + +#endif // ASSEMBLER diff --git a/src/fault/crash_screen.c b/src/fault/crash_screen.c new file mode 100644 index 00000000..eea82596 --- /dev/null +++ b/src/fault/crash_screen.c @@ -0,0 +1,579 @@ +#include +#include +#include +#include +#include + +#include "assert.h" +#include "crash_screen.h" +#include "disasm.h" +#include "map_parser.h" +#include "stacktrace.h" + +extern u16 sRenderedFramebuffer; +extern void audio_signal_game_loop_tick(void); +extern void stop_sounds_in_continuous_banks(void); +extern void read_controller_inputs(s32 threadID); + +// Configurable Defines +#define X_KERNING 6 +#define GLYPH_WIDTH 8 +#define GLYPH_HEIGHT 12 +#define FONT_ROWS 16 +#define LEFT_MARGIN 10 // for crash screen prints + +enum crashPages { + PAGE_SIMPLE, + PAGE_CONTEXT, + PAGE_STACKTRACE, + PAGE_DISASM, + PAGE_ASSERTS, + PAGE_COUNT +}; + +static char *crashPageNames[PAGE_COUNT + NUM_USER_PAGES] = { + [PAGE_SIMPLE] = "(Overview)", + [PAGE_CONTEXT] = "(Context)", + [PAGE_STACKTRACE] = "(Stack Trace)", + [PAGE_DISASM] = "(Disassembly)", + [PAGE_ASSERTS] = "(Assert)", +}; + +static u8 sCrashScreenCharToGlyph[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, +}; + +static u32 sCrashScreenFont[GLYPH_HEIGHT * FONT_ROWS * 2 + 1] = { + 0x00000000,0x00000000,0x00000000,0x40000000,0x007070f0,0x20000000,0x00888888,0x00000000,0x0098b888,0x00f00000,0x00a8a8f0,0x00880000,0x00c8b880,0x00880000,0x00888080,0x00880000,0x00707880,0x00f00000,0x00000000,0x00800000,0x00000000,0x00800000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20202070,0x00000000,0x20e05088,0x00000000,0x20205088,0x78780000,0x20208888,0x88880000,0x2020f888,0x88880000,0x002088a8,0x98880000,0x20f88870,0x68780000,0x00000008,0x00080000,0x00000000,0x00080000,0x00000000,0x00000000,0x00000000,0x00000000,0x50000000,0x00000000,0x5070f0f0,0x80000000,0x50888888,0x80000000,0x00088888,0xf0b00000,0x0010f0f0,0x88c80000,0x00208888,0x88800000,0x00408888,0x88800000,0x00f8f088,0xf0800000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x50707070,0x00000000,0xf8888888,0x00000000,0x50088080,0x70780000,0xf8308070,0x88800000,0x50088008,0x80700000,0x00888888,0x80080000,0x00707070,0x78f00000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000000,0x7010f0f8,0x08200000,0xa8308820,0x08200000,0xa0508820,0x78700000,0x70908820,0x88200000,0x28f88820,0x88200000,0xa8108820,0x88200000,0x7038f020,0x78180000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x48f8f888,0x00000000,0xa8808088,0x00000000,0xb0f08088,0x70880000,0x7008f088,0x88880000,0x68088088,0xf8880000,0xa8888088,0x80980000,0x9070f870,0x78680000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x6070f888,0x18000000,0x90808088,0x20000000,0xa0f08088,0x70880000,0x4088f050,0x20880000,0xa8888050,0x20500000,0x90888020,0x20500000,0x68708020,0x20200000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000000,0x20f87088,0x00000000,0x20088888,0x00000000,0x00088088,0x78a80000,0x001098a8,0x88a80000,0x002088a8,0x88a80000,0x002088d8,0x88a80000,0x00207088,0x78500000,0x00000000,0x08000000,0x00000000,0x70000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x00000000,0x20708888,0x80000000,0x40888888,0x80000000,0x40888850,0xf0880000,0x4070f820,0x88500000,0x40888850,0x88200000,0x40888888,0x88500000,0x20708888,0x88880000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x40000000,0x00000000,0x2070f888,0x20000000,0x10882088,0x00000000,0x10882088,0x60880000,0x10882050,0x20880000,0x10782020,0x20880000,0x10082020,0x20880000,0x2070f820,0x70780000,0x40000000,0x00080000,0x00000000,0x00700000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x200008f8,0x20000000,0xa8600808,0x00000000,0x70600810,0x60f80000,0x70000820,0x20100000,0xa8608840,0x20200000,0x20608880,0x20400000,0x000070f8,0x20f80000,0x00000000,0x20000000,0x00000000,0xc0000000,0x00000000,0x00000000,0x00000000,0x00100000,0x00000030,0x00200000,0x00008820,0x80200000,0x20609020,0x80200000,0x2060a020,0x90200000,0xf800c020,0xa0400000,0x2060a020,0xe0200000,0x20609020,0x90200000,0x00208820,0x88200000,0x00400030,0x00200000,0x00000000,0x00100000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000080,0x00200000,0x00088040,0x60200000,0x00108040,0x20200000,0x00208020,0x20200000,0x00408020,0x20200000,0x60208010,0x20200000,0x60108010,0x20200000,0x2008f808,0x70200000,0x40000008,0x00200000,0x00000004,0x00000000,0x00000000,0x00000000,0x00000000,0x00400000,0x00000060,0x00200000,0x00008820,0x00200000,0x0000d820,0x00200000,0x00f8a820,0xf0200000,0x7000a820,0xa8100000,0x00f88820,0xa8200000,0x00008820,0xa8200000,0x00008820,0xa8200000,0x00000060,0x00200000,0x00000000,0x00400000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00408820,0x00000000,0x0020c850,0x00000000,0x0010a888,0xb0680000,0x00089800,0xc8b00000,0x00108800,0x88000000,0x60208800,0x88000000,0x60408800,0x88000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x04000000,0x00000000,0x08707000,0x00000000,0x08888800,0x00000000,0x10088800,0x70000000,0x10108800,0x88000000,0x20208800,0x88000000,0x20008800,0x88000000,0x40207000,0x70000000,0x40000000,0x00000000,0x800000fc,0x00000000,0x00000000,0x00000000 +}; + +u8 crashPage = 0; +u8 updateBuffer = TRUE; + +static char crashScreenBuf[0x200]; + +char *gCauseDesc[18] = { + "Interrupt", + "TLB modification", + "TLB exception on load", + "TLB exception on store", + "Address error on load", + "Address error on store", + "Bus error on inst.", + "Bus error on data", + "Failed Assert: See Assert Page", + "Breakpoint exception", + "Reserved instruction", + "Coprocessor unusable", + "Arithmetic overflow", + "Trap exception", + "Virtual coherency on inst.", + "Floating point exception", + "Watchpoint exception", + "Virtual coherency on data", +}; + +char *gFpcsrDesc[6] = { + "Unimplemented operation", "Invalid operation", "Division by zero", "Overflow", "Underflow", + "Inexact operation", +}; + +static u32 sProgramPosition = 0; +static u16 gCrashScreenTextColor = 0xFFFF; +static struct { + OSThread thread; + u64 stack[THREAD2_STACK / sizeof(u64)]; + OSMesgQueue mesgQueue; + OSMesg mesg; + u16 *framebuffer; + u16 width; + u16 height; +} gCrashScreen; + +static void set_text_color(u32 r, u32 g, u32 b) { + gCrashScreenTextColor = GPACK_RGBA5551(r, g, b, 255); +} + +static void reset_text_color(void) { + gCrashScreenTextColor = 0xFFFF; +} + +void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) { + u16 *ptr; + s32 i, j; + + ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x; + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { + *ptr = 0x0001; + ptr++; + } + ptr += gCrashScreen.width - w; + } +} + +void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) { + const u32 *data; + u16 *ptr; + u32 bit; + u32 rowMask; + s32 i, j; + + if (glyph > 0x7F) return; + + data = &sCrashScreenFont[((glyph&0xF)*GLYPH_HEIGHT * 2) + (glyph >= 64)]; + + ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x; + + u16 color = gCrashScreenTextColor; + + for (i = 0; i < GLYPH_HEIGHT; i++) { + bit = 0x80000000U >> ((glyph >> 4) * GLYPH_WIDTH); + rowMask = *data++; + data ++; + + for (j = 0; j < (GLYPH_WIDTH); j++) { + if (bit & rowMask) { + *ptr = color; + } + ptr++; + bit >>= 1; + } + ptr += gCrashScreen.width - (GLYPH_WIDTH); + } +} + +static char *write_to_buf(char *buffer, const char *data, size_t size) { + return (char *) memcpy(buffer, data, size) + size; +} + +void crash_screen_print_with_newlines(s32 x, s32 y, const s32 xNewline, const char *fmt, ...) { + char *ptr; + u32 glyph; + s32 size; + s32 xOffset = x; + + va_list args; + va_start(args, fmt); + + size = _Printf(write_to_buf, crashScreenBuf, fmt, args); + + if (size > 0) { + ptr = crashScreenBuf; + + while (*ptr && size-- > 0) { + if (xOffset >= SCREEN_WIDTH - (xNewline + X_KERNING)) { + y += 10; + xOffset = xNewline; + } + + glyph = sCrashScreenCharToGlyph[*ptr & 0x7f]; + + if (*ptr == '\n') { + y += 10; + xOffset = x; + ptr++; + continue; + } else if (glyph != 0xff) { + crash_screen_draw_glyph(xOffset, y, glyph); + } + + ptr++; + xOffset += X_KERNING; + } + } + + va_end(args); +} + +void crash_screen_print(s32 x, s32 y, const char *fmt, ...) { + char *ptr; + u32 glyph; + s32 size; + + va_list args; + va_start(args, fmt); + + size = _Printf(write_to_buf, crashScreenBuf, fmt, args); + + if (size > 0) { + ptr = crashScreenBuf; + + while (*ptr && size-- > 0) { + glyph = sCrashScreenCharToGlyph[*ptr & 0x7f]; + + if (glyph != 0xff) { + crash_screen_draw_glyph(x, y, glyph); + } + + ptr++; + x += X_KERNING; + } + } + + va_end(args); +} + +void crash_screen_sleep(s32 ms) { + u64 cycles = ms * 1000LL * osClockRate / 1000000ULL; + osSetTime(0); + while (osGetTime() < cycles) { } +} + +void crash_screen_print_float_reg(s32 x, s32 y, s32 regNum, void *addr) { + u32 bits = *(u32 *) addr; + s32 exponent = ((bits & 0x7f800000U) >> 0x17) - 0x7F; + + if ((exponent >= -0x7E && exponent <= 0x7F) || bits == 0x0) { + crash_screen_print(x, y, "F%02d:%.3e", regNum, *(f32 *) addr); + } else { + crash_screen_print(x, y, "F%02d:%08XD", regNum, *(u32 *) addr); + } +} + +void crash_screen_print_fpcsr(u32 fpcsr) { + s32 i; + u32 bit = BIT(17); + + crash_screen_print(100, 220, "FPCSR:%08XH", fpcsr); + for (i = 0; i < 6; i++) { + if (fpcsr & bit) { + crash_screen_print(222, 220, "(%s)", gFpcsrDesc[i]); + return; + } + bit >>= 1; + } +} + +void draw_crash_overview(OSThread *thread, s32 cause) { + __OSThreadContext *tc = &thread->context; + + crash_screen_draw_rect(0, 20, 320, 240); + + crash_screen_print(LEFT_MARGIN, 20, "Thread %d (%s)", thread->id, gCauseDesc[cause]); + +#ifdef DEBUG_EXPORT_SYMBOLS + symtable_info_t info = get_symbol_info(tc->pc); + + crash_screen_print(LEFT_MARGIN, 40, "Crash at: %s", info.func == NULL ? "Unknown" : info.func); + if (info.line != -1) { + crash_screen_print(LEFT_MARGIN, 60, "File: %s", info.file); +#ifdef DEBUG_EXPORT_ALL_LINES + // This line only shows the correct value if every line is in the sym file + crash_screen_print(LEFT_MARGIN, 72, "Line: %d", info.line); +#endif // DEBUG_EXPORT_ALL_LINES + } +#endif // DEBUG_EXPORT_SYMBOLS + + crash_screen_print(LEFT_MARGIN, 84, "Address: 0x%08X", tc->pc); +} + +void draw_crash_context(OSThread *thread, s32 cause) { + __OSThreadContext *tc = &thread->context; + crash_screen_draw_rect(0, 20, 320, 240); + crash_screen_print(LEFT_MARGIN, 20, "Thread:%d (%s)", thread->id, gCauseDesc[cause]); + crash_screen_print(LEFT_MARGIN, 30, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr); + osWritebackDCacheAll(); +#ifdef DEBUG_EXPORT_SYMBOLS + char *fname = parse_map(tc->pc, TRUE); + crash_screen_print(LEFT_MARGIN, 40, "Crash at: %s", fname == NULL ? "Unknown" : fname); +#endif // DEBUG_EXPORT_SYMBOLS + crash_screen_print(LEFT_MARGIN, 52, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0, (u32) tc->v1); + crash_screen_print(LEFT_MARGIN, 62, "A0:%08XH A1:%08XH A2:%08XH", (u32) tc->a0, (u32) tc->a1, (u32) tc->a2); + crash_screen_print(LEFT_MARGIN, 72, "A3:%08XH T0:%08XH T1:%08XH", (u32) tc->a3, (u32) tc->t0, (u32) tc->t1); + crash_screen_print(LEFT_MARGIN, 82, "T2:%08XH T3:%08XH T4:%08XH", (u32) tc->t2, (u32) tc->t3, (u32) tc->t4); + crash_screen_print(LEFT_MARGIN, 92, "T5:%08XH T6:%08XH T7:%08XH", (u32) tc->t5, (u32) tc->t6, (u32) tc->t7); + crash_screen_print(LEFT_MARGIN, 102, "S0:%08XH S1:%08XH S2:%08XH", (u32) tc->s0, (u32) tc->s1, (u32) tc->s2); + crash_screen_print(LEFT_MARGIN, 112, "S3:%08XH S4:%08XH S5:%08XH", (u32) tc->s3, (u32) tc->s4, (u32) tc->s5); + crash_screen_print(LEFT_MARGIN, 122, "S6:%08XH S7:%08XH T8:%08XH", (u32) tc->s6, (u32) tc->s7, (u32) tc->t8); + crash_screen_print(LEFT_MARGIN, 132, "T9:%08XH GP:%08XH SP:%08XH", (u32) tc->t9, (u32) tc->gp, (u32) tc->sp); + crash_screen_print(LEFT_MARGIN, 142, "S8:%08XH RA:%08XH", (u32) tc->s8, (u32) tc->ra); +#ifdef DEBUG_EXPORT_SYMBOLS + fname = parse_map(tc->ra, TRUE); + crash_screen_print(LEFT_MARGIN, 152, "RA at: %s", fname == NULL ? "Unknown" : fname); +#endif // DEBUG_EXPORT_SYMBOLS + + crash_screen_print_fpcsr(tc->fpcsr); + + osWritebackDCacheAll(); + crash_screen_print_float_reg( 10, 170, 0, &tc->fp0.f.f_even); + crash_screen_print_float_reg(100, 170, 2, &tc->fp2.f.f_even); + crash_screen_print_float_reg(190, 170, 4, &tc->fp4.f.f_even); + crash_screen_print_float_reg( 10, 180, 6, &tc->fp6.f.f_even); + crash_screen_print_float_reg(100, 180, 8, &tc->fp8.f.f_even); + crash_screen_print_float_reg(190, 180, 10, &tc->fp10.f.f_even); + crash_screen_print_float_reg( 10, 190, 12, &tc->fp12.f.f_even); + crash_screen_print_float_reg(100, 190, 14, &tc->fp14.f.f_even); + crash_screen_print_float_reg(190, 190, 16, &tc->fp16.f.f_even); + crash_screen_print_float_reg( 10, 200, 18, &tc->fp18.f.f_even); + crash_screen_print_float_reg(100, 200, 20, &tc->fp20.f.f_even); + crash_screen_print_float_reg(190, 200, 22, &tc->fp22.f.f_even); + crash_screen_print_float_reg( 10, 210, 24, &tc->fp24.f.f_even); + crash_screen_print_float_reg(100, 210, 26, &tc->fp26.f.f_even); + crash_screen_print_float_reg(190, 210, 28, &tc->fp28.f.f_even); + crash_screen_print_float_reg( 10, 220, 30, &tc->fp30.f.f_even); +} + + +#ifdef PUPPYPRINT_DEBUG +void draw_crash_log(void) { + s32 i; + crash_screen_draw_rect(0, 20, 320, 210); + osWritebackDCacheAll(); +#define LINE_HEIGHT (25 + ((LOG_BUFFER_SIZE - 1) * 10)) + for (i = 0; i < LOG_BUFFER_SIZE; i++) { + crash_screen_print(LEFT_MARGIN, (LINE_HEIGHT - (i * 10)), consoleLogTable[i]); + } +#undef LINE_HEIGHT +} +#endif + +void draw_stacktrace(OSThread *thread, UNUSED s32 cause) { + __OSThreadContext *tc = &thread->context; + + crash_screen_draw_rect(0, 20, 320, 240); + crash_screen_print(LEFT_MARGIN, 25, "Stack Trace from %08X:", (u32) tc->sp); + +#if defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) + // Current Func (EPC) + crash_screen_print(LEFT_MARGIN, 35, "%08X (%s)", tc->pc, parse_map(tc->pc, TRUE)); + + // Previous Func (RA) + u32 ra = tc->ra; + symtable_info_t info = get_symbol_info(ra); + + crash_screen_print(LEFT_MARGIN, 45, "%08X (%s:%d)", ra, info.func, info.line); + + osWritebackDCacheAll(); + + static u32 generated = 0; + + if (stackTraceGenerated == FALSE) { + generated = generate_stack(thread); + stackTraceGenerated = TRUE; + } + for (u32 i = 0; i < generated; i++) { + crash_screen_print(LEFT_MARGIN, 55 + (i * 10), get_stack_entry(i)); + } +#else // defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) + // simple stack trace + u32 sp = tc->sp; + + for (int i = 0; i < STACK_LINE_COUNT; i++) { + crash_screen_print(LEFT_MARGIN, 55 + (i * 10), "%3d: %08X", i, *((u32*)(sp + (i * 4)))); + crash_screen_print(120, 55 + (i * 10), "%3d: %08X", i + STACK_LINE_COUNT, *((u32*)(sp + ((i + STACK_LINE_COUNT) * 4)))); + } +#endif // defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) +} + +void draw_disasm(OSThread *thread) { + __OSThreadContext *tc = &thread->context; + + crash_screen_draw_rect(0, 20, 320, 240); + if (sProgramPosition == 0) { + sProgramPosition = (tc->pc - 36); + } + crash_screen_print(LEFT_MARGIN, 25, "Program Counter: %08X", sProgramPosition); + osWritebackDCacheAll(); + + int skiplines = 0; +#ifdef DEBUG_EXPORT_SYMBOLS + int currline = 0; +#endif // DEBUG_EXPORT_SYMBOLS + + for (int i = 0; i < 19; i++) { + u32 addr = (sProgramPosition + (i * 4)); + + char *disasm = insn_disasm((InsnData *)addr); + + + if (disasm[0] == 0) { + crash_screen_print(LEFT_MARGIN + 22, 35 + (skiplines * 10) + (i * 10), "%08X", addr); + } else { +#ifdef DEBUG_EXPORT_SYMBOLS + symtable_info_t info = get_symbol_info(addr); + + if (info.func_offset == 0 && info.distance == 0 && currline != info.line) { + currline = info.line; + set_text_color(239, 196, 15); + crash_screen_print(LEFT_MARGIN, 35 + (skiplines * 10) + (i * 10), "<%s:>", info.func); + reset_text_color(); + skiplines++; + } +#ifndef DEBUG_EXPORT_ALL_LINES + // catch `jal` and `jalr` callsites + if (disasm[0] == 'j' && disasm[1] == 'a') { +#endif // DEBUG_EXPORT_ALL_LINES + if (info.line != -1) { + set_text_color(200, 200, 200); + crash_screen_print(LEFT_MARGIN, 35 + (skiplines * 10) + (i * 10), "%d:", info.line); + reset_text_color(); + } +#ifndef DEBUG_EXPORT_ALL_LINES + } +#endif // DEBUG_EXPORT_ALL_LINES + +#endif // DEBUG_EXPORT_SYMBOLS + if (addr == tc->pc) { + set_text_color(255, 0, 0); + } else { + reset_text_color(); + } + crash_screen_print(LEFT_MARGIN + 22, 35 + (skiplines * 10) + (i * 10), "%s", disasm); + } + + } + + reset_text_color(); + osWritebackDCacheAll(); +} + +void draw_assert(UNUSED OSThread *thread) { + crash_screen_draw_rect(0, 20, 320, 240); + + crash_screen_print(LEFT_MARGIN, 25, "Assert"); + + if (__n64Assert_Filename != NULL) { + crash_screen_print(LEFT_MARGIN, 35, "File: %s", __n64Assert_Filename); + crash_screen_print(LEFT_MARGIN, 45, "Line %d", __n64Assert_LineNum); + crash_screen_print(LEFT_MARGIN, 55, "Condition:"); + crash_screen_print(LEFT_MARGIN, 65, "(%s)", __n64Assert_Condition); + if (__n64Assert_MessageBuf[0] != 0) { + crash_screen_print(LEFT_MARGIN, 75, "Message:"); + crash_screen_print(LEFT_MARGIN, 85, " %s", __n64Assert_MessageBuf); + } + } else { + crash_screen_print(LEFT_MARGIN, 35, "No failed assert to report."); + } + + osWritebackDCacheAll(); +} + +void draw_crash_screen(OSThread *thread) { + __OSThreadContext *tc = &thread->context; + + s32 cause = ((tc->cause >> 2) & 0x1F); + if (cause == 23) { // EXC_WATCH + cause = 16; + } + if (cause == 31) { // EXC_VCED + cause = 17; + } + + if (gPlayer1Controller->buttonPressed & R_TRIG) { + crashPage++; + if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage++; + updateBuffer = TRUE; + } + if (gPlayer1Controller->buttonPressed & (L_TRIG | Z_TRIG)) { + crashPage--; + if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage--; + updateBuffer = TRUE; + } + + if (crashPage == PAGE_DISASM) { + 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; + } + if (crashPage == 255) { + crashPage = (PAGE_COUNT - 1); + if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage--; + } + if (updateBuffer) { + crash_screen_draw_rect(0, 0, 320, 20); + crash_screen_print(LEFT_MARGIN, 5, "Page:%02d %-22s L/Z: Left R: Right", crashPage, crashPageNames[crashPage]); + switch (crashPage) { + case PAGE_SIMPLE: draw_crash_overview(thread, cause); break; + case PAGE_CONTEXT: draw_crash_context(thread, cause); break; +#ifdef PUPPYPRINT_DEBUG + case PAGE_LOG: draw_crash_log(); break; +#endif + case PAGE_STACKTRACE: draw_stacktrace(thread, cause); break; + case PAGE_DISASM: draw_disasm(thread); break; + case PAGE_ASSERTS: draw_assert(thread); break; + } + + osWritebackDCacheAll(); + osViBlack(FALSE); + osViSwapBuffer(gCrashScreen.framebuffer); + updateBuffer = FALSE; + } +} + +OSThread *get_crashed_thread(void) { + OSThread *thread = __osGetCurrFaultedThread(); + + while (thread->priority != -1) { + if (thread->priority > OS_PRIORITY_IDLE && thread->priority < OS_PRIORITY_APPMAX + && ((thread->flags & (BIT(0) | BIT(1))) != 0)) { + return thread; + } + thread = thread->tlnext; + } + return NULL; +} + +void osFaultMain(void *arg) { + OSMesg mesg; + OSThread *thread = NULL; + + osSetEventMesg(OS_EVENT_CPU_BREAK, &gCrashScreen.mesgQueue, (OSMesg) 1); + osSetEventMesg(OS_EVENT_FAULT, &gCrashScreen.mesgQueue, (OSMesg) 2); + while (TRUE) { + if (thread == NULL) { + osRecvMesg(&gCrashScreen.mesgQueue, &mesg, 1); + thread = get_crashed_thread(); + gCrashScreen.framebuffer = (RGBA16 *) gFramebuffers[sRenderedFramebuffer]; + if (thread) { + gCrashScreen.thread.priority = 15; + crash_screen_sleep(200); + audio_signal_game_loop_tick(); + crash_screen_sleep(200); + // If an assert happened, go straight to that page + if (thread->context.cause == EXC_SYSCALL) { + crashPage = PAGE_ASSERTS; + } + continue; + } + } else { + if (gControllerBits) { +#if ENABLE_RUMBLE + block_until_rumble_pak_free(); +#endif + osContStartReadDataEx(&gSIEventMesgQueue); + } + read_controller_inputs(THREAD_2_CRASH_SCREEN); + draw_crash_screen(thread); + } + } +} + +void osCreateFaultHandler(void) { + gCrashScreen.framebuffer = (RGBA16 *) gFramebuffers[sRenderedFramebuffer]; + gCrashScreen.width = SCREEN_WD; + gCrashScreen.height = SCREEN_HT; + osCreateMesgQueue(&gCrashScreen.mesgQueue, &gCrashScreen.mesg, 1); + osCreateThread(&gCrashScreen.thread, FAULT_THREAD, thread2_crash_screen, NULL, + (u8 *) gCrashScreen.stack + sizeof(gCrashScreen.stack), + OS_PRIORITY_APPMAX + ); + osStartThread(&gCrashScreen.thread); +} + diff --git a/src/fault/crash_screen.h b/src/fault/crash_screen.h new file mode 100644 index 00000000..569a9c9b --- /dev/null +++ b/src/fault/crash_screen.h @@ -0,0 +1,6 @@ +#pragma once + +#define FAULT_THREAD 2 + +#define NUM_USER_PAGES 16 + diff --git a/src/fault/disasm.c b/src/fault/disasm.c new file mode 100644 index 00000000..cf2dd21e --- /dev/null +++ b/src/fault/disasm.c @@ -0,0 +1,394 @@ +#include +#include + +#include "sm64.h" +#include "macros.h" +#include "farcall.h" +#include "disasm.h" +#include "map_parser.h" + +static char insn_as_string[100]; + +InsnTemplate insn_db[] = { + // We want instructions with opcodes first (prioritized) + + // load/store + {I_TYPE, PARAM_LUI, 0b001111, 0, "lui"}, + {I_TYPE, PARAM_NONE, 0b100000, 0, "lb"}, + {I_TYPE, PARAM_NONE, 0b100100, 0, "lbu"}, + {I_TYPE, PARAM_NONE, 0b101000, 0, "sb"}, + {I_TYPE, PARAM_NONE, 0b100001, 0, "lh"}, + {I_TYPE, PARAM_NONE, 0b100101, 0, "lhu"}, + {I_TYPE, PARAM_NONE, 0b101001, 0, "sh"}, + {I_TYPE, PARAM_NONE, 0b100011, 0, "lw"}, + {I_TYPE, PARAM_NONE, 0b101011, 0, "sw"}, + {I_TYPE, PARAM_NONE, 0b110111, 0, "ld"}, + {I_TYPE, PARAM_NONE, 0b111111, 0, "sd"}, + {I_TYPE, PARAM_FLOAT_RT, 0b110001, 0, "lwc1"}, + {I_TYPE, PARAM_FLOAT_RT, 0b111001, 0, "swc1"}, + {I_TYPE, PARAM_FLOAT_RT, 0b110101, 0, "ldc1"}, + {I_TYPE, PARAM_FLOAT_RT, 0b111101, 0, "sdc1"}, + + // unaligned + {I_TYPE, PARAM_NONE, 0b100010, 0, "lwl"}, + {I_TYPE, PARAM_NONE, 0b100110, 0, "lwr"}, + {I_TYPE, PARAM_NONE, 0b101010, 0, "swl"}, + {I_TYPE, PARAM_NONE, 0b101110, 0, "swr"}, + // atomics + {I_TYPE, PARAM_NONE, 0b110000, 0, "ll"}, + {I_TYPE, PARAM_NONE, 0b111000, 0, "sc"}, + {I_TYPE, PARAM_NONE, 0b111100, 0, "scd"}, + // branches + {I_TYPE, PARAM_SWAP_RS_IMM, 0b000100, 0, "beq"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b010100, 0, "beql"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b000101, 0, "bne"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b010101, 0, "bnel"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b000111, 0, "bgtz"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b010111, 0, "bgtzl"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b000110, 0, "blez"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b010110, 0, "blezl"}, + {I_TYPE, PARAM_NONE, 0b001010, 0, "slti"}, + {I_TYPE, PARAM_NONE, 0b001011, 0, "sltiu"}, + + // jal (special) + {J_TYPE, PARAM_JAL, 0b000011, 0, "jal"}, + {J_TYPE, PARAM_JUMP, 0b000010, 0, "j"}, + + // bitwise ops (which are opcodes) + {I_TYPE, PARAM_NONE, 0b001100, 0, "andi"}, + {I_TYPE, PARAM_NONE, 0b001101, 0, "ori"}, + {I_TYPE, PARAM_NONE, 0b001110, 0, "xori"}, + + + // arithmetic + {I_TYPE, PARAM_SWAP_RS_IMM, 0b011000, 0, "daddi"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b011001, 0, "daddiu"}, + // and now the ones with 0 for the opcode + {R_TYPE, PARAM_NONE, 0, 0b100000, "add"}, + {R_TYPE, PARAM_NONE, 0, 0b100001, "addu"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b001000, 0, "addi"}, + {I_TYPE, PARAM_SWAP_RS_IMM, 0b001001, 0, "addiu"}, + {R_TYPE, PARAM_NONE, 0, 0b100010, "sub"}, + {R_TYPE, PARAM_NONE, 0, 0b100011, "subu"}, + {R_TYPE, PARAM_NONE, 0, 0b011000, "mult"}, + {R_TYPE, PARAM_NONE, 0, 0b011001, "multu"}, + {R_TYPE, PARAM_NONE, 0, 0b011010, "div"}, + {R_TYPE, PARAM_NONE, 0, 0b011011, "divu"}, + {R_TYPE, PARAM_MULT_MOVE, 0, 0b010000, "mfhi"}, + {R_TYPE, PARAM_MULT_MOVE, 0, 0b010001, "mthi"}, + {R_TYPE, PARAM_MULT_MOVE, 0, 0b010010, "mflo"}, + {R_TYPE, PARAM_MULT_MOVE, 0, 0b010011, "mtlo"}, + {R_TYPE, PARAM_NONE, 0, 0b101010, "slt"}, + {R_TYPE, PARAM_NONE, 0, 0b101011, "sltu"}, + + // bitwise ops (which are functions) + {R_TYPE, PARAM_NONE, 0, 0b100100, "and"}, + {R_TYPE, PARAM_NONE, 0, 0b100101, "or"}, + {R_TYPE, PARAM_NONE, 0, 0b100110, "xor"}, + {R_TYPE, PARAM_BITSHIFT, 0, 0b000000, "sll"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000100, "sllv"}, + {R_TYPE, PARAM_BITSHIFT, 0, 0b000010, "srl"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000110, "srlv"}, + {R_TYPE, PARAM_BITSHIFT, 0, 0b000011, "sra"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000111, "srav"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b100111, "nor"}, + + {R_TYPE, PARAM_NONE, 0, 0b001001, "jalr"}, + {R_TYPE, PARAM_NONE, 0, 0b001000, "jr"}, + {R_TYPE, PARAM_TRAP, 0, 0b110100, "teq"}, + {R_TYPE, PARAM_EMUX, 0, 0b110110, "tne"}, + + {0, PARAM_SYSCALL, 0, 0b001100, "syscall"}, + + // instructions involving doubles (deprioritized on the list) + {R_TYPE, PARAM_NONE, 0, 0b101101, "daddu"}, + {R_TYPE, PARAM_NONE, 0, 0b101110, "dsub"}, + {R_TYPE, PARAM_NONE, 0, 0b101111, "dsubu"}, + {R_TYPE, PARAM_NONE, 0, 0b011101, "dmultu"}, + {R_TYPE, PARAM_NONE, 0, 0b011110, "ddiv"}, + {R_TYPE, PARAM_NONE, 0, 0b011111, "ddivu"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010100, "dsllv"}, + {R_TYPE, PARAM_BITSHIFT, 0, 0b111100, "dsll32"}, + {R_TYPE, PARAM_BITSHIFT, 0, 0b111110, "dsrl32"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010110, "dsrlv"}, + {R_TYPE, PARAM_BITSHIFT, 0, 0b111111, "dsra32"}, + {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010111, "dsrav"}, +}; + + +char __mips_gpr[][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", + "$lo", "$hi" +}; + +char __mips_fpreg[][5] = { + "$f0", "$f1", "$f2", "$f3", + "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", + "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", + "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", + "$f28", "$f29", "$f30", "$f31", +}; + +u8 insn_is_jal(Insn *i) { + return (i->opcode == 0b000011); +} + +u8 insn_is_jalr(Insn *i) { + return (i->opcode == 0) && (i->rdata.function == 0b001001); +} + +// Last Resort C0/C1 disassembler, from libdragon +static void c1_disasm(u32 *ptr, char *out) { + static const char *fpu_ops[64]= { + "radd", "rsub", "rmul", "rdiv", "ssqrt", "sabs", "smov", "sneg", + "sround.l", "strunc.l", "sceil.l", "sfloor.l", "sround.w", "strunc.w", "sceil.w", "sfloor.w", + "*", "*", "*", "*", "*", "*", "*", "*", + "*", "*", "*", "*", "*", "*", "*", "*", + "scvt.s", "scvt.d", "*", "*", "scvt.w", "scvt.l", "*", "*", + "*", "*", "*", "*", "*", "*", "*", "*", + "hc.f", "hc.un", "hc.eq", "hc.ueq", "hc.olt", "hc.ult", "hc.ole", "hc.ule", + "hc.sf", "hc.ngle", "hc.seq", "hc.ngl", "hc.lt", "hc.nge", "hc.le", "hc.ngt", + }; + + char symbuf[64]; + + // Disassemble MIPS instruction + u32 pc = (u32)ptr; + u32 op = *ptr; + s16 imm16 = op & 0xFFFF; + u32 tgt16 = (pc + 4) + (imm16 << 2); + u32 imm26 = op & 0x3FFFFFF; + u32 tgt26 = ((pc + 4) & 0xf0000000) | (imm26 << 2); + const char *rs = __mips_gpr[(op >> 21) & 0x1F]; + const char *rt = __mips_gpr[(op >> 16) & 0x1F]; + const char *rd = __mips_gpr[(op >> 11) & 0x1F]; + const char *opn = "unimpl"; + if (((op >> 26) & 0x3F) == 17) { + u32 sub = (op >> 21) & 0x1F; + switch (sub) { + case 0: opn = "gmfc1"; break; + case 1: opn = "gdmfc1"; break; + case 4: opn = "gmtc1"; break; + case 5: opn = "gdmtc1"; break; + case 8: switch ((op >> 16) & 0x1F) { + case 0: opn = "ybc1f"; break; + case 2: opn = "ybc1fl"; break; + case 1: opn = "ybc1t"; break; + case 3: opn = "ybc1tl"; break; + } break; + case 16: case 17: case 20: case 21: + opn = fpu_ops[(op >> 0) & 0x3F]; + sprintf(symbuf, "%s.%s", opn, (sub == 16) ? "s" : (sub == 17) ? "d" : (sub == 20) ? "w" : "l"); + opn = symbuf; + rt = __mips_fpreg[(op >> 16) & 0x1F]; + rs = __mips_fpreg[(op >> 11) & 0x1F]; + rd = __mips_fpreg[(op >> 6) & 0x1F]; + break; + } + } + switch (*opn) { +#ifdef DEBUG_EXPORT_SYMBOLS + /* op tgt26 */ case 'j': sprintf(out, "%-9s %08x <%s>", opn+1, tgt26, parse_map(tgt26, FALSE)); break; + /* op rs, rt, tgt16 */case 'b': sprintf(out, "%-9s %s, %s, %08x <%s>", opn+1, rs, rt, tgt16, parse_map(tgt16, TRUE)); break; + /* op tgt16 */ case 'y': sprintf(out, "%-9s %08x <%s>", opn+1, tgt16, parse_map(tgt16, TRUE)); break; +#else + /* op tgt26 */ case 'j': sprintf(out, "%-9s %08x", opn+1, tgt26); break; + /* op rs, rt, tgt16 */case 'b': sprintf(out, "%-9s %s, %s, %08x", opn+1, rs, rt, tgt16); break; + /* op tgt16 */ case 'y': sprintf(out, "%-9s %08x", opn+1, tgt16); break; +#endif // DEBUG_EXPORT_SYMBOLS + /* op rt, rs, imm */ case 'i': sprintf(out, "%-9s %s, %s, %d", opn+1, rt, rs, (s16)op); break; + /* op rt, imm */ case 'k': sprintf(out, "%-9s %s, %d", opn+1, rt, (s16)op); break; + /* op rt, imm(rs) */ case 'm': sprintf(out, "%-9s %s, %d(%s)", opn+1, rt, (s16)op, rs); break; + /* op fd, imm(rs) */ case 'n': sprintf(out, "%-9s %s, %d(%s)", opn+1, __mips_fpreg[(op >> 16) & 0x1F], (s16)op, rs); break; + /* op rd, rs, rt */ case 'r': sprintf(out, "%-9s %s, %s, %s", opn+1, rd, rs, rt); break; + /* op rd, rs */ case 's': sprintf(out, "%-9s %s, %s", opn+1, rd, rs); break; + /* op rd, rt, sa */ case 'e': sprintf(out, "%-9s %s, %s, %ld", opn+1, rd, rt, (op >> 6) & 0x1F); break; + /* op rs */ case 'w': sprintf(out, "%-9s %s", opn+1, rs); break; + /* op rd */ case 'c': sprintf(out, "%-9s %s", opn+1, rd); break; + /* op */ case 'z': sprintf(out, "%-9s", opn+1); break; + /* op fd, fs, ft */ case 'f': sprintf(out, "%-9s %s, %s, %s", opn+1, rd, rs, rt); break; + /* op rt, fs */ case 'g': sprintf(out, "%-9s %s, %s", opn+1, rt, __mips_fpreg[(op >> 11) & 0x1F]); break; + /* op rs, rt */ case 'h': sprintf(out, "%-9s %s, %s", opn+1, rs, rt); break; + /* op code20 */ case 'a': sprintf(out, "%-9s 0x%lx", opn+1, (op>>6) & 0xFFFFF); break; + /* op rs, rt, code */ case 't': sprintf(out, "%-9s %s, %s, 0x%lx", opn+1, rs, rt, (op>>6) & 0x3FF); break; + default: sprintf(out, "%-9s", opn+1); break; + } +} + +char *cop1_insn_disasm(InsnData *pc) { + c1_disasm((u32 *)pc, insn_as_string); + + return insn_as_string; +} + +char *branch_insn_disasm(InsnData insn) { + static char *insn_names[] = { + [0b00001] = "bgez", + [0b00011] = "bgezl", + [0b10001] = "bgezal", + [0b10011] = "bgezall", + [0b00000] = "bltz", + [0b00010] = "bltzl", + [0b10000] = "bltzal", + [0b10010] = "bltzall", + }; + char *strp = &insn_as_string[0]; + char *rs = __mips_gpr[insn.b.rs]; + u16 offset = insn.b.offset; + + for (int i = 0; i < ARRAY_COUNT(insn_as_string); i++) insn_as_string[i] = 0; + + sprintf(strp, "%-9s %s %04X", insn_names[insn.b.sub], rs, offset); + + return insn_as_string; +} + +char *insn_disasm(InsnData *addr) { + InsnData insn = *addr; + char *strp = &insn_as_string[0]; + int successful_print = 0; + u32 target; + + if (insn.d == 0) { // trivial case + return "nop"; + } + + if (insn.i.opcode == OP_BRANCH) { + return branch_insn_disasm(insn); + } + if (insn.i.opcode == OP_COP0) { + return "cop0 (UNIMPL)"; + } + if (insn.i.opcode == OP_COP1) { + return cop1_insn_disasm(addr); + } + + 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, "%-9s %s %s %04X", insn_db[i].name, + __mips_gpr[insn.i.rt], + __mips_gpr[insn.i.rs], + insn.i.immediate + ); break; + case PARAM_LUI: + strp += sprintf(strp, "%-9s %s %04X", insn_db[i].name, + __mips_gpr[insn.i.rt], + insn.i.immediate + ); break; + break; + case PARAM_JAL: + target = 0x80000000 | ((insn.d & 0x1FFFFFF) * 4); +#ifdef DEBUG_EXPORT_SYMBOLS + strp += sprintf(strp, "%-9s %s(%08X)", insn_db[i].name, + parse_map(target, FALSE), target + ); +#else + strp += sprintf(strp, "%-9s %08X", insn_db[i].name, + target + ); +#endif // DEBUG_EXPORT_SYMBOLS + break; + case PARAM_JUMP: + target = 0x80000000 | (insn.d & 0x03FFFFFF); + strp += sprintf(strp, "%-9s %08X", insn_db[i].name, + target + ); + break; + case PARAM_FLOAT_RT: + strp += sprintf(strp, "%-9s %s, %04X (%s)", insn_db[i].name, + __mips_fpreg[insn.i.rt], + insn.i.immediate, + __mips_gpr[insn.i.rs] + ); break; + case PARAM_NONE: + strp += sprintf(strp, "%-9s %s %04X (%s)", insn_db[i].name, + __mips_gpr[insn.i.rt], + insn.i.immediate, + __mips_gpr[insn.i.rs] + ); break; + + } + successful_print = 1; + break; + } else if ( (insn.i.rdata.function == 0 && insn.i.opcode == 0) // specifically catch `sll` + || (insn.i.rdata.function != 0 && insn.i.rdata.function == insn_db[i].function) + ) { + switch (insn_db[i].arbitraryParam) { + case PARAM_BITSHIFT: + strp += sprintf(strp, "%-9s %s %s %04X", insn_db[i].name, + __mips_gpr[insn.i.rdata.rd], + __mips_gpr[insn.i.rt], + insn.i.rdata.shift_amt + ); + break; + case PARAM_SWAP_RS_RT: + strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, + __mips_gpr[insn.i.rdata.rd], + __mips_gpr[insn.i.rt], + __mips_gpr[insn.i.rs] + ); + break; + case PARAM_MULT_MOVE: + strp += sprintf(strp, "%-9s %s", insn_db[i].name, + __mips_gpr[insn.i.rdata.rd] + ); + break; + case PARAM_EMUX: + target = (insn.d >> 6) & 0x3FF; + if (insn.i.rs == insn.i.rt) { + strp += sprintf(strp, "%-9s %s 0x%02X", "emux", + __mips_gpr[insn.i.rs], + target + ); + } else { + strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, + __mips_gpr[insn.i.rs], + __mips_gpr[insn.i.rt] + ); + } + break; + case PARAM_TRAP: + strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, + __mips_gpr[insn.i.rs], + __mips_gpr[insn.i.rt] + ); + break; + case PARAM_SYSCALL: + strp += sprintf(strp, "%-9s %d", insn_db[i].name, + (insn.d & 0x03FFFFC0) >> 6 + ); + break; + case PARAM_NONE: + strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, + __mips_gpr[insn.i.rdata.rd], + __mips_gpr[insn.i.rs], + __mips_gpr[insn.i.rt] + ); + break; + + } + successful_print = 1; + break; + } + } + if (successful_print == 0) { + strp += sprintf(strp, "unimpl %08X", insn.d); + } + + return insn_as_string; +} diff --git a/src/fault/disasm.h b/src/fault/disasm.h new file mode 100644 index 00000000..609ed175 --- /dev/null +++ b/src/fault/disasm.h @@ -0,0 +1,88 @@ +#pragma once + +enum InsnTypes { + R_TYPE, + I_TYPE, + J_TYPE, + COP0, + COP1, +}; + +enum ParamTypes { + PARAM_NONE, + PARAM_SWAP_RS_IMM, + PARAM_BITSHIFT, + PARAM_FLOAT_RT, + PARAM_SWAP_RS_RT, + PARAM_JAL, + PARAM_JUMP, + PARAM_JR, + PARAM_LUI, + PARAM_MULT_MOVE, + PARAM_TRAP, + PARAM_EMUX, + PARAM_SYSCALL, +}; + +typedef struct PACKED { + u16 rd : 5; + u16 shift_amt : 5; + u16 function : 6; +} RTypeData; + +typedef struct PACKED { + u16 opcode : 6; + u16 rs : 5; + u16 rt : 5; + union { + RTypeData rdata; + u16 immediate; + }; +} Insn; + +typedef struct PACKED { + u16 opcode : 6; + u16 fmt : 5; + u16 ft : 5; + u16 fs : 5; + u16 fd : 5; + u16 func : 6; +} CzInsn; + +typedef struct PACKED { + u16 regimm : 6; + u16 rs : 5; + u16 sub : 5; + u16 offset; +} BranchInsn; + +typedef union { + Insn i; + CzInsn f; + BranchInsn b; + u32 d; +} InsnData; + +typedef struct PACKED { + u32 type; + u32 arbitraryParam; + u16 opcode : 6; + u16 function : 6; + u8 name[10]; +} InsnTemplate; + +typedef struct PACKED { + u32 type; + u32 arbitraryParam; + u16 function : 6; + u8 name[10]; +} COPzInsnTemplate; + +#define OP_COP0 0b010000 +#define OP_COP1 0b010001 +#define OP_BRANCH 0b000001 // technically "REGIMM" + +extern char *insn_disasm(InsnData *insn); +extern u8 insn_is_jal(Insn *i); +extern u8 insn_is_jalr(Insn *i); + diff --git a/src/fault/map_parser.c b/src/fault/map_parser.c new file mode 100644 index 00000000..26b72834 --- /dev/null +++ b/src/fault/map_parser.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include "game/memory.h" + +#include "map_parser.h" +#include "symtable.h" + +#ifdef DEBUG_EXPORT_SYMBOLS + +#define UNKNOWN_SYMBOL "???" + +char* __symbolize(void *vaddr, char *buf, int size, u32 andOffset) { + symtable_header_t symt = symt_open(); + if (symt.head[0]) { + u32 addr = (u32)vaddr; + int idx = 0; + addrtable_entry_t a = symt_addrtab_search(&symt, addr, &idx); + while (!ADDRENTRY_IS_FUNC(a)) { + a = symt_addrtab_entry(&symt, --idx); + } + + symtable_entry_t ALIGNED16 entry; + // Read the symbol name + symt_entry_fetch(&symt, &entry, idx); + char *func = symt_entry_func(&symt, &entry, addr, buf, size-12); + char lbuf[12]; + if (andOffset) { + sprintf(lbuf, "+0x%lx", addr - ADDRENTRY_ADDR(a)); + } else { + lbuf[0] = 0; + } + entry.func_off = addr - ADDRENTRY_ADDR(a); + + return strcat(func, lbuf); + } + sprintf(buf, "%s", UNKNOWN_SYMBOL); + return buf; +} + +char *parse_map(u32 addr, u32 andOffset) { + static char map_name[64] ALIGNED16; + char *ret = map_name; + + __symbolize((u32*)addr, map_name, sizeof(map_name), andOffset); + + if (ret[0] == ' ') { + ret++; + } + return ret; +} + +symtable_info_t get_symbol_info(u32 addr) { + static char filebuf[100]; + void *vaddr = (void *)addr; + symtable_header_t symt = symt_open(); + + if (symt.head[0]) { + symtable_info_t info; + u32 addr = (u32)vaddr; + int idx = 0; + symt_addrtab_search(&symt, addr, &idx); + + symtable_entry_t ALIGNED16 entry; + + // Read the symbol name + filebuf[0] = 0; + symt_entry_fetch(&symt, &entry, idx); + info.line = entry.line; + info.func_offset = entry.func_off; + addrtable_entry_t a = symt_addrtab_entry(&symt, idx); + info.distance = addr - ADDRENTRY_ADDR(a); + info.file = symt_entry_file(&symt, &entry, filebuf, sizeof(filebuf)); + info.func = parse_map(addr, FALSE); + + return info; + } + return (symtable_info_t){.line = -1}; +} + +#endif // DEBUG_EXPORT_SYMBOLS diff --git a/src/fault/map_parser.h b/src/fault/map_parser.h new file mode 100644 index 00000000..be2b3c51 --- /dev/null +++ b/src/fault/map_parser.h @@ -0,0 +1,14 @@ +#pragma once + +typedef struct { + char *file; + char *func; + int line; + u16 distance; + u16 func_offset; +} symtable_info_t; + +symtable_info_t get_symbol_info(u32 vaddr); +extern char *parse_map(u32 pc, u32 andOffset); +extern symtable_info_t walk_stack(u32 *addr); +extern char* __symbolize(void *vaddr, char *buf, int size, u32 andOffset); diff --git a/src/fault/stacktrace.c b/src/fault/stacktrace.c new file mode 100644 index 00000000..5e07b2c3 --- /dev/null +++ b/src/fault/stacktrace.c @@ -0,0 +1,121 @@ +#include +#include +#include + +#include "config/config_debug.h" + +#include "map_parser.h" +#include "symtable.h" +#include "segment_symbols.h" +#include "stacktrace.h" +#include "disasm.h" + +extern void __osCleanupThread(); + +#if defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) + +static StackFrame stack[STACK_LINE_COUNT]; +static u32 stackIdx; +u32 stackTraceGenerated = FALSE; + +#define STACK_END_STR "[End of stack]" + +static u8 is_top_of_stack(u32 ra) { + return (ra == ((u32)__osCleanupThread)); +} + +static u8 is_text_addr(u32 addr) { + if ((addr >= (u32)_mainSegmentStart) && (addr <= (u32)_mainSegmentTextEnd)) { + return TRUE; + } + else if ((addr >= (u32)_engineSegmentStart) && (addr <= (u32)_engineSegmentTextEnd)) { + return TRUE; + } + else if ((addr >= (u32)_goddardSegmentStart) && (addr <= (u32)_goddardSegmentTextEnd)) { + return TRUE; + } + + return FALSE; +} + +static void add_entry_to_stack(u32 addr, u32 ra, symtable_info_t *info) { + StackFrame *frame = &stack[stackIdx++]; + + frame->func = addr; + frame->offset = info->func_offset; + frame->ra = ra; + frame->line = info->line; + sprintf(frame->funcname, "%s", info->func); +} + +char *get_stack_entry(u32 idx) { + static char stackbuf[100]; + + sprintf(stackbuf, "%08X: %s:%d", stack[idx].func, stack[idx].funcname, stack[idx].line); + + return stackbuf; +} + +u32 generate_stack(OSThread *thread) { + static u32 breadcrumb = 0; + symtable_header_t symt = symt_open(); + + __OSThreadContext *tc = &thread->context; + + u32 sp = tc->sp; + breadcrumb = tc->ra; + + while (1) { // dont know the end goal yet + sp += 4; + + u32 val = *(u32*)sp; + + // make sure we're working on an actual address + if (is_text_addr(val + CALLSITE_OFFSET)) { + int idx = 0; + symtable_info_t info = get_symbol_info(val + CALLSITE_OFFSET); + addrtable_entry_t funcstart = symt_addrtab_search(&symt, breadcrumb, &idx); + + // If we can't logically go further, we're done! + if (is_top_of_stack(val)) { + symtable_info_t info = get_symbol_info(val + CALLSITE_OFFSET); + info.func = STACK_END_STR; + add_entry_to_stack(val + CALLSITE_OFFSET, breadcrumb, &info); + breadcrumb = val; + return stackIdx; + } + + // get the start of the current frame's func + while (!ADDRENTRY_IS_FUNC(funcstart) && !ADDRENTRY_IS_INLINE(funcstart)) { + funcstart = symt_addrtab_entry(&symt, --idx); + } + + // Make sure the address is an actual callsite + if (info.distance == 0) { + u32 jal = *(u32*)(val + CALLSITE_OFFSET); + + if (insn_is_jal((Insn *) &jal)) { + u32 jalTarget = 0x80000000 | ((jal & 0x03FFFFFF) * 4); + + // make sure JAL is to the current func + if (jalTarget == ADDRENTRY_ADDR(funcstart)) { + add_entry_to_stack(val + CALLSITE_OFFSET, breadcrumb, &info); + breadcrumb = val; + } + } else if (insn_is_jalr((Insn *) &jal)) { + // Always add a JALR to the stack, in absence of a better heuristic + add_entry_to_stack(val + CALLSITE_OFFSET, breadcrumb, &info); + breadcrumb = val; + } + } + + if (stackIdx >= STACK_LINE_COUNT) { + break; + } + } + } + + return stackIdx; +} + +#endif // DEBUG_EXPORT_SYMBOLS && DEBUG_FULL_STACK_TRACE diff --git a/src/fault/stacktrace.h b/src/fault/stacktrace.h new file mode 100644 index 00000000..1e6d0569 --- /dev/null +++ b/src/fault/stacktrace.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +typedef struct { + u32 func; + u32 offset; + u32 ra; + int line; + char funcname[100]; +} StackFrame; + +#define STACK_TRAVERSAL_LIMIT 100 +#define STACK_LINE_COUNT 17 +// RA points to 2 instructions past any given callsite +#define CALLSITE_OFFSET -8 + +extern u32 stackTraceGenerated; + +extern u32 generate_stack(OSThread *); +extern char *get_stack_entry(u32 idx); diff --git a/src/fault/symtable.c b/src/fault/symtable.c new file mode 100644 index 00000000..0ad11876 --- /dev/null +++ b/src/fault/symtable.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include "segments.h" +#include "game/memory.h" + +#include "symtable.h" + +#ifdef DEBUG_EXPORT_SYMBOLS + +u32 SYMT_ROM = 0xFFFFFFFF; +extern u8 _mapDataSegmentRomStart[]; +// The start and end of the exception vector +extern u8 __osExceptionPreamble[]; +extern u8 send_mesg[]; + +#define is_in_exception(addr) ((addr) >= (u32)__osExceptionPreamble && (addr) < (u32)send_mesg) + +// code provided by Wiseguy +static void headless_dma(u32 devAddr, void *dramAddr, u32 size) { + register u32 stat = IO_READ(PI_STATUS_REG); + while (stat & (PI_STATUS_IO_BUSY | PI_STATUS_DMA_BUSY)) { + stat = IO_READ(PI_STATUS_REG); + } + IO_WRITE(PI_DRAM_ADDR_REG, K0_TO_PHYS(dramAddr)); + IO_WRITE(PI_CART_ADDR_REG, K1_TO_PHYS((u32)osRomBase | devAddr)); + IO_WRITE(PI_WR_LEN_REG, size - 1); +} +static u32 headless_pi_status(void) { + return IO_READ(PI_STATUS_REG); +} +// end of code provided by Wiseguy + +void map_parser_dma(void *dst, void *src, size_t size) { + headless_dma((u32)src, dst, size); + while (headless_pi_status() & PI_STATUS_IO_BUSY); +} + +/** + * @brief Open the SYMT symbol table in the rompak. + * + * If not found, return a null header. + */ +symtable_header_t symt_open(void) { + SYMT_ROM = (u32)_mapDataSegmentRomStart; + + symtable_header_t ALIGNED8 symt_header; + + if (SYMT_ROM == 0) { + return (symtable_header_t){0}; + } + + osWritebackDCache(&symt_header, sizeof(symt_header)); + map_parser_dma( + &symt_header, + (uintptr_t *)SYMT_ROM, + sizeof(symtable_header_t) + ); + + if (symt_header.head[0] != 'S' || symt_header.head[1] != 'Y' || symt_header.head[2] != 'M' || symt_header.head[3] != 'T') { + osSyncPrintf("symt_open: invalid symbol table found at 0x%08lx\n", SYMT_ROM); + SYMT_ROM = 0; + return (symtable_header_t){0}; + } + if (symt_header.version != 2) { + osSyncPrintf("symt_open: unsupported symbol table version %ld -- please update your n64sym tool\n", symt_header.version); + SYMT_ROM = 0; + return (symtable_header_t){0}; + } + + return symt_header; +} + +/** + * @brief Return an entry in the address table by index + * + * @param symt SYMT file header + * @param idx Index of the entry to return + * @return addrtable_entry_t Entry of the address table + */ +addrtable_entry_t symt_addrtab_entry(symtable_header_t *symt, int idx) { + return IO_READ(0xB0000000 | (SYMT_ROM + symt->addrtab_off + idx * 4)); +} + +/** + * @brief Search the SYMT address table for the given address. + * + * Run a binary search to find the entry in the table. If there is a single exact match, + * the entry is returned. If there are multiple entries with the same address, the first + * entry is returned (this is the case for inlined functions: so some entries following + * the current one will have the same address). If there is no exact match, the entry + * with the biggest address just before the given address is returned. + * + * @param symt SYMT file header + * @param addr Address to search for + * @param idx If not null, will be set to the index of the entry found (or the index just before) + * @return The found entry (or the entry just before) + */ +addrtable_entry_t symt_addrtab_search(symtable_header_t *symt, u32 addr, int *idx) { + int min = 0; + int max = symt->addrtab_size - 1; + while (min < max) { + int mid = (min + max) / 2; + addrtable_entry_t entry = symt_addrtab_entry(symt, mid); + if (addr <= ADDRENTRY_ADDR(entry)) { + max = mid; + } else { + min = mid + 1; + } + } + addrtable_entry_t entry = symt_addrtab_entry(symt, min); + if (min > 0 && ADDRENTRY_ADDR(entry) > addr) { + entry = symt_addrtab_entry(symt, --min); + } + if (idx) { + *idx = min; + } + return entry; +} + +/** + * @brief Fetch a string from the string table + * + * @param symt SYMT file + * @param sidx Index of the first character of the string in the string table + * @param slen Length of the string + * @param buf Destination buffer + * @param size Size of the destination buffer + * @return char* Fetched string within the destination buffer (might not be at offset 0 for alignment reasons) + */ +char *symt_string(symtable_header_t *symt, int sidx, int slen, char *buf, int size) { + // Align 2-byte phase of the RAM buffer with the ROM address. This is required + // for map_parser_dma. + int tweak = (sidx ^ (u32)buf) & 1; + char *func = buf + tweak; size -= tweak; + int nbytes = MIN(slen, size); + + osWritebackDCache(buf, size); + map_parser_dma( + func, + (uintptr_t *)(SYMT_ROM + symt->strtab_off + sidx), + nbytes + ); + func[nbytes] = 0; + + if (tweak) { + buf[0] = ' '; + } + return func; +} + +/** + * @brief Fetch a symbol table entry from the SYMT file. + * + * @param symt SYMT file + * @param entry Output entry pointer + * @param idx Index of the entry to fetch + */ +void symt_entry_fetch(symtable_header_t *symt, symtable_entry_t *entry, int idx) { + osWritebackDCache(entry, sizeof(symtable_entry_t)); + + // char dbg[100]; + // sprintf(dbg,"symt_entry_fetch %d\n", idx); + // osSyncPrintf(dbg); + map_parser_dma( + entry, + (uintptr_t *)(SYMT_ROM + symt->symtab_off + idx * sizeof(symtable_entry_t)), + sizeof(symtable_entry_t) + ); +} + +// Fetch the function name of an entry +char *symt_entry_func(symtable_header_t *symt, symtable_entry_t *entry, u32 addr, char *buf, int size) { + if (is_in_exception(addr)) { + // Special case exception handlers. This is just to show something slightly + // more readable instead of "notcart+0x0" or similar assembly symbols + sprintf(buf, ""); + return buf; + } else { + return symt_string(symt, entry->func_sidx, entry->func_len, buf, size); + } +} + +// Fetch the file name of an entry +char *symt_entry_file(symtable_header_t *symt, symtable_entry_t *entry, char *buf, int size) { + return symt_string(symt, entry->file_sidx, entry->file_len, buf, size); +} + +#endif // DEBUG_EXPORT_SYMBOLS diff --git a/src/fault/symtable.h b/src/fault/symtable.h new file mode 100644 index 00000000..1f1d3eba --- /dev/null +++ b/src/fault/symtable.h @@ -0,0 +1,76 @@ +#pragma once + +/** + * @brief Symbol table file header + * + * The SYMT file is made of three main tables: + * + * * Address table: this is a sequence of 32-bit integers, each representing an address in the ROM. + * The table is sorted in ascending order to allow for binary search. Moreover, the lowest 2 bits + * of each address can store additional information: If bit 0 is set to 1, the address is the start + * of a function. If bit 1 is set to 1, the address is an inline duplicate. In fact, there might be + * multiple symbols at the same address for inlined functions, so we need one entry in this table + * for each entry; all of them will have the same address, and all but the last one will have bit + * 1 set to 1. + * * Symbol table: this is a sequence of symbol table entries, each representing a symbol. The size + * of this table (in number of entries) is exactly the same as the address table. In fact, each + * address of the address table can be thought of as an external member of this structure; it's + * split externally to allow for efficiency reasons. Each entry stores the function name, + * the source file name and line number, and the binary offset of the symbol within the containing + * function. + * * String table: this table can be thought as a large buffer holding all the strings needed by all + * symbol entries (function names and file names). Each symbol entry stores a string as an offset + * within the symbol table and a length. This allows to reuse the same string (or prefix thereof) + * multiple times. Notice that strings are not null terminated in the string table. + * + * The SYMT file is generated by the n64sym tool during the build process. + */ +typedef struct { + char head[4]; ///< Magic ID "SYMT" + u32 version; ///< Version of the symbol table + u32 addrtab_off; ///< Offset of the address table in the file + u32 addrtab_size; ///< Size of the address table in the file (number of entries) + u32 symtab_off; ///< Offset of the symbol table in the file + u32 symtab_size; ///< Size of the symbol table in the file (number of entries); always equal to addrtab_size. + u32 strtab_off; ///< Offset of the string table in the file + u32 strtab_size; ///< Size of the string table in the file (number of entries) +} symtable_header_t; + +/** @brief Symbol table entry **/ +typedef struct { + u32 func_sidx; ///< Offset of the function name in the string table + u32 file_sidx; ///< Offset of the file name in the string table + u16 func_len; ///< Length of the function name + u16 file_len; ///< Length of the file name + u16 line; ///< Line number (or 0 if this symbol generically refers to a whole function) + u16 func_off; ///< Offset of the symbol within its function +} symtable_entry_t; + +/** + * @brief Entry in the address table. + * + * This is an address in RAM, with the lowest 2 bits used to store additional information. + * See the ADDRENTRY_* macros to access the various components. + */ +typedef u32 addrtable_entry_t; + +#define ADDRENTRY_ADDR(e) ((e) & ~3) ///< Address (without the flags) +#define ADDRENTRY_IS_FUNC(e) ((e) & 1) ///< TRUE if the address is the start of a function +#define ADDRENTRY_IS_INLINE(e) ((e) & 2) ///< TRUE if the address is an inline duplicate + +#define MIPS_OP_ADDIU_SP(op) (((op) & 0xFFFF0000) == 0x27BD0000) ///< Matches: addiu $sp, $sp, imm +#define MIPS_OP_DADDIU_SP(op) (((op) & 0xFFFF0000) == 0x67BD0000) ///< Matches: daddiu $sp, $sp, imm +#define MIPS_OP_JR_RA(op) (((op) & 0xFFFFFFFF) == 0x03E00008) ///< Matches: jr $ra +#define MIPS_OP_SD_RA_SP(op) (((op) & 0xFFFF0000) == 0xAFBF0000) ///< Matches: sw $ra, imm($sp) +#define MIPS_OP_SD_FP_SP(op) (((op) & 0xFFFF0000) == 0xAFBE0000) ///< Matches: sw $fp, imm($sp) +#define MIPS_OP_LUI_GP(op) (((op) & 0xFFFF0000) == 0x3C1C0000) ///< Matches: lui $gp, imm +#define MIPS_OP_NOP(op) ((op) == 0x00000000) ///< Matches: nop +#define MIPS_OP_MOVE_FP_SP(op) ((op) == 0x03A0F025) ///< Matches: move $fp, $sp + +symtable_header_t symt_open(void); +addrtable_entry_t symt_addrtab_entry(symtable_header_t *symt, int idx); +addrtable_entry_t symt_addrtab_search(symtable_header_t *symt, u32 addr, int *idx); +char *symt_string(symtable_header_t *symt, int sidx, int slen, char *buf, int size); +void symt_entry_fetch(symtable_header_t *symt, symtable_entry_t *entry, int idx); +char *symt_entry_func(symtable_header_t *symt, symtable_entry_t *entry, u32 addr, char *buf, int size); +char *symt_entry_file(symtable_header_t *symt, symtable_entry_t *entry, char *buf, int size); From b15217ad77d38eee03f678be15e769a0e31d6d80 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Mon, 15 Sep 2025 21:12:41 -0400 Subject: [PATCH 2/6] game compiles --- src/fault/crash_screen.c | 105 ++++++++++++++++++--------------------- src/fault/crash_screen.h | 11 ++++ src/fault/disasm.c | 4 +- src/fault/map_parser.c | 2 - src/fault/stacktrace.c | 22 ++++---- src/fault/symtable.c | 3 -- 6 files changed, 68 insertions(+), 79 deletions(-) diff --git a/src/fault/crash_screen.c b/src/fault/crash_screen.c index eea82596..0ba487c1 100644 --- a/src/fault/crash_screen.c +++ b/src/fault/crash_screen.c @@ -15,6 +15,8 @@ extern void audio_signal_game_loop_tick(void); extern void stop_sounds_in_continuous_banks(void); extern void read_controller_inputs(s32 threadID); +static OSFaultContext __osCurrentFaultContext; + // Configurable Defines #define X_KERNING 6 #define GLYPH_WIDTH 8 @@ -87,15 +89,6 @@ char *gFpcsrDesc[6] = { static u32 sProgramPosition = 0; static u16 gCrashScreenTextColor = 0xFFFF; -static struct { - OSThread thread; - u64 stack[THREAD2_STACK / sizeof(u64)]; - OSMesgQueue mesgQueue; - OSMesg mesg; - u16 *framebuffer; - u16 width; - u16 height; -} gCrashScreen; static void set_text_color(u32 r, u32 g, u32 b) { gCrashScreenTextColor = GPACK_RGBA5551(r, g, b, 255); @@ -109,13 +102,13 @@ void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) { u16 *ptr; s32 i, j; - ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x; + ptr = __osCurrentFaultContext.cfb + __osCurrentFaultContext.width * y + x; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { *ptr = 0x0001; ptr++; } - ptr += gCrashScreen.width - w; + ptr += __osCurrentFaultContext.width - w; } } @@ -130,7 +123,7 @@ void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) { data = &sCrashScreenFont[((glyph&0xF)*GLYPH_HEIGHT * 2) + (glyph >= 64)]; - ptr = gCrashScreen.framebuffer + gCrashScreen.width * y + x; + ptr = __osCurrentFaultContext.cfb + __osCurrentFaultContext.width * y + x; u16 color = gCrashScreenTextColor; @@ -146,7 +139,7 @@ void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) { ptr++; bit >>= 1; } - ptr += gCrashScreen.width - (GLYPH_WIDTH); + ptr += __osCurrentFaultContext.width - (GLYPH_WIDTH); } } @@ -169,7 +162,7 @@ void crash_screen_print_with_newlines(s32 x, s32 y, const s32 xNewline, const ch ptr = crashScreenBuf; while (*ptr && size-- > 0) { - if (xOffset >= SCREEN_WIDTH - (xNewline + X_KERNING)) { + if (xOffset >= __osCurrentFaultContext.width - (xNewline + X_KERNING)) { y += 10; xOffset = xNewline; } @@ -240,7 +233,7 @@ void crash_screen_print_float_reg(s32 x, s32 y, s32 regNum, void *addr) { void crash_screen_print_fpcsr(u32 fpcsr) { s32 i; - u32 bit = BIT(17); + u32 bit = FPCSR_CE; crash_screen_print(100, 220, "FPCSR:%08XH", fpcsr); for (i = 0; i < 6; i++) { @@ -335,7 +328,7 @@ void draw_crash_log(void) { } #endif -void draw_stacktrace(OSThread *thread, UNUSED s32 cause) { +void draw_stacktrace(OSThread *thread, s32 cause) { __OSThreadContext *tc = &thread->context; crash_screen_draw_rect(0, 20, 320, 240); @@ -435,7 +428,7 @@ void draw_disasm(OSThread *thread) { osWritebackDCacheAll(); } -void draw_assert(UNUSED OSThread *thread) { +void draw_assert( OSThread *thread) { crash_screen_draw_rect(0, 20, 320, 240); crash_screen_print(LEFT_MARGIN, 25, "Assert"); @@ -467,27 +460,27 @@ void draw_crash_screen(OSThread *thread) { cause = 17; } - if (gPlayer1Controller->buttonPressed & R_TRIG) { - crashPage++; - if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage++; - updateBuffer = TRUE; - } - if (gPlayer1Controller->buttonPressed & (L_TRIG | Z_TRIG)) { - crashPage--; - if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage--; - updateBuffer = TRUE; - } - - if (crashPage == PAGE_DISASM) { - if (gPlayer1Controller->buttonDown & D_CBUTTONS) { - sProgramPosition += 4; - updateBuffer = TRUE; - } - if (gPlayer1Controller->buttonDown & U_CBUTTONS) { - sProgramPosition -= 4; - updateBuffer = TRUE; - } - } + // if (gPlayer1Controller->buttonPressed & R_TRIG) { + // crashPage++; + // if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage++; + // updateBuffer = TRUE; + // } + // if (gPlayer1Controller->buttonPressed & (L_TRIG | Z_TRIG)) { + // crashPage--; + // if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage--; + // updateBuffer = TRUE; + // } + + // if (crashPage == PAGE_DISASM) { + // 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; @@ -512,7 +505,7 @@ void draw_crash_screen(OSThread *thread) { osWritebackDCacheAll(); osViBlack(FALSE); - osViSwapBuffer(gCrashScreen.framebuffer); + osViSwapBuffer(__osCurrentFaultContext.cfb); updateBuffer = FALSE; } } @@ -534,15 +527,14 @@ void osFaultMain(void *arg) { OSMesg mesg; OSThread *thread = NULL; - osSetEventMesg(OS_EVENT_CPU_BREAK, &gCrashScreen.mesgQueue, (OSMesg) 1); - osSetEventMesg(OS_EVENT_FAULT, &gCrashScreen.mesgQueue, (OSMesg) 2); + osSetEventMesg(OS_EVENT_CPU_BREAK, &__osCurrentFaultContext.mesgQueue, (OSMesg) 1); + osSetEventMesg(OS_EVENT_FAULT, &__osCurrentFaultContext.mesgQueue, (OSMesg) 2); while (TRUE) { if (thread == NULL) { - osRecvMesg(&gCrashScreen.mesgQueue, &mesg, 1); + osRecvMesg(&__osCurrentFaultContext.mesgQueue, &mesg, 1); thread = get_crashed_thread(); - gCrashScreen.framebuffer = (RGBA16 *) gFramebuffers[sRenderedFramebuffer]; if (thread) { - gCrashScreen.thread.priority = 15; + __osCurrentFaultContext.thread.priority = 15; crash_screen_sleep(200); audio_signal_game_loop_tick(); crash_screen_sleep(200); @@ -553,27 +545,24 @@ void osFaultMain(void *arg) { continue; } } else { - if (gControllerBits) { -#if ENABLE_RUMBLE - block_until_rumble_pak_free(); -#endif - osContStartReadDataEx(&gSIEventMesgQueue); - } - read_controller_inputs(THREAD_2_CRASH_SCREEN); +// if (gControllerBits) { +// #if ENABLE_RUMBLE +// block_until_rumble_pak_free(); +// #endif +// osContStartReadDataEx(&gSIEventMesgQueue); +// } + read_controller_inputs(FAULT_THREAD); draw_crash_screen(thread); } } } void osCreateFaultHandler(void) { - gCrashScreen.framebuffer = (RGBA16 *) gFramebuffers[sRenderedFramebuffer]; - gCrashScreen.width = SCREEN_WD; - gCrashScreen.height = SCREEN_HT; - osCreateMesgQueue(&gCrashScreen.mesgQueue, &gCrashScreen.mesg, 1); - osCreateThread(&gCrashScreen.thread, FAULT_THREAD, thread2_crash_screen, NULL, - (u8 *) gCrashScreen.stack + sizeof(gCrashScreen.stack), + osCreateMesgQueue(&__osCurrentFaultContext.mesgQueue, &__osCurrentFaultContext.mesg, 1); + osCreateThread(&__osCurrentFaultContext.thread, FAULT_THREAD, osFaultMain, NULL, + (u8 *) __osCurrentFaultContext.stack + sizeof(__osCurrentFaultContext.stack), OS_PRIORITY_APPMAX ); - osStartThread(&gCrashScreen.thread); + osStartThread(&__osCurrentFaultContext.thread); } diff --git a/src/fault/crash_screen.h b/src/fault/crash_screen.h index 569a9c9b..cc0f031b 100644 --- a/src/fault/crash_screen.h +++ b/src/fault/crash_screen.h @@ -4,3 +4,14 @@ #define NUM_USER_PAGES 16 +typedef struct { + OSMesgQueue mesgQueue; + OSMesg mesg; + OSThread thread; + OSContPad pad; + u32 width; + u32 height; + u16 *cfb; + u64 stack[100]; +} OSFaultContext; + diff --git a/src/fault/disasm.c b/src/fault/disasm.c index cf2dd21e..2540aab7 100644 --- a/src/fault/disasm.c +++ b/src/fault/disasm.c @@ -1,9 +1,7 @@ +#include #include #include -#include "sm64.h" -#include "macros.h" -#include "farcall.h" #include "disasm.h" #include "map_parser.h" diff --git a/src/fault/map_parser.c b/src/fault/map_parser.c index 26b72834..1bfc04b7 100644 --- a/src/fault/map_parser.c +++ b/src/fault/map_parser.c @@ -1,9 +1,7 @@ #include -#include #include #include #include -#include "game/memory.h" #include "map_parser.h" #include "symtable.h" diff --git a/src/fault/stacktrace.c b/src/fault/stacktrace.c index 5e07b2c3..04653450 100644 --- a/src/fault/stacktrace.c +++ b/src/fault/stacktrace.c @@ -1,12 +1,8 @@ #include -#include #include -#include "config/config_debug.h" - #include "map_parser.h" #include "symtable.h" -#include "segment_symbols.h" #include "stacktrace.h" #include "disasm.h" @@ -25,15 +21,15 @@ static u8 is_top_of_stack(u32 ra) { } static u8 is_text_addr(u32 addr) { - if ((addr >= (u32)_mainSegmentStart) && (addr <= (u32)_mainSegmentTextEnd)) { - return TRUE; - } - else if ((addr >= (u32)_engineSegmentStart) && (addr <= (u32)_engineSegmentTextEnd)) { - return TRUE; - } - else if ((addr >= (u32)_goddardSegmentStart) && (addr <= (u32)_goddardSegmentTextEnd)) { - return TRUE; - } + // if ((addr >= (u32)_mainSegmentStart) && (addr <= (u32)_mainSegmentTextEnd)) { + // return TRUE; + // } + // else if ((addr >= (u32)_engineSegmentStart) && (addr <= (u32)_engineSegmentTextEnd)) { + // return TRUE; + // } + // else if ((addr >= (u32)_goddardSegmentStart) && (addr <= (u32)_goddardSegmentTextEnd)) { + // return TRUE; + // } return FALSE; } diff --git a/src/fault/symtable.c b/src/fault/symtable.c index 0ad11876..7746f8f7 100644 --- a/src/fault/symtable.c +++ b/src/fault/symtable.c @@ -1,10 +1,7 @@ #include -#include #include #include #include -#include "segments.h" -#include "game/memory.h" #include "symtable.h" From 9e0b2a71109de622fb3692218f1aacefc3aa5484 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Mon, 15 Sep 2025 21:15:59 -0400 Subject: [PATCH 3/6] format --- src/fault/assert.h | 79 ++++--- src/fault/crash_screen.c | 261 ++++++++++++--------- src/fault/crash_screen.h | 3 +- src/fault/disasm.c | 483 ++++++++++++++++++++------------------- src/fault/disasm.h | 13 +- src/fault/map_parser.c | 12 +- src/fault/map_parser.h | 10 +- src/fault/stacktrace.c | 14 +- src/fault/stacktrace.h | 6 +- src/fault/symtable.c | 67 +++--- src/fault/symtable.h | 76 +++--- 11 files changed, 533 insertions(+), 491 deletions(-) diff --git a/src/fault/assert.h b/src/fault/assert.h index c466c48f..a8e1860a 100644 --- a/src/fault/assert.h +++ b/src/fault/assert.h @@ -2,26 +2,27 @@ #define ASSERT_MESGBUF_SIZE 256 - #ifndef __ASSEMBLER__ -extern char *__n64Assert_Filename; -extern u32 __n64Assert_LineNum; -extern char *__n64Assert_Condition; +extern char* __n64Assert_Filename; +extern u32 __n64Assert_LineNum; +extern char* __n64Assert_Condition; extern char __n64Assert_MessageBuf[ASSERT_MESGBUF_SIZE + 1]; -extern void __n64Assert(char *fileName, u32 lineNum, char *cond); +extern void __n64Assert(char* fileName, u32 lineNum, char* cond); /** * Will always cause a crash with your message of choice */ -#define errorf(message, ...) { \ - sprintf(__n64Assert_MessageBuf, message ## __VA_ARGS__); \ - __n64Assert(__FILE__, __LINE__, " errorf() "); \ -} -#define error(message) { \ - sprintf(__n64Assert_MessageBuf, message); \ - __n64Assert(__FILE__, __LINE__, " error() "); \ -} +#define errorf(message, ...) \ + { \ + sprintf(__n64Assert_MessageBuf, message##__VA_ARGS__); \ + __n64Assert(__FILE__, __LINE__, " errorf() "); \ + } +#define error(message) \ + { \ + sprintf(__n64Assert_MessageBuf, message); \ + __n64Assert(__FILE__, __LINE__, " error() "); \ + } /** * Wrapper for assert/aggress @@ -31,18 +32,20 @@ extern void __n64Assert(char *fileName, u32 lineNum, char *cond); /** * `aggress` and `aggressf` will always cause a crash if `cond` is not true (handle with care) */ -#define aggressf(cond, ...) do {\ - if ((cond) == FALSE) { \ - sprintf(__n64Assert_MessageBuf, __VA_ARGS__); \ - __assert_wrapper(#cond); \ - } \ -} while (0); -#define aggress(cond) do {\ - if ((cond) == FALSE) { \ - __n64Assert_MessageBuf[0] = 0; \ - __assert_wrapper(#cond); \ - } \ -} while (0); +#define aggressf(cond, ...) \ + do { \ + if ((cond) == FALSE) { \ + sprintf(__n64Assert_MessageBuf, __VA_ARGS__); \ + __assert_wrapper(#cond); \ + } \ + } while (0); +#define aggress(cond) \ + do { \ + if ((cond) == FALSE) { \ + __n64Assert_MessageBuf[0] = 0; \ + __assert_wrapper(#cond); \ + } \ + } while (0); /** * Will cause a crash if cond is not true, and DEBUG is defined. @@ -50,23 +53,25 @@ extern void __n64Assert(char *fileName, u32 lineNum, char *cond); * improve codegen on release builds */ #ifdef DEBUG_ASSERTIONS -#define assertf(cond, ...) do {\ - if ((cond) == FALSE) { \ - sprintf(__n64Assert_MessageBuf, __VA_ARGS__); \ - __assert_wrapper(#cond); \ - } \ -} while (0); +#define assertf(cond, ...) \ + do { \ + if ((cond) == FALSE) { \ + sprintf(__n64Assert_MessageBuf, __VA_ARGS__); \ + __assert_wrapper(#cond); \ + } \ + } while (0); #else #define assertf(cond, ...) #endif #ifdef DEBUG_ASSERTIONS -#define assert(cond) do {\ - if ((cond) == FALSE) { \ - __n64Assert_MessageBuf[0] = 0; \ - __assert_wrapper(#cond); \ - } \ -} while (0); +#define assert(cond) \ + do { \ + if ((cond) == FALSE) { \ + __n64Assert_MessageBuf[0] = 0; \ + __assert_wrapper(#cond); \ + } \ + } while (0); #else #define assert(cond) #endif diff --git a/src/fault/crash_screen.c b/src/fault/crash_screen.c index 0ba487c1..bd3ab56f 100644 --- a/src/fault/crash_screen.c +++ b/src/fault/crash_screen.c @@ -18,42 +18,71 @@ extern void read_controller_inputs(s32 threadID); static OSFaultContext __osCurrentFaultContext; // Configurable Defines -#define X_KERNING 6 -#define GLYPH_WIDTH 8 +#define X_KERNING 6 +#define GLYPH_WIDTH 8 #define GLYPH_HEIGHT 12 -#define FONT_ROWS 16 -#define LEFT_MARGIN 10 // for crash screen prints - -enum crashPages { - PAGE_SIMPLE, - PAGE_CONTEXT, - PAGE_STACKTRACE, - PAGE_DISASM, - PAGE_ASSERTS, - PAGE_COUNT -}; +#define FONT_ROWS 16 +#define LEFT_MARGIN 10 // for crash screen prints + +enum crashPages { PAGE_SIMPLE, PAGE_CONTEXT, PAGE_STACKTRACE, PAGE_DISASM, PAGE_ASSERTS, PAGE_COUNT }; -static char *crashPageNames[PAGE_COUNT + NUM_USER_PAGES] = { - [PAGE_SIMPLE] = "(Overview)", - [PAGE_CONTEXT] = "(Context)", - [PAGE_STACKTRACE] = "(Stack Trace)", - [PAGE_DISASM] = "(Disassembly)", - [PAGE_ASSERTS] = "(Assert)", +static char* crashPageNames[PAGE_COUNT + NUM_USER_PAGES] = { + [PAGE_SIMPLE] = "(Overview)", [PAGE_CONTEXT] = "(Context)", [PAGE_STACKTRACE] = "(Stack Trace)", + [PAGE_DISASM] = "(Disassembly)", [PAGE_ASSERTS] = "(Assert)", }; static u8 sCrashScreenCharToGlyph[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, }; static u32 sCrashScreenFont[GLYPH_HEIGHT * FONT_ROWS * 2 + 1] = { - 0x00000000,0x00000000,0x00000000,0x40000000,0x007070f0,0x20000000,0x00888888,0x00000000,0x0098b888,0x00f00000,0x00a8a8f0,0x00880000,0x00c8b880,0x00880000,0x00888080,0x00880000,0x00707880,0x00f00000,0x00000000,0x00800000,0x00000000,0x00800000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20202070,0x00000000,0x20e05088,0x00000000,0x20205088,0x78780000,0x20208888,0x88880000,0x2020f888,0x88880000,0x002088a8,0x98880000,0x20f88870,0x68780000,0x00000008,0x00080000,0x00000000,0x00080000,0x00000000,0x00000000,0x00000000,0x00000000,0x50000000,0x00000000,0x5070f0f0,0x80000000,0x50888888,0x80000000,0x00088888,0xf0b00000,0x0010f0f0,0x88c80000,0x00208888,0x88800000,0x00408888,0x88800000,0x00f8f088,0xf0800000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x50707070,0x00000000,0xf8888888,0x00000000,0x50088080,0x70780000,0xf8308070,0x88800000,0x50088008,0x80700000,0x00888888,0x80080000,0x00707070,0x78f00000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000000,0x7010f0f8,0x08200000,0xa8308820,0x08200000,0xa0508820,0x78700000,0x70908820,0x88200000,0x28f88820,0x88200000,0xa8108820,0x88200000,0x7038f020,0x78180000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x48f8f888,0x00000000,0xa8808088,0x00000000,0xb0f08088,0x70880000,0x7008f088,0x88880000,0x68088088,0xf8880000,0xa8888088,0x80980000,0x9070f870,0x78680000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x6070f888,0x18000000,0x90808088,0x20000000,0xa0f08088,0x70880000,0x4088f050,0x20880000,0xa8888050,0x20500000,0x90888020,0x20500000,0x68708020,0x20200000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000000,0x20f87088,0x00000000,0x20088888,0x00000000,0x00088088,0x78a80000,0x001098a8,0x88a80000,0x002088a8,0x88a80000,0x002088d8,0x88a80000,0x00207088,0x78500000,0x00000000,0x08000000,0x00000000,0x70000000,0x00000000,0x00000000,0x00000000,0x00000000,0x10000000,0x00000000,0x20708888,0x80000000,0x40888888,0x80000000,0x40888850,0xf0880000,0x4070f820,0x88500000,0x40888850,0x88200000,0x40888888,0x88500000,0x20708888,0x88880000,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x40000000,0x00000000,0x2070f888,0x20000000,0x10882088,0x00000000,0x10882088,0x60880000,0x10882050,0x20880000,0x10782020,0x20880000,0x10082020,0x20880000,0x2070f820,0x70780000,0x40000000,0x00080000,0x00000000,0x00700000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x200008f8,0x20000000,0xa8600808,0x00000000,0x70600810,0x60f80000,0x70000820,0x20100000,0xa8608840,0x20200000,0x20608880,0x20400000,0x000070f8,0x20f80000,0x00000000,0x20000000,0x00000000,0xc0000000,0x00000000,0x00000000,0x00000000,0x00100000,0x00000030,0x00200000,0x00008820,0x80200000,0x20609020,0x80200000,0x2060a020,0x90200000,0xf800c020,0xa0400000,0x2060a020,0xe0200000,0x20609020,0x90200000,0x00208820,0x88200000,0x00400030,0x00200000,0x00000000,0x00100000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000080,0x00200000,0x00088040,0x60200000,0x00108040,0x20200000,0x00208020,0x20200000,0x00408020,0x20200000,0x60208010,0x20200000,0x60108010,0x20200000,0x2008f808,0x70200000,0x40000008,0x00200000,0x00000004,0x00000000,0x00000000,0x00000000,0x00000000,0x00400000,0x00000060,0x00200000,0x00008820,0x00200000,0x0000d820,0x00200000,0x00f8a820,0xf0200000,0x7000a820,0xa8100000,0x00f88820,0xa8200000,0x00008820,0xa8200000,0x00008820,0xa8200000,0x00000060,0x00200000,0x00000000,0x00400000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00408820,0x00000000,0x0020c850,0x00000000,0x0010a888,0xb0680000,0x00089800,0xc8b00000,0x00108800,0x88000000,0x60208800,0x88000000,0x60408800,0x88000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x04000000,0x00000000,0x08707000,0x00000000,0x08888800,0x00000000,0x10088800,0x70000000,0x10108800,0x88000000,0x20208800,0x88000000,0x20008800,0x88000000,0x40207000,0x70000000,0x40000000,0x00000000,0x800000fc,0x00000000,0x00000000,0x00000000 + 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x007070f0, 0x20000000, 0x00888888, 0x00000000, 0x0098b888, + 0x00f00000, 0x00a8a8f0, 0x00880000, 0x00c8b880, 0x00880000, 0x00888080, 0x00880000, 0x00707880, 0x00f00000, + 0x00000000, 0x00800000, 0x00000000, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x20202070, 0x00000000, 0x20e05088, 0x00000000, 0x20205088, 0x78780000, 0x20208888, 0x88880000, + 0x2020f888, 0x88880000, 0x002088a8, 0x98880000, 0x20f88870, 0x68780000, 0x00000008, 0x00080000, 0x00000000, + 0x00080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x50000000, 0x00000000, 0x5070f0f0, 0x80000000, + 0x50888888, 0x80000000, 0x00088888, 0xf0b00000, 0x0010f0f0, 0x88c80000, 0x00208888, 0x88800000, 0x00408888, + 0x88800000, 0x00f8f088, 0xf0800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x50707070, 0x00000000, 0xf8888888, 0x00000000, 0x50088080, + 0x70780000, 0xf8308070, 0x88800000, 0x50088008, 0x80700000, 0x00888888, 0x80080000, 0x00707070, 0x78f00000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000, + 0x00000000, 0x7010f0f8, 0x08200000, 0xa8308820, 0x08200000, 0xa0508820, 0x78700000, 0x70908820, 0x88200000, + 0x28f88820, 0x88200000, 0xa8108820, 0x88200000, 0x7038f020, 0x78180000, 0x20000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x48f8f888, 0x00000000, + 0xa8808088, 0x00000000, 0xb0f08088, 0x70880000, 0x7008f088, 0x88880000, 0x68088088, 0xf8880000, 0xa8888088, + 0x80980000, 0x9070f870, 0x78680000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6070f888, 0x18000000, 0x90808088, 0x20000000, 0xa0f08088, + 0x70880000, 0x4088f050, 0x20880000, 0xa8888050, 0x20500000, 0x90888020, 0x20500000, 0x68708020, 0x20200000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000, + 0x00000000, 0x20f87088, 0x00000000, 0x20088888, 0x00000000, 0x00088088, 0x78a80000, 0x001098a8, 0x88a80000, + 0x002088a8, 0x88a80000, 0x002088d8, 0x88a80000, 0x00207088, 0x78500000, 0x00000000, 0x08000000, 0x00000000, + 0x70000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x00000000, 0x20708888, 0x80000000, + 0x40888888, 0x80000000, 0x40888850, 0xf0880000, 0x4070f820, 0x88500000, 0x40888850, 0x88200000, 0x40888888, + 0x88500000, 0x20708888, 0x88880000, 0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x40000000, 0x00000000, 0x2070f888, 0x20000000, 0x10882088, 0x00000000, 0x10882088, + 0x60880000, 0x10882050, 0x20880000, 0x10782020, 0x20880000, 0x10082020, 0x20880000, 0x2070f820, 0x70780000, + 0x40000000, 0x00080000, 0x00000000, 0x00700000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x200008f8, 0x20000000, 0xa8600808, 0x00000000, 0x70600810, 0x60f80000, 0x70000820, 0x20100000, + 0xa8608840, 0x20200000, 0x20608880, 0x20400000, 0x000070f8, 0x20f80000, 0x00000000, 0x20000000, 0x00000000, + 0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00100000, 0x00000030, 0x00200000, 0x00008820, 0x80200000, + 0x20609020, 0x80200000, 0x2060a020, 0x90200000, 0xf800c020, 0xa0400000, 0x2060a020, 0xe0200000, 0x20609020, + 0x90200000, 0x00208820, 0x88200000, 0x00400030, 0x00200000, 0x00000000, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000080, 0x00200000, 0x00088040, 0x60200000, 0x00108040, 0x20200000, 0x00208020, + 0x20200000, 0x00408020, 0x20200000, 0x60208010, 0x20200000, 0x60108010, 0x20200000, 0x2008f808, 0x70200000, + 0x40000008, 0x00200000, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00400000, 0x00000060, + 0x00200000, 0x00008820, 0x00200000, 0x0000d820, 0x00200000, 0x00f8a820, 0xf0200000, 0x7000a820, 0xa8100000, + 0x00f88820, 0xa8200000, 0x00008820, 0xa8200000, 0x00008820, 0xa8200000, 0x00000060, 0x00200000, 0x00000000, + 0x00400000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00408820, 0x00000000, + 0x0020c850, 0x00000000, 0x0010a888, 0xb0680000, 0x00089800, 0xc8b00000, 0x00108800, 0x88000000, 0x60208800, + 0x88000000, 0x60408800, 0x88000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x04000000, 0x00000000, 0x08707000, 0x00000000, 0x08888800, 0x00000000, 0x10088800, + 0x70000000, 0x10108800, 0x88000000, 0x20208800, 0x88000000, 0x20008800, 0x88000000, 0x40207000, 0x70000000, + 0x40000000, 0x00000000, 0x800000fc, 0x00000000, 0x00000000, 0x00000000 }; u8 crashPage = 0; @@ -61,7 +90,7 @@ u8 updateBuffer = TRUE; static char crashScreenBuf[0x200]; -char *gCauseDesc[18] = { +char* gCauseDesc[18] = { "Interrupt", "TLB modification", "TLB exception on load", @@ -82,9 +111,8 @@ char *gCauseDesc[18] = { "Virtual coherency on data", }; -char *gFpcsrDesc[6] = { - "Unimplemented operation", "Invalid operation", "Division by zero", "Overflow", "Underflow", - "Inexact operation", +char* gFpcsrDesc[6] = { + "Unimplemented operation", "Invalid operation", "Division by zero", "Overflow", "Underflow", "Inexact operation", }; static u32 sProgramPosition = 0; @@ -99,7 +127,7 @@ static void reset_text_color(void) { } void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) { - u16 *ptr; + u16* ptr; s32 i, j; ptr = __osCurrentFaultContext.cfb + __osCurrentFaultContext.width * y + x; @@ -113,15 +141,16 @@ void crash_screen_draw_rect(s32 x, s32 y, s32 w, s32 h) { } void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) { - const u32 *data; - u16 *ptr; + const u32* data; + u16* ptr; u32 bit; u32 rowMask; s32 i, j; - if (glyph > 0x7F) return; + if (glyph > 0x7F) + return; - data = &sCrashScreenFont[((glyph&0xF)*GLYPH_HEIGHT * 2) + (glyph >= 64)]; + data = &sCrashScreenFont[((glyph & 0xF) * GLYPH_HEIGHT * 2) + (glyph >= 64)]; ptr = __osCurrentFaultContext.cfb + __osCurrentFaultContext.width * y + x; @@ -130,7 +159,7 @@ void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) { for (i = 0; i < GLYPH_HEIGHT; i++) { bit = 0x80000000U >> ((glyph >> 4) * GLYPH_WIDTH); rowMask = *data++; - data ++; + data++; for (j = 0; j < (GLYPH_WIDTH); j++) { if (bit & rowMask) { @@ -143,12 +172,12 @@ void crash_screen_draw_glyph(s32 x, s32 y, s32 glyph) { } } -static char *write_to_buf(char *buffer, const char *data, size_t size) { - return (char *) memcpy(buffer, data, size) + size; +static char* write_to_buf(char* buffer, const char* data, size_t size) { + return (char*)memcpy(buffer, data, size) + size; } -void crash_screen_print_with_newlines(s32 x, s32 y, const s32 xNewline, const char *fmt, ...) { - char *ptr; +void crash_screen_print_with_newlines(s32 x, s32 y, const s32 xNewline, const char* fmt, ...) { + char* ptr; u32 glyph; s32 size; s32 xOffset = x; @@ -186,8 +215,8 @@ void crash_screen_print_with_newlines(s32 x, s32 y, const s32 xNewline, const ch va_end(args); } -void crash_screen_print(s32 x, s32 y, const char *fmt, ...) { - char *ptr; +void crash_screen_print(s32 x, s32 y, const char* fmt, ...) { + char* ptr; u32 glyph; s32 size; @@ -217,17 +246,18 @@ void crash_screen_print(s32 x, s32 y, const char *fmt, ...) { void crash_screen_sleep(s32 ms) { u64 cycles = ms * 1000LL * osClockRate / 1000000ULL; osSetTime(0); - while (osGetTime() < cycles) { } + while (osGetTime() < cycles) { + } } -void crash_screen_print_float_reg(s32 x, s32 y, s32 regNum, void *addr) { - u32 bits = *(u32 *) addr; +void crash_screen_print_float_reg(s32 x, s32 y, s32 regNum, void* addr) { + u32 bits = *(u32*)addr; s32 exponent = ((bits & 0x7f800000U) >> 0x17) - 0x7F; if ((exponent >= -0x7E && exponent <= 0x7F) || bits == 0x0) { - crash_screen_print(x, y, "F%02d:%.3e", regNum, *(f32 *) addr); + crash_screen_print(x, y, "F%02d:%.3e", regNum, *(f32*)addr); } else { - crash_screen_print(x, y, "F%02d:%08XD", regNum, *(u32 *) addr); + crash_screen_print(x, y, "F%02d:%08XD", regNum, *(u32*)addr); } } @@ -245,8 +275,8 @@ void crash_screen_print_fpcsr(u32 fpcsr) { } } -void draw_crash_overview(OSThread *thread, s32 cause) { - __OSThreadContext *tc = &thread->context; +void draw_crash_overview(OSThread* thread, s32 cause) { + __OSThreadContext* tc = &thread->context; crash_screen_draw_rect(0, 20, 320, 240); @@ -268,26 +298,26 @@ void draw_crash_overview(OSThread *thread, s32 cause) { crash_screen_print(LEFT_MARGIN, 84, "Address: 0x%08X", tc->pc); } -void draw_crash_context(OSThread *thread, s32 cause) { - __OSThreadContext *tc = &thread->context; +void draw_crash_context(OSThread* thread, s32 cause) { + __OSThreadContext* tc = &thread->context; crash_screen_draw_rect(0, 20, 320, 240); crash_screen_print(LEFT_MARGIN, 20, "Thread:%d (%s)", thread->id, gCauseDesc[cause]); crash_screen_print(LEFT_MARGIN, 30, "PC:%08XH SR:%08XH VA:%08XH", tc->pc, tc->sr, tc->badvaddr); osWritebackDCacheAll(); #ifdef DEBUG_EXPORT_SYMBOLS - char *fname = parse_map(tc->pc, TRUE); + char* fname = parse_map(tc->pc, TRUE); crash_screen_print(LEFT_MARGIN, 40, "Crash at: %s", fname == NULL ? "Unknown" : fname); #endif // DEBUG_EXPORT_SYMBOLS - crash_screen_print(LEFT_MARGIN, 52, "AT:%08XH V0:%08XH V1:%08XH", (u32) tc->at, (u32) tc->v0, (u32) tc->v1); - crash_screen_print(LEFT_MARGIN, 62, "A0:%08XH A1:%08XH A2:%08XH", (u32) tc->a0, (u32) tc->a1, (u32) tc->a2); - crash_screen_print(LEFT_MARGIN, 72, "A3:%08XH T0:%08XH T1:%08XH", (u32) tc->a3, (u32) tc->t0, (u32) tc->t1); - crash_screen_print(LEFT_MARGIN, 82, "T2:%08XH T3:%08XH T4:%08XH", (u32) tc->t2, (u32) tc->t3, (u32) tc->t4); - crash_screen_print(LEFT_MARGIN, 92, "T5:%08XH T6:%08XH T7:%08XH", (u32) tc->t5, (u32) tc->t6, (u32) tc->t7); - crash_screen_print(LEFT_MARGIN, 102, "S0:%08XH S1:%08XH S2:%08XH", (u32) tc->s0, (u32) tc->s1, (u32) tc->s2); - crash_screen_print(LEFT_MARGIN, 112, "S3:%08XH S4:%08XH S5:%08XH", (u32) tc->s3, (u32) tc->s4, (u32) tc->s5); - crash_screen_print(LEFT_MARGIN, 122, "S6:%08XH S7:%08XH T8:%08XH", (u32) tc->s6, (u32) tc->s7, (u32) tc->t8); - crash_screen_print(LEFT_MARGIN, 132, "T9:%08XH GP:%08XH SP:%08XH", (u32) tc->t9, (u32) tc->gp, (u32) tc->sp); - crash_screen_print(LEFT_MARGIN, 142, "S8:%08XH RA:%08XH", (u32) tc->s8, (u32) tc->ra); + crash_screen_print(LEFT_MARGIN, 52, "AT:%08XH V0:%08XH V1:%08XH", (u32)tc->at, (u32)tc->v0, (u32)tc->v1); + crash_screen_print(LEFT_MARGIN, 62, "A0:%08XH A1:%08XH A2:%08XH", (u32)tc->a0, (u32)tc->a1, (u32)tc->a2); + crash_screen_print(LEFT_MARGIN, 72, "A3:%08XH T0:%08XH T1:%08XH", (u32)tc->a3, (u32)tc->t0, (u32)tc->t1); + crash_screen_print(LEFT_MARGIN, 82, "T2:%08XH T3:%08XH T4:%08XH", (u32)tc->t2, (u32)tc->t3, (u32)tc->t4); + crash_screen_print(LEFT_MARGIN, 92, "T5:%08XH T6:%08XH T7:%08XH", (u32)tc->t5, (u32)tc->t6, (u32)tc->t7); + crash_screen_print(LEFT_MARGIN, 102, "S0:%08XH S1:%08XH S2:%08XH", (u32)tc->s0, (u32)tc->s1, (u32)tc->s2); + crash_screen_print(LEFT_MARGIN, 112, "S3:%08XH S4:%08XH S5:%08XH", (u32)tc->s3, (u32)tc->s4, (u32)tc->s5); + crash_screen_print(LEFT_MARGIN, 122, "S6:%08XH S7:%08XH T8:%08XH", (u32)tc->s6, (u32)tc->s7, (u32)tc->t8); + crash_screen_print(LEFT_MARGIN, 132, "T9:%08XH GP:%08XH SP:%08XH", (u32)tc->t9, (u32)tc->gp, (u32)tc->sp); + crash_screen_print(LEFT_MARGIN, 142, "S8:%08XH RA:%08XH", (u32)tc->s8, (u32)tc->ra); #ifdef DEBUG_EXPORT_SYMBOLS fname = parse_map(tc->ra, TRUE); crash_screen_print(LEFT_MARGIN, 152, "RA at: %s", fname == NULL ? "Unknown" : fname); @@ -296,25 +326,24 @@ void draw_crash_context(OSThread *thread, s32 cause) { crash_screen_print_fpcsr(tc->fpcsr); osWritebackDCacheAll(); - crash_screen_print_float_reg( 10, 170, 0, &tc->fp0.f.f_even); - crash_screen_print_float_reg(100, 170, 2, &tc->fp2.f.f_even); - crash_screen_print_float_reg(190, 170, 4, &tc->fp4.f.f_even); - crash_screen_print_float_reg( 10, 180, 6, &tc->fp6.f.f_even); - crash_screen_print_float_reg(100, 180, 8, &tc->fp8.f.f_even); + crash_screen_print_float_reg(10, 170, 0, &tc->fp0.f.f_even); + crash_screen_print_float_reg(100, 170, 2, &tc->fp2.f.f_even); + crash_screen_print_float_reg(190, 170, 4, &tc->fp4.f.f_even); + crash_screen_print_float_reg(10, 180, 6, &tc->fp6.f.f_even); + crash_screen_print_float_reg(100, 180, 8, &tc->fp8.f.f_even); crash_screen_print_float_reg(190, 180, 10, &tc->fp10.f.f_even); - crash_screen_print_float_reg( 10, 190, 12, &tc->fp12.f.f_even); + crash_screen_print_float_reg(10, 190, 12, &tc->fp12.f.f_even); crash_screen_print_float_reg(100, 190, 14, &tc->fp14.f.f_even); crash_screen_print_float_reg(190, 190, 16, &tc->fp16.f.f_even); - crash_screen_print_float_reg( 10, 200, 18, &tc->fp18.f.f_even); + crash_screen_print_float_reg(10, 200, 18, &tc->fp18.f.f_even); crash_screen_print_float_reg(100, 200, 20, &tc->fp20.f.f_even); crash_screen_print_float_reg(190, 200, 22, &tc->fp22.f.f_even); - crash_screen_print_float_reg( 10, 210, 24, &tc->fp24.f.f_even); + crash_screen_print_float_reg(10, 210, 24, &tc->fp24.f.f_even); crash_screen_print_float_reg(100, 210, 26, &tc->fp26.f.f_even); crash_screen_print_float_reg(190, 210, 28, &tc->fp28.f.f_even); - crash_screen_print_float_reg( 10, 220, 30, &tc->fp30.f.f_even); + crash_screen_print_float_reg(10, 220, 30, &tc->fp30.f.f_even); } - #ifdef PUPPYPRINT_DEBUG void draw_crash_log(void) { s32 i; @@ -328,11 +357,11 @@ void draw_crash_log(void) { } #endif -void draw_stacktrace(OSThread *thread, s32 cause) { - __OSThreadContext *tc = &thread->context; +void draw_stacktrace(OSThread* thread, s32 cause) { + __OSThreadContext* tc = &thread->context; crash_screen_draw_rect(0, 20, 320, 240); - crash_screen_print(LEFT_MARGIN, 25, "Stack Trace from %08X:", (u32) tc->sp); + crash_screen_print(LEFT_MARGIN, 25, "Stack Trace from %08X:", (u32)tc->sp); #if defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) // Current Func (EPC) @@ -355,19 +384,20 @@ void draw_stacktrace(OSThread *thread, s32 cause) { for (u32 i = 0; i < generated; i++) { crash_screen_print(LEFT_MARGIN, 55 + (i * 10), get_stack_entry(i)); } -#else // defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) +#else // defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) // simple stack trace u32 sp = tc->sp; for (int i = 0; i < STACK_LINE_COUNT; i++) { crash_screen_print(LEFT_MARGIN, 55 + (i * 10), "%3d: %08X", i, *((u32*)(sp + (i * 4)))); - crash_screen_print(120, 55 + (i * 10), "%3d: %08X", i + STACK_LINE_COUNT, *((u32*)(sp + ((i + STACK_LINE_COUNT) * 4)))); + crash_screen_print(120, 55 + (i * 10), "%3d: %08X", i + STACK_LINE_COUNT, + *((u32*)(sp + ((i + STACK_LINE_COUNT) * 4)))); } #endif // defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) } -void draw_disasm(OSThread *thread) { - __OSThreadContext *tc = &thread->context; +void draw_disasm(OSThread* thread) { + __OSThreadContext* tc = &thread->context; crash_screen_draw_rect(0, 20, 320, 240); if (sProgramPosition == 0) { @@ -384,8 +414,7 @@ void draw_disasm(OSThread *thread) { for (int i = 0; i < 19; i++) { u32 addr = (sProgramPosition + (i * 4)); - char *disasm = insn_disasm((InsnData *)addr); - + char* disasm = insn_disasm((InsnData*)addr); if (disasm[0] == 0) { crash_screen_print(LEFT_MARGIN + 22, 35 + (skiplines * 10) + (i * 10), "%08X", addr); @@ -421,14 +450,13 @@ void draw_disasm(OSThread *thread) { } crash_screen_print(LEFT_MARGIN + 22, 35 + (skiplines * 10) + (i * 10), "%s", disasm); } - } reset_text_color(); osWritebackDCacheAll(); } -void draw_assert( OSThread *thread) { +void draw_assert(OSThread* thread) { crash_screen_draw_rect(0, 20, 320, 240); crash_screen_print(LEFT_MARGIN, 25, "Assert"); @@ -449,8 +477,8 @@ void draw_assert( OSThread *thread) { osWritebackDCacheAll(); } -void draw_crash_screen(OSThread *thread) { - __OSThreadContext *tc = &thread->context; +void draw_crash_screen(OSThread* thread) { + __OSThreadContext* tc = &thread->context; s32 cause = ((tc->cause >> 2) & 0x1F); if (cause == 23) { // EXC_WATCH @@ -487,20 +515,34 @@ void draw_crash_screen(OSThread *thread) { } if (crashPage == 255) { crashPage = (PAGE_COUNT - 1); - if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) crashPage--; + if (crashPage == PAGE_ASSERTS && tc->cause != EXC_SYSCALL) + crashPage--; } if (updateBuffer) { crash_screen_draw_rect(0, 0, 320, 20); - crash_screen_print(LEFT_MARGIN, 5, "Page:%02d %-22s L/Z: Left R: Right", crashPage, crashPageNames[crashPage]); + crash_screen_print(LEFT_MARGIN, 5, "Page:%02d %-22s L/Z: Left R: Right", crashPage, + crashPageNames[crashPage]); switch (crashPage) { - case PAGE_SIMPLE: draw_crash_overview(thread, cause); break; - case PAGE_CONTEXT: draw_crash_context(thread, cause); break; + case PAGE_SIMPLE: + draw_crash_overview(thread, cause); + break; + case PAGE_CONTEXT: + draw_crash_context(thread, cause); + break; #ifdef PUPPYPRINT_DEBUG - case PAGE_LOG: draw_crash_log(); break; + case PAGE_LOG: + draw_crash_log(); + break; #endif - case PAGE_STACKTRACE: draw_stacktrace(thread, cause); break; - case PAGE_DISASM: draw_disasm(thread); break; - case PAGE_ASSERTS: draw_assert(thread); break; + case PAGE_STACKTRACE: + draw_stacktrace(thread, cause); + break; + case PAGE_DISASM: + draw_disasm(thread); + break; + case PAGE_ASSERTS: + draw_assert(thread); + break; } osWritebackDCacheAll(); @@ -510,8 +552,8 @@ void draw_crash_screen(OSThread *thread) { } } -OSThread *get_crashed_thread(void) { - OSThread *thread = __osGetCurrFaultedThread(); +OSThread* get_crashed_thread(void) { + OSThread* thread = __osGetCurrFaultedThread(); while (thread->priority != -1) { if (thread->priority > OS_PRIORITY_IDLE && thread->priority < OS_PRIORITY_APPMAX @@ -523,12 +565,12 @@ OSThread *get_crashed_thread(void) { return NULL; } -void osFaultMain(void *arg) { +void osFaultMain(void* arg) { OSMesg mesg; - OSThread *thread = NULL; + OSThread* thread = NULL; - osSetEventMesg(OS_EVENT_CPU_BREAK, &__osCurrentFaultContext.mesgQueue, (OSMesg) 1); - osSetEventMesg(OS_EVENT_FAULT, &__osCurrentFaultContext.mesgQueue, (OSMesg) 2); + osSetEventMesg(OS_EVENT_CPU_BREAK, &__osCurrentFaultContext.mesgQueue, (OSMesg)1); + osSetEventMesg(OS_EVENT_FAULT, &__osCurrentFaultContext.mesgQueue, (OSMesg)2); while (TRUE) { if (thread == NULL) { osRecvMesg(&__osCurrentFaultContext.mesgQueue, &mesg, 1); @@ -545,12 +587,12 @@ void osFaultMain(void *arg) { continue; } } else { -// if (gControllerBits) { -// #if ENABLE_RUMBLE -// block_until_rumble_pak_free(); -// #endif -// osContStartReadDataEx(&gSIEventMesgQueue); -// } + // if (gControllerBits) { + // #if ENABLE_RUMBLE + // block_until_rumble_pak_free(); + // #endif + // osContStartReadDataEx(&gSIEventMesgQueue); + // } read_controller_inputs(FAULT_THREAD); draw_crash_screen(thread); } @@ -560,9 +602,6 @@ void osFaultMain(void *arg) { void osCreateFaultHandler(void) { osCreateMesgQueue(&__osCurrentFaultContext.mesgQueue, &__osCurrentFaultContext.mesg, 1); osCreateThread(&__osCurrentFaultContext.thread, FAULT_THREAD, osFaultMain, NULL, - (u8 *) __osCurrentFaultContext.stack + sizeof(__osCurrentFaultContext.stack), - OS_PRIORITY_APPMAX - ); + (u8*)__osCurrentFaultContext.stack + sizeof(__osCurrentFaultContext.stack), OS_PRIORITY_APPMAX); osStartThread(&__osCurrentFaultContext.thread); } - diff --git a/src/fault/crash_screen.h b/src/fault/crash_screen.h index cc0f031b..6c1876b7 100644 --- a/src/fault/crash_screen.h +++ b/src/fault/crash_screen.h @@ -11,7 +11,6 @@ typedef struct { OSContPad pad; u32 width; u32 height; - u16 *cfb; + u16* cfb; u64 stack[100]; } OSFaultContext; - diff --git a/src/fault/disasm.c b/src/fault/disasm.c index 2540aab7..9174af64 100644 --- a/src/fault/disasm.c +++ b/src/fault/disasm.c @@ -11,152 +11,136 @@ InsnTemplate insn_db[] = { // We want instructions with opcodes first (prioritized) // load/store - {I_TYPE, PARAM_LUI, 0b001111, 0, "lui"}, - {I_TYPE, PARAM_NONE, 0b100000, 0, "lb"}, - {I_TYPE, PARAM_NONE, 0b100100, 0, "lbu"}, - {I_TYPE, PARAM_NONE, 0b101000, 0, "sb"}, - {I_TYPE, PARAM_NONE, 0b100001, 0, "lh"}, - {I_TYPE, PARAM_NONE, 0b100101, 0, "lhu"}, - {I_TYPE, PARAM_NONE, 0b101001, 0, "sh"}, - {I_TYPE, PARAM_NONE, 0b100011, 0, "lw"}, - {I_TYPE, PARAM_NONE, 0b101011, 0, "sw"}, - {I_TYPE, PARAM_NONE, 0b110111, 0, "ld"}, - {I_TYPE, PARAM_NONE, 0b111111, 0, "sd"}, - {I_TYPE, PARAM_FLOAT_RT, 0b110001, 0, "lwc1"}, - {I_TYPE, PARAM_FLOAT_RT, 0b111001, 0, "swc1"}, - {I_TYPE, PARAM_FLOAT_RT, 0b110101, 0, "ldc1"}, - {I_TYPE, PARAM_FLOAT_RT, 0b111101, 0, "sdc1"}, + { I_TYPE, PARAM_LUI, 0b001111, 0, "lui" }, + { I_TYPE, PARAM_NONE, 0b100000, 0, "lb" }, + { I_TYPE, PARAM_NONE, 0b100100, 0, "lbu" }, + { I_TYPE, PARAM_NONE, 0b101000, 0, "sb" }, + { I_TYPE, PARAM_NONE, 0b100001, 0, "lh" }, + { I_TYPE, PARAM_NONE, 0b100101, 0, "lhu" }, + { I_TYPE, PARAM_NONE, 0b101001, 0, "sh" }, + { I_TYPE, PARAM_NONE, 0b100011, 0, "lw" }, + { I_TYPE, PARAM_NONE, 0b101011, 0, "sw" }, + { I_TYPE, PARAM_NONE, 0b110111, 0, "ld" }, + { I_TYPE, PARAM_NONE, 0b111111, 0, "sd" }, + { I_TYPE, PARAM_FLOAT_RT, 0b110001, 0, "lwc1" }, + { I_TYPE, PARAM_FLOAT_RT, 0b111001, 0, "swc1" }, + { I_TYPE, PARAM_FLOAT_RT, 0b110101, 0, "ldc1" }, + { I_TYPE, PARAM_FLOAT_RT, 0b111101, 0, "sdc1" }, // unaligned - {I_TYPE, PARAM_NONE, 0b100010, 0, "lwl"}, - {I_TYPE, PARAM_NONE, 0b100110, 0, "lwr"}, - {I_TYPE, PARAM_NONE, 0b101010, 0, "swl"}, - {I_TYPE, PARAM_NONE, 0b101110, 0, "swr"}, + { I_TYPE, PARAM_NONE, 0b100010, 0, "lwl" }, + { I_TYPE, PARAM_NONE, 0b100110, 0, "lwr" }, + { I_TYPE, PARAM_NONE, 0b101010, 0, "swl" }, + { I_TYPE, PARAM_NONE, 0b101110, 0, "swr" }, // atomics - {I_TYPE, PARAM_NONE, 0b110000, 0, "ll"}, - {I_TYPE, PARAM_NONE, 0b111000, 0, "sc"}, - {I_TYPE, PARAM_NONE, 0b111100, 0, "scd"}, + { I_TYPE, PARAM_NONE, 0b110000, 0, "ll" }, + { I_TYPE, PARAM_NONE, 0b111000, 0, "sc" }, + { I_TYPE, PARAM_NONE, 0b111100, 0, "scd" }, // branches - {I_TYPE, PARAM_SWAP_RS_IMM, 0b000100, 0, "beq"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b010100, 0, "beql"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b000101, 0, "bne"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b010101, 0, "bnel"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b000111, 0, "bgtz"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b010111, 0, "bgtzl"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b000110, 0, "blez"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b010110, 0, "blezl"}, - {I_TYPE, PARAM_NONE, 0b001010, 0, "slti"}, - {I_TYPE, PARAM_NONE, 0b001011, 0, "sltiu"}, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b000100, 0, "beq" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b010100, 0, "beql" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b000101, 0, "bne" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b010101, 0, "bnel" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b000111, 0, "bgtz" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b010111, 0, "bgtzl" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b000110, 0, "blez" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b010110, 0, "blezl" }, + { I_TYPE, PARAM_NONE, 0b001010, 0, "slti" }, + { I_TYPE, PARAM_NONE, 0b001011, 0, "sltiu" }, // jal (special) - {J_TYPE, PARAM_JAL, 0b000011, 0, "jal"}, - {J_TYPE, PARAM_JUMP, 0b000010, 0, "j"}, + { J_TYPE, PARAM_JAL, 0b000011, 0, "jal" }, + { J_TYPE, PARAM_JUMP, 0b000010, 0, "j" }, // bitwise ops (which are opcodes) - {I_TYPE, PARAM_NONE, 0b001100, 0, "andi"}, - {I_TYPE, PARAM_NONE, 0b001101, 0, "ori"}, - {I_TYPE, PARAM_NONE, 0b001110, 0, "xori"}, - + { I_TYPE, PARAM_NONE, 0b001100, 0, "andi" }, + { I_TYPE, PARAM_NONE, 0b001101, 0, "ori" }, + { I_TYPE, PARAM_NONE, 0b001110, 0, "xori" }, // arithmetic - {I_TYPE, PARAM_SWAP_RS_IMM, 0b011000, 0, "daddi"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b011001, 0, "daddiu"}, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b011000, 0, "daddi" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b011001, 0, "daddiu" }, // and now the ones with 0 for the opcode - {R_TYPE, PARAM_NONE, 0, 0b100000, "add"}, - {R_TYPE, PARAM_NONE, 0, 0b100001, "addu"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b001000, 0, "addi"}, - {I_TYPE, PARAM_SWAP_RS_IMM, 0b001001, 0, "addiu"}, - {R_TYPE, PARAM_NONE, 0, 0b100010, "sub"}, - {R_TYPE, PARAM_NONE, 0, 0b100011, "subu"}, - {R_TYPE, PARAM_NONE, 0, 0b011000, "mult"}, - {R_TYPE, PARAM_NONE, 0, 0b011001, "multu"}, - {R_TYPE, PARAM_NONE, 0, 0b011010, "div"}, - {R_TYPE, PARAM_NONE, 0, 0b011011, "divu"}, - {R_TYPE, PARAM_MULT_MOVE, 0, 0b010000, "mfhi"}, - {R_TYPE, PARAM_MULT_MOVE, 0, 0b010001, "mthi"}, - {R_TYPE, PARAM_MULT_MOVE, 0, 0b010010, "mflo"}, - {R_TYPE, PARAM_MULT_MOVE, 0, 0b010011, "mtlo"}, - {R_TYPE, PARAM_NONE, 0, 0b101010, "slt"}, - {R_TYPE, PARAM_NONE, 0, 0b101011, "sltu"}, + { R_TYPE, PARAM_NONE, 0, 0b100000, "add" }, + { R_TYPE, PARAM_NONE, 0, 0b100001, "addu" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b001000, 0, "addi" }, + { I_TYPE, PARAM_SWAP_RS_IMM, 0b001001, 0, "addiu" }, + { R_TYPE, PARAM_NONE, 0, 0b100010, "sub" }, + { R_TYPE, PARAM_NONE, 0, 0b100011, "subu" }, + { R_TYPE, PARAM_NONE, 0, 0b011000, "mult" }, + { R_TYPE, PARAM_NONE, 0, 0b011001, "multu" }, + { R_TYPE, PARAM_NONE, 0, 0b011010, "div" }, + { R_TYPE, PARAM_NONE, 0, 0b011011, "divu" }, + { R_TYPE, PARAM_MULT_MOVE, 0, 0b010000, "mfhi" }, + { R_TYPE, PARAM_MULT_MOVE, 0, 0b010001, "mthi" }, + { R_TYPE, PARAM_MULT_MOVE, 0, 0b010010, "mflo" }, + { R_TYPE, PARAM_MULT_MOVE, 0, 0b010011, "mtlo" }, + { R_TYPE, PARAM_NONE, 0, 0b101010, "slt" }, + { R_TYPE, PARAM_NONE, 0, 0b101011, "sltu" }, // bitwise ops (which are functions) - {R_TYPE, PARAM_NONE, 0, 0b100100, "and"}, - {R_TYPE, PARAM_NONE, 0, 0b100101, "or"}, - {R_TYPE, PARAM_NONE, 0, 0b100110, "xor"}, - {R_TYPE, PARAM_BITSHIFT, 0, 0b000000, "sll"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000100, "sllv"}, - {R_TYPE, PARAM_BITSHIFT, 0, 0b000010, "srl"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000110, "srlv"}, - {R_TYPE, PARAM_BITSHIFT, 0, 0b000011, "sra"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000111, "srav"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b100111, "nor"}, - - {R_TYPE, PARAM_NONE, 0, 0b001001, "jalr"}, - {R_TYPE, PARAM_NONE, 0, 0b001000, "jr"}, - {R_TYPE, PARAM_TRAP, 0, 0b110100, "teq"}, - {R_TYPE, PARAM_EMUX, 0, 0b110110, "tne"}, - - {0, PARAM_SYSCALL, 0, 0b001100, "syscall"}, + { R_TYPE, PARAM_NONE, 0, 0b100100, "and" }, + { R_TYPE, PARAM_NONE, 0, 0b100101, "or" }, + { R_TYPE, PARAM_NONE, 0, 0b100110, "xor" }, + { R_TYPE, PARAM_BITSHIFT, 0, 0b000000, "sll" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000100, "sllv" }, + { R_TYPE, PARAM_BITSHIFT, 0, 0b000010, "srl" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000110, "srlv" }, + { R_TYPE, PARAM_BITSHIFT, 0, 0b000011, "sra" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b000111, "srav" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b100111, "nor" }, + + { R_TYPE, PARAM_NONE, 0, 0b001001, "jalr" }, + { R_TYPE, PARAM_NONE, 0, 0b001000, "jr" }, + { R_TYPE, PARAM_TRAP, 0, 0b110100, "teq" }, + { R_TYPE, PARAM_EMUX, 0, 0b110110, "tne" }, + + { 0, PARAM_SYSCALL, 0, 0b001100, "syscall" }, // instructions involving doubles (deprioritized on the list) - {R_TYPE, PARAM_NONE, 0, 0b101101, "daddu"}, - {R_TYPE, PARAM_NONE, 0, 0b101110, "dsub"}, - {R_TYPE, PARAM_NONE, 0, 0b101111, "dsubu"}, - {R_TYPE, PARAM_NONE, 0, 0b011101, "dmultu"}, - {R_TYPE, PARAM_NONE, 0, 0b011110, "ddiv"}, - {R_TYPE, PARAM_NONE, 0, 0b011111, "ddivu"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010100, "dsllv"}, - {R_TYPE, PARAM_BITSHIFT, 0, 0b111100, "dsll32"}, - {R_TYPE, PARAM_BITSHIFT, 0, 0b111110, "dsrl32"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010110, "dsrlv"}, - {R_TYPE, PARAM_BITSHIFT, 0, 0b111111, "dsra32"}, - {R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010111, "dsrav"}, + { R_TYPE, PARAM_NONE, 0, 0b101101, "daddu" }, + { R_TYPE, PARAM_NONE, 0, 0b101110, "dsub" }, + { R_TYPE, PARAM_NONE, 0, 0b101111, "dsubu" }, + { R_TYPE, PARAM_NONE, 0, 0b011101, "dmultu" }, + { R_TYPE, PARAM_NONE, 0, 0b011110, "ddiv" }, + { R_TYPE, PARAM_NONE, 0, 0b011111, "ddivu" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010100, "dsllv" }, + { R_TYPE, PARAM_BITSHIFT, 0, 0b111100, "dsll32" }, + { R_TYPE, PARAM_BITSHIFT, 0, 0b111110, "dsrl32" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010110, "dsrlv" }, + { R_TYPE, PARAM_BITSHIFT, 0, 0b111111, "dsra32" }, + { R_TYPE, PARAM_SWAP_RS_RT, 0, 0b010111, "dsrav" }, }; - -char __mips_gpr[][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", - "$lo", "$hi" -}; +char __mips_gpr[][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", "$lo", "$hi" }; char __mips_fpreg[][5] = { - "$f0", "$f1", "$f2", "$f3", - "$f4", "$f5", "$f6", "$f7", - "$f8", "$f9", "$f10", "$f11", - "$f12", "$f13", "$f14", "$f15", - "$f16", "$f17", "$f18", "$f19", - "$f20", "$f21", "$f22", "$f23", - "$f24", "$f25", "$f26", "$f27", - "$f28", "$f29", "$f30", "$f31", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", + "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", + "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", }; -u8 insn_is_jal(Insn *i) { +u8 insn_is_jal(Insn* i) { return (i->opcode == 0b000011); } -u8 insn_is_jalr(Insn *i) { +u8 insn_is_jalr(Insn* i) { return (i->opcode == 0) && (i->rdata.function == 0b001001); } // Last Resort C0/C1 disassembler, from libdragon -static void c1_disasm(u32 *ptr, char *out) { - static const char *fpu_ops[64]= { - "radd", "rsub", "rmul", "rdiv", "ssqrt", "sabs", "smov", "sneg", +static void c1_disasm(u32* ptr, char* out) { + static const char* fpu_ops[64] = { + "radd", "rsub", "rmul", "rdiv", "ssqrt", "sabs", "smov", "sneg", "sround.l", "strunc.l", "sceil.l", "sfloor.l", "sround.w", "strunc.w", "sceil.w", "sfloor.w", - "*", "*", "*", "*", "*", "*", "*", "*", - "*", "*", "*", "*", "*", "*", "*", "*", - "scvt.s", "scvt.d", "*", "*", "scvt.w", "scvt.l", "*", "*", - "*", "*", "*", "*", "*", "*", "*", "*", - "hc.f", "hc.un", "hc.eq", "hc.ueq", "hc.olt", "hc.ult", "hc.ole", "hc.ule", - "hc.sf", "hc.ngle", "hc.seq", "hc.ngl", "hc.lt", "hc.nge", "hc.le", "hc.ngt", + "*", "*", "*", "*", "*", "*", "*", "*", + "*", "*", "*", "*", "*", "*", "*", "*", + "scvt.s", "scvt.d", "*", "*", "scvt.w", "scvt.l", "*", "*", + "*", "*", "*", "*", "*", "*", "*", "*", + "hc.f", "hc.un", "hc.eq", "hc.ueq", "hc.olt", "hc.ult", "hc.ole", "hc.ule", + "hc.sf", "hc.ngle", "hc.seq", "hc.ngl", "hc.lt", "hc.nge", "hc.le", "hc.ngt", }; char symbuf[64]; @@ -168,24 +152,45 @@ static void c1_disasm(u32 *ptr, char *out) { u32 tgt16 = (pc + 4) + (imm16 << 2); u32 imm26 = op & 0x3FFFFFF; u32 tgt26 = ((pc + 4) & 0xf0000000) | (imm26 << 2); - const char *rs = __mips_gpr[(op >> 21) & 0x1F]; - const char *rt = __mips_gpr[(op >> 16) & 0x1F]; - const char *rd = __mips_gpr[(op >> 11) & 0x1F]; - const char *opn = "unimpl"; + const char* rs = __mips_gpr[(op >> 21) & 0x1F]; + const char* rt = __mips_gpr[(op >> 16) & 0x1F]; + const char* rd = __mips_gpr[(op >> 11) & 0x1F]; + const char* opn = "unimpl"; if (((op >> 26) & 0x3F) == 17) { u32 sub = (op >> 21) & 0x1F; switch (sub) { - case 0: opn = "gmfc1"; break; - case 1: opn = "gdmfc1"; break; - case 4: opn = "gmtc1"; break; - case 5: opn = "gdmtc1"; break; - case 8: switch ((op >> 16) & 0x1F) { - case 0: opn = "ybc1f"; break; - case 2: opn = "ybc1fl"; break; - case 1: opn = "ybc1t"; break; - case 3: opn = "ybc1tl"; break; - } break; - case 16: case 17: case 20: case 21: + case 0: + opn = "gmfc1"; + break; + case 1: + opn = "gdmfc1"; + break; + case 4: + opn = "gmtc1"; + break; + case 5: + opn = "gdmtc1"; + break; + case 8: + switch ((op >> 16) & 0x1F) { + case 0: + opn = "ybc1f"; + break; + case 2: + opn = "ybc1fl"; + break; + case 1: + opn = "ybc1t"; + break; + case 3: + opn = "ybc1tl"; + break; + } + break; + case 16: + case 17: + case 20: + case 21: opn = fpu_ops[(op >> 0) & 0x3F]; sprintf(symbuf, "%s.%s", opn, (sub == 16) ? "s" : (sub == 17) ? "d" : (sub == 20) ? "w" : "l"); opn = symbuf; @@ -197,64 +202,103 @@ static void c1_disasm(u32 *ptr, char *out) { } switch (*opn) { #ifdef DEBUG_EXPORT_SYMBOLS - /* op tgt26 */ case 'j': sprintf(out, "%-9s %08x <%s>", opn+1, tgt26, parse_map(tgt26, FALSE)); break; - /* op rs, rt, tgt16 */case 'b': sprintf(out, "%-9s %s, %s, %08x <%s>", opn+1, rs, rt, tgt16, parse_map(tgt16, TRUE)); break; - /* op tgt16 */ case 'y': sprintf(out, "%-9s %08x <%s>", opn+1, tgt16, parse_map(tgt16, TRUE)); break; + /* op tgt26 */ case 'j': + sprintf(out, "%-9s %08x <%s>", opn + 1, tgt26, parse_map(tgt26, FALSE)); + break; + /* op rs, rt, tgt16 */ case 'b': + sprintf(out, "%-9s %s, %s, %08x <%s>", opn + 1, rs, rt, tgt16, parse_map(tgt16, TRUE)); + break; + /* op tgt16 */ case 'y': + sprintf(out, "%-9s %08x <%s>", opn + 1, tgt16, parse_map(tgt16, TRUE)); + break; #else - /* op tgt26 */ case 'j': sprintf(out, "%-9s %08x", opn+1, tgt26); break; - /* op rs, rt, tgt16 */case 'b': sprintf(out, "%-9s %s, %s, %08x", opn+1, rs, rt, tgt16); break; - /* op tgt16 */ case 'y': sprintf(out, "%-9s %08x", opn+1, tgt16); break; + /* op tgt26 */ case 'j': + sprintf(out, "%-9s %08x", opn + 1, tgt26); + break; + /* op rs, rt, tgt16 */ case 'b': + sprintf(out, "%-9s %s, %s, %08x", opn + 1, rs, rt, tgt16); + break; + /* op tgt16 */ case 'y': + sprintf(out, "%-9s %08x", opn + 1, tgt16); + break; #endif // DEBUG_EXPORT_SYMBOLS - /* op rt, rs, imm */ case 'i': sprintf(out, "%-9s %s, %s, %d", opn+1, rt, rs, (s16)op); break; - /* op rt, imm */ case 'k': sprintf(out, "%-9s %s, %d", opn+1, rt, (s16)op); break; - /* op rt, imm(rs) */ case 'm': sprintf(out, "%-9s %s, %d(%s)", opn+1, rt, (s16)op, rs); break; - /* op fd, imm(rs) */ case 'n': sprintf(out, "%-9s %s, %d(%s)", opn+1, __mips_fpreg[(op >> 16) & 0x1F], (s16)op, rs); break; - /* op rd, rs, rt */ case 'r': sprintf(out, "%-9s %s, %s, %s", opn+1, rd, rs, rt); break; - /* op rd, rs */ case 's': sprintf(out, "%-9s %s, %s", opn+1, rd, rs); break; - /* op rd, rt, sa */ case 'e': sprintf(out, "%-9s %s, %s, %ld", opn+1, rd, rt, (op >> 6) & 0x1F); break; - /* op rs */ case 'w': sprintf(out, "%-9s %s", opn+1, rs); break; - /* op rd */ case 'c': sprintf(out, "%-9s %s", opn+1, rd); break; - /* op */ case 'z': sprintf(out, "%-9s", opn+1); break; - /* op fd, fs, ft */ case 'f': sprintf(out, "%-9s %s, %s, %s", opn+1, rd, rs, rt); break; - /* op rt, fs */ case 'g': sprintf(out, "%-9s %s, %s", opn+1, rt, __mips_fpreg[(op >> 11) & 0x1F]); break; - /* op rs, rt */ case 'h': sprintf(out, "%-9s %s, %s", opn+1, rs, rt); break; - /* op code20 */ case 'a': sprintf(out, "%-9s 0x%lx", opn+1, (op>>6) & 0xFFFFF); break; - /* op rs, rt, code */ case 't': sprintf(out, "%-9s %s, %s, 0x%lx", opn+1, rs, rt, (op>>6) & 0x3FF); break; - default: sprintf(out, "%-9s", opn+1); break; + /* op rt, rs, imm */ case 'i': + sprintf(out, "%-9s %s, %s, %d", opn + 1, rt, rs, (s16)op); + break; + /* op rt, imm */ case 'k': + sprintf(out, "%-9s %s, %d", opn + 1, rt, (s16)op); + break; + /* op rt, imm(rs) */ case 'm': + sprintf(out, "%-9s %s, %d(%s)", opn + 1, rt, (s16)op, rs); + break; + /* op fd, imm(rs) */ case 'n': + sprintf(out, "%-9s %s, %d(%s)", opn + 1, __mips_fpreg[(op >> 16) & 0x1F], (s16)op, rs); + break; + /* op rd, rs, rt */ case 'r': + sprintf(out, "%-9s %s, %s, %s", opn + 1, rd, rs, rt); + break; + /* op rd, rs */ case 's': + sprintf(out, "%-9s %s, %s", opn + 1, rd, rs); + break; + /* op rd, rt, sa */ case 'e': + sprintf(out, "%-9s %s, %s, %ld", opn + 1, rd, rt, (op >> 6) & 0x1F); + break; + /* op rs */ case 'w': + sprintf(out, "%-9s %s", opn + 1, rs); + break; + /* op rd */ case 'c': + sprintf(out, "%-9s %s", opn + 1, rd); + break; + /* op */ case 'z': + sprintf(out, "%-9s", opn + 1); + break; + /* op fd, fs, ft */ case 'f': + sprintf(out, "%-9s %s, %s, %s", opn + 1, rd, rs, rt); + break; + /* op rt, fs */ case 'g': + sprintf(out, "%-9s %s, %s", opn + 1, rt, __mips_fpreg[(op >> 11) & 0x1F]); + break; + /* op rs, rt */ case 'h': + sprintf(out, "%-9s %s, %s", opn + 1, rs, rt); + break; + /* op code20 */ case 'a': + sprintf(out, "%-9s 0x%lx", opn + 1, (op >> 6) & 0xFFFFF); + break; + /* op rs, rt, code */ case 't': + sprintf(out, "%-9s %s, %s, 0x%lx", opn + 1, rs, rt, (op >> 6) & 0x3FF); + break; + default: + sprintf(out, "%-9s", opn + 1); + break; } } -char *cop1_insn_disasm(InsnData *pc) { - c1_disasm((u32 *)pc, insn_as_string); +char* cop1_insn_disasm(InsnData* pc) { + c1_disasm((u32*)pc, insn_as_string); return insn_as_string; } -char *branch_insn_disasm(InsnData insn) { - static char *insn_names[] = { - [0b00001] = "bgez", - [0b00011] = "bgezl", - [0b10001] = "bgezal", - [0b10011] = "bgezall", - [0b00000] = "bltz", - [0b00010] = "bltzl", - [0b10000] = "bltzal", - [0b10010] = "bltzall", +char* branch_insn_disasm(InsnData insn) { + static char* insn_names[] = { + [0b00001] = "bgez", [0b00011] = "bgezl", [0b10001] = "bgezal", [0b10011] = "bgezall", + [0b00000] = "bltz", [0b00010] = "bltzl", [0b10000] = "bltzal", [0b10010] = "bltzall", }; - char *strp = &insn_as_string[0]; - char *rs = __mips_gpr[insn.b.rs]; + char* strp = &insn_as_string[0]; + char* rs = __mips_gpr[insn.b.rs]; u16 offset = insn.b.offset; - for (int i = 0; i < ARRAY_COUNT(insn_as_string); i++) insn_as_string[i] = 0; + for (int i = 0; i < ARRAY_COUNT(insn_as_string); i++) + insn_as_string[i] = 0; sprintf(strp, "%-9s %s %04X", insn_names[insn.b.sub], rs, offset); return insn_as_string; } -char *insn_disasm(InsnData *addr) { +char* insn_disasm(InsnData* addr) { InsnData insn = *addr; - char *strp = &insn_as_string[0]; + char* strp = &insn_as_string[0]; int successful_print = 0; u32 target; @@ -272,113 +316,76 @@ char *insn_disasm(InsnData *addr) { return cop1_insn_disasm(addr); } - for (int i = 0; i < ARRAY_COUNT(insn_as_string); i++) insn_as_string[i] = 0; + 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, "%-9s %s %s %04X", insn_db[i].name, - __mips_gpr[insn.i.rt], - __mips_gpr[insn.i.rs], - insn.i.immediate - ); break; + strp += sprintf(strp, "%-9s %s %s %04X", insn_db[i].name, __mips_gpr[insn.i.rt], + __mips_gpr[insn.i.rs], insn.i.immediate); + break; case PARAM_LUI: - strp += sprintf(strp, "%-9s %s %04X", insn_db[i].name, - __mips_gpr[insn.i.rt], - insn.i.immediate - ); break; + strp += sprintf(strp, "%-9s %s %04X", insn_db[i].name, __mips_gpr[insn.i.rt], insn.i.immediate); + break; break; case PARAM_JAL: target = 0x80000000 | ((insn.d & 0x1FFFFFF) * 4); #ifdef DEBUG_EXPORT_SYMBOLS - strp += sprintf(strp, "%-9s %s(%08X)", insn_db[i].name, - parse_map(target, FALSE), target - ); + strp += sprintf(strp, "%-9s %s(%08X)", insn_db[i].name, parse_map(target, FALSE), target); #else - strp += sprintf(strp, "%-9s %08X", insn_db[i].name, - target - ); + strp += sprintf(strp, "%-9s %08X", insn_db[i].name, target); #endif // DEBUG_EXPORT_SYMBOLS break; case PARAM_JUMP: target = 0x80000000 | (insn.d & 0x03FFFFFF); - strp += sprintf(strp, "%-9s %08X", insn_db[i].name, - target - ); + strp += sprintf(strp, "%-9s %08X", insn_db[i].name, target); break; case PARAM_FLOAT_RT: - strp += sprintf(strp, "%-9s %s, %04X (%s)", insn_db[i].name, - __mips_fpreg[insn.i.rt], - insn.i.immediate, - __mips_gpr[insn.i.rs] - ); break; + strp += sprintf(strp, "%-9s %s, %04X (%s)", insn_db[i].name, __mips_fpreg[insn.i.rt], + insn.i.immediate, __mips_gpr[insn.i.rs]); + break; case PARAM_NONE: - strp += sprintf(strp, "%-9s %s %04X (%s)", insn_db[i].name, - __mips_gpr[insn.i.rt], - insn.i.immediate, - __mips_gpr[insn.i.rs] - ); break; - + strp += sprintf(strp, "%-9s %s %04X (%s)", insn_db[i].name, __mips_gpr[insn.i.rt], insn.i.immediate, + __mips_gpr[insn.i.rs]); + break; } successful_print = 1; break; - } else if ( (insn.i.rdata.function == 0 && insn.i.opcode == 0) // specifically catch `sll` - || (insn.i.rdata.function != 0 && insn.i.rdata.function == insn_db[i].function) - ) { + } else if ((insn.i.rdata.function == 0 && insn.i.opcode == 0) // specifically catch `sll` + || (insn.i.rdata.function != 0 && insn.i.rdata.function == insn_db[i].function)) { switch (insn_db[i].arbitraryParam) { case PARAM_BITSHIFT: - strp += sprintf(strp, "%-9s %s %s %04X", insn_db[i].name, - __mips_gpr[insn.i.rdata.rd], - __mips_gpr[insn.i.rt], - insn.i.rdata.shift_amt - ); + strp += sprintf(strp, "%-9s %s %s %04X", insn_db[i].name, __mips_gpr[insn.i.rdata.rd], + __mips_gpr[insn.i.rt], insn.i.rdata.shift_amt); break; case PARAM_SWAP_RS_RT: - strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, - __mips_gpr[insn.i.rdata.rd], - __mips_gpr[insn.i.rt], - __mips_gpr[insn.i.rs] - ); + strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, __mips_gpr[insn.i.rdata.rd], + __mips_gpr[insn.i.rt], __mips_gpr[insn.i.rs]); break; case PARAM_MULT_MOVE: - strp += sprintf(strp, "%-9s %s", insn_db[i].name, - __mips_gpr[insn.i.rdata.rd] - ); + strp += sprintf(strp, "%-9s %s", insn_db[i].name, __mips_gpr[insn.i.rdata.rd]); break; case PARAM_EMUX: target = (insn.d >> 6) & 0x3FF; if (insn.i.rs == insn.i.rt) { - strp += sprintf(strp, "%-9s %s 0x%02X", "emux", - __mips_gpr[insn.i.rs], - target - ); + strp += sprintf(strp, "%-9s %s 0x%02X", "emux", __mips_gpr[insn.i.rs], target); } else { - strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, - __mips_gpr[insn.i.rs], - __mips_gpr[insn.i.rt] - ); + strp += + sprintf(strp, "%-9s %s %s", insn_db[i].name, __mips_gpr[insn.i.rs], __mips_gpr[insn.i.rt]); } break; case PARAM_TRAP: - strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, - __mips_gpr[insn.i.rs], - __mips_gpr[insn.i.rt] - ); + strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, __mips_gpr[insn.i.rs], __mips_gpr[insn.i.rt]); break; case PARAM_SYSCALL: - strp += sprintf(strp, "%-9s %d", insn_db[i].name, - (insn.d & 0x03FFFFC0) >> 6 - ); + strp += sprintf(strp, "%-9s %d", insn_db[i].name, (insn.d & 0x03FFFFC0) >> 6); break; case PARAM_NONE: - strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, - __mips_gpr[insn.i.rdata.rd], - __mips_gpr[insn.i.rs], - __mips_gpr[insn.i.rt] - ); + strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, __mips_gpr[insn.i.rdata.rd], + __mips_gpr[insn.i.rs], __mips_gpr[insn.i.rt]); break; - } successful_print = 1; break; diff --git a/src/fault/disasm.h b/src/fault/disasm.h index 609ed175..e47eda87 100644 --- a/src/fault/disasm.h +++ b/src/fault/disasm.h @@ -60,7 +60,7 @@ typedef union { Insn i; CzInsn f; BranchInsn b; - u32 d; + u32 d; } InsnData; typedef struct PACKED { @@ -78,11 +78,10 @@ typedef struct PACKED { u8 name[10]; } COPzInsnTemplate; -#define OP_COP0 0b010000 -#define OP_COP1 0b010001 +#define OP_COP0 0b010000 +#define OP_COP1 0b010001 #define OP_BRANCH 0b000001 // technically "REGIMM" -extern char *insn_disasm(InsnData *insn); -extern u8 insn_is_jal(Insn *i); -extern u8 insn_is_jalr(Insn *i); - +extern char* insn_disasm(InsnData* insn); +extern u8 insn_is_jal(Insn* i); +extern u8 insn_is_jalr(Insn* i); diff --git a/src/fault/map_parser.c b/src/fault/map_parser.c index 1bfc04b7..e80af811 100644 --- a/src/fault/map_parser.c +++ b/src/fault/map_parser.c @@ -10,7 +10,7 @@ #define UNKNOWN_SYMBOL "???" -char* __symbolize(void *vaddr, char *buf, int size, u32 andOffset) { +char* __symbolize(void* vaddr, char* buf, int size, u32 andOffset) { symtable_header_t symt = symt_open(); if (symt.head[0]) { u32 addr = (u32)vaddr; @@ -23,7 +23,7 @@ char* __symbolize(void *vaddr, char *buf, int size, u32 andOffset) { symtable_entry_t ALIGNED16 entry; // Read the symbol name symt_entry_fetch(&symt, &entry, idx); - char *func = symt_entry_func(&symt, &entry, addr, buf, size-12); + char* func = symt_entry_func(&symt, &entry, addr, buf, size - 12); char lbuf[12]; if (andOffset) { sprintf(lbuf, "+0x%lx", addr - ADDRENTRY_ADDR(a)); @@ -38,9 +38,9 @@ char* __symbolize(void *vaddr, char *buf, int size, u32 andOffset) { return buf; } -char *parse_map(u32 addr, u32 andOffset) { +char* parse_map(u32 addr, u32 andOffset) { static char map_name[64] ALIGNED16; - char *ret = map_name; + char* ret = map_name; __symbolize((u32*)addr, map_name, sizeof(map_name), andOffset); @@ -52,7 +52,7 @@ char *parse_map(u32 addr, u32 andOffset) { symtable_info_t get_symbol_info(u32 addr) { static char filebuf[100]; - void *vaddr = (void *)addr; + void* vaddr = (void*)addr; symtable_header_t symt = symt_open(); if (symt.head[0]) { @@ -75,7 +75,7 @@ symtable_info_t get_symbol_info(u32 addr) { return info; } - return (symtable_info_t){.line = -1}; + return (symtable_info_t){ .line = -1 }; } #endif // DEBUG_EXPORT_SYMBOLS diff --git a/src/fault/map_parser.h b/src/fault/map_parser.h index be2b3c51..3e2cd262 100644 --- a/src/fault/map_parser.h +++ b/src/fault/map_parser.h @@ -1,14 +1,14 @@ #pragma once typedef struct { - char *file; - char *func; + char* file; + char* func; int line; u16 distance; u16 func_offset; } symtable_info_t; symtable_info_t get_symbol_info(u32 vaddr); -extern char *parse_map(u32 pc, u32 andOffset); -extern symtable_info_t walk_stack(u32 *addr); -extern char* __symbolize(void *vaddr, char *buf, int size, u32 andOffset); +extern char* parse_map(u32 pc, u32 andOffset); +extern symtable_info_t walk_stack(u32* addr); +extern char* __symbolize(void* vaddr, char* buf, int size, u32 andOffset); diff --git a/src/fault/stacktrace.c b/src/fault/stacktrace.c index 04653450..efeb6070 100644 --- a/src/fault/stacktrace.c +++ b/src/fault/stacktrace.c @@ -34,8 +34,8 @@ static u8 is_text_addr(u32 addr) { return FALSE; } -static void add_entry_to_stack(u32 addr, u32 ra, symtable_info_t *info) { - StackFrame *frame = &stack[stackIdx++]; +static void add_entry_to_stack(u32 addr, u32 ra, symtable_info_t* info) { + StackFrame* frame = &stack[stackIdx++]; frame->func = addr; frame->offset = info->func_offset; @@ -44,7 +44,7 @@ static void add_entry_to_stack(u32 addr, u32 ra, symtable_info_t *info) { sprintf(frame->funcname, "%s", info->func); } -char *get_stack_entry(u32 idx) { +char* get_stack_entry(u32 idx) { static char stackbuf[100]; sprintf(stackbuf, "%08X: %s:%d", stack[idx].func, stack[idx].funcname, stack[idx].line); @@ -52,11 +52,11 @@ char *get_stack_entry(u32 idx) { return stackbuf; } -u32 generate_stack(OSThread *thread) { +u32 generate_stack(OSThread* thread) { static u32 breadcrumb = 0; symtable_header_t symt = symt_open(); - __OSThreadContext *tc = &thread->context; + __OSThreadContext* tc = &thread->context; u32 sp = tc->sp; breadcrumb = tc->ra; @@ -90,7 +90,7 @@ u32 generate_stack(OSThread *thread) { if (info.distance == 0) { u32 jal = *(u32*)(val + CALLSITE_OFFSET); - if (insn_is_jal((Insn *) &jal)) { + if (insn_is_jal((Insn*)&jal)) { u32 jalTarget = 0x80000000 | ((jal & 0x03FFFFFF) * 4); // make sure JAL is to the current func @@ -98,7 +98,7 @@ u32 generate_stack(OSThread *thread) { add_entry_to_stack(val + CALLSITE_OFFSET, breadcrumb, &info); breadcrumb = val; } - } else if (insn_is_jalr((Insn *) &jal)) { + } else if (insn_is_jalr((Insn*)&jal)) { // Always add a JALR to the stack, in absence of a better heuristic add_entry_to_stack(val + CALLSITE_OFFSET, breadcrumb, &info); breadcrumb = val; diff --git a/src/fault/stacktrace.h b/src/fault/stacktrace.h index 1e6d0569..2d794c2c 100644 --- a/src/fault/stacktrace.h +++ b/src/fault/stacktrace.h @@ -11,11 +11,11 @@ typedef struct { } StackFrame; #define STACK_TRAVERSAL_LIMIT 100 -#define STACK_LINE_COUNT 17 +#define STACK_LINE_COUNT 17 // RA points to 2 instructions past any given callsite #define CALLSITE_OFFSET -8 extern u32 stackTraceGenerated; -extern u32 generate_stack(OSThread *); -extern char *get_stack_entry(u32 idx); +extern u32 generate_stack(OSThread*); +extern char* get_stack_entry(u32 idx); diff --git a/src/fault/symtable.c b/src/fault/symtable.c index 7746f8f7..307a2d22 100644 --- a/src/fault/symtable.c +++ b/src/fault/symtable.c @@ -16,7 +16,7 @@ extern u8 send_mesg[]; #define is_in_exception(addr) ((addr) >= (u32)__osExceptionPreamble && (addr) < (u32)send_mesg) // code provided by Wiseguy -static void headless_dma(u32 devAddr, void *dramAddr, u32 size) { +static void headless_dma(u32 devAddr, void* dramAddr, u32 size) { register u32 stat = IO_READ(PI_STATUS_REG); while (stat & (PI_STATUS_IO_BUSY | PI_STATUS_DMA_BUSY)) { stat = IO_READ(PI_STATUS_REG); @@ -30,41 +30,40 @@ static u32 headless_pi_status(void) { } // end of code provided by Wiseguy -void map_parser_dma(void *dst, void *src, size_t size) { +void map_parser_dma(void* dst, void* src, size_t size) { headless_dma((u32)src, dst, size); - while (headless_pi_status() & PI_STATUS_IO_BUSY); + while (headless_pi_status() & PI_STATUS_IO_BUSY) + ; } -/** +/** * @brief Open the SYMT symbol table in the rompak. - * + * * If not found, return a null header. */ symtable_header_t symt_open(void) { SYMT_ROM = (u32)_mapDataSegmentRomStart; symtable_header_t ALIGNED8 symt_header; - + if (SYMT_ROM == 0) { - return (symtable_header_t){0}; + return (symtable_header_t){ 0 }; } osWritebackDCache(&symt_header, sizeof(symt_header)); - map_parser_dma( - &symt_header, - (uintptr_t *)SYMT_ROM, - sizeof(symtable_header_t) - ); + map_parser_dma(&symt_header, (uintptr_t*)SYMT_ROM, sizeof(symtable_header_t)); - if (symt_header.head[0] != 'S' || symt_header.head[1] != 'Y' || symt_header.head[2] != 'M' || symt_header.head[3] != 'T') { + if (symt_header.head[0] != 'S' || symt_header.head[1] != 'Y' || symt_header.head[2] != 'M' + || symt_header.head[3] != 'T') { osSyncPrintf("symt_open: invalid symbol table found at 0x%08lx\n", SYMT_ROM); SYMT_ROM = 0; - return (symtable_header_t){0}; + return (symtable_header_t){ 0 }; } if (symt_header.version != 2) { - osSyncPrintf("symt_open: unsupported symbol table version %ld -- please update your n64sym tool\n", symt_header.version); + osSyncPrintf("symt_open: unsupported symbol table version %ld -- please update your n64sym tool\n", + symt_header.version); SYMT_ROM = 0; - return (symtable_header_t){0}; + return (symtable_header_t){ 0 }; } return symt_header; @@ -72,18 +71,18 @@ symtable_header_t symt_open(void) { /** * @brief Return an entry in the address table by index - * + * * @param symt SYMT file header * @param idx Index of the entry to return * @return addrtable_entry_t Entry of the address table */ -addrtable_entry_t symt_addrtab_entry(symtable_header_t *symt, int idx) { +addrtable_entry_t symt_addrtab_entry(symtable_header_t* symt, int idx) { return IO_READ(0xB0000000 | (SYMT_ROM + symt->addrtab_off + idx * 4)); } /** * @brief Search the SYMT address table for the given address. - * + * * Run a binary search to find the entry in the table. If there is a single exact match, * the entry is returned. If there are multiple entries with the same address, the first * entry is returned (this is the case for inlined functions: so some entries following @@ -95,7 +94,7 @@ addrtable_entry_t symt_addrtab_entry(symtable_header_t *symt, int idx) { * @param idx If not null, will be set to the index of the entry found (or the index just before) * @return The found entry (or the entry just before) */ -addrtable_entry_t symt_addrtab_search(symtable_header_t *symt, u32 addr, int *idx) { +addrtable_entry_t symt_addrtab_search(symtable_header_t* symt, u32 addr, int* idx) { int min = 0; int max = symt->addrtab_size - 1; while (min < max) { @@ -119,7 +118,7 @@ addrtable_entry_t symt_addrtab_search(symtable_header_t *symt, u32 addr, int *id /** * @brief Fetch a string from the string table - * + * * @param symt SYMT file * @param sidx Index of the first character of the string in the string table * @param slen Length of the string @@ -127,19 +126,16 @@ addrtable_entry_t symt_addrtab_search(symtable_header_t *symt, u32 addr, int *id * @param size Size of the destination buffer * @return char* Fetched string within the destination buffer (might not be at offset 0 for alignment reasons) */ -char *symt_string(symtable_header_t *symt, int sidx, int slen, char *buf, int size) { +char* symt_string(symtable_header_t* symt, int sidx, int slen, char* buf, int size) { // Align 2-byte phase of the RAM buffer with the ROM address. This is required // for map_parser_dma. int tweak = (sidx ^ (u32)buf) & 1; - char *func = buf + tweak; size -= tweak; + char* func = buf + tweak; + size -= tweak; int nbytes = MIN(slen, size); osWritebackDCache(buf, size); - map_parser_dma( - func, - (uintptr_t *)(SYMT_ROM + symt->strtab_off + sidx), - nbytes - ); + map_parser_dma(func, (uintptr_t*)(SYMT_ROM + symt->strtab_off + sidx), nbytes); func[nbytes] = 0; if (tweak) { @@ -150,26 +146,23 @@ char *symt_string(symtable_header_t *symt, int sidx, int slen, char *buf, int si /** * @brief Fetch a symbol table entry from the SYMT file. - * + * * @param symt SYMT file * @param entry Output entry pointer * @param idx Index of the entry to fetch */ -void symt_entry_fetch(symtable_header_t *symt, symtable_entry_t *entry, int idx) { +void symt_entry_fetch(symtable_header_t* symt, symtable_entry_t* entry, int idx) { osWritebackDCache(entry, sizeof(symtable_entry_t)); // char dbg[100]; // sprintf(dbg,"symt_entry_fetch %d\n", idx); // osSyncPrintf(dbg); - map_parser_dma( - entry, - (uintptr_t *)(SYMT_ROM + symt->symtab_off + idx * sizeof(symtable_entry_t)), - sizeof(symtable_entry_t) - ); + map_parser_dma(entry, (uintptr_t*)(SYMT_ROM + symt->symtab_off + idx * sizeof(symtable_entry_t)), + sizeof(symtable_entry_t)); } // Fetch the function name of an entry -char *symt_entry_func(symtable_header_t *symt, symtable_entry_t *entry, u32 addr, char *buf, int size) { +char* symt_entry_func(symtable_header_t* symt, symtable_entry_t* entry, u32 addr, char* buf, int size) { if (is_in_exception(addr)) { // Special case exception handlers. This is just to show something slightly // more readable instead of "notcart+0x0" or similar assembly symbols @@ -181,7 +174,7 @@ char *symt_entry_func(symtable_header_t *symt, symtable_entry_t *entry, u32 addr } // Fetch the file name of an entry -char *symt_entry_file(symtable_header_t *symt, symtable_entry_t *entry, char *buf, int size) { +char* symt_entry_file(symtable_header_t* symt, symtable_entry_t* entry, char* buf, int size) { return symt_string(symt, entry->file_sidx, entry->file_len, buf, size); } diff --git a/src/fault/symtable.h b/src/fault/symtable.h index 1f1d3eba..0efea2a4 100644 --- a/src/fault/symtable.h +++ b/src/fault/symtable.h @@ -1,10 +1,10 @@ #pragma once -/** +/** * @brief Symbol table file header - * + * * The SYMT file is made of three main tables: - * + * * * Address table: this is a sequence of 32-bit integers, each representing an address in the ROM. * The table is sorted in ascending order to allow for binary search. Moreover, the lowest 2 bits * of each address can store additional information: If bit 0 is set to 1, the address is the start @@ -15,62 +15,62 @@ * * Symbol table: this is a sequence of symbol table entries, each representing a symbol. The size * of this table (in number of entries) is exactly the same as the address table. In fact, each * address of the address table can be thought of as an external member of this structure; it's - * split externally to allow for efficiency reasons. Each entry stores the function name, + * split externally to allow for efficiency reasons. Each entry stores the function name, * the source file name and line number, and the binary offset of the symbol within the containing * function. * * String table: this table can be thought as a large buffer holding all the strings needed by all * symbol entries (function names and file names). Each symbol entry stores a string as an offset * within the symbol table and a length. This allows to reuse the same string (or prefix thereof) * multiple times. Notice that strings are not null terminated in the string table. - * + * * The SYMT file is generated by the n64sym tool during the build process. */ typedef struct { - char head[4]; ///< Magic ID "SYMT" - u32 version; ///< Version of the symbol table - u32 addrtab_off; ///< Offset of the address table in the file - u32 addrtab_size; ///< Size of the address table in the file (number of entries) - u32 symtab_off; ///< Offset of the symbol table in the file - u32 symtab_size; ///< Size of the symbol table in the file (number of entries); always equal to addrtab_size. - u32 strtab_off; ///< Offset of the string table in the file - u32 strtab_size; ///< Size of the string table in the file (number of entries) + char head[4]; ///< Magic ID "SYMT" + u32 version; ///< Version of the symbol table + u32 addrtab_off; ///< Offset of the address table in the file + u32 addrtab_size; ///< Size of the address table in the file (number of entries) + u32 symtab_off; ///< Offset of the symbol table in the file + u32 symtab_size; ///< Size of the symbol table in the file (number of entries); always equal to addrtab_size. + u32 strtab_off; ///< Offset of the string table in the file + u32 strtab_size; ///< Size of the string table in the file (number of entries) } symtable_header_t; /** @brief Symbol table entry **/ typedef struct { - u32 func_sidx; ///< Offset of the function name in the string table - u32 file_sidx; ///< Offset of the file name in the string table - u16 func_len; ///< Length of the function name - u16 file_len; ///< Length of the file name - u16 line; ///< Line number (or 0 if this symbol generically refers to a whole function) - u16 func_off; ///< Offset of the symbol within its function + u32 func_sidx; ///< Offset of the function name in the string table + u32 file_sidx; ///< Offset of the file name in the string table + u16 func_len; ///< Length of the function name + u16 file_len; ///< Length of the file name + u16 line; ///< Line number (or 0 if this symbol generically refers to a whole function) + u16 func_off; ///< Offset of the symbol within its function } symtable_entry_t; -/** +/** * @brief Entry in the address table. - * + * * This is an address in RAM, with the lowest 2 bits used to store additional information. * See the ADDRENTRY_* macros to access the various components. */ typedef u32 addrtable_entry_t; -#define ADDRENTRY_ADDR(e) ((e) & ~3) ///< Address (without the flags) -#define ADDRENTRY_IS_FUNC(e) ((e) & 1) ///< TRUE if the address is the start of a function -#define ADDRENTRY_IS_INLINE(e) ((e) & 2) ///< TRUE if the address is an inline duplicate +#define ADDRENTRY_ADDR(e) ((e) & ~3) ///< Address (without the flags) +#define ADDRENTRY_IS_FUNC(e) ((e) & 1) ///< TRUE if the address is the start of a function +#define ADDRENTRY_IS_INLINE(e) ((e) & 2) ///< TRUE if the address is an inline duplicate -#define MIPS_OP_ADDIU_SP(op) (((op) & 0xFFFF0000) == 0x27BD0000) ///< Matches: addiu $sp, $sp, imm -#define MIPS_OP_DADDIU_SP(op) (((op) & 0xFFFF0000) == 0x67BD0000) ///< Matches: daddiu $sp, $sp, imm -#define MIPS_OP_JR_RA(op) (((op) & 0xFFFFFFFF) == 0x03E00008) ///< Matches: jr $ra -#define MIPS_OP_SD_RA_SP(op) (((op) & 0xFFFF0000) == 0xAFBF0000) ///< Matches: sw $ra, imm($sp) -#define MIPS_OP_SD_FP_SP(op) (((op) & 0xFFFF0000) == 0xAFBE0000) ///< Matches: sw $fp, imm($sp) -#define MIPS_OP_LUI_GP(op) (((op) & 0xFFFF0000) == 0x3C1C0000) ///< Matches: lui $gp, imm -#define MIPS_OP_NOP(op) ((op) == 0x00000000) ///< Matches: nop -#define MIPS_OP_MOVE_FP_SP(op) ((op) == 0x03A0F025) ///< Matches: move $fp, $sp +#define MIPS_OP_ADDIU_SP(op) (((op) & 0xFFFF0000) == 0x27BD0000) ///< Matches: addiu $sp, $sp, imm +#define MIPS_OP_DADDIU_SP(op) (((op) & 0xFFFF0000) == 0x67BD0000) ///< Matches: daddiu $sp, $sp, imm +#define MIPS_OP_JR_RA(op) (((op) & 0xFFFFFFFF) == 0x03E00008) ///< Matches: jr $ra +#define MIPS_OP_SD_RA_SP(op) (((op) & 0xFFFF0000) == 0xAFBF0000) ///< Matches: sw $ra, imm($sp) +#define MIPS_OP_SD_FP_SP(op) (((op) & 0xFFFF0000) == 0xAFBE0000) ///< Matches: sw $fp, imm($sp) +#define MIPS_OP_LUI_GP(op) (((op) & 0xFFFF0000) == 0x3C1C0000) ///< Matches: lui $gp, imm +#define MIPS_OP_NOP(op) ((op) == 0x00000000) ///< Matches: nop +#define MIPS_OP_MOVE_FP_SP(op) ((op) == 0x03A0F025) ///< Matches: move $fp, $sp symtable_header_t symt_open(void); -addrtable_entry_t symt_addrtab_entry(symtable_header_t *symt, int idx); -addrtable_entry_t symt_addrtab_search(symtable_header_t *symt, u32 addr, int *idx); -char *symt_string(symtable_header_t *symt, int sidx, int slen, char *buf, int size); -void symt_entry_fetch(symtable_header_t *symt, symtable_entry_t *entry, int idx); -char *symt_entry_func(symtable_header_t *symt, symtable_entry_t *entry, u32 addr, char *buf, int size); -char *symt_entry_file(symtable_header_t *symt, symtable_entry_t *entry, char *buf, int size); +addrtable_entry_t symt_addrtab_entry(symtable_header_t* symt, int idx); +addrtable_entry_t symt_addrtab_search(symtable_header_t* symt, u32 addr, int* idx); +char* symt_string(symtable_header_t* symt, int sidx, int slen, char* buf, int size); +void symt_entry_fetch(symtable_header_t* symt, symtable_entry_t* entry, int idx); +char* symt_entry_func(symtable_header_t* symt, symtable_entry_t* entry, u32 addr, char* buf, int size); +char* symt_entry_file(symtable_header_t* symt, symtable_entry_t* entry, char* buf, int size); From 0c1c4a1ec66db05ddaf17a27de8fd8ecc79f44b9 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Tue, 16 Sep 2025 20:39:24 -0400 Subject: [PATCH 4/6] warnings --- src/fault/crash_screen.c | 7 ++++++- src/fault/crash_screen.h | 6 ++++++ src/fault/stacktrace.c | 12 ++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/fault/crash_screen.c b/src/fault/crash_screen.c index bd3ab56f..eecfd1ee 100644 --- a/src/fault/crash_screen.c +++ b/src/fault/crash_screen.c @@ -180,7 +180,7 @@ void crash_screen_print_with_newlines(s32 x, s32 y, const s32 xNewline, const ch char* ptr; u32 glyph; s32 size; - s32 xOffset = x; + u32 xOffset = x; va_list args; va_start(args, fmt); @@ -568,6 +568,11 @@ OSThread* get_crashed_thread(void) { void osFaultMain(void* arg) { OSMesg mesg; OSThread* thread = NULL; + OSFaultProgramArguments *args = (OSFaultProgramArguments *)arg; + + __osCurrentFaultContext.width = args->width; + __osCurrentFaultContext.height = args->height; + __osCurrentFaultContext.cfb = args->cfb; osSetEventMesg(OS_EVENT_CPU_BREAK, &__osCurrentFaultContext.mesgQueue, (OSMesg)1); osSetEventMesg(OS_EVENT_FAULT, &__osCurrentFaultContext.mesgQueue, (OSMesg)2); diff --git a/src/fault/crash_screen.h b/src/fault/crash_screen.h index 6c1876b7..8182f781 100644 --- a/src/fault/crash_screen.h +++ b/src/fault/crash_screen.h @@ -14,3 +14,9 @@ typedef struct { u16* cfb; u64 stack[100]; } OSFaultContext; + +typedef struct { + u32 width; + u32 height; + u16 *cfb; +} OSFaultProgramArguments; diff --git a/src/fault/stacktrace.c b/src/fault/stacktrace.c index efeb6070..ee161254 100644 --- a/src/fault/stacktrace.c +++ b/src/fault/stacktrace.c @@ -1,15 +1,12 @@ #include #include +#include #include "map_parser.h" #include "symtable.h" #include "stacktrace.h" #include "disasm.h" -extern void __osCleanupThread(); - -#if defined(DEBUG_EXPORT_SYMBOLS) && defined(DEBUG_FULL_STACK_TRACE) - static StackFrame stack[STACK_LINE_COUNT]; static u32 stackIdx; u32 stackTraceGenerated = FALSE; @@ -20,6 +17,7 @@ static u8 is_top_of_stack(u32 ra) { return (ra == ((u32)__osCleanupThread)); } +// TODO: static u8 is_text_addr(u32 addr) { // if ((addr >= (u32)_mainSegmentStart) && (addr <= (u32)_mainSegmentTextEnd)) { // return TRUE; @@ -45,9 +43,9 @@ static void add_entry_to_stack(u32 addr, u32 ra, symtable_info_t* info) { } char* get_stack_entry(u32 idx) { - static char stackbuf[100]; + static char stackbuf[256]; - sprintf(stackbuf, "%08X: %s:%d", stack[idx].func, stack[idx].funcname, stack[idx].line); + sprintf(stackbuf, "%08lX: %s:%d", stack[idx].func, stack[idx].funcname, stack[idx].line); return stackbuf; } @@ -113,5 +111,3 @@ u32 generate_stack(OSThread* thread) { return stackIdx; } - -#endif // DEBUG_EXPORT_SYMBOLS && DEBUG_FULL_STACK_TRACE From e9f0088f32ef3b23f3077eb27e235e92ac99d383 Mon Sep 17 00:00:00 2001 From: someone2639 Date: Tue, 16 Sep 2025 20:43:32 -0400 Subject: [PATCH 5/6] the rest of the warnings --- src/fault/disasm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/fault/disasm.c b/src/fault/disasm.c index 9174af64..90b4ea55 100644 --- a/src/fault/disasm.c +++ b/src/fault/disasm.c @@ -203,23 +203,23 @@ static void c1_disasm(u32* ptr, char* out) { switch (*opn) { #ifdef DEBUG_EXPORT_SYMBOLS /* op tgt26 */ case 'j': - sprintf(out, "%-9s %08x <%s>", opn + 1, tgt26, parse_map(tgt26, FALSE)); + sprintf(out, "%-9s %08lx <%s>", opn + 1, tgt26, parse_map(tgt26, FALSE)); break; /* op rs, rt, tgt16 */ case 'b': - sprintf(out, "%-9s %s, %s, %08x <%s>", opn + 1, rs, rt, tgt16, parse_map(tgt16, TRUE)); + sprintf(out, "%-9s %s, %s, %08lx <%s>", opn + 1, rs, rt, tgt16, parse_map(tgt16, TRUE)); break; /* op tgt16 */ case 'y': - sprintf(out, "%-9s %08x <%s>", opn + 1, tgt16, parse_map(tgt16, TRUE)); + sprintf(out, "%-9s %08lx <%s>", opn + 1, tgt16, parse_map(tgt16, TRUE)); break; #else /* op tgt26 */ case 'j': - sprintf(out, "%-9s %08x", opn + 1, tgt26); + sprintf(out, "%-9s %08lx", opn + 1, tgt26); break; /* op rs, rt, tgt16 */ case 'b': - sprintf(out, "%-9s %s, %s, %08x", opn + 1, rs, rt, tgt16); + sprintf(out, "%-9s %s, %s, %08lx", opn + 1, rs, rt, tgt16); break; /* op tgt16 */ case 'y': - sprintf(out, "%-9s %08x", opn + 1, tgt16); + sprintf(out, "%-9s %08lx", opn + 1, tgt16); break; #endif // DEBUG_EXPORT_SYMBOLS /* op rt, rs, imm */ case 'i': @@ -333,14 +333,14 @@ char* insn_disasm(InsnData* addr) { case PARAM_JAL: target = 0x80000000 | ((insn.d & 0x1FFFFFF) * 4); #ifdef DEBUG_EXPORT_SYMBOLS - strp += sprintf(strp, "%-9s %s(%08X)", insn_db[i].name, parse_map(target, FALSE), target); + strp += sprintf(strp, "%-9s %s(%08lX)", insn_db[i].name, parse_map(target, FALSE), target); #else - strp += sprintf(strp, "%-9s %08X", insn_db[i].name, target); + strp += sprintf(strp, "%-9s %08lX", insn_db[i].name, target); #endif // DEBUG_EXPORT_SYMBOLS break; case PARAM_JUMP: target = 0x80000000 | (insn.d & 0x03FFFFFF); - strp += sprintf(strp, "%-9s %08X", insn_db[i].name, target); + strp += sprintf(strp, "%-9s %08lX", insn_db[i].name, target); break; case PARAM_FLOAT_RT: strp += sprintf(strp, "%-9s %s, %04X (%s)", insn_db[i].name, __mips_fpreg[insn.i.rt], @@ -370,7 +370,7 @@ char* insn_disasm(InsnData* addr) { case PARAM_EMUX: target = (insn.d >> 6) & 0x3FF; if (insn.i.rs == insn.i.rt) { - strp += sprintf(strp, "%-9s %s 0x%02X", "emux", __mips_gpr[insn.i.rs], target); + strp += sprintf(strp, "%-9s %s 0x%02lX", "emux", __mips_gpr[insn.i.rs], target); } else { strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, __mips_gpr[insn.i.rs], __mips_gpr[insn.i.rt]); @@ -380,7 +380,7 @@ char* insn_disasm(InsnData* addr) { strp += sprintf(strp, "%-9s %s %s", insn_db[i].name, __mips_gpr[insn.i.rs], __mips_gpr[insn.i.rt]); break; case PARAM_SYSCALL: - strp += sprintf(strp, "%-9s %d", insn_db[i].name, (insn.d & 0x03FFFFC0) >> 6); + strp += sprintf(strp, "%-9s %ld", insn_db[i].name, (insn.d & 0x03FFFFC0) >> 6); break; case PARAM_NONE: strp += sprintf(strp, "%-9s %s %s %s", insn_db[i].name, __mips_gpr[insn.i.rdata.rd], @@ -392,7 +392,7 @@ char* insn_disasm(InsnData* addr) { } } if (successful_print == 0) { - strp += sprintf(strp, "unimpl %08X", insn.d); + strp += sprintf(strp, "unimpl %08lX", insn.d); } return insn_as_string; From a0b1017cca5bde5954d41ded48241c4c4b9ed93e Mon Sep 17 00:00:00 2001 From: someone2639 Date: Tue, 16 Sep 2025 20:52:12 -0400 Subject: [PATCH 6/6] define user pages --- src/fault/crash_screen.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fault/crash_screen.h b/src/fault/crash_screen.h index 8182f781..f0d3fc14 100644 --- a/src/fault/crash_screen.h +++ b/src/fault/crash_screen.h @@ -15,8 +15,11 @@ typedef struct { u64 stack[100]; } OSFaultContext; +typedef void (*OSFaultUserPage)(OSThread *); + typedef struct { u32 width; u32 height; u16 *cfb; + OSFaultUserPage pages[NUM_USER_PAGES]; } OSFaultProgramArguments;