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 <types.h>
#include <timer.h>
#include <log.h>
Include dependency graph for backtrace.c:

Macros

#define LOG_LEVEL_DEFAULT   LOG_LEVEL_DEBUG
 
#define CONFIG_ARCH_RISCV32   1
 
#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.
 

Functions

static int backtrace_check_address (void *pc)
 Checks whether a given program counter (PC) address is within a valid range.
 
static int riscv_backtrace_find_lr_offset (char *LR)
 Finds the offset of the Link Register (LR) from the return address in a backtrace.
 
int riscv_ins32_get_push_lr_framesize (uint32_t inst, int *offset)
 Determines the frame size for a push to the link register (LR) in a RISC-V instruction.
 
static int riscv_ins16_get_push_lr_framesize (uint16_t inst, int *offset)
 Determines the frame size for a push to the link register (LR) in a RISC-V compressed instruction.
 
int riscv_ins32_backtrace_stask_push (uint32_t inst)
 Checks if a RISC-V instruction corresponds to stack push instructions like addi sp, sp, imm and addiw sp, sp, imm, and calculates the effective stack push size based on the immediate value.
 
static int riscv_ins16_backtrace_stask_push (uint32_t inst)
 Processes compressed RISC-V instructions related to stack pointer adjustments.
 
static int riscv_backtrace_from_stack (long **pSP, char **pPC, char **pLR)
 Perform a backtrace from the current stack pointer and program counter.
 
static int backtrace_from_stack (long **pSP, char **pPC, char **pLR)
 Performs a backtrace from the current stack frame.
 
static int riscv_ins32_backtrace_return_pop (uint32_t inst)
 Handles the backtrace return pop for a 32-bit instruction.
 
static int riscv_ins16_backtrace_return_pop (uint16_t inst)
 Handles the backtrace return pop for a 16-bit instruction.
 
static int riscv_ins32_backtrace_stack_pop (unsigned int inst)
 Handles the backtrace stack pop for a 32-bit instruction.
 
static int riscv_ins16_backtrace_stack_pop (uint16_t inst)
 Handles the backtrace stack pop for a 16-bit instruction.
 
static int riscv_backtrace_from_lr (long **pSP, char **pPC, char *LR)
 Reconstructs a backtrace using the link register (LR) and program counter (PC).
 
int backtrace (char *PC, long *SP, char *LR)
 Perform a backtrace from the given program counter (PC), stack pointer (SP), and link register (LR).
 
int dump_stack (void)
 Dumps the current stack trace by fetching the program counter (PC), stack pointer (SP), and link register (LR).
 

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

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

◆ CONFIG_ARCH_RISCV32

#define CONFIG_ARCH_RISCV32   1

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

◆ LOG_LEVEL_DEFAULT

#define LOG_LEVEL_DEFAULT   LOG_LEVEL_DEBUG

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

Function Documentation

◆ backtrace()

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

Perform a backtrace from the given program counter (PC), stack pointer (SP), and link register (LR).

Perform a backtrace to find the call stack.

This function tries to traverse the stack to generate a backtrace, logging the current PC at each level. If the stack backtrace fails, it attempts to trace using the LR as a fallback.

Parameters
PCPointer to the program counter.
SPPointer to the stack pointer.
LRPointer to the link register (return address).
Returns
The number of backtrace levels found, or 0 if the backtrace failed.

◆ 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_stack()

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

Performs a backtrace from the current stack frame.

This function is used to trace the call stack, starting from the provided program counter and stack pointer. Before performing the backtrace, it checks if the program counter is valid (i.e., points to executable code). If the program counter is invalid, the function returns an error code (-1). Otherwise, it delegates the actual backtrace work to riscv_backtrace_from_stack.

Parameters
[in,out]pSPPointer to the stack pointer. The stack pointer is updated with the result of the backtrace.
[in,out]pPCPointer to the program counter. The program counter is updated with the result of the backtrace.
Returns
0 if the backtrace is successful and the program counter is updated correctly, or -1 if an invalid program counter is provided or the backtrace fails.

◆ dump_stack()

int dump_stack ( void  )

Dumps the current stack trace by fetching the program counter (PC), stack pointer (SP), and link register (LR).

Dumps the current stack state and performs a backtrace.

This function retrieves the current values of the stack pointer, program counter, and link register, then uses these to generate a backtrace. If either the stack pointer or program counter is invalid, it returns 0.

