Backtrace tweaks (#4012)

* Disallow multiple halt methods

* Warn for nonsense config

* Use DRAM range from metadata
This commit is contained in:
Dániel Buga 2025-09-01 14:53:02 +02:00 committed by GitHub
parent af1956d477
commit 55d8228987
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 81 additions and 96 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `exception-handler` now panics. (#3838)
- Only halt cores in panics when `halt-cores` feature is enabled. (#4010)
- It is no longer possible to select multiple halt method features (`halt-cores`, `custom-halt`, `semihosting`) (#4012)
### Fixed

View File

@ -23,6 +23,7 @@ cfg-if = "1.0.0"
critical-section = "1.1.2"
defmt = { version = "1", optional = true }
esp-config = { version = "0.5.0", path = "../esp-config" }
esp-metadata-generated = { version = "0.1.0", path = "../esp-metadata-generated" }
esp-println = { version = "0.15.0", optional = true, default-features = false, path = "../esp-println" }
heapless = "0.8"
semihosting = { version = "0.1.20", optional = true }
@ -34,13 +35,13 @@ esp-config = { version = "0.5.0", path = "../esp-config", features = ["build"]
[features]
default = ["colors"]
esp32 = ["esp-println?/esp32", "semihosting?/openocd-semihosting", "print-float-registers"]
esp32c2 = ["esp-println?/esp32c2"]
esp32c3 = ["esp-println?/esp32c3"]
esp32c6 = ["esp-println?/esp32c6"]
esp32h2 = ["esp-println?/esp32h2"]
esp32s2 = ["esp-println?/esp32s2", "semihosting?/openocd-semihosting"]
esp32s3 = ["esp-println?/esp32s3", "semihosting?/openocd-semihosting", "print-float-registers"]
esp32 = ["esp-println?/esp32", "esp-metadata-generated/esp32", "semihosting?/openocd-semihosting", "print-float-registers"]
esp32c2 = ["esp-println?/esp32c2", "esp-metadata-generated/esp32c2"]
esp32c3 = ["esp-println?/esp32c3", "esp-metadata-generated/esp32c3"]
esp32c6 = ["esp-println?/esp32c6", "esp-metadata-generated/esp32c6"]
esp32h2 = ["esp-println?/esp32h2", "esp-metadata-generated/esp32h2"]
esp32s2 = ["esp-println?/esp32s2", "esp-metadata-generated/esp32s2", "semihosting?/openocd-semihosting"]
esp32s3 = ["esp-println?/esp32s3", "esp-metadata-generated/esp32s3", "semihosting?/openocd-semihosting", "print-float-registers"]
## Use `esp-println`
println = ["dep:esp-println"]
@ -60,6 +61,8 @@ custom-halt = []
custom-pre-backtrace = []
## Halt both CPUs on ESP32 / ESP32-S3 instead of doing a `loop {}` in case of a panic
halt-cores = []
## Exit with a semihosting call in case of a panic
semihosting = ["dep:semihosting"]
## Include a panic handler
panic-handler = []

View File

@ -1,5 +1,16 @@
use esp_config::generate_config_from_yaml_definition;
#[macro_export]
macro_rules! assert_unique_features {
($($feature:literal),+ $(,)?) => {
assert!(
(0 $(+ cfg!(feature = $feature) as usize)+ ) <= 1,
"At most one of the following features must be enabled: {}",
[$($feature),+].join(", ")
);
};
}
#[macro_export]
macro_rules! assert_unique_used_features {
($($feature:literal),+ $(,)?) => {
@ -15,8 +26,17 @@ fn main() {
// Ensure that exactly a backend is selected:
assert_unique_used_features!("defmt", "println");
if cfg!(feature = "custom-halt") && cfg!(feature = "halt-cores") {
panic!("Only one of `custom-halt` and `halt-cores` can be enabled");
// Ensure that there aren't multiple halt methods selected:
assert_unique_features!("custom-halt", "halt-cores", "semihosting");
if !cfg!(feature = "panic-handler")
&& cfg!(any(
feature = "custom-halt",
feature = "halt-cores",
feature = "semihosting"
))
{
print_warning("A halt method is selected, but esp-backtrace is not the panic handler.")
}
// emit config
@ -25,3 +45,7 @@ fn main() {
.expect("Failed to read esp_config.yml for esp-backtrace");
generate_config_from_yaml_definition(&cfg_yaml, true, true, None).unwrap();
}
fn print_warning(message: impl core::fmt::Display) {
println!("cargo:warning={message}");
}

View File

@ -25,6 +25,9 @@
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
#![no_std]
#[macro_use]
extern crate esp_metadata_generated;
#[cfg(feature = "defmt")]
use defmt as _;
#[cfg(feature = "println")]
@ -120,67 +123,17 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
abort();
}
// Ensure that the address is in DRAM and that it is 16-byte aligned.
// Ensure that the address is in DRAM.
//
// Based loosely on the `esp_stack_ptr_in_dram` function from
// `components/esp_hw_support/include/esp_memory_utils.h` in ESP-IDF.
//
// Address ranges can be found in `components/soc/$CHIP/include/soc/soc.h` as
// `SOC_DRAM_LOW` and `SOC_DRAM_HIGH`.
// Address ranges can be found in `esp-metadata/devices/$CHIP.toml` in the `device` table.
fn is_valid_ram_address(address: u32) -> bool {
if (address & 0xF) != 0 {
return false;
}
#[cfg(feature = "esp32")]
if !(0x3FFA_E000..=0x4000_0000).contains(&address) {
return false;
}
#[cfg(feature = "esp32c2")]
if !(0x3FCA_0000..=0x3FCE_0000).contains(&address) {
return false;
}
#[cfg(feature = "esp32c3")]
if !(0x3FC8_0000..=0x3FCE_0000).contains(&address) {
return false;
}
#[cfg(feature = "esp32c6")]
if !(0x4080_0000..=0x4088_0000).contains(&address) {
return false;
}
#[cfg(feature = "esp32h2")]
if !(0x4080_0000..=0x4085_0000).contains(&address) {
return false;
}
#[cfg(feature = "esp32s2")]
if !(0x3FFB_0000..=0x4000_0000).contains(&address) {
return false;
}
#[cfg(feature = "esp32s3")]
if !(0x3FC8_8000..=0x3FD0_0000).contains(&address) {
return false;
}
true
memory_range!("DRAM").contains(&address)
}
#[cfg(feature = "halt-cores")]
fn halt() -> ! {
cfg_if::cfg_if! {
if #[cfg(feature = "custom-halt")] {
// call custom code
unsafe extern "Rust" {
fn custom_halt() -> !;
}
unsafe { custom_halt() }
} else if #[cfg(any(feature = "esp32", feature = "esp32s3"))] {
// multi-core
fn halt() {
#[cfg(any(feature = "esp32", feature = "esp32s3"))]
{
#[cfg(feature = "esp32")]
mod registers {
pub(crate) const OPTIONS0: u32 = 0x3ff48000;
@ -212,9 +165,6 @@ fn halt() -> ! {
);
}
}
}
loop {}
}
#[cfg(feature = "panic-handler")]
@ -236,13 +186,20 @@ fn abort() -> ! {
cfg_if::cfg_if! {
if #[cfg(feature = "semihosting")] {
critical_section::with(|_| {
semihosting::process::abort();
});
} else if #[cfg(feature = "halt-cores")] {
halt();
} else {
critical_section::with(|_| {
loop {}
})
} else if #[cfg(feature = "custom-halt")] {
// call custom code
unsafe extern "Rust" {
fn custom_halt() -> !;
}
unsafe { custom_halt() }
}
}
#[allow(unreachable_code)]
critical_section::with(|_| loop {})
}