SyterKit 0.4.0.x
SyterKit is a bare-metal framework
Loading...
Searching...
No Matches
Macros | Functions | Variables
backtrace.c File Reference
#include <io.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <types.h>
#include <timer.h>
#include <log.h>
Include dependency graph for backtrace.c:

Macros

#define BT_SCAN_MAX_LIMIT   0xFFFFFF
 Maximum limit for backtrace scanning.
 
#define BT_LEVEL_LIMIT   64
 Maximum number of backtrace levels.
 
#define PC2ADDR(pc)   ((char *) (((uint32_t) (pc)) & 0xfffffffe))
 Converts a program counter (PC) value to an address.
 
#define insn_length(x)
 Determines the length of an instruction in bytes based on its encoding.
 
#define BITS(x, high, low)   ((x) & (((1 << ((high) - (low) + 1)) - 1) << (low)))
 Extracts a specific bit field from a value.
 
#define ARM_STATE   0
 ARM state macro definition.
 
#define THUMB_STATE   1
 THUMB state macro definition.
 
#define IS_THUMB_ADDR(pc)   ((uint32_t) (pc) &0x1)
 Macro to check if the program counter (PC) is in THUMB mode.
 

Functions

static int backtrace_check_address (void *pc)
 Checks whether a given program counter (PC) address is within a valid range.
 
static int thumb_thumb32bit_code (uint16_t ic)
 Checks if a given Thumb instruction is a 32-bit Thumb instruction.
 
static int find_lr_offset (char *LR, bool *state)
 Finds the offset for the Link Register (LR) based on the processor state.
 
static int thumb_get_next_inst (int *error, int *offset, char *ins16_h_addr, char *ins16_l_addr, int lsb, int *thumb32bit)
 Retrieves the next Thumb instruction from the given addresses.
 
static int thumb_get_push_lr_ins_framesize (uint32_t inst, int *offset, int thumb32bit)
 Calculates the frame size for a push or store-multiple instruction that includes the link register (lr).
 
static int thumb_backtrace_stack_push (uint32_t inst, int thumb32bit)
 Calculate the frame size based on the instruction and determine the stack adjustment.
 
static int thumb_backtrace_from_stack (int **pSP, char **pPC, char **pLR)
 Perform a backtrace from the stack and retrieve the next return address and program counter (PC).
 
static int arm_get_push_lr_ins_framesize (uint32_t inst, int *offset)
 Analyzes an ARM instruction to determine the frame size and the offset for the link register (LR).
 
static int arm_backtrace_stack_push (uint32_t inst)
 Analyzes an ARM instruction to determine the frame size for stack operations.
 
static int arm_bakctrace_from_stack (int **pSP, char **pPC, char **pLR)
 Performs backtrace from the stack to find the return address and program counter.
 
static int backtrace_from_stack (int **pSP, char **pPC, char **pLR)
 Backtrace from stack based on program counter (PC) state.
 
static int thumb_backtrace_stack_pop (uint32_t inst, uint8_t *sp_change, int thumb32bit)
 Pop a frame from the stack for Thumb instructions.
 
static int thumb_backtrace_return_pop (uint32_t inst, int thumb32bit)
 Process the return instruction for Thumb mode and determine the frame size.
 
static int thumb_get_push_ins_framesize (uint32_t inst, uint8_t *jump, int thumb32bit)
 Calculate the frame size for a "push" instruction in Thumb mode.
 
static int thumb_backtrace_from_lr (int **pSP, char **pPC, char *LR)
 Perform a backtrace from the Link Register (LR) in Thumb mode.
 
static int arm_backtrace_return_pop (uint32_t inst)
 Analyze the ARM instruction to determine the frame size for backtrace.
 
static int arm_backtrace_stack_pop (uint32_t inst)
 Analyze the ARM instruction to determine the frame size for stack pop operations.
 
static int arm_backtrace_from_lr (int **pSP, char **pPC, char *LR)
 Perform backtrace from the link register (LR) to determine the stack pointer (SP) and program counter (PC).
 
static int backtrace_from_lr (int **pSP, char **pPC, char *LR)
 Perform a backtrace from the Link Register (LR).
 
int backtrace (char *PC, long *SP, char *LR)
 Perform a backtrace to find the call stack.
 
int dump_stack (void)
 Dumps the current stack state and performs a backtrace.
 

Variables

uint8_t __spl_start []
 Pointer to the start of the image in memory.
 
uint8_t __stack_srv_end []
 Pointer to the end of the stack service region.
 

