From 295d61ba827a2dc2f493d6deacecc088b8e7e4ff Mon Sep 17 00:00:00 2001 From: Arceveti Date: Tue, 21 May 2024 17:11:42 -0700 Subject: [PATCH] Update stack trace page + other fixes --- src/crash_screen/cs_descriptions.c | 32 ++++++------- src/crash_screen/pages/page_segments.c | 2 +- src/crash_screen/pages/page_stack.c | 46 +++++++++++++------ src/crash_screen/pages/page_summary.c | 2 +- src/crash_screen/popups/popup_reginspect.c | 2 +- src/crash_screen/util/register_data/CPU.inc.c | 2 +- 6 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/crash_screen/cs_descriptions.c b/src/crash_screen/cs_descriptions.c index 27dc5a52e..02dabc972 100644 --- a/src/crash_screen/cs_descriptions.c +++ b/src/crash_screen/cs_descriptions.c @@ -99,22 +99,22 @@ const char* str_null_fallback(const char* str, const char* fallback) { //! TODO: One list with both id and pri. static const IdNamePair sThreadIDNames[] = { - { .id = THREAD_0, .name = "libultra?", }, // Uses sThreadPriNames. - { .id = THREAD_1_IDLE, .name = "idle", }, - { .id = THREAD_2, .name = "unused", }, - { .id = THREAD_3_MAIN, .name = "main", }, - { .id = THREAD_4_SOUND, .name = "sound", }, //! TODO: libultra scheduler also uses ID 4 and has no set priority. Is there a way to differentiate the two? - { .id = THREAD_5_GAME_LOOP, .name = "game loop", }, - { .id = THREAD_6_RUMBLE, .name = "rumble", }, - { .id = THREAD_7_HVQM, .name = "hvqm", }, - { .id = THREAD_8_TIMEKEEPER, .name = "timekeeper", }, - { .id = THREAD_9_DA_COUNTER, .name = "da counter", }, - { .id = THREAD_13_FAULT, .name = "unf fault", }, - { .id = THREAD_14_USB, .name = "unf usb", }, - { .id = THREAD_15_RDB, .name = "unf rdb", }, - { .id = THREAD_1000_CRASH_SCREEN_0, .name = "crash screen 0", }, - { .id = THREAD_1001_CRASH_SCREEN_1, .name = "crash screen 1", }, - { .id = THREAD_1002_CRASH_SCREEN_2, .name = "crash screen 2", }, + { .id = THREAD_0, .name = "libultra?", }, // Uses sThreadPriNames. + { .id = THREAD_1_IDLE, .name = "idle", }, + { .id = THREAD_2, .name = "unused", }, + { .id = THREAD_3_MAIN, .name = "main", }, + { .id = THREAD_4_SOUND, .name = "sound", }, //! TODO: libultra scheduler also uses ID 4 and has no set priority. Is there a way to differentiate the two? + { .id = THREAD_5_GAME_LOOP, .name = "game loop", }, + { .id = THREAD_6_RUMBLE, .name = "rumble", }, + { .id = THREAD_7_HVQM, .name = "hvqm", }, + { .id = THREAD_8_TIMEKEEPER, .name = "timekeeper", }, + { .id = THREAD_9_DA_COUNTER, .name = "da counter", }, + { .id = THREAD_13_FAULT, .name = "unf fault", }, + { .id = THREAD_14_USB, .name = "unf usb", }, + { .id = THREAD_15_RDB, .name = "unf rdb", }, + { .id = THREAD_1000_CRASH_SCREEN_0, .name = "crash screen 0", }, + { .id = THREAD_1001_CRASH_SCREEN_1, .name = "crash screen 1", }, + { .id = THREAD_1002_CRASH_SCREEN_2, .name = "crash screen 2", }, }; static const IdNamePair sThreadPriNames[] = { { .id = OS_PRIORITY_SIMGR, .name = "si manager", }, diff --git a/src/crash_screen/pages/page_segments.c b/src/crash_screen/pages/page_segments.c index 183caf402..ec3fa8a9e 100644 --- a/src/crash_screen/pages/page_segments.c +++ b/src/crash_screen/pages/page_segments.c @@ -99,7 +99,7 @@ void draw_segments_list(CSTextCoord_u32 line) { // Line 2: if (showAddresses && isLoaded) { if (isHardcoded) { - cs_print(TEXT_X(1), y, STR_COLOR_PREFIX"hardcoded", COLOR_RGBA32_GRAY); + cs_print(TEXT_X(1), y, STR_COLOR_PREFIX"hardcoded", COLOR_RGBA32_CRASH_HEADER); } else { const RGBA32 romColor = COLOR_RGBA32_LIGHT_BLUE; CSTextCoord_u32 romStrStart = cs_print(TEXT_X(1), y, STR_COLOR_PREFIX"loaded:", COLOR_RGBA32_CRASH_HEADER); diff --git a/src/crash_screen/pages/page_stack.c b/src/crash_screen/pages/page_stack.c index a444e40cd..59e061c28 100644 --- a/src/crash_screen/pages/page_stack.c +++ b/src/crash_screen/pages/page_stack.c @@ -6,6 +6,7 @@ #include "crash_screen/util/insn_disasm.h" #include "crash_screen/util/map_parser.h" #include "crash_screen/cs_controls.h" +#include "crash_screen/cs_descriptions.h" #include "crash_screen/cs_draw.h" #include "crash_screen/cs_main.h" #include "crash_screen/cs_pages.h" @@ -26,7 +27,7 @@ struct CSSetting cs_settings_group_page_stack[] = { [CS_OPT_HEADER_PAGE_STACK ] = { .type = CS_OPT_TYPE_HEADER, .name = "STACK TRACE", .valNames = &gValNames_bool, .val = SECTION_EXPANDED_DEFAULT, .defaultVal = SECTION_EXPANDED_DEFAULT, .lowerBound = FALSE, .upperBound = TRUE, }, - [CS_OPT_STACK_SHOW_ADDRESSES ] = { .type = CS_OPT_TYPE_SETTING, .name = "Show stack addresses", .valNames = &gValNames_bool, .val = FALSE, .defaultVal = FALSE, .lowerBound = FALSE, .upperBound = TRUE, }, + [CS_OPT_STACK_SHOW_ADDRESSES ] = { .type = CS_OPT_TYPE_SETTING, .name = "Show addresses in stack", .valNames = &gValNames_bool, .val = FALSE, .defaultVal = FALSE, .lowerBound = FALSE, .upperBound = TRUE, }, [CS_OPT_STACK_SHOW_OFFSETS ] = { .type = CS_OPT_TYPE_SETTING, .name = "Show function offsets", .valNames = &gValNames_bool, .val = TRUE, .defaultVal = TRUE, .lowerBound = FALSE, .upperBound = TRUE, }, [CS_OPT_END_STACK ] = { .type = CS_OPT_TYPE_END, }, }; @@ -144,14 +145,14 @@ _Bool fill_function_stack_trace(void) { Address* sp = (Address*)((Address)t_sp); if (IS_DEBUG_MAP_ENABLED()) { - const Address t_ra = tc->ra; // thread $ra - Address* ra = (Address*)((Address)t_ra - LINK_SIZE); + const Address t_ra = ((Address)tc->ra - LINK_SIZE); // thread $ra - link + Address* ra = (Address*)t_ra; _Bool err = FALSE; if (!stacktrace_step(&sp, &ra, epc)) { // $EPC is in a leaf function, so get the next entry from $ra because it's not in the stack. - if (stacktrace_step(&sp, &ra, ((Address)t_ra - LINK_SIZE))) { - append_stack_entry_to_buffer((Address)t_sp, (t_ra - LINK_SIZE)); + if (stacktrace_step(&sp, &ra, t_ra)) { + append_stack_entry_to_buffer(t_sp, t_ra); } else { set_stack_trace_error_mesg(stack_error_leaf_not_at_top); err = TRUE; @@ -165,8 +166,9 @@ _Bool fill_function_stack_trace(void) { success = TRUE; break; } - append_stack_entry_to_buffer((Address)ra, (*ra - LINK_SIZE)); - if (!stacktrace_step(&sp, &ra, ((Address)*ra - LINK_SIZE))) { + Address raddr = ((Address)*ra - LINK_SIZE); + append_stack_entry_to_buffer((Address)ra, raddr); + if (!stacktrace_step(&sp, &ra, raddr)) { set_stack_trace_error_mesg(stack_error_leaf_not_at_top); break; } @@ -178,18 +180,20 @@ _Bool fill_function_stack_trace(void) { // Just uses all aligned .text addresses in the stack. if (!success) { // Align sp to lower 32 of 64: - sp = (Address*)(ALIGNFLOOR((Address)sp, sizeof(Doubleword)) + sizeof(Address)); + Address* ra = (Address*)(ALIGNFLOOR((Address)sp, sizeof(Doubleword)) + sizeof(Address)); // Loop through the stack buffer and find all the addresses that point to a function. while (sStackTraceBufferEnd < STACK_TRACE_BUFFER_SIZE) { - if (*sp == (Address)__osCleanupThread) { + if (*ra == (Address)__osCleanupThread) { success = TRUE; break; - } else if (addr_is_in_text_segment(*sp)) { - append_stack_entry_to_buffer((Address)sp, (*sp - LINK_SIZE)); + } + Address raddr = ((Address)*ra - LINK_SIZE); + if (addr_is_in_text_segment(raddr)) { + append_stack_entry_to_buffer((Address)ra, raddr); } - sp += 2; + ra += 2; } } @@ -245,6 +249,11 @@ void stack_trace_print_entries(CSTextCoord_u32 line, CSTextCoord_u32 numLines) { ((currIndex == 0) ? COLOR_RGBA32_CRASH_AT : COLOR_RGBA32_WHITE), function->stackAddr ); + } else if (row > 0) { + charX += cs_print(TEXT_X(charX), y, + STR_COLOR_PREFIX"at ", + COLOR_RGBA32_GRAY + ); } Address currAddr = function->currAddr; @@ -273,6 +282,7 @@ void stack_trace_print_entries(CSTextCoord_u32 line, CSTextCoord_u32 numLines) { STR_COLOR_PREFIX"%s", COLOR_RGBA32_CRASH_FUNCTION_NAME, get_map_symbol_name(symbol) ); + // cs_print_addr_location_info(TEXT_X(charX), y, (CRASH_SCREEN_NUM_CHARS_X - charX), currAddr, TRUE); } else { // "[address in function]" cs_print(TEXT_X(charX), y, @@ -292,14 +302,24 @@ void stack_trace_print_entries(CSTextCoord_u32 line, CSTextCoord_u32 numLines) { // prints any function pointers it finds in the stack format: // SP address: function name void page_stack_draw(void) { + OSThread* thread = gInspectThread; CSTextCoord_u32 line = 1; CSTextCoord_u32 charX = 0; + charX += cs_print(TEXT_X(charX), TEXT_Y(line++), + (STR_COLOR_PREFIX"SP: "STR_COLOR_PREFIX STR_HEX_WORD" "STR_COLOR_PREFIX"in thread: "STR_COLOR_PREFIX"%d %s"), + COLOR_RGBA32_CRASH_VARIABLE, COLOR_RGBA32_WHITE, + (Address)thread->context.sp, + COLOR_RGBA32_CRASH_HEADER, COLOR_RGBA32_CRASH_THREAD_NAME, + thread->id, str_null_fallback(get_thread_name(thread), "unknown") + ); + + cs_draw_divider(DIVIDER_Y(line)); + charX = 0; if (cs_get_setting_val(CS_OPT_GROUP_PAGE_STACK, CS_OPT_STACK_SHOW_ADDRESSES)) { cs_print(TEXT_X(0), TEXT_Y(line), "IN STACK:"); charX = STRLEN("00000000:"); } - cs_print(TEXT_X(charX), TEXT_Y(line), STR_COLOR_PREFIX"FUNCTION:", COLOR_RGBA32_CRASH_FUNCTION_NAME); #ifdef INCLUDE_DEBUG_MAP diff --git a/src/crash_screen/pages/page_summary.c b/src/crash_screen/pages/page_summary.c index 49d03baf5..a41399816 100644 --- a/src/crash_screen/pages/page_summary.c +++ b/src/crash_screen/pages/page_summary.c @@ -159,7 +159,7 @@ void cs_draw_register_info_long(CSTextCoord_u32 charX, CSTextCoord_u32 line, Reg // FP is part of FPCSR. if (reg.valInfo.type == REG_VAL_TYPE_CONDBIT) { - name = "FP"; + name = "FC"; data = ((Reg_FPR_31)data).C; } diff --git a/src/crash_screen/popups/popup_reginspect.c b/src/crash_screen/popups/popup_reginspect.c index 2e259bfca..70e10c690 100644 --- a/src/crash_screen/popups/popup_reginspect.c +++ b/src/crash_screen/popups/popup_reginspect.c @@ -437,7 +437,7 @@ void reginspect_draw_contents(RegisterId regId) { line += gCSNumLinesPrinted; if (checkThread && (regInfo->offset != REGINFO_NULL_OFFSET)) { cs_print(TEXT_X(2), TEXT_Y(line), STR_COLOR_PREFIX" on thread %d (%s)", COLOR_RGBA32_CRASH_VARIABLE, - gInspectThread->id, get_thread_name(gInspectThread) + gInspectThread->id, str_null_fallback(get_thread_name(gInspectThread), "unknown") ); line += gCSNumLinesPrinted; } diff --git a/src/crash_screen/util/register_data/CPU.inc.c b/src/crash_screen/util/register_data/CPU.inc.c index 4150442f4..2e8222024 100644 --- a/src/crash_screen/util/register_data/CPU.inc.c +++ b/src/crash_screen/util/register_data/CPU.inc.c @@ -19,7 +19,7 @@ ALIGNED32 static const RegisterInfo sRegInfo_CPU[CPU_NUM_REGISTERS] = { [REG_CPU_K0] = DEF_CPU_SREG(k0, "K0", FALSE, REG_DESC_KERNEL), [REG_CPU_K1] = DEF_CPU_SREG(k1, "K1", FALSE, REG_DESC_KERNEL), [REG_CPU_GP] = DEF_CPU_TREG(gp, "GP", TRUE, REG_DESC_GP ), [REG_CPU_SP] = DEF_CPU_TREG(sp, "SP", TRUE, REG_DESC_SP ), - [REG_CPU_FP] = DEF_CPU_TREG(s8, "S8", FALSE, REG_DESC_FP ), + [REG_CPU_FP] = DEF_CPU_TREG(s8, "FP", FALSE, REG_DESC_FP ), //! TODO: "FP" or "S8"? [REG_CPU_RA] = DEF_CPU_TREG(ra, "RA", TRUE, REG_DESC_RA ), }; #define CASE_CPU_REG(_idx, _reg) CASE_REG(CPU, _idx, _reg)