libdragon
Loading...
Searching...
No Matches
Data Structures | Enumerations | Functions
backtrace_internal.h 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...
 

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_from (void **buffer, int size, uint32_t *pc, uint32_t *sp, uint32_t *fp, uint32_t *exception_ra)
 Like backtrace, but start from an arbitrary context. Useful for backtracing a thread.
 
char * __symbolize (void *vaddr, char *buf, int size)
 Return the symbol associated to a given address.
 

Detailed Description

Author
Giovanni Bajo giova.nosp@m.nnib.nosp@m.ajo@g.nosp@m.mail.nosp@m..com

Data Structure Documentation

◆ bt_func_t

struct bt_func_t

Description of a function for the purpose of backtracing (filled by __bt_analyze_func)

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)

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.

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)

◆ __symbolize()

char * __symbolize ( void *  vaddr,
char *  buf,
int  size 
)

Return the symbol associated to a given address.

This function inspect the symbol table (if any) to search for the specified address. It returns the function name the address belongs to, and the offset within the function as a string in the format "function_name+0x1234".

If the symbol table is not found in the rompack or the address is not found, the return string is "???".

Parameters
vaddrAddress to symbolize
bufBuffer where to store the result
sizeSize of the buffer
Returns
char* Pointer to the return string. This is within the provided buffer, but not necessarily at the beginning because of DMA alignment constraints.