1//! Panic handler for `probe-run`.
2//!
3//! When this panic handler is used, panics will make `probe-run` print a backtrace and exit with a
4//! non-zero status code, indicating failure. This building block can be used to run on-device
5//! tests.
6//!
7//! # Panic Messages
8//!
9//! By default, `panic-probe` *ignores* the panic message. You can enable one of the following
10//! features to print it instead:
11//!
12//! - `print-rtt`: Prints the panic message over plain RTT (via `rtt-target`). RTT must be
13//! initialized by the app.
14//! - `print-defmt`: Prints the panic message via [defmt]'s transport (note that defmt will not be
15//! used to efficiently format the message).
16//!
17//! [defmt]: https://github.com/knurling-rs/defmt/
18
19#![no_std]
20#![cfg(target_os = "none")]
21#![doc(html_logo_url = "https://knurling.ferrous-systems.com/knurling_logo_light_text.svg")]
22
23#[cfg(not(cortex_m))]
24compile_error!("`panic-probe` only supports Cortex-M targets (thumbvN-none-eabi[hf])");
25
26// Functionality `cfg`d out on platforms with OS/libstd.
27#[cfg(target_os = "none")]
28mod imp {
29 use core::panic::PanicInfo;
30 use core::sync::atomic::{AtomicBool, Ordering};
31
32 #[cfg(feature = "print-rtt")]
33 use crate::print_rtt::print;
34
35 #[cfg(feature = "print-defmt")]
36 use crate::print_defmt::print;
37
38 #[cfg(not(any(feature = "print-rtt", feature = "print-defmt")))]
39 fn print(_: &core::panic::PanicInfo) {}
40
41 #[panic_handler]
42 fn panic(info: &PanicInfo) -> ! {
43 static PANICKED: AtomicBool = AtomicBool::new(false);
44
45 cortex_m::interrupt::disable();
46
47 // Guard against infinite recursion, just in case.
48 if !PANICKED.load(Ordering::Relaxed) {
49 PANICKED.store(true, Ordering::Relaxed);
50
51 print(info);
52 }
53
54 crate::hard_fault();
55 }
56}
57
58/// Trigger a `HardFault` via `udf` instruction.
59///
60/// This function may be used to as `defmt::panic_handler` to avoid double prints.
61///
62/// # Examples
63///
64/// ```
65/// #[defmt::panic_handler]
66/// fn panic() -> ! {
67/// panic_probe::hard_fault();
68/// }
69/// ```
70#[cfg(target_os = "none")]
71pub fn hard_fault() -> ! {
72 // If `UsageFault` is enabled, we disable that first, since otherwise `udf` will cause that
73 // exception instead of `HardFault`.
74 #[cfg(not(any(armv6m, armv8m_base)))]
75 {
76 const SHCSR: *mut u32 = 0xE000ED24usize as _;
77 const USGFAULTENA: usize = 18;
78
79 unsafe {
80 let mut shcsr = core::ptr::read_volatile(SHCSR);
81 shcsr &= !(1 << USGFAULTENA);
82 core::ptr::write_volatile(SHCSR, shcsr);
83 }
84 }
85
86 cortex_m::asm::udf();
87}
88
89#[cfg(feature = "print-rtt")]
90mod print_rtt {
91 use core::panic::PanicInfo;
92 use rtt_target::rprintln;
93
94 pub fn print(info: &PanicInfo) {
95 rprintln!("{}", info);
96 }
97}
98
99#[cfg(feature = "print-defmt")]
100mod print_defmt {
101 use core::panic::PanicInfo;
102
103 pub fn print(info: &PanicInfo) {
104 defmt::error!("{}", defmt::Display2Format(info));
105 }
106}
107