panic_semihosting/
lib.rs

1//! Report panic messages to the host stderr using semihosting
2//!
3//! This crate contains an implementation of `panic_fmt` that logs panic messages to the host stderr
4//! using [`cortex-m-semihosting`]. Before logging the message the panic handler disables (masks)
5//! the device specific interrupts. After logging the message the panic handler trigger a breakpoint
6//! and then goes into an infinite loop.
7//!
8//! Currently, this crate only supports the ARM Cortex-M architecture.
9//!
10//! [`cortex-m-semihosting`]: https://crates.io/crates/cortex-m-semihosting
11//!
12//! # Usage
13//!
14//! ``` ignore
15//! #![no_std]
16//!
17//! extern crate panic_semihosting;
18//!
19//! fn main() {
20//!     panic!("FOO")
21//! }
22//! ```
23//!
24//! ``` text
25//! (gdb) monitor arm semihosting enable
26//! (gdb) continue
27//! Program received signal SIGTRAP, Trace/breakpoint trap.
28//! rust_begin_unwind (args=..., file=..., line=8, col=5)
29//!     at $CRATE/src/lib.rs:69
30//! 69          asm::bkpt();
31//! ```
32//!
33//! ``` text
34//! $ openocd -f (..)
35//! (..)
36//! panicked at 'FOO', src/main.rs:6:5
37//! ```
38//!
39//! # Optional features
40//!
41//! ## `exit`
42//!
43//! When this feature is enabled the panic handler performs an exit semihosting call after logging
44//! the panic message. This is useful when emulating the program on QEMU as it causes the QEMU
45//! process to exit with a non-zero exit code; thus it can be used to implement Cortex-M tests that
46//! run on the host.
47//!
48//! We discourage using this feature when the program will run on hardware as the exit call can
49//! leave the hardware debugger in an inconsistent state.
50
51#![cfg(all(target_arch = "arm", target_os = "none"))]
52#![deny(missing_docs)]
53#![deny(warnings)]
54#![no_std]
55
56extern crate cortex_m;
57extern crate cortex_m_semihosting as sh;
58
59use core::fmt::Write;
60use core::panic::PanicInfo;
61
62#[cfg(not(feature = "exit"))]
63use cortex_m::asm;
64use cortex_m::interrupt;
65#[cfg(feature = "exit")]
66use sh::debug::{self, EXIT_FAILURE};
67use sh::hio;
68
69#[panic_handler]
70fn panic(info: &PanicInfo) -> ! {
71    interrupt::disable();
72
73    if let Ok(mut hstdout) = hio::hstdout() {
74        writeln!(hstdout, "{}", info).ok();
75    }
76
77    match () {
78        // Exit the QEMU process
79        #[cfg(feature = "exit")]
80        () => debug::exit(EXIT_FAILURE),
81        // OK to fire a breakpoint here because we know the microcontroller is connected to a
82        // debugger
83        #[cfg(not(feature = "exit"))]
84        () => asm::bkpt(),
85    }
86
87    loop {}
88}