1#![cfg_attr(target_arch = "riscv32", doc = "\n")]
6#![cfg_attr(
7 target_arch = "riscv32",
8 doc = "\nPlease note that you **need** to force frame pointers (i.e. `\"-C\", \"force-frame-pointers\",` in your `.cargo/config.toml`).\n"
9)]
10#![cfg_attr(
11 target_arch = "riscv32",
12 doc = "Otherwise the panic handler will emit a stack dump which needs tooling to decode it.\n\n"
13)]
14#![cfg_attr(target_arch = "riscv32", doc = "\n")]
15#![doc = document_features::document_features!()]
21#![doc = ""]
28#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_backtrace_config_table.md"))]
29#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
30#![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))]
31#![no_std]
32
33#[macro_use]
34extern crate esp_metadata_generated;
35
36#[cfg(feature = "defmt")]
37use defmt as _;
38#[cfg(feature = "println")]
39use esp_println as _;
40
41const MAX_BACKTRACE_ADDRESSES: usize =
42 esp_config::esp_config_int!(usize, "ESP_BACKTRACE_CONFIG_BACKTRACE_FRAMES");
43
44pub struct Backtrace(pub(crate) heapless::Vec<BacktraceFrame, MAX_BACKTRACE_ADDRESSES>);
45
46impl Backtrace {
47 #[inline]
49 pub fn capture() -> Self {
50 arch::backtrace()
51 }
52
53 #[inline]
55 pub fn frames(&self) -> &[BacktraceFrame] {
56 &self.0
57 }
58}
59
60pub struct BacktraceFrame {
61 pub(crate) pc: usize,
62}
63
64impl BacktraceFrame {
65 pub fn program_counter(&self) -> usize {
66 self.pc - crate::arch::RA_OFFSET
67 }
68}
69
70#[cfg(feature = "panic-handler")]
71const RESET: &str = "\u{001B}[0m";
72#[cfg(feature = "panic-handler")]
73const RED: &str = "\u{001B}[31m";
74
75#[cfg(all(feature = "panic-handler", feature = "defmt"))]
76macro_rules! println {
77 ($($arg:tt)*) => {
78 defmt::error!($($arg)*);
79 };
80}
81
82#[cfg(all(feature = "panic-handler", feature = "defmt", stack_dump))]
83pub(crate) use println;
84
85#[cfg(all(feature = "panic-handler", feature = "println"))]
86macro_rules! println {
87 ($($arg:tt)*) => {
88 esp_println::println!($($arg)*);
89 };
90}
91
92#[cfg(feature = "panic-handler")]
93fn set_color_code(_code: &str) {
94 #[cfg(all(feature = "colors", feature = "println"))]
95 {
96 println!("{}", _code);
97 }
98}
99
100#[cfg_attr(target_arch = "riscv32", path = "riscv.rs")]
101#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")]
102pub(crate) mod arch;
103
104#[cfg(feature = "panic-handler")]
105#[panic_handler]
106fn panic_handler(info: &core::panic::PanicInfo) -> ! {
107 pre_backtrace();
108
109 set_color_code(RED);
110 println!("");
111 println!("====================== PANIC ======================");
112
113 println!("{}", info);
114 set_color_code(RESET);
115
116 cfg_if::cfg_if! {
117 if #[cfg(not(stack_dump))]
118 {
119 println!("");
120 println!("Backtrace:");
121 println!("");
122
123 let backtrace = Backtrace::capture();
124 #[cfg(target_arch = "riscv32")]
125 if backtrace.frames().is_empty() {
126 println!(
127 "No backtrace available - make sure to force frame-pointers. (see https://crates.io/crates/esp-backtrace)"
128 );
129 }
130 for frame in backtrace.frames() {
131 println!("0x{:x}", frame.program_counter());
132 }
133 } else {
134 arch::dump_stack();
135 }
136 }
137
138 abort()
139}
140
141fn is_valid_ram_address(address: u32) -> bool {
145 memory_range!("DRAM").contains(&address)
146}
147
148#[cfg(feature = "halt-cores")]
149fn halt() {
150 #[cfg(any(feature = "esp32", feature = "esp32s3"))]
151 {
152 #[cfg(feature = "esp32")]
153 mod registers {
154 pub(crate) const OPTIONS0: u32 = 0x3ff48000;
155 pub(crate) const SW_CPU_STALL: u32 = 0x3ff480ac;
156 }
157
158 #[cfg(feature = "esp32s3")]
159 mod registers {
160 pub(crate) const OPTIONS0: u32 = 0x60008000;
161 pub(crate) const SW_CPU_STALL: u32 = 0x600080bc;
162 }
163
164 let sw_cpu_stall = registers::SW_CPU_STALL as *mut u32;
165
166 unsafe {
167 let options0 = registers::OPTIONS0 as *mut u32;
173
174 options0.write_volatile(options0.read_volatile() & !(0b1111) | 0b1010);
175
176 sw_cpu_stall.write_volatile(
177 sw_cpu_stall.read_volatile() & !(0b111111 << 20) & !(0b111111 << 26)
178 | (0x21 << 20)
179 | (0x21 << 26),
180 );
181 }
182 }
183}
184
185#[cfg(feature = "panic-handler")]
186fn pre_backtrace() {
187 #[cfg(feature = "custom-pre-backtrace")]
188 {
189 unsafe extern "Rust" {
190 fn custom_pre_backtrace();
191 }
192 unsafe { custom_pre_backtrace() }
193 }
194}
195
196#[cfg(feature = "panic-handler")]
197fn abort() -> ! {
198 println!("");
199 println!("");
200 println!("");
201
202 cfg_if::cfg_if! {
203 if #[cfg(feature = "semihosting")] {
204 arch::interrupt_free(|| {
205 semihosting::process::abort();
206 });
207 } else if #[cfg(feature = "halt-cores")] {
208 halt();
209 } else if #[cfg(feature = "custom-halt")] {
210 unsafe extern "Rust" {
212 fn custom_halt() -> !;
213 }
214 unsafe { custom_halt() }
215 }
216 }
217
218 #[allow(unreachable_code)]
219 arch::interrupt_free(|| {
220 #[allow(clippy::empty_loop)]
221 loop {}
222 })
223}