Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
backtrace.c File Reference

Go to the source code of this file.

Data Structures

struct  bt_func_t
 Description of a function for the purpose of backtracing (filled by __bt_analyze_func) More...
 
struct  backtrace_cb_ctx
 

Macros

#define BACKTRACE_DEBUG   0
 Enable to debug why a backtrace is wrong.
 
#define FUNCTION_ALIGNMENT   32
 Function alignment enfored by the compiler (-falign-functions).
 
#define true   1
 
#define false   0
 
#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) == 0xFFBF0000)
 Matches: sd $ra, imm($sp)
 
#define MIPS_OP_SW_RA_SP(op)   (((op) & 0xFFFF0000) == 0xAFBF0000)
 Matches: sw $ra, imm($sp)
 
#define MIPS_OP_SD_FP_SP(op)   (((op) & 0xFFFF0000) == 0xFFBE0000)
 Matches: sd $fp, imm($sp)
 
#define MIPS_OP_SW_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 debugf   osSyncPrintf
 
#define symbolsPerChunk   0x1000
 
#define chunkSize   ((sizeof(Symbol) * symbolsPerChunk))
 
#define inthandler   ((uint32_t*)0x8006A9F0)
 
#define inthandler_end   ((uint32_t*)0x8006B35C)
 

Typedefs

typedef s64 int64_t
 
typedef s32 int32_t
 
typedef s16 int16_t
 
typedef s8 int8_t
 
typedef u64 uint64_t
 
typedef u32 uint32_t
 
typedef u16 uint16_t
 
typedef u8 uint8_t
 
typedef s32 bool
 

Enumerations

enum  bt_func_type { BT_FUNCTION , BT_FUNCTION_FRAMEPOINTER , BT_EXCEPTION , BT_LEAF }
 The "type" of funciton as categorized by the backtrace heuristic (__bt_analyze_func) More...
 

Functions

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 backtrace (void **buffer, int size)
 Walk the stack and return the current call stack.
 
int backtrace_thread (void **buffer, int size, OSThread *thread)
 
s32 address2symbol (u32 address, Symbol *out)
 Uses the symbol table to look up the symbol corresponding to the given address.
 
char * load_symbol_string (char *dest, u32 addr, int n)
 
void backtrace_address_to_string (u32 address, char *dest)
 Converts a function address to a string representation using its name, offset, and file.
 
void debug_backtrace (void)
 Print a backtrace.
 

Data Structure Documentation

◆ bt_func_t

struct bt_func_t
Data Fields
bt_func_type type Type of the function.
int stack_size Size of the stack frame.
int ra_offset Offset of the return address from the top of the stack frame.
int fp_offset Offset of the saved fp from the top of the stack frame; this is != 0 only if the function modifies fp (maybe as a frame pointer, but not necessarily)

◆ backtrace_cb_ctx

struct backtrace_cb_ctx
Data Fields
void ** buffer
int size
int i

Macro Definition Documentation

◆ BACKTRACE_DEBUG

#define BACKTRACE_DEBUG   0

Enable to debug why a backtrace is wrong.

Definition at line 11 of file backtrace.c.

◆ FUNCTION_ALIGNMENT

#define FUNCTION_ALIGNMENT   32

Function alignment enfored by the compiler (-falign-functions).

Definition at line 14 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ true

#define true   1

Definition at line 26 of file backtrace.c.

◆ false

#define false   0

Definition at line 27 of file backtrace.c.

◆ MIPS_OP_ADDIU_SP

#define MIPS_OP_ADDIU_SP ( op)    (((op) & 0xFFFF0000) == 0x27BD0000)

Matches: addiu $sp, $sp, imm.

Definition at line 45 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_DADDIU_SP

#define MIPS_OP_DADDIU_SP ( op)    (((op) & 0xFFFF0000) == 0x67BD0000)

Matches: daddiu $sp, $sp, imm.

Definition at line 46 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_JR_RA

#define MIPS_OP_JR_RA ( op)    (((op) & 0xFFFFFFFF) == 0x03E00008)

Matches: jr $ra.

Definition at line 47 of file backtrace.c.

◆ MIPS_OP_SD_RA_SP

