Module f3::examples::exception [] [src]

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:

$ 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:

(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:

(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.

#![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 {}
}Run