11#define BACKTRACE_DEBUG 0
14#define FUNCTION_ALIGNMENT 32
45#define MIPS_OP_ADDIU_SP(op) (((op) & 0xFFFF0000) == 0x27BD0000)
46#define MIPS_OP_DADDIU_SP(op) (((op) & 0xFFFF0000) == 0x67BD0000)
47#define MIPS_OP_JR_RA(op) (((op) & 0xFFFFFFFF) == 0x03E00008)
48#define MIPS_OP_SD_RA_SP(op) (((op) & 0xFFFF0000) == 0xFFBF0000)
49#define MIPS_OP_SW_RA_SP(op) (((op) & 0xFFFF0000) == 0xAFBF0000)
50#define MIPS_OP_SD_FP_SP(op) (((op) & 0xFFFF0000) == 0xFFBE0000)
51#define MIPS_OP_SW_FP_SP(op) (((op) & 0xFFFF0000) == 0xAFBE0000)
52#define MIPS_OP_LUI_GP(op) (((op) & 0xFFFF0000) == 0x3C1C0000)
53#define MIPS_OP_NOP(op) ((op) == 0x00000000)
54#define MIPS_OP_MOVE_FP_SP(op) ((op) == 0x03A0F025)
56#define debugf osSyncPrintf
65static u32 get_physical_address(u32 addr) {
66 return 0x80000000 | osVirtualToPhysical((
void*)addr);
70static bool is_valid_address(
uint32_t addr) {
71 addr = get_physical_address(addr);
72 return addr >= 0x80000400 && addr < 0x80800000 && (addr & 3) == 0;
75static void backtrace_foreach(
void (*cb)(
void *arg,
void *ptr),
void *arg) {
97 :
"=r"(ra),
"=r"(sp),
"=r"(fp)
101 debugf(
"backtrace: start\n");
109 ra = (
uint32_t*)backtrace_foreach + 64;
119 debugf(
"backtrace: %s, ra=%p, sp=%p, fp=%p ra_offset=%d, fp_offset=%d, stack_size=%d\n",
121 ra, sp, fp, func.ra_offset, func.fp_offset, func.stack_size);
127 debugf(
"backtrace: framepointer used but not saved onto stack at %p\n", ra);
131 if (!is_valid_address((
uint32_t)sp)) {
132 debugf(
"backtrace: interrupted because of invalid frame pointer 0x%08lx\n", (
uint32_t)sp);
208 ra = exception_ra - 2;
218 if (is_valid_address((
uint32_t)ra)) {
225static void backtrace_foreach_foreign(
void (*cb)(
void *arg,
void *ptr),
void *arg,
uint32_t *sp,
uint32_t *ra,
uint32_t *fp) {
240 debugf(
"backtrace: %s, ra=%p, sp=%p, fp=%p ra_offset=%d, fp_offset=%d, stack_size=%d\n",
242 ra, sp, fp, func.ra_offset, func.fp_offset, func.stack_size);
248 debugf(
"backtrace: framepointer used but not saved onto stack at %p\n", ra);
252 if (!is_valid_address((
uint32_t)sp)) {
253 debugf(
"backtrace: interrupted because of invalid frame pointer 0x%08lx\n", (
uint32_t)sp);
267 ra = exception_ra - 2;
277 if (is_valid_address((
uint32_t)ra)) {
290static void backtrace_cb(
void *arg,
void *ptr) {
292 if (ctx->
i >= 0 && ctx->
i < ctx->
size)
294 if (ctx->
i < ctx->
size)
304 backtrace_foreach(backtrace_cb, &ctx);
314 u32 sp = (u32)thread->context.sp;
315 u32 pc = (u32)thread->context.pc;
316 u32 fp = (u32)thread->context.s8;
317 backtrace_cb(&ctx, (
void*)pc);
332 #define symbolsPerChunk 0x1000
333 #define chunkSize ((sizeof(Symbol) * symbolsPerChunk))
335 static u32 romHeader[0x10];
336 nuPiReadRom(0, &romHeader,
sizeof(romHeader));
339 if (symbolTableRomAddr == NULL) {
340 osSyncPrintf(
"address2symbol: no symbols available (SYMBOL_TABLE_PTR is NULL)\n");
346 nuPiReadRom(symbolTableRomAddr, &symt,
sizeof(
SymbolTable));
347 if (symt.
magic[0] !=
'S' || symt.
magic[1] !=
'Y' || symt.
magic[2] !=
'M' || symt.
magic[3] !=
'S') {
363 nuPiReadRom(chunkAddr, chunk,
chunkSize);
371 }
else if (address < sym.
address) {
388 u32 aligned = addr & ~3;
389 nuPiReadRom(aligned, dest, n);
393 return (
char*)((u32)dest + (addr & 3));
400 if (offset >= 0 && offset < 0x1000) {
410 sprintf(dest,
"%s", namep);
412 sprintf(dest,
"%s+0x%X", namep, offset);
415 sprintf(dest,
"%s (%s)", namep, filep);
417 sprintf(dest,
"%s (%s+0x%X)", namep, filep, offset);
419 sprintf(dest,
"%p", address);
430 for (
i = 0;
i < max;
i++) {
492 #define inthandler ((uint32_t*)0x8006A9F0)
493 #define inthandler_end ((uint32_t*)0x8006B35C)
499 .stack_size = 0, .ra_offset = 0, .fp_offset = 0
507 if (!is_valid_address(addr)) {
509 osSyncPrintf(
"backtrace: interrupted because of invalid return address 0x%08x\n", addr);
512 op = *(
uint32_t*)get_physical_address(addr);
549 if (from_exception) {
555 if (addr == func_start) {
#define MIPS_OP_LUI_GP(op)
Matches: lui $gp, imm.
int backtrace(void **buffer, int size)
Walk the stack and return the current call stack.
#define MIPS_OP_DADDIU_SP(op)
Matches: daddiu $sp, $sp, imm.
#define MIPS_OP_SD_FP_SP(op)
Matches: sd $fp, imm($sp)
char * load_symbol_string(char *dest, u32 addr, int n)
void debug_backtrace(void)
Print a backtrace.
bool __bt_analyze_func(bt_func_t *func, uint32_t *ptr, uint32_t func_start, bool from_exception)
Analyze a function to find out its stack frame layout and properties (useful for backtracing).
int stack_size
Size of the stack frame.
int backtrace_thread(void **buffer, int size, OSThread *thread)
void backtrace_address_to_string(u32 address, char *dest)
Converts a function address to a string representation using its name, offset, and file.
int ra_offset
Offset of the return address from the top of the stack frame.
#define MIPS_OP_SD_RA_SP(op)
Matches: sd $ra, imm($sp)
s32 address2symbol(u32 address, Symbol *out)
Uses the symbol table to look up the symbol corresponding to the given address.
bt_func_type
The "type" of funciton as categorized by the backtrace heuristic (__bt_analyze_func)
@ BT_FUNCTION_FRAMEPOINTER
The function uses the register fp as frame pointer (normally, this happens only when the function use...
@ BT_LEAF
Leaf function (no calls), no stack frame allocated, sp/ra not modified.
@ BT_EXCEPTION
This is an exception handler (inthandler.S)
@ BT_FUNCTION
Regular function with a stack frame.
#define MIPS_OP_SW_RA_SP(op)
Matches: sw $ra, imm($sp)
#define MIPS_OP_NOP(op)
Matches: nop.
int fp_offset
Offset of the saved fp from the top of the stack frame; this is != 0 only if the function modifies fp...
#define MIPS_OP_ADDIU_SP(op)
Matches: addiu $sp, $sp, imm.
bt_func_type type
Type of the function.
#define MIPS_OP_SW_FP_SP(op)
Matches: sw $fp, imm($sp)
#define MIPS_OP_MOVE_FP_SP(op)
Matches: move $fp, $sp.
#define FUNCTION_ALIGNMENT
Function alignment enfored by the compiler (-falign-functions).
Description of a function for the purpose of backtracing (filled by __bt_analyze_func)
u32 fileOffset
Offset of the file name and line string.
#define SYMBOL_TABLE_PTR_ROM_ADDR
ROM address of the pointer to the symbol table.
u32 nameOffset
Offset of the symbol name string.
void osSyncPrintf(const char *fmt,...)