#define MIPS_OP_SD_RA_SP ( op)    (((op) & 0xFFFF0000) == 0xFFBF0000)

Matches: sd $ra, imm($sp)

Definition at line 48 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_SW_RA_SP

#define MIPS_OP_SW_RA_SP ( op)    (((op) & 0xFFFF0000) == 0xAFBF0000)

Matches: sw $ra, imm($sp)

Definition at line 49 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_SD_FP_SP

#define MIPS_OP_SD_FP_SP ( op)    (((op) & 0xFFFF0000) == 0xFFBE0000)

Matches: sd $fp, imm($sp)

Definition at line 50 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_SW_FP_SP

#define MIPS_OP_SW_FP_SP ( op)    (((op) & 0xFFFF0000) == 0xAFBE0000)

Matches: sw $fp, imm($sp)

Definition at line 51 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_LUI_GP

#define MIPS_OP_LUI_GP ( op)    (((op) & 0xFFFF0000) == 0x3C1C0000)

Matches: lui $gp, imm.

Definition at line 52 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_NOP

#define MIPS_OP_NOP ( op)    ((op) == 0x00000000)

Matches: nop.

Definition at line 53 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ MIPS_OP_MOVE_FP_SP

#define MIPS_OP_MOVE_FP_SP ( op)    ((op) == 0x03A0F025)

Matches: move $fp, $sp.

Definition at line 54 of file backtrace.c.

Referenced by __bt_analyze_func().

◆ debugf

#define debugf   osSyncPrintf

Definition at line 56 of file backtrace.c.

◆ symbolsPerChunk

#define symbolsPerChunk   0x1000

◆ chunkSize

#define chunkSize   ((sizeof(Symbol) * symbolsPerChunk))

◆ inthandler

#define inthandler   ((uint32_t*)0x8006A9F0)

◆ inthandler_end

#define inthandler_end   ((uint32_t*)0x8006B35C)

Typedef Documentation

◆ int64_t

typedef s64 int64_t

Definition at line 16 of file backtrace.c.

◆ int32_t

typedef s32 int32_t

Definition at line 17 of file backtrace.c.

◆ int16_t

typedef s16 int16_t

Definition at line 18 of file backtrace.c.

◆ int8_t

typedef s8 int8_t

Definition at line 19 of file backtrace.c.

◆ uint64_t

typedef u64 uint64_t

Definition at line 20 of file backtrace.c.

◆ uint32_t

typedef u32 uint32_t

Definition at line 21 of file backtrace.c.

◆ uint16_t

typedef u16 uint16_t

Definition at line 22 of file backtrace.c.

◆ uint8_t

typedef u8 uint8_t

Definition at line 23 of file backtrace.c.

◆ bool

typedef s32 bool

Definition at line 25 of file backtrace.c.

Enumeration Type Documentation

◆ bt_func_type

The "type" of funciton as categorized by the backtrace heuristic (__bt_analyze_func)

Enumerator
BT_FUNCTION 

Regular function with a stack frame.

BT_FUNCTION_FRAMEPOINTER 

The function uses the register fp as frame pointer (normally, this happens only when the function uses alloca)

BT_EXCEPTION 

This is an exception handler (inthandler.S)

BT_LEAF 

Leaf function (no calls), no stack frame allocated, sp/ra not modified.

Definition at line 30 of file backtrace.c.

