hal_arm/
excep.rs

1use core::fmt::Display;
2use core::mem::align_of;
3
4#[repr(C)]
5pub struct ExcepStackFrame {
6    r0: u32,
7    r1: u32,
8    r2: u32,
9    r3: u32,
10    r12: u32,
11    lr: u32,
12    pc: u32,
13    psr: u32,
14}
15
16impl ExcepStackFrame {
17    pub fn new(stack_ptr: *const usize) -> Self {
18        unsafe {
19            let frame = &*(stack_ptr as *const ExcepStackFrame);
20            ExcepStackFrame {
21                r0: frame.r0,
22                r1: frame.r1,
23                r2: frame.r2,
24                r3: frame.r3,
25                r12: frame.r12,
26                lr: frame.lr,
27                pc: frame.pc,
28                psr: frame.psr,
29            }
30        }
31    }
32}
33
34impl Display for ExcepStackFrame {
35    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36        write!(
37            f,
38            "R0:  0x{:08x} R1:  0x{:08x} R2:  0x{:08x} R3:  0x{:08x}\n\
39             R12: 0x{:08x} LR:  0x{:08x} PC:  0x{:08x} PSR: 0x{:08x}",
40            self.r0, self.r1, self.r2, self.r3, self.r12, self.lr, self.pc, self.psr
41        )
42    }
43}
44
45const BACKTRACE_MAX_FRAMES: usize = 20;
46
47#[inline]
48fn is_call_aligned(ptr: *const usize) -> bool {
49    (ptr as usize).is_multiple_of(align_of::<usize>())
50}
51
52#[repr(C)]
53pub struct ExcepBacktrace {
54    stack_frame: ExcepStackFrame,
55    initial_fp: *const usize,
56}
57
58impl ExcepBacktrace {
59    pub fn new(stack_frame: ExcepStackFrame, initial_fp: *const usize) -> Self {
60        ExcepBacktrace {
61            stack_frame,
62            initial_fp,
63        }
64    }
65}
66
67impl Display for ExcepBacktrace {
68    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
69        writeln!(
70            f,
71            "---------------------------------------------------------------"
72        )?;
73        writeln!(f, "{}", self.stack_frame)?;
74        writeln!(
75            f,
76            "---------------------------------------------------------------"
77        )?;
78
79        let mut fp = self.initial_fp;
80        write!(f, "\nBacktrace:\n")?;
81
82        if let Some(symbol) = crate::debug::find_nearest_symbol(self.stack_frame.pc as usize) {
83            writeln!(f, "0:     {} (0x{:08x})", symbol, self.stack_frame.pc)?;
84        } else {
85            writeln!(f, "0:     0x{:08x}", self.stack_frame.pc)?;
86        }
87
88        if fp.is_null() || !is_call_aligned(fp) {
89            writeln!(f, "<invalid frame pointer: 0x{:08x}>", fp as usize)?;
90            return writeln!(f);
91        }
92
93        for i in 1..BACKTRACE_MAX_FRAMES {
94            // Read the return address from the stack.
95            let ret_addr = unsafe { fp.add(1).read_volatile() };
96            // Read the frame pointer from the current frame.
97            let next_fp = unsafe { *fp };
98
99            if ret_addr == 0 || ret_addr == 1 {
100                break;
101            }
102
103            // Return addresses in Thumb mode carry bit0 = 1.
104            let ret_addr = ret_addr & !1;
105
106            // Print the return address.
107            if let Some(symbol) = crate::debug::find_nearest_symbol(ret_addr) {
108                writeln!(f, "{i}:     {symbol} (0x{ret_addr:08x})")?;
109            } else {
110                writeln!(f, "{i}:     0x{ret_addr:08x}")?;
111            }
112
113            // If the next frame pointer is 0 or 1. (thumb mode adds +1 to the address)
114            if next_fp == 0 || next_fp == 1 {
115                break;
116            }
117
118            let fp_addr = fp as usize;
119            let next_fp_addr = next_fp;
120
121            if next_fp_addr <= fp_addr {
122                writeln!(f, "<invalid frame pointer: 0x{next_fp_addr:08x}>")?;
123                break;
124            }
125
126            if !is_call_aligned(next_fp_addr as *const usize) {
127                writeln!(f, "<invalid frame pointer: 0x{next_fp_addr:08x}>")?;
128                break;
129            }
130
131            // Move to the next frame.
132            fp = next_fp as *const usize;
133
134            if i == BACKTRACE_MAX_FRAMES - 1 {
135                writeln!(f, "{i}:     ...")?;
136            }
137        }
138
139        writeln!(f)
140    }
141}
142
143pub struct FaultStatus {
144    pub fault: hal_api::Fault,
145}
146
147impl Display for FaultStatus {
148    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149        match self.fault {
150            hal_api::Fault::Hard => write!(f, "Hard Fault - No additional info"),
151            hal_api::Fault::MemManage => crate::debug::print_mem_manage_fault_status(f),
152            hal_api::Fault::Bus => crate::debug::print_bus_fault_status(f),
153            hal_api::Fault::Usage => crate::debug::print_usage_fault_status(f),
154        }
155    }
156}