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
// Auto-generated. Do not modify this file! Instead modify examples/exception.rs
//! Exceptions handlers are smart! They help you find the source of crashes
//!
//! At the end there's a program that crashes. Run it with `(gdb) continue`:
//!
//! By the time you hit the exception, you'll see the following output in `itmdump`:
//!
//! ``` text
//! $ itmdump /tmp/itm.fifo
//! (..)
//! EXCEPTION HardFault @ PC=0x080000a2
//! ```
//!
//! which indicates that this is a "hard fault" exception. It also tells you were the crash
//! originated! The PC (Program Counter) value is the address of the instruction that generated the
//! crash. You can disassemble your program around that address using GDB:
//!
//! ``` text
//! (gdb) disas /m 0x080000a2
//! Dump of assembler code for function exception::main:
//! 32      pub extern "C" fn main() -> ! {
//!    0x08000092 <+0>:     sub     sp, #8
//!    0x08000094 <+2>:     b.n     0x8000096 <exception::main+4>
//!
//! 33          // This reads beyond the boundary of available RAM (40KiB starting at
//! 34          // 0x4000_0000) and triggers a hard fault exception
//! 35          let _hard_fault_exception = unsafe {
//! 36              *((0x4000_0000 + 40 * 1024) as *const u32)
//!    0x08000096 <+4>:     b.n     0x8000098 <exception::main+6>
//!    0x08000098 <+6>:     b.n     0x800009a <exception::main+8>
//!    0x0800009a <+8>:     movw    r0, #40960      ; 0xa000
//!    0x0800009e <+12>:    movt    r0, #16384      ; 0x4000
//!    0x080000a2 <+16>:    ldr     r0, [r0, #0]    ; <--
//!    0x080000a4 <+18>:    str     r0, [sp, #4]
//!
//! 37          };
//! 38
//! 39          loop {}
//!    0x080000a6 <+20>:    b.n     0x80000a8 <exception::main+22>
//!    0x080000a8 <+22>:    b.n     0x80000a8 <exception::main+22>
//!
//! End of assembler dump.
//! ```
//!
//! `ldr r0, [r0, #0]` is the faulty instruction. It tries to load the word at the address that `r0`
//! indicates. From the two previous instructions, you can tell that `r0` holds the value
//! `0x4000a000`.
//!
//! Wait! That's not everything. There's also a local `sf` variable that points to the stack frame
//! where the exception occurred. If you print it under GDB, you'll see the state of several
//! registers at the moment of the crash:
//!
//! ``` text
//! (gdb) p/x *sf
//! $1 = {r0 = 0x4000a000, r1 = 0x48001000, r2 = 0x55550000, r3 = 0x48001000,
//!   r12 = 0x8003950, lr = 0x8000085, pc = 0x80000a2, xpsr = 0x1000000}
//! ```
//!
//! See? `r0 = 0x4000a000` that matches our expectations from reading the disassembly.
//!
//! ``` rust,no_run
//! #![no_main]
//! #![no_std]
//!
//! extern crate f3;
//!
//! #[export_name = "main"]
//! pub extern "C" fn main() -> ! {
//!     // This reads beyond the boundary of available RAM (40KiB starting at
//!     // 0x4000_0000) and triggers an exception
//!     let _hard_fault_exception =
//!         unsafe { *((0x4000_0000 + 40 * 1024) as *const u32) };
//!
//!     loop {}
//! }
//! ```