30 {
34 BT_LEAF
bt_func_type
The "type" of funciton as categorized by the backtrace heuristic (__bt_analyze_func)
Definition backtrace.c:30
@ BT_FUNCTION_FRAMEPOINTER
The function uses the register fp as frame pointer (normally, this happens only when the function use...
Definition backtrace.c:32
@ BT_LEAF
Leaf function (no calls), no stack frame allocated, sp/ra not modified.
Definition backtrace.c:34
@ BT_EXCEPTION
This is an exception handler (inthandler.S)
Definition backtrace.c:33
@ BT_FUNCTION
Regular function with a stack frame.
Definition backtrace.c:31

Function Documentation

◆ __bt_analyze_func()

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).

This function implements the core heuristic used by the backtrace engine. It analyzes the actual code of a function in memory instruction by instruction, trying to find out whether the function uses a stack frame or not, whether it uses a frame pointer, and where the return address is stored.

Since we do not have DWARF informations or similar metadata, we can just do educated guesses. A mistake in the heuristic will result probably in a wrong backtrace from this point on.

The heuristic works as follows:

  • Most functions do have a stack frame. In fact, 99.99% of the functions you can find in a call stack must have a stack frame, because the only functions without a stack frame are leaf functions (functions that do not call other functions), which in turns can never be part of a stack trace.
  • The heuristic walks the function code backwards, looking for the stack frame. Specifically, it looks for an instruction saving the RA register to the stack (eg: sd $ra, nn($sp)), and an instruction creating the stack frame (eg: addiu $sp, $sp, -nn). Once both are found, the heuristic knows how to fill in .stack_size and .ra_offset fields of the function description structure, and it can stop.
  • Some functions also modify $fp (the frame pointer register): sometimes, they just use it as one additional free register, and other times they really use it as frame pointer. If the heuristic finds the instruction move $fp, $sp, it knows that the function uses $fp as frame pointer, and will mark the function as BT_FUNCTION_FRAMEPOINTER. In any case, the field .fp_offset will be filled in with the offset in the stack where $fp is stored, so that the backtrace engine can track the current value of the register in any case.
  • The 0.01% of the functions that do not have a stack frame but appear in the call stack are leaf functions interrupted by exceptions. Leaf functions pose two important problems: first, $ra is not saved into the stack so there is no way to know where to go back. Second, there is no clear indication where the function begins (as we normally stops analysis when we see the stack frame creation). So in this case the heuristic would fail. We rely thus on two hints coming from the caller:
    • First, we expect the caller to set from_exception=true, so that we know that we might potentially deal with a leaf function.
    • Second, the caller should provide the function start address, so that we stop the analysis when we reach it, and mark the function as BT_LEAF.
    • If the function start address is not provided (because e.g. the symbol table was not found and thus we have no information about function starts), the last ditch heuristic is to look for the nops that are normally used to align the function start to the FUNCTION_ALIGNMENT boundary. Obviously this is a very fragile heuristic (it will fail if the function required no nops to be properly aligned), but it is the best we can do. Worst case, in this specific case of a leaf function interrupted by the exception, the stack trace will be wrong from this point on.
Parameters
funcOutput function description structure
ptrPointer to the function code at the point where the backtrace starts. This is normally the point where a JAL opcode is found, as we are walking up the call stack.
func_startStart of the function being analyzed. This is optional: the heuristic can work without this hint, but it is useful in certain situations (eg: to better walk up after an exception).
from_exceptionIf true, this function was interrupted by an exception. This is a hint that the function might even be a leaf function without a stack frame, and that we must use special heuristics for it.
Returns
true if the backtrace can continue, false if must be aborted (eg: we are within invalid memory)

Definition at line 490 of file backtrace.c.

490 {
491 // exceptasm.s
492 #define inthandler ((uint32_t*)0x8006A9F0)
493 #define inthandler_end ((uint32_t*)0x8006B35C)
494
495 uint32_t addr;
496
497 *func = (bt_func_t){
498 .type = (ptr >= inthandler && ptr < inthandler_end) ? BT_EXCEPTION : BT_FUNCTION,
499 .stack_size = 0, .ra_offset = 0, .fp_offset = 0
500 };
501
502 addr = (uint32_t)ptr;
503 while (1) {
504 uint32_t op;
505
506 // Validate that we can dereference the virtual address without raising an exception
507 if (!is_valid_address(addr)) {
508 // This address is invalid, probably something is corrupted. Avoid looking further.
509 osSyncPrintf("backtrace: interrupted because of invalid return address 0x%08x\n", addr);
510 return false;
511 }
512 op = *(uint32_t*)get_physical_address(addr);
513 if (MIPS_OP_ADDIU_SP(op) || MIPS_OP_DADDIU_SP(op)) {
514 // Extract the stack size only from the start of the function, where the
515 // stack is allocated (negative value). This is important because the RA
516 // could point to a leaf basis block at the end of the function (like in the
517 // assert case), and if we picked the positive ADDIU SP at the end of the
518 // proper function body, we might miss a fp_offset.
519 if (op & 0x8000)
520 func->stack_size = -(int16_t)(op & 0xFFFF);
521 } else if (MIPS_OP_SD_RA_SP(op)) {
522 func->ra_offset = (int16_t)(op & 0xFFFF) + 4; // +4 = load low 32 bit of RA
523 // If we found a stack size, it might be a red herring (an alloca); we need one
524 // happening "just before" sd ra,xx(sp)
525 func->stack_size = 0;
526 } else if (MIPS_OP_SW_RA_SP(op)) {
527 // 32-bit version of above
528 func->ra_offset = (int16_t)(op & 0xFFFF);
529 func->stack_size = 0;
530 } else if (MIPS_OP_SD_FP_SP(op)) {
531 func->fp_offset = (int16_t)(op & 0xFFFF) + 4; // +4 = load low 32 bit of FP
532 } else if (MIPS_OP_SW_FP_SP(op)) {
533 // 32-bit version of above
534 func->fp_offset = (int16_t)(op & 0xFFFF);
535 } else if (MIPS_OP_LUI_GP(op)) {
536 // Loading gp is commonly done in _start, so it's useless to go back more
537 return false;
538 } else if (MIPS_OP_MOVE_FP_SP(op)) {
539 // This function uses the frame pointer. Uses that as base of the stack.
540 // Even with -fomit-frame-pointer (default on our toolchain), the compiler
541 // still emits a framepointer for functions using a variable stack size
542 // (eg: using alloca() or VLAs).
544 }
545 // We found the stack frame size and the offset of the return address in the stack frame
546 // We can stop looking and process the frame
547 if (func->stack_size != 0 && func->ra_offset != 0)
548 break;
549 if (from_exception) {
550 // The function we are analyzing was interrupted by an exception, so it might
551 // potentially be a leaf function (no stack frame). We need to make sure to stop
552 // at the beginning of the function and mark it as leaf function. Use
553 // func_start if specified, or try to guess using the nops used to align the function
554 // (crossing fingers that they're there).
555 if (addr == func_start) {
556 // The frame that was interrupted by an interrupt handler is a special case: the
557 // function could be a leaf function with no stack. If we were able to identify
558 // the function start (via the symbol table) and we reach it, it means that
559 // we are in a real leaf function.
560 func->type = BT_LEAF;
561 break;
562 } else if (!func_start && MIPS_OP_NOP(op) && (addr + 4) % FUNCTION_ALIGNMENT == 0) {
563 // If we are in the frame interrupted by an interrupt handler, and we does not know
564 // the start of the function (eg: no symbol table), then try to stop by looking for
565 // a NOP that pads between functions. Obviously the NOP we find can be either a false
566 // positive or a false negative, but we can't do any better without symbols.
567 func->type = BT_LEAF;
568 break;
569 }
570 }
571 addr -= 4;
572 }
573 return true;
574}
#define MIPS_OP_LUI_GP(op)
Matches: lui $gp, imm.
Definition backtrace.c:52
#define MIPS_OP_DADDIU_SP(op)
Matches: daddiu $sp, $sp, imm.
Definition backtrace.c:46
u32 uint32_t
Definition backtrace.c:21
#define MIPS_OP_SD_FP_SP(op)
Matches: sd $fp, imm($sp)
Definition backtrace.c:50
#define inthandler_end
s16 int16_t
Definition backtrace.c:18
int stack_size
Size of the stack frame.
Definition backtrace.c:40
int ra_offset
Offset of the return address from the top of the stack frame.
Definition backtrace.c:41
#define MIPS_OP_SD_RA_SP(op)
Matches: sd $ra, imm($sp)
Definition backtrace.c:48
#define MIPS_OP_SW_RA_SP(op)
Matches: sw $ra, imm($sp)
Definition backtrace.c:49
#define MIPS_OP_NOP(op)
Matches: nop.
Definition backtrace.c:53
int fp_offset
Offset of the saved fp from the top of the stack frame; this is != 0 only if the function modifies fp...
Definition backtrace.c:42
#define MIPS_OP_ADDIU_SP(op)
Matches: addiu $sp, $sp, imm.
Definition backtrace.c:45
bt_func_type type
Type of the function.
Definition backtrace.c:39
#define MIPS_OP_SW_FP_SP(op)
Matches: sw $fp, imm($sp)
Definition backtrace.c:51
#define inthandler
#define MIPS_OP_MOVE_FP_SP(op)
Matches: move $fp, $sp.
Definition backtrace.c:54
#define FUNCTION_ALIGNMENT
Function alignment enfored by the compiler (-falign-functions).
Definition backtrace.c:14
Description of a function for the purpose of backtracing (filled by __bt_analyze_func)
Definition backtrace.c:38
void osSyncPrintf(const char *fmt,...)
Definition is_debug.c:32

◆ backtrace()

int backtrace ( void ** buffer,
int size )

Walk the stack and return the current call stack.

This function will analyze the current execution context, walking the stack and returning informations on the active call frames.

This function adheres to POSIX specification. It does not allocate memory so it is safe to be called even in the context of low memory conditions or possibly corrupted heap.

If called within an interrupt or exception handler, the function is able to correctly walk backward the interrupt handler and show the context even before the exception was triggered.

Parameters
bufferEmpty array of pointers. This will be populated with pointers to the return addresses for each call frame.
sizeSize of the buffer, that is, maximum number of call frames that will be walked by the function.
Returns
Number of call frames walked (at most, size).

Definition at line 298 of file backtrace.c.

298 {
299 struct backtrace_cb_ctx ctx = {
300 buffer,
301 size,
302 -1, // skip backtrace itself
303 };
304 backtrace_foreach(backtrace_cb, &ctx);
305 return ctx.i;
306}

Referenced by debug_backtrace().

◆ backtrace_thread()

int backtrace_thread ( void ** buffer,
int size,
OSThread * thread )

Definition at line 308 of file backtrace.c.

308 {
309 struct backtrace_cb_ctx ctx = {
310 buffer,
311 size,
312 0,
313 };
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);
318 backtrace_foreach_foreign(backtrace_cb, &ctx, (uint32_t*)sp, (uint32_t*)pc, (uint32_t*)fp);
319 return ctx.i;
320}

