[Embedded Rust] How can one debug STM32/OpenOCD from CLion/IntelliJ Rust?

I'm trying to debug an ARM binary running on a STM32F3DISCOVERY board using CLion + IntelliJ Rust.

I've been following @japaric's excellent discovery blog, where he describes how to debug an STM32 binary using gdb from the command line through openocd, and that works great:

gdb

For increased productivity, I'd like to debug natively within the CLion IDE.

The openocd command used is:

$ openocd \
  -f interface/stlink-v2-1.cfg \
  -f target/stm32f3x.cfg

Which opens a GDB server on port 3333.

The sample program I am trying to load is from an LED routlette example:

#![deny(unsafe_code)]
#![no_main]
#![no_std]

extern crate aux5;
#[macro_use]
extern crate cortex_m_rt;

use aux5::prelude::*;
use aux5::{Delay, Leds};

entry!(main);

fn main() -> ! {
    let (mut delay, mut leds): (Delay, Leds) = aux5::init();

    let ms = 50_u8;
    loop {
        for curr in 0..8 {
            let next = (curr + 1) % 8;

            leds[next].on();
            delay.delay_ms(ms);
            leds[curr].off();
            delay.delay_ms(ms);
        }
    }
}

CLion supports a Remote Debug run configuration, which I've so far configured like (testing in CLion 2018.1.6 on macOS):

If a binary has already been loaded through gdb from the command line, CLion is able to connect and run the binary remotely, and pausing will pause the microcontroller and show disassembly in the CLion window.

The following things don't work at the moment:

  • Loading a compiled binary from CLion
  • Viewing / stepping through the Rust source
  • Inputting breakpoints from the IDE

Does anyone have any ideas on how to improve this?

It looks like one user, @perlindgren has attempted this as well:

I'm experimenting with debugging Rust on embedded (Nucleo STM32F401re) using openocd and arm-none-eabi-gdb. I have it somewhat working. Here is the current status.

  1. The program is not loaded. (I had to use the pause and in the gdb console load it, the file has the right path, so it loads correctly)
  2. Breakpoints do not work, setting them in the IDE has no effect, stepping works and even (surprisingly) run to line. Setting breakpoints in the gdb console works fine.
  3. Variables are sometimes not shown. When they work, they are also updated in the source file. However mouse overs never work.
  4. Watching local (stack) as well as static (heap) variables always work.

I'm on the latest nightly xargo/cargo and nightly rustup channel. Arch linux with the CLion December 26 build. The bebug config:
/usr/bin/arm-none-eabi-gdb
(GNU gdb (GDB) 8.0.1)
'target remote' args: :3333
Symbol file:/home/pln/CLionProjects/rtfm-app/target/thumbv7em-none-eabihf/debug/examples/bare0
Sysroot:
(Empty)

To me it seems not so far from working and the Rust support in CLion looks promising (perhaps the best amongst RustDT (not supported), and vscode (RLS based)). So a couple of questions/remarks.
.gbinit will run before the 'target remote' from the plugin is launched. I tried to use that to load the binary, but I did not get that to work. It would be better with a 'classic' script option, allowing you to override the default connection procedure. Regarding the breakpoint integration, I have no clue what is wrong, as there seems to be some connection in between the IDE and gdb. (Rust uses C++ style namespaces/symbols, so that should not be a problem.) Another observation, if you try run to line, on a line not reachable, the debugger will not halt even if you press pause. I also tried using the OpenOCD Dowload & Run plugin, but it did not do the trick as being tailored to C/C++ (It could be a good stard for a dedicated Rust embedded debug plugin though...).

CC @matklad @Undin

1 Like

I would also be interested what the answer is.

@stefaneicher you can up vote / follow this Intellij Rust GitHub issue.

If anyone else runs into issues with this, its possible that your OpenOCD config for your board is incorrect.

Like the OP I'm following along the discovery tutorial (which has moved to a full book here).

In CLion/IntelliJ all you need to do is create an OpenOCD Download and Run, you don't need the GDB Remote Debug job as the OpenOCD task will start its own.

You don't need a Target, but if you accidentally choose one, it won't let you unchoose it, so you can make one that "Does Nothing".

The executable will be your debug build file (you can see mine is led-roulette).

Leave it using the built in gdb as this is a multi-arch build which will work.

Now, the board config file. After banging my head on this for a while, I decided to just look inside it. Finding it is a bit tricky, mine (on a Mac) was located here:

usr/local/Cellar/open-ocd/0.10.0/share/openocd/scripts/board/stm32f3discovery.cfg

Here it is in full

# This is an STM32F3 discovery board with a single STM32F303VCT6 chip.
# http://www.st.com/internet/evalboard/product/254044.jsp

source [find interface/stlink-v2.cfg]

transport select hla_swd

source [find target/stm32f3x.cfg]

reset_config srst_only

What you might notice is that it references almost the same files as the tutorial uses from the command line... but the version number on the first one is wrong.

interface/stlink-v2-1.cfg vs source [find interface/stlink-v2.cfg]

I duplicated the file (in the same directory) and changed that line, and my duplicated file then showed up in IntelliJs "Assist".

There's one more thing to do though. At the bottom in the Before Launch you'll need to get rid of the "Build" task and add in one to build your project. Frustratingly you can't use Cargo tasks here (it runs them but then doesn't run the OpenOCD task). Instead I just created an external task to run cargo build from the command line.

After I did that, it works pretty much as expected. You can put in break points, reset the MCU from the IDE and step through your code.

1 Like