Macro Definition Documentation

◆ ARM_STATE

#define ARM_STATE   0

ARM state macro definition.

This macro represents the ARM state in ARM architecture.

◆ BITS

#define BITS (   x,
  high,
  low 
)    ((x) & (((1 << ((high) - (low) + 1)) - 1) << (low)))

Extracts a specific bit field from a value.

This macro extracts a bit field from a value x based on the specified high and low bit positions. The bits are masked and shifted to the right, leaving the desired bit field.

Parameters
xThe value from which to extract the bit field.
highThe index of the highest bit (inclusive).
lowThe index of the lowest bit (inclusive).
Returns
The extracted bit field.

◆ BT_LEVEL_LIMIT

#define BT_LEVEL_LIMIT   64

Maximum number of backtrace levels.

This constant defines the maximum depth of the backtrace. It limits how many stack frames the backtrace function can unwind before stopping.

◆ BT_SCAN_MAX_LIMIT

#define BT_SCAN_MAX_LIMIT   0xFFFFFF

Maximum limit for backtrace scanning.

This constant defines the maximum limit for scanning the backtrace. The backtrace function will scan instructions and stack frames up to this size. If the limit is exceeded, the backtrace operation will fail.

◆ insn_length

#define insn_length (   x)
Value:
(((x) &0x03) < 0x03 ? 2 : ((x) &0x1f) < 0x1f ? 4 \
: ((x) &0x3f) < 0x3f ? 6 \
: 8)

Determines the length of an instruction in bytes based on its encoding.

This macro computes the length of an instruction in bytes, given a 32-bit instruction encoding. The length is determined based on specific bit patterns in the instruction word.

Parameters
xThe instruction encoding (32-bit).
Returns
The length of the instruction in bytes (either 2, 4, 6, or 8).

◆ IS_THUMB_ADDR

#define IS_THUMB_ADDR (   pc)    ((uint32_t) (pc) &0x1)

Macro to check if the program counter (PC) is in THUMB mode.

This macro checks whether the given program counter address (PC) points to the THUMB mode. According to ARM architecture, if the least significant bit (LSB) of the program counter (PC) is 1, the instruction set is in THUMB mode.

Parameters
pcThe program counter (typically the address of an instruction)
Returns
Returns a non-zero value if the address is in THUMB mode, otherwise returns 0.

◆ PC2ADDR

#define PC2ADDR (   pc)    ((char *) (((uint32_t) (pc)) & 0xfffffffe))

Converts a program counter (PC) value to an address.

This macro takes a program counter (PC) value and converts it to a valid address by clearing the least significant bit. This operation is commonly used to align PC addresses properly for instruction fetch.

Parameters
pcThe program counter value to convert.
Returns
The corresponding address, aligned to a 2-byte boundary.

◆ THUMB_STATE

#define THUMB_STATE   1

THUMB state macro definition.

This macro represents the THUMB state in ARM architecture.

Function Documentation

◆ arm_backtrace_from_lr()

static int arm_backtrace_from_lr ( int **  pSP,
char **  pPC,
char *  LR 
)
static

Perform backtrace from the link register (LR) to determine the stack pointer (SP) and program counter (PC).

This function performs a backtrace from the provided LR (link register) to locate the stack pointer and program counter of the current function. It checks the validity of addresses, scans instructions to compute the stack frame size, and adjusts the program counter based on the ARM instruction set state (ARM or Thumb).

Parameters
pSPA pointer to the stack pointer (SP) to be updated.
pPCA pointer to the program counter (PC) to be updated.
LRThe link register value from which the backtrace will begin.
Returns
1 if backtrace is successful with no offset, 0 if backtrace is successful with offset, or -1 if there is an error during the process.

◆ arm_backtrace_return_pop()

static int arm_backtrace_return_pop ( uint32_t  inst)
static

Analyze the ARM instruction to determine the frame size for backtrace.

This function interprets an ARM instruction and determines the frame size based on the instruction type. It handles the following instructions:

  • pop {..., pc}: Pops the program counter (pc) from the stack.
  • bx lr: Branches to the link register (lr), effectively returning from a function.
  • ldr pc, [sp], #4: Loads the program counter (pc) from the stack and updates the stack pointer.
Parameters
instThe ARM instruction to analyze.
Returns
The size of the frame affected by the instruction.

◆ arm_backtrace_stack_pop()

static int arm_backtrace_stack_pop ( uint32_t  inst)
static

Analyze the ARM instruction to determine the frame size for stack pop operations.