Returns
The backtrace level, or 0 if SP or PC is invalid.

◆ riscv_backtrace_find_lr_offset()

static int riscv_backtrace_find_lr_offset ( char *  LR)
static

Finds the offset of the Link Register (LR) from the return address in a backtrace.

This function attempts to determine the offset of the Link Register (LR) from the return address in a backtrace. It checks whether the LR corresponds to an IRQ handler exit address and adjusts accordingly. The function also checks the validity of the address and computes the instruction length based on the encoded instruction in memory.

Parameters
LRThe address of the Link Register (LR) to be checked.
Returns
The offset from the LR to the return address if valid, 0 if invalid or the address is within an IRQ handler exit region.

◆ riscv_backtrace_from_lr()

static int riscv_backtrace_from_lr ( long **  pSP,
char **  pPC,
char *  LR 
)
static

Reconstructs a backtrace using the link register (LR) and program counter (PC).

This function inspects the instructions at the current PC and LR, computes the stack frames, and updates the SP and PC accordingly. It tries to decode 16-bit and 32-bit instructions and handles different instruction formats for backtrace purposes.

Parameters
pSPPointer to the stack pointer to be updated.
pPCPointer to the program counter to be updated.
LRLink register (return address) to start the backtrace from.
Returns
1 if successful, 0 if the link register offset is zero, -1 on failure.

◆ riscv_backtrace_from_stack()

static int riscv_backtrace_from_stack ( long **  pSP,
char **  pPC,
char **  pLR 
)
static

Perform a backtrace from the current stack pointer and program counter.

This function walks the stack to retrieve the calling function's information by analyzing the return address (LR) and corresponding program counter (PC) values. It starts by looking for instructions that push the link register (LR) to the stack, then works backwards through the stack frames. The function handles both 16-bit and 32-bit instructions in RISC-V architecture.

The function attempts to find the appropriate return address and adjusts the stack pointer (SP) accordingly. It then calculates the program counter (PC) from the link register (LR) by finding the corresponding offset. The function is responsible for determining whether the address information is valid and updates the SP and PC pointers.

The function returns 1 if a valid backtrace is successfully performed, or 0 if the link register's offset is zero. If an error is encountered at any point, the function prints an error message and returns -1.

Parameters
pSPPointer to the stack pointer (SP) to be updated.
pPCPointer to the program counter (PC) to be updated.
Returns
int Returns:
  • 1 if a valid backtrace is successfully performed.
  • 0 if the link register's offset is zero.
  • -1 in case of failure (e.g., invalid addresses or instructions).
Note
The backtrace relies on the presence of valid instruction addresses and will fail if the stack pointer or program counter point to invalid regions. The function also uses insn_length() to determine instruction lengths and adjusts the stack and program counter accordingly.

◆ riscv_ins16_backtrace_return_pop()

static int riscv_ins16_backtrace_return_pop ( uint16_t  inst)
static

Handles the backtrace return pop for a 16-bit instruction.

This function checks if the provided 16-bit instruction matches the return address instruction and returns the corresponding result.

Parameters
instThe 16-bit instruction to check.
Returns
0 if the instruction matches the return instruction, -1 otherwise.

◆ riscv_ins16_backtrace_stack_pop()

static int riscv_ins16_backtrace_stack_pop ( uint16_t  inst)
static

Handles the backtrace stack pop for a 16-bit instruction.

This function checks if the provided 16-bit instruction is a stack pointer adjustment (either c.addi16sp, c.addi sp, or c.addiw sp) and computes the corresponding stack adjustment.

Parameters
instThe 16-bit instruction to check.
Returns
The computed stack pop value, or -1 if no valid stack pop is found.

◆ riscv_ins16_backtrace_stask_push()

static int riscv_ins16_backtrace_stask_push ( uint32_t  inst)
static

Processes compressed RISC-V instructions related to stack pointer adjustments.

This function checks if a 16-bit compressed RISC-V instruction corresponds to one of the following stack pointer modification operations:

  • c.addi16sp (compressed addi16sp instruction, used for modifying the stack pointer with a 9-bit signed immediate)
  • c.addi sp (compressed addi instruction for modifying sp with a 6-bit immediate)
  • c.addiw sp (compressed addiw instruction for modifying sp with a 6-bit immediate)

