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 let ret_addr = unsafe { fp.add(1).read_volatile() };
96 let next_fp = unsafe { *fp };
98
99 if ret_addr == 0 || ret_addr == 1 {
100 break;
101 }
102
103 let ret_addr = ret_addr & !1;
105
106 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 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 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}