Referenced by crash_screen_draw().

◆ address2symbol()

s32 address2symbol ( u32 address,
Symbol * out )

Uses the symbol table to look up the symbol corresponding to the given address.

The address should be inside some function, otherwise an incorrect symbol will be returned.

Parameters
addressAddress to look up
outOutput symbol
Returns
Offset into out->address, -1 if not found

Definition at line 331 of file backtrace.c.

331 {
332 #define symbolsPerChunk 0x1000
333 #define chunkSize ((sizeof(Symbol) * symbolsPerChunk))
334
335 static u32 romHeader[0x10];
336 nuPiReadRom(0, &romHeader, sizeof(romHeader));
337
338 u32 symbolTableRomAddr = romHeader[SYMBOL_TABLE_PTR_ROM_ADDR / sizeof(*romHeader)];
339 if (symbolTableRomAddr == NULL) {
340 osSyncPrintf("address2symbol: no symbols available (SYMBOL_TABLE_PTR is NULL)\n");
341 return -1;
342 }
343
344 // Read the header
345 SymbolTable symt;
346 nuPiReadRom(symbolTableRomAddr, &symt, sizeof(SymbolTable));
347 if (symt.magic[0] != 'S' || symt.magic[1] != 'Y' || symt.magic[2] != 'M' || symt.magic[3] != 'S') {
348 osSyncPrintf("address2symbol: no symbols available (invalid magic '%c%c%c%c')\n", symt.magic[0], symt.magic[1], symt.magic[2], symt.magic[3]);
349 return -1;
350 }
351 if (symt.symbolCount <= 0) {
352 osSyncPrintf("address2symbol: no symbols available (symbolCount=%d)\n", symt.symbolCount);
353 return -1;
354 }
355
356 // Read symbols in chunks
357 static Symbol chunk[chunkSize];
358 s32 i;
359 for (i = 0; i < symt.symbolCount; i++) {
360 // Do we need to load the next chunk?
361 if (i % symbolsPerChunk == 0) {
362 u32 chunkAddr = symbolTableRomAddr + sizeof(SymbolTable) + (i / symbolsPerChunk) * chunkSize;
363 nuPiReadRom(chunkAddr, chunk, chunkSize);
364 }
365
366 Symbol sym = chunk[i % symbolsPerChunk];
367
368 if (sym.address == address) {
369 *out = sym;
370 return 0;
371 } else if (address < sym.address) {
372 // Symbols are sorted by address, so if we passed the address, we can stop
373 break;
374 } else {
375 // Keep searching, but remember this as the last symbol
376 // incase we don't find an exact match
377 *out = sym;
378 }
379 }
380 return address - out->address;
381}
#define symbolsPerChunk
#define chunkSize
#define SYMBOL_TABLE_PTR_ROM_ADDR
ROM address of the pointer to the symbol table.
Definition backtrace.h:12
u32 address
RAM address.
Definition backtrace.h:15
char magic[4]
Definition backtrace.h:21
u32 symbolCount
Definition backtrace.h:22