This function interprets an ARM instruction and determines the frame size based on the instruction type. It handles the following instructions:

  • add sp, sp, #imm: Adds an immediate value to the stack pointer (sp).
  • pop {...}: Pops a set of registers from the stack.
  • vpop {...}: Pops a set of vector registers from the stack.
  • ldr xxx, [sp], #4: Loads a value from the stack into a register and updates the stack pointer.
Parameters
instThe ARM instruction to analyze.
Returns
The size of the frame affected by the instruction.

◆ arm_backtrace_stack_push()

static int arm_backtrace_stack_push ( uint32_t  inst)
static

Analyzes an ARM instruction to determine the frame size for stack operations.

This function inspects the provided ARM instruction to determine the size of the stack frame based on common instructions such as sub sp, sp, #imm, push, vpush, and str xxx, [sp, #-4]!. It returns the size of the stack frame in terms of the number of words (4-byte units) affected by the instruction.

Parameters
instThe ARM instruction to be analyzed (32-bit uint32_teger).
Returns
The size of the stack frame in terms of the number of 4-byte words, or -1 if no relevant instruction is found.

◆ arm_bakctrace_from_stack()

static int arm_bakctrace_from_stack ( int **  pSP,
char **  pPC,
char **  pLR 
)
static

Performs backtrace from the stack to find the return address and program counter.

This function attempts to deduce the return address (LR) and program counter (PC) by analyzing the stack and the instructions around it. It parses the stack to find the correct frame size, validates the text addresses, and adjusts the program counter based on the instruction state (ARM/Thumb).

Parameters
pSPPointer to the current stack pointer (SP).
pPCPointer to the current program counter (PC).
pLRPointer to the link register (LR).
Returns
1 if a valid return address is found, 0 if the backtrace is incomplete, and -1 if an error occurs.

◆ arm_get_push_lr_ins_framesize()

static int arm_get_push_lr_ins_framesize ( uint32_t  inst,
int *  offset 
)
static

Analyzes an ARM instruction to determine the frame size and the offset for the link register (LR).

This function inspects the provided ARM instruction to detect specific types of instructions related to pushing the link register (LR) onto the stack. It calculates the size of the stack frame and determines the offset of the link register, if applicable.

Parameters
instThe ARM instruction to be analyzed (32-bit uint32_teger).
offsetPointer to an integer where the offset of LR will be stored.
Returns
The size of the stack frame in terms of the number of registers pushed, or -1 if no relevant instruction is found.

◆ backtrace()

int backtrace ( char *  PC,
long *  SP,
char *  LR 
)

Perform a backtrace to find the call stack.

This function attempts to walk the call stack by analyzing the program counter (PC), stack pointer (SP), and link register (LR) to determine the sequence of function calls leading to the current execution point.

The backtrace process works by using the stack and link register to trace the call hierarchy, logging each level of the backtrace, and attempting recovery from any errors. If the backtrace from the stack fails, it will attempt to trace using the link register (LR).

Parameters
PCThe current program counter (PC), typically pointing to the instruction where the backtrace starts.
SPThe current stack pointer (SP), pointing to the top of the stack.
LRThe link register (LR), used to store return addresses for function calls.
Returns
The number of backtrace levels successfully traversed. Returns 0 if no valid backtrace could be performed.

◆ backtrace_check_address()

static int backtrace_check_address ( void *  pc)
inlinestatic

Checks whether a given program counter (PC) address is within a valid range.

This function checks if the provided PC (program counter) value lies within the memory region between __spl_start and __stack_srv_end. It ensures that the PC value points to a valid memory address in the executable region of the program.

Parameters
pcThe program counter value to check.
Returns
1 if the PC is within the valid address range, 0 otherwise.

◆ backtrace_from_lr()

static int backtrace_from_lr ( int **  pSP,
char **  pPC,
char *  LR 
)
static

Perform a backtrace from the Link Register (LR).

This function determines whether the current address is in Thumb mode or ARM mode and calls the appropriate backtrace function based on the result.

Parameters
pSPPointer to the stack pointer.
pPCPointer to the program counter.
LRThe link register address to backtrace from.
Returns
1 if backtrace is successful, 0 if the frame is not valid, -1 on error.

◆ backtrace_from_stack()

static int backtrace_from_stack ( int **  pSP,
char **  pPC,
char **  pLR 
)
static

Backtrace from stack based on program counter (PC) state.

This function performs a backtrace by checking if the current code is running in ARM or Thumb state and calls the appropriate backtrace function accordingly. If the program counter (PC) address is invalid, it returns an error.

