#![cfg_attr(target_arch = "riscv32", doc = "\n")]
#![cfg_attr(
target_arch = "riscv32",
doc = "\nPlease note that you **need** to force frame pointers (i.e. `\"-C\", \"force-frame-pointers\",` in your `.cargo/config.toml`).\n"
)]
#![cfg_attr(
target_arch = "riscv32",
doc = "Otherwise the panic handler will emit a stack dump which needs tooling to decode it.\n\n"
)]
#![cfg_attr(target_arch = "riscv32", doc = "\n")]
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
#![doc = ""]
#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_backtrace_config_table.md"))]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
#![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))]
#![no_std]
#[macro_use]
extern crate esp_metadata_generated;
#[cfg(feature = "defmt")]
use defmt as _;
#[cfg(feature = "println")]
use esp_println as _;
const MAX_BACKTRACE_ADDRESSES: usize =
esp_config::esp_config_int!(usize, "ESP_BACKTRACE_CONFIG_BACKTRACE_FRAMES");
#[derive(Clone)]
pub struct Backtrace(pub(crate) heapless::Vec<BacktraceFrame, MAX_BACKTRACE_ADDRESSES>);
impl Backtrace {
#[inline]
pub fn capture() -> Self {
arch::backtrace()
}
#[inline]
pub fn frames(&self) -> &[BacktraceFrame] {
&self.0
}
}
#[derive(Clone)]
pub struct BacktraceFrame {
pub(crate) pc: usize,
}
impl BacktraceFrame {
pub fn program_counter(&self) -> usize {
self.pc - crate::arch::RA_OFFSET
}
}
#[cfg(feature = "panic-handler")]
const RESET: &str = "\u{001B}[0m";
#[cfg(feature = "panic-handler")]
const RED: &str = "\u{001B}[31m";
#[cfg(all(feature = "panic-handler", feature = "defmt"))]
macro_rules! println {
($($arg:tt)*) => {
defmt::error!($($arg)*);
};
}
#[cfg(all(feature = "panic-handler", feature = "defmt", stack_dump))]
pub(crate) use println;
#[cfg(all(feature = "panic-handler", feature = "println"))]
macro_rules! println {
($($arg:tt)*) => {
esp_println::println!($($arg)*);
};
}
#[cfg(feature = "panic-handler")]
fn set_color_code(_code: &str) {
#[cfg(all(feature = "colors", feature = "println"))]
{
println!("{}", _code);
}
}
#[cfg_attr(target_arch = "riscv32", path = "riscv.rs")]
#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")]
pub(crate) mod arch;
#[cfg(feature = "panic-handler")]
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
pre_backtrace();
set_color_code(RED);
println!("");
println!("====================== PANIC ======================");
println!("{}", info);
set_color_code(RESET);
cfg_if::cfg_if! {
if #[cfg(not(stack_dump))]
{
println!("");
println!("Backtrace:");
println!("");
let backtrace = Backtrace::capture();
#[cfg(target_arch = "riscv32")]
if backtrace.frames().is_empty() {
println!(
"No backtrace available - make sure to force frame-pointers. (see https://crates.io/crates/esp-backtrace)"
);
}
for frame in backtrace.frames() {
println!("0x{:x}", frame.program_counter());
}
} else {
arch::dump_stack();
}
}
abort()
}
fn is_valid_ram_address(address: u32) -> bool {
memory_range!("DRAM").contains(&address)
}
#[cfg(feature = "halt-cores")]
fn halt() {
#[cfg(any(feature = "esp32", feature = "esp32s3"))]
{
#[cfg(feature = "esp32")]
mod registers {
pub(crate) const OPTIONS0: u32 = 0x3ff48000;
pub(crate) const SW_CPU_STALL: u32 = 0x3ff480ac;
}
#[cfg(feature = "esp32s3")]
mod registers {
pub(crate) const OPTIONS0: u32 = 0x60008000;
pub(crate) const SW_CPU_STALL: u32 = 0x600080bc;
}
let sw_cpu_stall = registers::SW_CPU_STALL as *mut u32;
unsafe {
let options0 = registers::OPTIONS0 as *mut u32;
options0.write_volatile(options0.read_volatile() & !(0b1111) | 0b1010);
sw_cpu_stall.write_volatile(
sw_cpu_stall.read_volatile() & !(0b111111 << 20) & !(0b111111 << 26)
| (0x21 << 20)
| (0x21 << 26),
);
}
}
}
#[cfg(feature = "panic-handler")]
fn pre_backtrace() {
#[cfg(feature = "custom-pre-backtrace")]
{
unsafe extern "Rust" {
fn custom_pre_backtrace();
}
unsafe { custom_pre_backtrace() }
}
}
#[cfg(feature = "panic-handler")]
fn abort() -> ! {
println!("");
println!("");
println!("");
cfg_if::cfg_if! {
if #[cfg(feature = "semihosting")] {
arch::interrupt_free(|| {
semihosting::process::abort();
});
} else if #[cfg(feature = "halt-cores")] {
halt();
} else if #[cfg(feature = "custom-halt")] {
unsafe extern "Rust" {
fn custom_halt() -> !;
}
unsafe { custom_halt() }
}
}
#[allow(unreachable_code)]
arch::interrupt_free(|| {
#[allow(clippy::empty_loop)]
loop {}
})
}