Referenced by backtrace_address_to_string().

◆ load_symbol_string()

char * load_symbol_string ( char * dest,
u32 addr,
int n )

Definition at line 383 of file backtrace.c.

383 {
384 if (addr == NULL) {
385 return NULL;
386 }
387
388 u32 aligned = addr & ~3;
389 nuPiReadRom(aligned, dest, n);
390 dest[n-1] = '\0'; // Ensure null-termination
391
392 // Shift to start of string
393 return (char*)((u32)dest + (addr & 3));
394}

Referenced by backtrace_address_to_string().

◆ backtrace_address_to_string()

void backtrace_address_to_string ( u32 address,
char * dest )

Converts a function address to a string representation using its name, offset, and file.

Definition at line 396 of file backtrace.c.

396 {
397 Symbol sym;
398 s32 offset = address2symbol(address, &sym);
399
400 if (offset >= 0 && offset < 0x1000) { // 0x1000 = arbitrary func size limit
401 char name[0x40];
402 char file[0x40];
403 char* namep = load_symbol_string(name, sym.nameOffset, ARRAY_COUNT(name));
404 char* filep = load_symbol_string(file, sym.fileOffset, ARRAY_COUNT(file));
405
406 offset = 0; // Don't show offsets
407
408 if (filep == NULL)
409 if (offset == 0)
410 sprintf(dest, "%s", namep);
411 else
412 sprintf(dest, "%s+0x%X", namep, offset);
413 else
414 if (offset == 0)
415 sprintf(dest, "%s (%s)", namep, filep);
416 else
417 sprintf(dest, "%s (%s+0x%X)", namep, filep, offset);
418 } else {
419 sprintf(dest, "%p", address);
420 }
421}
char * load_symbol_string(char *dest, u32 addr, int n)
Definition backtrace.c:383
s32 address2symbol(u32 address, Symbol *out)
Uses the symbol table to look up the symbol corresponding to the given address.
Definition backtrace.c:331
u32 fileOffset
Offset of the file name and line string.
Definition backtrace.h:17
u32 nameOffset
Offset of the symbol name string.
Definition backtrace.h:16
#define ARRAY_COUNT(arr)
Definition macros.h:40

Referenced by crash_screen_draw(), and debug_backtrace().

◆ debug_backtrace()

void debug_backtrace ( void )

Print a backtrace.

Definition at line 423 of file backtrace.c.

423 {
424 s32 bt[32];
425 s32 max = backtrace((void**)bt, ARRAY_COUNT(bt));
426 s32 i;
427 char buf[128];
428
429 osSyncPrintf("Backtrace:\n");
430 for (i = 0; i < max; i++) {
431 backtrace_address_to_string(bt[i], buf);
432 osSyncPrintf(" %s\n", buf);
433 }
434}
int backtrace(void **buffer, int size)
Walk the stack and return the current call stack.
Definition backtrace.c:298
void backtrace_address_to_string(u32 address, char *dest)
Converts a function address to a string representation using its name, offset, and file.
Definition backtrace.c:396