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 {}
}