Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overlay-aware backtrace #103

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions include/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@
#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)) { \
IS_DEBUG_PANIC("Assertion failed: " #condition); \
}
#define ASSERT_MSG(condition, msg, args...) \
if (!(condition)) { \
char assertMsg[0x40]; \
char assertMsg[0x60]; \
sprintf(assertMsg, msg, ##args); \
IS_DEBUG_PANIC(assertMsg); \
}
Expand Down
32 changes: 32 additions & 0 deletions src/43F0.c
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/crash_screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down
21 changes: 13 additions & 8 deletions src/dx/backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/dx/backtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions src/dx/debug_menu.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -69,3 +73,5 @@ API_CALLABLE(_dxDebugFloatPrintf);
Call(_dxDebugFloatPrintf, Ref(__FILE__), __LINE__, Ref(text), a, b, c, d, e, f, g)

#endif

#endif
7 changes: 6 additions & 1 deletion src/evt/evt.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "common.h"
#include "vars_access.h"
#include "dx/backtrace.h"

extern u32* gMapFlags;
extern s32* gMapVars;
Expand Down Expand Up @@ -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:
Expand Down
40 changes: 27 additions & 13 deletions tools/build/append_symbol_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"):
Expand All @@ -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
Expand All @@ -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])
Expand Down Expand Up @@ -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 = {}
Expand All @@ -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))
Expand All @@ -114,14 +126,16 @@ 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
padding_size = (f.tell() + 15) & ~15
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)
Expand Down
Loading