1#![allow(rustdoc::bare_urls, unused_macros)]
2#![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))]
3#![doc = include_str!("../README.md")]
4#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
5#![no_std]
6
7#[cfg(feature = "defmt")]
8use defmt as _;
9#[cfg(feature = "println")]
10use esp_println as _;
11
12const MAX_BACKTRACE_ADDRESSES: usize = 10;
13
14#[cfg(feature = "colors")]
15const RESET: &str = "\u{001B}[0m";
16#[cfg(feature = "colors")]
17const RED: &str = "\u{001B}[31m";
18
19#[cfg(feature = "defmt")]
20macro_rules! println {
21 ("") => {
22 };
24 ($($arg:tt)*) => {
25 defmt::error!($($arg)*);
26 };
27}
28
29#[cfg(all(feature = "println", not(feature = "defmt")))]
30macro_rules! println {
31 ($($arg:tt)*) => {
32 esp_println::println!($($arg)*);
33 };
34}
35
36#[allow(unused, unused_variables)]
37fn set_color_code(code: &str) {
38 #[cfg(feature = "println")]
39 {
40 println!("{}", code);
41 }
42}
43
44#[cfg_attr(target_arch = "riscv32", path = "riscv.rs")]
45#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")]
46pub mod arch;
47
48#[cfg(feature = "panic-handler")]
49#[panic_handler]
50fn panic_handler(info: &core::panic::PanicInfo) -> ! {
51 pre_backtrace();
52
53 #[cfg(feature = "colors")]
54 set_color_code(RED);
55
56 println!("");
57 println!("====================== PANIC ======================");
58
59 #[cfg(not(feature = "defmt"))]
60 println!("{}", info);
61
62 #[cfg(feature = "defmt")]
63 println!("{}", info);
64
65 println!("");
66 println!("Backtrace:");
67 println!("");
68
69 let backtrace = crate::arch::backtrace();
70 #[cfg(target_arch = "riscv32")]
71 if backtrace.iter().filter(|e| e.is_some()).count() == 0 {
72 println!("No backtrace available - make sure to force frame-pointers. (see https://crates.io/crates/esp-backtrace)");
73 }
74 for addr in backtrace.into_iter().flatten() {
75 #[cfg(all(feature = "colors", feature = "println"))]
76 println!("{}0x{:x}", RED, addr - crate::arch::RA_OFFSET);
77
78 #[cfg(not(all(feature = "colors", feature = "println")))]
79 println!("0x{:x}", addr - crate::arch::RA_OFFSET);
80 }
81
82 #[cfg(feature = "colors")]
83 set_color_code(RESET);
84
85 #[cfg(feature = "semihosting")]
86 semihosting::process::abort();
87
88 #[cfg(not(feature = "semihosting"))]
89 halt();
90}
91
92#[cfg(all(feature = "exception-handler", target_arch = "xtensa"))]
93#[no_mangle]
94#[link_section = ".rwtext"]
95unsafe fn __user_exception(cause: arch::ExceptionCause, context: arch::Context) {
96 pre_backtrace();
97
98 #[cfg(feature = "colors")]
99 set_color_code(RED);
100
101 #[cfg(not(feature = "defmt"))]
103 esp_println::println!("\n\nException occurred '{}'", cause);
104
105 #[cfg(feature = "defmt")]
106 defmt::error!("\n\nException occurred '{}'", cause);
107
108 println!("{:?}", context);
109
110 let backtrace = crate::arch::backtrace_internal(context.A1, 0);
111 for e in backtrace {
112 if let Some(addr) = e {
113 println!("0x{:x}", addr);
114 }
115 }
116 println!("");
117 println!("");
118 println!("");
119
120 #[cfg(feature = "colors")]
121 set_color_code(RESET);
122
123 #[cfg(feature = "semihosting")]
124 semihosting::process::abort();
125
126 #[cfg(not(feature = "semihosting"))]
127 halt();
128}
129
130#[cfg(all(feature = "exception-handler", target_arch = "riscv32"))]
131#[export_name = "ExceptionHandler"]
132fn exception_handler(context: &arch::TrapFrame) -> ! {
133 pre_backtrace();
134
135 let mepc = context.pc;
136 let code = context.mcause & 0xff;
137 let mtval = context.mtval;
138
139 #[cfg(feature = "colors")]
140 set_color_code(RED);
141
142 if code == 14 {
143 println!("");
144 println!(
145 "Stack overflow detected at 0x{:x} called by 0x{:x}",
146 mepc, context.ra
147 );
148 println!("");
149 } else {
150 let code = match code {
151 0 => "Instruction address misaligned",
152 1 => "Instruction access fault",
153 2 => "Illegal instruction",
154 3 => "Breakpoint",
155 4 => "Load address misaligned",
156 5 => "Load access fault",
157 6 => "Store/AMO address misaligned",
158 7 => "Store/AMO access fault",
159 8 => "Environment call from U-mode",
160 9 => "Environment call from S-mode",
161 10 => "Reserved",
162 11 => "Environment call from M-mode",
163 12 => "Instruction page fault",
164 13 => "Load page fault",
165 14 => "Reserved",
166 15 => "Store/AMO page fault",
167 _ => "UNKNOWN",
168 };
169
170 println!(
171 "Exception '{}' mepc=0x{:08x}, mtval=0x{:08x}",
172 code, mepc, mtval
173 );
174 #[cfg(not(feature = "defmt"))]
175 println!("{:x?}", context);
176
177 #[cfg(feature = "defmt")]
178 println!("{:?}", context);
179
180 let backtrace = crate::arch::backtrace_internal(context.s0 as u32, 0);
181 if backtrace.iter().filter(|e| e.is_some()).count() == 0 {
182 println!("No backtrace available - make sure to force frame-pointers. (see https://crates.io/crates/esp-backtrace)");
183 }
184 for addr in backtrace.into_iter().flatten() {
185 #[cfg(all(feature = "colors", feature = "println"))]
186 println!("{}0x{:x}", RED, addr - crate::arch::RA_OFFSET);
187
188 #[cfg(not(all(feature = "colors", feature = "println")))]
189 println!("0x{:x}", addr - crate::arch::RA_OFFSET);
190 }
191 }
192
193 println!("");
194 println!("");
195 println!("");
196
197 #[cfg(feature = "colors")]
198 set_color_code(RESET);
199
200 #[cfg(feature = "semihosting")]
201 semihosting::process::abort();
202
203 #[cfg(not(feature = "semihosting"))]
204 halt();
205}
206
207fn is_valid_ram_address(address: u32) -> bool {
215 if (address & 0xF) != 0 {
216 return false;
217 }
218
219 #[cfg(feature = "esp32")]
220 if !(0x3FFA_E000..=0x4000_0000).contains(&address) {
221 return false;
222 }
223
224 #[cfg(feature = "esp32c2")]
225 if !(0x3FCA_0000..=0x3FCE_0000).contains(&address) {
226 return false;
227 }
228
229 #[cfg(feature = "esp32c3")]
230 if !(0x3FC8_0000..=0x3FCE_0000).contains(&address) {
231 return false;
232 }
233
234 #[cfg(feature = "esp32c6")]
235 if !(0x4080_0000..=0x4088_0000).contains(&address) {
236 return false;
237 }
238
239 #[cfg(feature = "esp32h2")]
240 if !(0x4080_0000..=0x4085_0000).contains(&address) {
241 return false;
242 }
243
244 #[cfg(feature = "esp32p4")]
245 if !(0x4FF0_0000..=0x4FFC_0000).contains(&address) {
246 return false;
247 }
248
249 #[cfg(feature = "esp32s2")]
250 if !(0x3FFB_0000..=0x4000_0000).contains(&address) {
251 return false;
252 }
253
254 #[cfg(feature = "esp32s3")]
255 if !(0x3FC8_8000..=0x3FD0_0000).contains(&address) {
256 return false;
257 }
258
259 true
260}
261
262#[cfg(all(
263 any(
264 not(any(feature = "esp32", feature = "esp32p4", feature = "esp32s3")),
265 not(feature = "halt-cores")
266 ),
267 not(feature = "custom-halt")
268))]
269#[allow(unused)]
270fn halt() -> ! {
271 loop {
272 continue;
273 }
274}
275
276#[cfg(feature = "custom-halt")]
277fn halt() -> ! {
278 extern "Rust" {
279 fn custom_halt() -> !;
280 }
281 unsafe { custom_halt() }
282}
283
284#[cfg(all(any(feature = "esp32", feature = "esp32s3"), feature = "halt-cores"))]
286#[allow(unused)]
287fn halt() -> ! {
288 #[cfg(feature = "esp32")]
289 mod registers {
290 pub(crate) const OPTIONS0: u32 = 0x3ff48000;
291 pub(crate) const SW_CPU_STALL: u32 = 0x3ff480ac;
292 }
293
294 #[cfg(feature = "esp32p4")]
295 mod registers {
296 pub(crate) const SW_CPU_STALL: u32 = 0x50115200;
297 }
298
299 #[cfg(feature = "esp32s3")]
300 mod registers {
301 pub(crate) const OPTIONS0: u32 = 0x60008000;
302 pub(crate) const SW_CPU_STALL: u32 = 0x600080bc;
303 }
304
305 let sw_cpu_stall = registers::SW_CPU_STALL as *mut u32;
306
307 #[cfg(feature = "esp32p4")]
308 unsafe {}
309
310 #[cfg(not(feature = "esp32p4"))]
311 unsafe {
312 let options0 = registers::OPTIONS0 as *mut u32;
318
319 options0.write_volatile(options0.read_volatile() & !(0b1111) | 0b1010);
320
321 sw_cpu_stall.write_volatile(
322 sw_cpu_stall.read_volatile() & !(0b111111 << 20) & !(0b111111 << 26)
323 | (0x21 << 20)
324 | (0x21 << 26),
325 );
326 }
327
328 loop {}
329}
330
331#[cfg(not(feature = "custom-pre-backtrace"))]
332#[allow(unused)]
333fn pre_backtrace() {}
334
335#[cfg(feature = "custom-pre-backtrace")]
336fn pre_backtrace() {
337 extern "Rust" {
338 fn custom_pre_backtrace();
339 }
340 unsafe { custom_pre_backtrace() }
341}