panic_ramdump/lib.rs
1//! Writes panic messages to the beginning of RAM
2//!
3//! This crate contains an implementation of `panic_fmt` that logs panic messages to the beginning
4//! of RAM, recklessly overwriting the previous contents of that area. After logging the message
5//! the panic handler goes into an infinite loop, so a debugging probe can connect and pick up the
6//! panic.
7//!
8//! Unlike other methods this allows to discover the panic reason post-mortem by attaching a
9//! debugger probe after the device crashed.
10//!
11//! Currently this crate was only tested on ARM Cortex-M architecture but should be easily portable
12//! to other platforms as required.
13//!
14//! # Usage
15//!
16//! ``` ignore
17//! #![no_std]
18//!
19//! extern crate panic_ramdump;
20//!
21//! fn main() {
22//! panic!("FOO")
23//! }
24//! ```
25//!
26//! ``` text
27//! (gdb) x/s 0x20000000
28//! 0x20000000: "panicked at 'FOO!', src/main.rs:6:5\n\276\244\001"
29//! ```
30//!
31#![allow(clippy::empty_loop)]
32#![deny(missing_docs)]
33#![deny(warnings)]
34#![no_std]
35
36use core::fmt::Write;
37use core::panic::PanicInfo;
38
39use cortex_m::interrupt;
40
41struct Ram {
42 offset: u32,
43}
44
45/// Internal Write implementation to output the formatted panic string into RAM
46impl core::fmt::Write for Ram {
47 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
48 // Obtain RAM start address from linker symbol _sbss
49 extern "C" {
50 static mut __sbss: u8;
51 }
52
53 let data = s.as_bytes();
54 let len = data.len();
55
56 unsafe {
57 core::ptr::copy(
58 data.as_ptr() as *mut u8,
59 (&mut __sbss as *mut u8).offset(self.offset as isize),
60 len,
61 )
62 };
63
64 self.offset += len as u32;
65 Ok(())
66 }
67}
68
69#[panic_handler]
70fn panic(info: &PanicInfo) -> ! {
71 interrupt::disable();
72
73 writeln!(Ram { offset: 0 }, "{}", info).ok();
74
75 loop {}
76}