Parameters
pSPPointer to the stack pointer.
pPCPointer to the program counter.
pLRPointer to the link register.
Returns
0 if backtrace was successful, -1 if the PC is invalid or an error occurred.

◆ dump_stack()

int dump_stack ( void  )

Dumps the current stack state and performs a backtrace.

This function captures the current program counter (PC), stack pointer (SP), link register (LR), and current processor status register (CPSR). It uses inline assembly to obtain these values, then performs a backtrace to provide insight into the function call stack.

The function also checks if the processor is in THUMB mode based on the CPSR state and adjusts the program counter (PC) accordingly. If the program counter or stack pointer is invalid, the function will return early with a status of 0.

Returns
The result of the backtrace function, representing the number of successfully traced backtrace levels, or 0 if the stack pointer (SP) or program counter (PC) is invalid.

◆ find_lr_offset()

static int find_lr_offset ( char *  LR,
bool state 
)
static

Finds the offset for the Link Register (LR) based on the processor state.

This function computes the offset for the Link Register (LR) based on the current processor state (ARM or THUMB) and the instruction sequence at the return address. It checks for specific branch instructions such as bx and blx and adjusts the LR offset accordingly.

The function will also handle both 16-bit and 32-bit instructions based on the processor mode and update the state of the processor.

Parameters
LRA pointer to the Link Register value (the return address).
stateA pointer to a boolean representing the processor state. It can be either ARM_STATE or THUMB_STATE.
Returns
The offset to be applied to the LR, typically 2 or 4 bytes, depending on the type of instruction found.

◆ thumb_backtrace_from_lr()

static int thumb_backtrace_from_lr ( int **  pSP,
char **  pPC,
char *  LR 
)
static

Perform a backtrace from the Link Register (LR) in Thumb mode.

This function extracts the frame size from the LR and updates the SP and PC based on the Thumb instruction set. It scans the instructions, identifies the backtrace points, and handles stack frame adjustments.

Parameters
pSPPointer to the stack pointer.
pPCPointer to the program counter.
LRThe link register address to backtrace from.
Returns
1 if backtrace is successful, 0 if the frame is not valid, -1 on error.

◆ thumb_backtrace_from_stack()

static int thumb_backtrace_from_stack ( int **  pSP,
char **  pPC,
char **  pLR 
)
static

Perform a backtrace from the stack and retrieve the next return address and program counter (PC).

This function traverses the stack to reconstruct a backtrace by parsing Thumb instructions and calculating the correct stack pointer (SP), program counter (PC), and link register (LR). It uses the Thumb instruction set to decode stack frames and returns the updated SP, PC, and LR values.

Parameters
pSPPointer to the current stack pointer (SP).
pPCPointer to the current program counter (PC).
pLRPointer to the current link register (LR).
Returns
  • 1: If the backtrace is successfully completed.
  • 0: If the backtrace is successful but no LR was found.
  • -1: If an error occurs (e.g., invalid address, overflow, or failed instruction parsing).

◆ thumb_backtrace_return_pop()

static int thumb_backtrace_return_pop ( uint32_t  inst,
int  thumb32bit 
)
static

Process the return instruction for Thumb mode and determine the frame size.

This function checks if the current instruction is a return instruction, such as "bx lr", which is used for returning from functions in ARM architecture. It specifically handles the case for Thumb mode instructions and sets the frame size appropriately.

Parameters
instThe Thumb instruction to analyze.
thumb32bitFlag indicating if the instruction is Thumb-32 bit (true) or not (false).
Returns
0 if the return instruction is detected, otherwise the frame size (or -1 if not detected).

◆ thumb_backtrace_stack_pop()

static int thumb_backtrace_stack_pop ( uint32_t  inst,
uint8_t sp_change,
int  thumb32bit 
)
static

Pop a frame from the stack for Thumb instructions.

This function processes a Thumb instruction to determine the frame size and updates the stack pointer change flag. It distinguishes between normal "pop" and vector "vpop" instructions.

Parameters
instThe Thumb instruction to analyze.
sp_changePointer to a flag that will be set to 1 if the stack pointer changes.
thumb32bitFlag indicating if the instruction is Thumb-32 bit (true) or not (false).
Returns
The size of the frame to pop, or -1 if no valid "pop" instruction is found.

◆ thumb_backtrace_stack_push()

static int thumb_backtrace_stack_push ( uint32_t  inst,
int  thumb32bit 
)
static

Calculate the frame size based on the instruction and determine the stack adjustment.

