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
//! Writes panic messages to the beginning of RAM //! //! This crate contains an implementation of `panic_fmt` that logs panic messages to the beginning //! of RAM, recklessly overwriting the previous contents of that area. After logging the message //! the panic handler goes into an infinite loop, so a debugging probe can connect and pick up the //! panic. //! //! Unlike other methods this allows to discover the panic reason post-mortem by attaching a //! debugger probe after the device crashed. //! //! Currently this crate was only tested on ARM Cortex-M architecture but should be easily portable //! to other platforms as required. //! //! # Usage //! //! ``` ignore //! #![no_std] //! //! extern crate panic_ramdump; //! //! fn main() { //! panic!("FOO") //! } //! ``` //! //! ``` text //! (gdb) x/s 0x20000000 //! 0x20000000: "panicked at 'FOO!', src/main.rs:6:5\n\276\244\001" //! ``` //! #![allow(clippy::empty_loop)] #![deny(missing_docs)] #![deny(warnings)] #![no_std] use core::fmt::Write; use core::panic::PanicInfo; use cortex_m::interrupt; struct Ram { offset: u32, } /// Internal Write implementation to output the formatted panic string into RAM impl core::fmt::Write for Ram { fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { // Obtain RAM start address from linker symbol _sbss extern "C" { static mut __sbss: u8; } let data = s.as_bytes(); let len = data.len(); unsafe { core::ptr::copy( data.as_ptr() as *mut u8, (&mut __sbss as *mut u8).offset(self.offset as isize), len, ) }; self.offset += len as u32; Ok(()) } } #[panic_handler] fn panic(info: &PanicInfo) -> ! { interrupt::disable(); writeln!(Ram { offset: 0 }, "{}", info).ok(); loop {} }