If the instruction matches one of these formats, it extracts the immediate value and calculates the corresponding adjustment to the stack pointer, returning the size of the adjustment in terms of long units. The function returns -1 if the instruction doesn't correspond to any recognized format or if the immediate value does not result in a valid stack adjustment.

Parameters
instThe 16-bit compressed RISC-V instruction to be analyzed.
Returns
int Returns the stack adjustment size (in terms of long units) if the instruction is valid, otherwise returns -1.
Note
  • The function assumes that the instruction is valid and checks for stack pointer adjustments only.
  • For c.addi16sp, the immediate is a 9-bit signed value that modifies the stack pointer (sp).
  • For c.addi sp, sp, imm and c.addiw sp, imm, the immediate is a 6-bit signed value used to modify sp.
  • The function divides the immediate value by sizeof(long) to return the number of long units adjusted.

◆ riscv_ins16_get_push_lr_framesize()

static int riscv_ins16_get_push_lr_framesize ( uint16_t  inst,
int *  offset 
)
static

Determines the frame size for a push to the link register (LR) in a RISC-V compressed instruction.

This function analyzes a 16-bit RISC-V compressed instruction (C-extension) to determine if it corresponds to a "push" operation to the link register (LR) or the stack pointer (SP), and computes the associated frame size or offset. The function specifically handles instructions that manipulate the stack pointer or the link register in compressed RISC-V instructions.

Parameters
instThe 16-bit compressed instruction to analyze.
offsetA pointer to an integer where the computed offset (in terms of long size) will be stored.
Returns
int Returns 0 if the instruction is valid and corresponds to a push operation, -1 otherwise.

◆ riscv_ins32_backtrace_return_pop()

static int riscv_ins32_backtrace_return_pop ( uint32_t  inst)
static

Handles the backtrace return pop for a 32-bit instruction.

This function checks if the provided 32-bit instruction matches the return address instruction and returns the corresponding result.

Parameters
instThe 32-bit instruction to check.
Returns
0 if the instruction matches the return instruction, -1 otherwise.

◆ riscv_ins32_backtrace_stack_pop()

static int riscv_ins32_backtrace_stack_pop ( unsigned int  inst)
static

Handles the backtrace stack pop for a 32-bit instruction.

This function checks if the instruction is a stack pointer adjustment (addi or addiw) and computes the corresponding stack adjustment. It handles both immediate values and calculates the stack width.

Parameters
instThe 32-bit instruction to check.
Returns
The computed stack pop value, or -1 if no match is found.

◆ riscv_ins32_backtrace_stask_push()

int riscv_ins32_backtrace_stask_push ( uint32_t  inst)

Checks if a RISC-V instruction corresponds to stack push instructions like addi sp, sp, imm and addiw sp, sp, imm, and calculates the effective stack push size based on the immediate value.

This function examines a 32-bit RISC-V instruction and checks if it corresponds to one of two stack adjustment operations:

  • addi sp, sp, imm (add immediate to the stack pointer)
  • addiw sp, sp, imm (add immediate to the stack pointer, with word extension).

If the instruction matches one of these operations, it calculates the immediate value and adjusts the stack pointer accordingly. The size of the stack push is calculated based on the immediate value, and the function returns this value divided by the size of a long type.

If the instruction does not correspond to one of the stack push operations, the function returns -1.

Parameters
instThe 32-bit RISC-V instruction to check.
Returns
int Returns the stack push size in terms of the number of long units if the instruction corresponds to a valid stack push operation, otherwise returns -1.
Note
The instruction must modify the stack pointer (sp) to be considered valid. The immediate value is expected to be a signed 12-bit value and may represent a positive or negative offset to the stack pointer.

◆ riscv_ins32_get_push_lr_framesize()

int riscv_ins32_get_push_lr_framesize ( uint32_t  inst,
int *  offset 
)

Determines the frame size for a push to the link register (LR) in a RISC-V instruction.

This function analyzes a 32-bit RISC-V instruction to determine whether it corresponds to a "push" operation to the link register (LR) or the stack pointer (SP), and computes the associated frame size or offset. The function specifically handles instructions that manipulate the stack pointer or the link register.

Parameters
instThe 32-bit instruction to analyze.
offsetA pointer to an integer where the computed offset (in terms of long size) will be stored.
Returns
int Returns 0 if the instruction is valid and corresponds to a push operation, -1 otherwise.

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.