diff --git a/include/macros.h b/include/macros.h index e77e8c1bf..3b4664854 100644 --- a/include/macros.h +++ b/include/macros.h @@ -43,9 +43,9 @@ #define PANIC() IS_DEBUG_PANIC("Panic") #define PANIC_MSG(msg, args...) \ do { \ - char panicMsg[0x40]; \ + char panicMsg[0x60]; \ sprintf(panicMsg, msg, ##args); \ - IS_DEBUG_PANIC(msg); \ + IS_DEBUG_PANIC(panicMsg); \ } while (0) #define ASSERT(condition) \ if (!(condition)) { \ @@ -53,7 +53,7 @@ } #define ASSERT_MSG(condition, msg, args...) \ if (!(condition)) { \ - char assertMsg[0x40]; \ + char assertMsg[0x60]; \ sprintf(assertMsg, msg, ##args); \ IS_DEBUG_PANIC(assertMsg); \ } diff --git a/src/43F0.c b/src/43F0.c index 84eab7d37..d5235d80c 100644 --- a/src/43F0.c +++ b/src/43F0.c @@ -1,6 +1,8 @@ #include "common.h" #include "nu/nusys.h" #include "gcc/string.h" +#include "dx/debug_menu.h" +#include "ld_addrs.h" u16 heap_nextMallocID = 0; @@ -435,6 +437,8 @@ void copy_matrix(Matrix4f src, Matrix4f dest) { bcopy(src, dest, sizeof(Matrix4f)); } +static struct { u32 ram; u32 rom } loadedSegmentMap[128]; // dict ram -> rom + // maybe u32 u32 dma_copy(Addr romStart, Addr romEnd, void* vramDest) { u32 length = romEnd - romStart; @@ -450,9 +454,37 @@ u32 dma_copy(Addr romStart, Addr romEnd, void* vramDest) { nuPiReadRom((u32)romStart + i, vramDest + i, length - i); } + // Mark segment as loaded and return length + for (s32 i = 0; i < ARRAY_COUNT(loadedSegmentMap); i++) { + if (loadedSegmentMap[i].ram == (u32)vramDest) { + loadedSegmentMap[i].rom = (u32)romStart; + return length; + } + } + for (s32 i = 0; i < ARRAY_COUNT(loadedSegmentMap); i++) { + if (loadedSegmentMap[i].ram == 0) { + loadedSegmentMap[i].ram = (u32)vramDest; + loadedSegmentMap[i].rom = (u32)romStart; + return length; + } + } + debug_print("loadedSegmentMap overflow\n"); return length; } +b32 dma_is_segment_loaded(u32 romStart) { + // main is loaded by boot.s, and is always loaded + if (romStart == main_ROM_START) + return TRUE; + + for (s32 i = 0; i < ARRAY_COUNT(loadedSegmentMap); i++) { + if (loadedSegmentMap[i].rom == romStart) { + return TRUE; + } + } + return FALSE; +} + s32 dma_write(Addr romStart, Addr romEnd, void* vramDest) { u32 length = romEnd - romStart; s32 i; diff --git a/src/crash_screen.c b/src/crash_screen.c index 4021ce079..4b87fe16f 100644 --- a/src/crash_screen.c +++ b/src/crash_screen.c @@ -62,7 +62,7 @@ const char* gFPCSRFaultCauses[6] = { "Inexact operation", }; -char crashScreenAssertMessage[0x30] = {0}; +char crashScreenAssertMessage[0x60] = {0}; void crash_screen_set_assert_info(const char* message) { strncpy(crashScreenAssertMessage, message, sizeof(crashScreenAssertMessage)); @@ -330,7 +330,7 @@ void crash_screen_draw(OSThread* faultedThread) { for (; i < max; i++) { backtrace_address_to_string(bt[i], buf); - crash_screen_printf_proportional(x + 10, y += 10, "at %s", buf); + crash_screen_printf_proportional(x + 10, y += 10, "in %s", buf); } y += 5; diff --git a/src/dx/backtrace.c b/src/dx/backtrace.c index c0b3af53b..2d1686e46 100644 --- a/src/dx/backtrace.c +++ b/src/dx/backtrace.c @@ -318,6 +318,8 @@ int backtrace_thread(void **buffer, int size, OSThread *thread) { return ctx.i; } +b32 dma_is_segment_loaded(u32 romStart); + /** * @brief Uses the symbol table to look up the symbol corresponding to the given address. * @@ -328,7 +330,7 @@ int backtrace_thread(void **buffer, int size, OSThread *thread) { * @return Offset into out->address, -1 if not found */ s32 address2symbol(u32 address, Symbol* out) { - #define symbolsPerChunk 0x1000 + #define symbolsPerChunk 0x100 #define chunkSize ((sizeof(Symbol) * symbolsPerChunk)) static u32 romHeader[0x10]; @@ -364,6 +366,9 @@ s32 address2symbol(u32 address, Symbol* out) { Symbol sym = chunk[i % symbolsPerChunk]; + if (!dma_is_segment_loaded(sym.segmentRomStart)) + continue; + if (sym.address == address) { *out = sym; return 0; @@ -396,22 +401,22 @@ void backtrace_address_to_string(u32 address, char* dest) { Symbol sym; s32 offset = address2symbol(address, &sym); - if (offset >= 0 && offset < 0x1000) { // 0x1000 = arbitrary func size limit + if (offset >= 0 && offset < 0x4000) { // 0x4000 = arbitrary func size limit char name[32]; char file[32]; char* namep = load_symbol_string(name, sym.nameOffset, ARRAY_COUNT(name)); char* filep = load_symbol_string(file, sym.fileOffset, ARRAY_COUNT(file)); if (filep == NULL) - if (offset == 0) + //if (offset == 0) sprintf(dest, "%s", namep); - else - sprintf(dest, "%s+0x%X", namep, offset); + //else + // sprintf(dest, "%s+0x%X", namep, offset); else - if (offset == 0) + //if (offset == 0) sprintf(dest, "%s (%s)", namep, filep); - else - sprintf(dest, "%s (%s+0x%X)", namep, filep, offset); + //else + // sprintf(dest, "%s (%s+0x%X)", namep, filep, offset); } else { sprintf(dest, "0x%08X", address); } diff --git a/src/dx/backtrace.h b/src/dx/backtrace.h index 9cca5f795..6ce1ad56a 100644 --- a/src/dx/backtrace.h +++ b/src/dx/backtrace.h @@ -15,6 +15,7 @@ typedef struct Symbol { u32 address; ///< RAM address. u32 nameOffset; ///< Offset of the symbol name string. u32 fileOffset; ///< Offset of the file name and line string. + u32 segmentRomStart; ///< ROM start of segment. } Symbol; typedef struct SymbolTable { diff --git a/src/dx/debug_menu.h b/src/dx/debug_menu.h index 1db089381..a66d857b1 100644 --- a/src/dx/debug_menu.h +++ b/src/dx/debug_menu.h @@ -1,5 +1,9 @@ #include "common.h" #include "dx/config.h" + +#ifndef __DX_DEBUG_MENU_H__ +#define __DX_DEBUG_MENU_H__ + #if DX_DEBUG_MENU || defined(DX_QUICK_LAUNCH_BATTLE) #define DX_DEBUG_DUMMY_ID 0xDEAD @@ -69,3 +73,5 @@ API_CALLABLE(_dxDebugFloatPrintf); Call(_dxDebugFloatPrintf, Ref(__FILE__), __LINE__, Ref(text), a, b, c, d, e, f, g) #endif + +#endif diff --git a/src/evt/evt.c b/src/evt/evt.c index 0b83e5d36..a6771aa2d 100644 --- a/src/evt/evt.c +++ b/src/evt/evt.c @@ -1,5 +1,6 @@ #include "common.h" #include "vars_access.h" +#include "dx/backtrace.h" extern u32* gMapFlags; extern s32* gMapVars; @@ -1357,7 +1358,11 @@ s32 evt_execute_next_command(Evt* script) { s32 nargs; commandsExecuted++; - ASSERT_MSG(commandsExecuted < 10000, "Script %x is blocking for ages (infinite loop?)", script->ptrFirstLine); + if (commandsExecuted > 10000) { + char scriptName[0x40]; + backtrace_address_to_string(script->ptrFirstLine, scriptName); + PANIC_MSG("Script %s in infinite loop", scriptName); + } switch (script->curOpcode) { case EVT_OP_INTERNAL_FETCH: diff --git a/tools/build/append_symbol_table.py b/tools/build/append_symbol_table.py index e696374e7..c931b96ef 100644 --- a/tools/build/append_symbol_table.py +++ b/tools/build/append_symbol_table.py @@ -9,20 +9,24 @@ def readelf(elf: str) -> List[Tuple[int, str, str, int]]: - addr2name = {} # funcs + addr2name = {} # funcs and globals addr2line = {} # debug info + segment2romstart = {} # segment name -> rom start address - process = subprocess.Popen(["mips-linux-gnu-readelf", "-s", elf, "--wide", "-wL"], stdout=subprocess.PIPE) + process = subprocess.Popen(["mips-linux-gnu-objdump", elf, "-t", "--wide", "--dwarf=decodedline", "--demangle"], stdout=subprocess.PIPE) for line in io.TextIOWrapper(process.stdout, encoding="utf-8"): parts = line.split() - # 75082: 8048d5bc 44 FUNC GLOBAL DEFAULT 1845 func_802BC0B8_E2E9E8 - if len(parts) == 8 and parts[3] == "FUNC": - addr = int(parts[1], 16) + # 8004bbd0 g F .main 00000060 GetSelfAnimationFromTable + if len(parts) == 6 and parts[2] in ["F", "O"]: + addr = int(parts[0], 16) + segment = parts[3][1:] name = parts[-1] + if segment.endswith("_bss") or segment == "ABS*": # ignore BSS + continue if name.startswith("dead_"): continue - addr2name[addr] = name + addr2name[addr] = (name, segment) # npc.c 120 0x8003910c x elif len(parts) >= 4 and parts[2].startswith("0x"): @@ -33,12 +37,19 @@ def readelf(elf: str) -> List[Tuple[int, str, str, int]]: addr = int(parts[2], 0) addr2line[addr] = (file_basename, line_number) + # 00001000 g *ABS* 00000000 main_ROM_START + elif len(parts) == 5 and parts[-1].endswith("_ROM_START"): + addr = int(parts[0], 16) + segment = parts[-1][0:-len("_ROM_START")] + segment2romstart[segment] = addr + sorted_addr2name_addrs = sorted(addr2name.keys()) symbols = [] for addr, (file_basename, line_number) in addr2line.items(): if addr in addr2name: - symbols.append((addr, addr2name[addr], file_basename, line_number)) + name, segment = addr2name[addr] + symbols.append((addr, name, file_basename, line_number, segment2romstart[segment])) else: # find closest addr2name < addr closest_addr = None @@ -48,13 +59,14 @@ def readelf(elf: str) -> List[Tuple[int, str, str, int]]: else: break if closest_addr is not None: - symbols.append((addr, addr2name[closest_addr], file_basename, line_number)) + name, segment = addr2name[closest_addr] + symbols.append((addr, name, file_basename, line_number, segment2romstart[segment])) # non-debug builds if len(symbols) == 0: print("no debug symbols found, using func names only") - for addr, name in addr2name.items(): - symbols.append((addr, name, "", -1)) + for addr, (name, segment) in addr2name.items(): + symbols.append((addr, name, "", -1, segment2romstart[segment])) # sort by address symbols.sort(key=lambda x: x[0]) @@ -89,7 +101,7 @@ def readelf(elf: str) -> List[Tuple[int, str, str, int]]: f.write(b"SYMS") f.write(struct.pack(">I", len(symbols))) - sizeof_symbol = 4 + 4 + 4 # sizeof(Symbol) + sizeof_symbol = 4 + 4 + 4 + 4 # sizeof(Symbol) strings_begin = f.tell() + sizeof_symbol * len(symbols) strings = bytearray() string_map = {} @@ -103,7 +115,7 @@ def add_string(s: str): strings += b"\0" return string_map[s] - for addr, name, file_basename, line_number in symbols: + for addr, name, file_basename, line_number, segment_rom_start in symbols: # file_line = file_line.replace(root_dir + "/", "") f.write(struct.pack(">I", addr)) @@ -114,6 +126,8 @@ def add_string(s: str): else: f.write(struct.pack(">I", add_string(f"{file_basename}:{line_number}"))) # can make more efficient + f.write(struct.pack(">I", segment_rom_start)) + f.write(strings) # Pad to the nearest 16-byte alignment @@ -121,7 +135,7 @@ def add_string(s: str): padding_bytes = b"\x00" * (padding_size - f.tell()) f.write(padding_bytes) - print("symbol table size: {} kib".format((f.tell() - symbol_table_addr) / 1024)) + print("symbol table size: {} kib ({} symbols)".format((f.tell() - symbol_table_addr) / 1024, len(symbols))) print(f"updating SYMBOL_TABLE_PTR_ROM_ADDR") f.seek(SYMBOL_TABLE_PTR_ROM_ADDR)