oveRTOS C API
Embedded RTOS framework — build system, configuration, and portable C API
Loading...
Searching...
No Matches
Enumerations | Functions
ove_arm_backtrace.h File Reference

Validate that an LR points right after a Thumb-2 bl imm (32-bit) or blx reg (16-bit) — the only Thumb encodings that set LR with return-address semantics. More...

#include <stdint.h>
Include dependency graph for ove_arm_backtrace.h:

Go to the source code of this file.

Enumerations

enum  {
  OVE_ARM_EXC_R0 = 0 , OVE_ARM_EXC_R1 = 1 , OVE_ARM_EXC_R2 = 2 , OVE_ARM_EXC_R3 = 3 ,
  OVE_ARM_EXC_R12 = 4 , OVE_ARM_EXC_LR = 5 , OVE_ARM_EXC_PC = 6 , OVE_ARM_EXC_XPSR = 7
}
 

Functions

int ove_arm_backtrace_lr_is_post_bl (uintptr_t lr_clean, uintptr_t text_lo, uintptr_t text_hi)
 
int ove_arm_backtrace_walk (uintptr_t psp, uintptr_t text_lo, uintptr_t text_hi, uintptr_t sram_lo, uintptr_t sram_hi, uint32_t fill, uintptr_t *out, int max)
 Multi-frame stack-scan unwinder for Cortex-M / Thumb-2 tasks.
 

Detailed Description

Validate that an LR points right after a Thumb-2 bl imm (32-bit) or blx reg (16-bit) — the only Thumb encodings that set LR with return-address semantics.

Used by the walker to reject stray function-pointer values that pass the text-range filter but aren't real return addresses (e.g. LVGL draw-task callbacks, vtable entries, timer callbacks).

Safe to call from ISR context — reads hit .text (flash), no SRAM access.

Parameters
[in]lr_cleanCandidate LR with Thumb bit already cleared.
[in]text_loInclusive lower .text bound.
[in]text_hiExclusive upper .text bound.
Returns
Non-zero when the two halfwords at (lr-4) / (lr-2) encode bl imm or blx reg, zero otherwise.

Function Documentation

◆ ove_arm_backtrace_walk()

int ove_arm_backtrace_walk ( uintptr_t  psp,
uintptr_t  text_lo,
uintptr_t  text_hi,
uintptr_t  sram_lo,
uintptr_t  sram_hi,
uint32_t  fill,
uintptr_t *  out,
int  max 
)

Multi-frame stack-scan unwinder for Cortex-M / Thumb-2 tasks.

A classic r7 FP-chain walk doesn't work on GCC with -fno-omit-frame-pointer — the compiler emits

push {r7, lr}
sub sp, #N
add r7, sp, #K ; K typically 0, occasionally up to ~108

so r7 points at the start of locals, not at the saved-r7 slot, and the offset from r7 to the saved-LR slot varies per function.

Instead the walker scans words above the 8-word hardware exception frame, looking for pairs that look like a saved {r7, lr} push. A candidate word must:

  • have the Thumb bit set,
  • point (after clearing bit 0) into [text_lo, text_hi),
  • sit right after a bl imm or blx reg,
  • have its preceding word (the saved-r7) fit the prologue invariant: saved_r7_value = (saved_lr_slot_addr + 4) + K_caller for K_caller in [0, 128],
  • the pair's footprint must sit strictly above the most recently accepted saved-r7 (ascending-chain invariant).

Scan terminates on: fill-pattern match (when fill != 0), leaving SRAM, hitting OVE_ARM_STACK_SCAN_WORDS, or filling max slots.

Parameters
[in]pspPSP at exception entry (or equivalent — points at the stacked R0 of the interrupted task). Caller is responsible for pcs[0]=stacked PC; this function writes frames 1..max-1. frame[OVE_ARM_EXC_LR] is NOT used as a normal frame — caller may use it as a fallback only when this function returns 0.
[in]text_loInclusive .text lower bound (must exclude ISR vector table so small integer stack values can't alias vectors).
[in]text_hiExclusive .text upper bound (linker __etext / __text_region_end).
[in]sram_loInclusive SRAM lower bound.
[in]sram_hiExclusive SRAM upper bound.
[in]fillStack-fill pattern that terminates the scan, or 0 to disable the check. FreeRTOS uses 0xA5A5A5A5 from tskSTACK_FILL_BYTE; Zephyr without CONFIG_INIT_STACKS should pass 0.
[out]outOutput buffer for walked return addresses, Thumb bit cleared, inner frames first.
[in]maxCapacity of out (number of slots).
Returns
Number of slots written to out (0..max).