From 9f49f9eb5932d27f4271b732d9676e6b959750c7 Mon Sep 17 00:00:00 2001 From: Per Lindgren <per.lindgren@ltu.se> Date: Thu, 30 Jan 2020 16:27:53 +0100 Subject: [PATCH] panic --- Cargo.toml | 1 + README.md | 11 +++++------ examples/itm.rs | 5 ++--- examples/panic.rs | 28 ++++++++++++++++++++++++++++ openocd.gdb | 24 ++++++++++++++++++++---- 5 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 examples/panic.rs diff --git a/Cargo.toml b/Cargo.toml index ab13ba6..1577f79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ cortex-m-semihosting = "0.3.5" cortex-m = "0.6.2" aligned = "0.3.2" ufmt = "0.1.0" +panic-itm = "0.4.1" [dependencies.cortex-m-rt] version = "0.6.12" diff --git a/README.md b/README.md index c3bf7f2..b0e3a53 100644 --- a/README.md +++ b/README.md @@ -127,15 +127,14 @@ In a separate terminal: ``` console $ mkfifo /tmp/itm.fifo -$ itmdump -f /tmp/itm.fifo -F +$ itmdump -f /tmp/itm.fifo +Hello, again! ``` Now you can compile and run the `itm.rs` application using the same steps as the `hello` program. In the `itmdump` console you should now have the trace output. ``` console -$ mkfifo /tmp/itm.log -$ itmdump -f /tmp/itm.log -F -Hello, again! +$ cargo run --example itm ``` Under the hood there is much less overhead, the serial transfer rate is set to 2MBit in between the ITM (inside of the MCU) and `stlink` programmer (onboard the Nucleo devkit). So in theory we can transmit some 200kByte/s data over ITM. However, we are limited by the USB interconnection and `openocd` to receive and forward packages. @@ -146,7 +145,7 @@ The `stlink` programmer, buffers packages but has limited buffer space. Hence in ### Rust `panic` Handling -The `rust` compiler statically analyses your code, but in cases some errors cannot be detected at compile time (e.g., array indexing out of bounds, division by zore etc.). The `rust` compiler generates code checking such faults at run-time, instead of just crashing (or even worse, continuing with faulty/undefined values like a `C` program would) . A fault in Rust will render a `panic`, whith an associated error message (useful to debugging the application). We can choose how such `panic`s should be treated, e.g., transmitting the error message using `semihosting`, `ITM`, some other channel (e.g. a serial port), or simply aborting the program. +The `rust` compiler statically analyses your code, but in cases some errors cannot be detected at compile time (e.g., array indexing out of bounds, division by zero etc.). The `rust` compiler generates code checking such faults at run-time, instead of just crashing (or even worse, continuing with faulty/undefined values like a `C` program would) . A fault in Rust will render a `panic`, with an associated error message (useful to debugging the application). We can choose how such `panic`s should be treated, e.g., transmitting the error message using `semihosting`, `ITM`, some other channel (e.g. a serial port), or simply aborting the program. The `panic` example demonstrates some possible use cases. @@ -169,7 +168,7 @@ Breakpoint 1, rust_begin_unwind (_info=0x20017fb4) $1 = core::panic::PanicInfo {payload: core::any::&Any {pointer: 0x8000760 <.Lanon.21a036e607595cc96ffa1870690e4414.142> "\017\004\000", vtable: 0x8000760 <.Lanon.21a036e607595cc96ffa1870690e4414.142>}, message: core::option::Option<&core::fmt::Arguments>::Some(0x20017fd0), location: core::panic::Location {file: <error reading variable>, line: 27, col: 5}} ``` -Here `p *_info` prints the arument to `rust_begin_unwind`, at the far end you will find `line: 27, col 5`, which correstponds to the source code calling `panic("Ooops")`. (`gdb` is not (yet) Rust aware enough to figure out how the `file` field should be interpreted, but at least we get some useful information). +Here `p *_info` prints the arument to `rust_begin_unwind`, at the far end you will find `line: 27, col 5`, which corresponds to the source code calling `panic("Ooops")`. (`gdb` is not (yet) Rust aware enough to figure out how the `file` field should be interpreted, but at least we get some useful information). Alternatively we can trace the panic message over `semihosting` (comment out `extern crate panic_halt` and uncomment `extern crate panic_semihosting`). diff --git a/examples/itm.rs b/examples/itm.rs index b4c9401..a522c0d 100644 --- a/examples/itm.rs +++ b/examples/itm.rs @@ -2,10 +2,9 @@ //! //! ITM is much faster than semihosting. Like 4 orders of magnitude or so. //! -//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two -//! `monitor` commands in the `.gdbinit` file. +//! You'll need [`itmdump`] to view the output. //! -//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/ +//! [`itmdump`]: https://docs.rs/itm/0.3.1/itm/ //! //! --- diff --git a/examples/panic.rs b/examples/panic.rs new file mode 100644 index 0000000..27ad333 --- /dev/null +++ b/examples/panic.rs @@ -0,0 +1,28 @@ +//! Changing the panicking behavior +//! +//! The easiest way to change the panicking behavior is to use a different [panic handler crate][0]. +//! +//! [0]: https://crates.io/keywords/panic-impl + +#![no_main] +#![no_std] + +// Pick one of these panic handlers: + +// `panic!` halts execution; the panic message is ignored +extern crate panic_halt; + +// Reports panic messages to the host stderr using semihosting +// NOTE to use this you need to uncomment the `panic-semihosting` dependency in Cargo.toml +// extern crate panic_semihosting; + +// Logs panic messages using the ITM (Instrumentation Trace Macrocell) +// NOTE to use this you need to uncomment the `panic-itm` dependency in Cargo.toml +//extern crate panic_itm; + +use cortex_m_rt::entry; + +#[entry] +fn main() -> ! { + panic!("Oops") +} diff --git a/openocd.gdb b/openocd.gdb index 92d2058..3d73217 100644 --- a/openocd.gdb +++ b/openocd.gdb @@ -1,11 +1,22 @@ target extended-remote :3333 set print asm-demangle on + monitor arm semihosting enable -monitor tpiu config internal /tmp/itm.fifo uart off 16000000 2000000 +# ITM tracing +# send captured ITM to the file (or fifo) /tmp/itm.fifo +# (the microcontroller SWO pin must be connected to the programmer SWO pin) +# 16000000 must match the core clock frequency +# in this case the speed of SWO will be negotiated +monitor tpiu config internal /tmp/itm.fifo uart off 16000000 + +# OR: make the microcontroller SWO pin output compatible with UART (8N1) +# 16000000 must match the core clock frequency +# 2000000 is the frequency of the SWO pin +# monitor tpiu config external uart off 16000000 2000000 -# enable itm ports +# enable ITM ports monitor itm port 0 on monitor itm port 1 on monitor itm port 2 on @@ -14,12 +25,17 @@ monitor itm port 2 on break main # detect unhandled exceptions, hard faults and panics +break DefaultHandler break HardFault -break core::panicking::panic_fmt +break rust_begin_unwind # un-comment to check that flashing was successful # compare-sections +# make sure the processor is reset before loading (flashing) monitor reset init + load -stepi \ No newline at end of file + +# start the process but immediately halt the processor +stepi -- GitLab