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