This function analyzes Thumb instructions to determine the frame size of a function prologue, based on push or stack adjustment operations. It handles both 16-bit and 32-bit Thumb instructions.

Parameters
instThe instruction to analyze (32-bit).
thumb32bitFlag indicating whether the instruction is a 32-bit Thumb instruction (1 for Thumb-32, 0 for Thumb-16).
Returns
The calculated frame size (number of registers pushed or stack adjusted), or -1 if no match is found.

◆ thumb_get_next_inst()

static int thumb_get_next_inst ( int *  error,
int *  offset,
char *  ins16_h_addr,
char *  ins16_l_addr,
int  lsb,
int *  thumb32bit 
)
static

Retrieves the next Thumb instruction from the given addresses.

This function fetches the next instruction in the Thumb instruction set from two 16-bit instruction addresses. It checks whether the instruction is a 32-bit Thumb-2 instruction (Thumb-32), and if so, combines the two 16-bit values to form a 32-bit instruction. It also updates the offset and returns the appropriate instruction.

The function uses the lsb (least significant bit) flag to determine which part of the instruction to select when the instruction is not Thumb-32.

Parameters
errorA pointer to an integer that will be set to -1 in case of an error.
offsetA pointer to the offset, which will be updated if a Thumb-32 instruction is found.
ins16_h_addrAddress of the high part of the instruction (16 bits).
ins16_l_addrAddress of the low part of the instruction (16 bits).
lsbFlag indicating whether to fetch the least significant bit of the instruction.
thumb32bitA pointer to an integer that will be set to 1 if a Thumb-32 instruction is detected, otherwise 0.
Returns
Returns the 32-bit instruction if Thumb-32 is detected, otherwise returns the appropriate 16-bit instruction.

◆ thumb_get_push_ins_framesize()

static int thumb_get_push_ins_framesize ( uint32_t  inst,
uint8_t jump,
int  thumb32bit 
)
static

Calculate the frame size for a "push" instruction in Thumb mode.

This function checks if the instruction is a "push" instruction or a "sub sp" instruction in Thumb-32 bit mode. It determines the frame size based on the instruction and sets the jump flag if needed.

Parameters
instThe Thumb instruction to analyze.
jumpPointer to a flag that will be set to 1 if the instruction is a "push".
thumb32bitFlag indicating if the instruction is Thumb-32 bit (true) or not (false).
Returns
The calculated frame size, or -1 if the instruction does not match "push" or "sub sp".

◆ thumb_get_push_lr_ins_framesize()

static int thumb_get_push_lr_ins_framesize ( uint32_t  inst,
int *  offset,
int  thumb32bit 
)
static

Calculates the frame size for a push or store-multiple instruction that includes the link register (lr).

This function processes a Thumb instruction to determine the frame size (number of registers pushed) based on the presence of the link register (lr). It checks both Thumb-2 (32-bit) and Thumb-1 (16-bit) instructions and computes the frame size accordingly.

Parameters
instThe instruction to analyze (32-bit Thumb instruction).
offsetPointer to an integer that will be set to 1 if a push or store-multiple instruction is found, otherwise 0.
thumb32bitA flag indicating whether the instruction is a 32-bit Thumb instruction (1 if Thumb-32, 0 if Thumb-16).
Returns
The number of registers pushed (frame size) or -1 if no matching instruction is found.

◆ thumb_thumb32bit_code()

static int thumb_thumb32bit_code ( uint16_t  ic)
static

Checks if a given Thumb instruction is a 32-bit Thumb instruction.

This function examines the top 5 bits of the input instruction to determine whether it corresponds to a specific set of Thumb instructions (0x1D, 0x1E, or 0x1F). These values indicate a 32-bit Thumb instruction.

Parameters
icA 16-bit uint32_teger representing the Thumb instruction to be checked.
Returns
Returns 1 if the instruction is a 32-bit Thumb instruction (i.e., its top 5 bits match 0x1D, 0x1E, or 0x1F), otherwise returns 0.

Variable Documentation

◆ __spl_start

uint8_t __spl_start[]
extern

Pointer to the start of the image in memory.

This variable marks the start address of the memory region that contains the program image. It is used to check if a program counter (PC) value falls within the valid range of executable memory.

◆ __stack_srv_end

uint8_t __stack_srv_end[]
extern

Pointer to the end of the stack service region.

This variable marks the end address of the memory region used for the stack service. It is used to check if a program counter (PC) value falls within the valid memory region, preventing access to out-of-bounds memory.