GithubHelp home page GithubHelp logo

knurling-rs / probe-run Goto Github PK

View Code? Open in Web Editor NEW
644.0 13.0 75.0 4.55 MB

Run embedded programs just like native ones

License: Apache License 2.0

Rust 100.00%
cargo-runner embedded-rust ferrous-systems

probe-run's Introduction

⚠️ As of 11.10.2023 probe-run is in maintainance mode. We recommend everyone to switch to probe-rs. Read following article on the why and on how to migrate: https://ferrous-systems.com/blog/probe-run-deprecation/

probe-run

Runs embedded programs just like native ones

probe-run is a custom Cargo runner that transparently runs Rust firmware on an embedded device.

probe-run is powered by probe-rs and thus supports all the devices and probes supported by probe-rs.

Features

  • Acts as a Cargo runner, integrating into cargo run.
  • Displays program output streamed from the device via RTT.
  • Exits the firmware and prints a stack backtrace on hardware breakpoints (e.g. bkpt), Rust panics and unrecoverable hardware exceptions (e.g. HardFault).

Installation

To install probe-run, use cargo install probe-run.

On Linux, you might have to install libudev and libusb from your package manager before installing probe-run.

# ubuntu
$ sudo apt install -y libusb-1.0-0-dev libudev-dev

# fedora
$ sudo dnf install -y libusbx-devel systemd-devel

Using the latest probe-rs

probe-run inherits device support from the probe-rs library. If your target chip does not appear in the output of probe-run --list-chips it could be that:

  1. The latest git version probe-rs supports your chip but the latest version on crates.io does not. You could try building probe-run against the latest probe-rs version; see instructions below.
  2. probe-rs does not yet support the device. You'll need to request support in the probe-rs issue tracker.

To build probe-run against the latest git version probe-rs and install it follow these steps:

$ # clone the latest version of probe-run; line below uses version v0.3.3
$ git clone --depth 1 --branch v0.3.3 https://github.com/knurling-rs/probe-run

$ cd probe-run

$ # modify Cargo.toml to use the git version of probe-rs
$ # append these lines to Cargo.toml; command below is UNIX-y
$ cat >> Cargo.toml << STOP
[patch.crates-io]
probe-rs = { git = "https://github.com/probe-rs/probe-rs" }
STOP

$ # install this patched version
$ cargo install --path .

Note that you may need to modify probe-rs-rtt and/or probe-run itself to get probe-run to compile. As we only support the crates.io version of probe-rs in the unmodified Cargo.toml we cannot provide further assistance in that case.

Setup

NOTE for new Cargo projects we recommend starting from app-template

1. Set the Cargo runner

The recommend way to use probe-run is to set as the Cargo runner of your application.

Add these two lines to your Cargo configuration file (.cargo/config.toml) and set the particular --chip value for your target. In this case it is nRF52840_xxAA for the nRF52840:

[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-run --chip nRF52840_xxAA"
#                          ^^^^^^^^^^^^^

To list all supported chips run probe-run --list-chips.

1.1 Env variable

To support multiple devices, or permit overriding default behavior, you may prefer to:

  1. set the ${PROBE_RUN_CHIP} environment variable, and
  2. set runner (or CARGO_TARGET_${TARGET_ARCH}_RUNNER) to probe-run:
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-run"

1.2 Multiple probes

If you have several probes connected, you can specify which one to use by adding the --probe option to the runner or setting the ${PROBE_RUN_PROBE} environment variable with a value containing either ${VID}:${PID} or ${VID}:${PID}:${SERIAL}:

// --probe
$ probe-run --probe '0483:3748' --chip ${PROBE_RUN_CHIP}

// PROBE_RUN_PROBE
$ PROBE_RUN_PROBE='1366:0101:123456' cargo run

To list all connected probes, run probe-run --list-probes.

2. Enable debug info

Next check that debug info is enabled for all profiles. If you are using the cortex-m-quickstart template then this is already the case. If not check or add these lines to Cargo.toml.

[dependencies]
...
panic-probe = { version = "0.2", features = ["print-rtt"] }

# Cargo.toml
[profile.dev]
debug = 1 # default is `true`; not needed if not already overridden

[profile.release]
debug = 1 # default is `false`; using `true` is also OK as symbols reside on the host, not the target

3. Look out for old dependencies

The cortex-m dependency must be version 0.6.3 or newer. Older versions are not supported. Check your Cargo.lock for old versions. Run cargo update to update the cortex-m dependency if an older one appears in Cargo.lock.

4. Run

You are all set. You can now run your firmware using cargo run. For example,

use cortex_m::asm;
use cortex_m_rt::entry;
use panic_probe as _;
use rtt_target::rprintln;

#[entry]
fn main() -> ! {
    rtt_init_print!(); // You may prefer to initialize another way
    rprintln!("Hello, world!");
    loop { asm::bkpt() }
}

would output

$ cargo run --bin hello
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `probe-run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/debug/hello`
  (HOST) INFO  flashing program (30.22 KiB)
  (HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
INFO:hello -- Hello, world!
────────────────────────────────────────────────────────────────────────────────
  (HOST) INFO  exiting because the device halted.
To see the backtrace at the exit point repeat this run with
`probe-run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/debug/hello --force-backtrace`

Stack backtraces

When the device raises a hard fault exception, indicating e.g. a panic or a stack overflow, probe-run will print a backtrace and exit with a non-zero exit code.

This backtrace follows the format of the std backtraces you get from std::panic! but includes <exception entry> lines to indicate where an exception/interrupt occurred.

#![no_main]
#![no_std]

use cortex_m::asm;
#[entry]
fn main() -> ! {
    // trigger a hard fault exception with the UDF instruction.
    asm::udf()
}
    Finished dev [optimized + debuginfo] target(s) in 0.04s
     Running `probe-run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/debug/hard-fault`
  (HOST) INFO  flashing program (30.08 KiB)
  (HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
stack backtrace:
   0: HardFaultTrampoline
      <exception entry>
   1: __udf
   2: cortex_m::asm::udf
        at /<...>/cortex-m-0.6.4/src/asm.rs:104
   3: panic::__cortex_m_rt_main
        at src/bin/hard-fault.rs:12
   4: main
        at src/bin/hard-fault.rs:8
   5: ResetTrampoline
        at /<...>3/cortex-m-rt-0.6.13/src/lib.rs:547
   6: Reset
        at /<...>/cortex-m-rt-0.6.13/src/lib.rs:550

If we look at the return code emitted by this cargo run, we'll see that it is non-0:

$ echo $?
134

⚠️ NOTE when you run your application with probe-run, the HardFault handler (default or user-defined) will NOT be executed.

Backtrace options

--backtrace

The --backtrace flag is optional and can get passed the following values:

  • --backtrace=always - forced backtrace (if you'd like to see a backtrace at the end of successful program run)
  • --backtrace=never - suppresed backtrace
  • --backtrace=auto - default, shows a backtrace if the program panics or the stack overflows

Run it like this (example for a forced backtrace):

$ cargo run --bin hello --backtrace=always

--backtrace-limit

The --backtrace-limit flag is optional and defaults to 50. It is possible to set any number.

--backtrace-limit=0 is accepted and means "no limit".

To show a shortened backtrace showing 5 frames, run:

$ cargo run --bin panic --backtrace-limit=5

Note: if --backtrace=never is set, setting --backtrace-limit has no effect.

Troubleshooting

"Error: no probe was found."

First, check your hardware:

  • make sure that your development board has an on-board hardware debugger. If it doesn't, you'll need a separate hardware debugger that works with the JTAG or SWD interface. Some boards have a USB micro-B or Type-C connector but only come with bootloader firmware that lets you load new program over USB Mass Storage, instead of having a dedicated on-board JTAG or SWD to USB chip; probe-run cannot be used with these boards.
  • make sure that it is connected to the right port on your development board
  • make sure that you are using a data cable– some cables are built for charging only! When in doubt, try using a different cable.
  • make sure you have the right drivers for the debugger installed (st-link or j-link)

If this doesn't resolve the issue, try the following:

[Linux only] udev rules haven't been set

Check if your device shows up in lsusb:

$ lsusb
Bus 001 Device 008: ID 1366:1015 SEGGER J-Link

If your device shows up like in the example, skip to the next troubleshooting section

If it doesn't show up, you need to give your system permission to access the device as a non-root user so that probe-run can find your device.

In order to grant these permissions, you'll need to add a new set of udev rules.

To learn how to do this for the nRF52840 Development Kit, check out the installation instructions in our embedded training materials.

afterwards, your device should show up in probe-run --list-probes similar to this:

$ probe-run --list-probes
The following devices were found:
[0]: J-Link (J-Link) (VID: 1366, PID: 1015, Serial: <redacted>, JLink)

No external or on-board debugger present

To use probe-run you need a "probe" (also known as "debugger") that sits between your PC and the microcontroller.

Most development boards, especially the bigger ones, have a probe "on-board": If the product description of your board mentions something like a J-Link or ST-Link on-board debugger you're good to go. With these boards, all you need to do is connect your PC to the dev board using a USB cable you are all set to use probe-run!

If this is not the case for your board, check in the datasheet if it exposes exposes SWD or JTAG pins. If they are exposed, you can connect a "stand alone" probe device to the microcontroller and then connect the probe to your PC via USB. Some examples of stand alone probes are: the ST-Link and the J-Link.

Note that this may involve some soldering if your board does not come with a pre-attached header to plug your debugger into.

Error: RTT up channel 0 not found

This may instead present as Error: RTT control block not found in target memory.

Your code, or a library you're using (e.g. RTIC) might be putting your CPU to sleep when idle. You can verify that this is the problem by busy looping instead of sleeping. When using RTIC, this can be achieved by adding an idle handler to your app:

#[idle]
fn idle(_ctx: idle::Context) -> ! {
     loop {}
}

Assuming you'd like to still sleep in order to save power, you need to configure your microcontroller so that RTT can still be handled even when the CPU is sleeping. How to do this varies between microcontrollers.

On an STM32G0 running RTIC it can be done by amending your init function to set the dmaen bit on RCC.ahbenr. e.g.:

#[init]
fn init(ctx: init::Context) -> init::LateResources {
     ctx.device.RCC.ahbenr.write(|w| w.dmaen().set_bit());
     ...
}

defmt version mismatch

end-user

Follow the instructions in the error message to resolve the mismatch.

developer

If you are hacking around with probe-run, you can disable the version check by setting the PROBE_RUN_IGNORE_VERSION environment variable to true or 1 at runtime.

Developer Information

running your locally modified probe-run

For easier copy-paste-ability, here's an example how to try out your local probe_run modifications.

$ cd probe-run/
$ PROBE_RUN_IGNORE_VERSION=1 cargo run -- --chip nRF52840_xxAA --backtrace-limit=10 hello
  ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ                                   ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ ˆˆˆˆˆ
  environment variables                                        extra flags             binary to be
  (optional)                                                   (optional)              flashed & run

running snapshot tests

To check whether your change has altered probe-run in unexpected ways, please run the snapshot tests in tests before opening a PR if at all possible.

You can do so by connecting a nrf52840 Development Kit and running

$ cargo test -- --ignored

Support Us

probe-run is part of the Knurling project, Ferrous Systems' effort at improving tooling used to develop for embedded systems.

If you think that our work is useful, consider sponsoring it via GitHub Sponsors.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.

probe-run's People

Contributors

andresovela avatar berkowski avatar bobmcwhirter avatar bobo1239 avatar bors[bot] avatar briocheberlin avatar burrbull avatar davidlattimore avatar dirbaio avatar eboskma avatar elpiel avatar haata avatar hasheddan avatar hoverbear avatar huntc avatar jannic avatar japaric avatar javier-varez avatar jonas-schievink avatar jonathanpallant avatar justahero avatar koba789 avatar korken89 avatar mattico avatar suyashb95 avatar therealprof avatar urhengulas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

probe-run's Issues

Output size info when flashing

The flashing step currently just outputs "flashing program", it would be nice if it contained a bit more info pertaining to the program it is flashing.

In particular, total flash usage is a small but important piece of info – it lets you estimate how long the flashing step might take, and is a useful metric to keep in mind while developing in general.

`release/debug=false` works but `dev/debug=false` doesn't

If release works then dev should also work.

STR: with defmt's log example (all the other examples produce similar errors)

$ # dev/debug=false
$ cargo run --bin log
(..)
stack backtrace:
   0: 0x00000bec - __bkpt
   1: 0x00000632 - log::__cortex_m_rt_main
   2: 0x000002d6 - main
   3: 0x0000261a - Reset
Error: debug information is missing. Likely fixes:
1. compile the Rust code with `debug = 1` or higher. This is configured in the `profile.*` section of Cargo.toml
2. use a recent version of the `cortex-m` crates (e.g. cortex-m 0.6.3 or newer). Check versions in Cargo.lock
3. if linking to C code, compile the C code with the `-g` flag

Caused by:
    Do not have unwind info for the given address.

$ # release/debug=false
$ cargo run --release --bin log
stack backtrace:
   0: 0x00000974 - __bkpt
   1: 0x0000080e - log::__cortex_m_rt_main
   2: 0x00000108 - main
   3: 0x000008c2 - Reset

$ # dev/debug=true
$ cargo run --bin log
stack backtrace:
   0: 0x00000ede - __bkpt
   1: 0x000009ea - log::__cortex_m_rt_main
   2: 0x0000065c - main
   3: 0x00002b2a - Reset

Document CLI options

Current output:

$ probe-run --help
probe-run 0.1.3

USAGE:
    probe-run [FLAGS] <ELF> --chip <chip>

FLAGS:
        --defmt
    -h, --help          Prints help information
        --list-chips
    -V, --version       Prints version information

OPTIONS:
        --chip <chip>

ARGS:
    <ELF>

display filter via env variable

use case: defmt supports emission filters on the target side (via Cargo features like defmt-info) but these have crate granularity via the DEFMT_LOG environment variable, which supports crate level granulartiy. To filter that further at module level granularity we can use an env variable like env_logger's RUST_LOG.

user interface: We can reuse RUST_LOG's syntax: krate::module=level,krate2::module2=level2 for familiarity.

implementation: log messages include the module in their call site info. probe-run can read the env var, parse it, filter out incoming log messages and print to the console only those that pass the filter.

unresolved questions:

  • env var name? DEFMT_DISPLAY_FILTER? PROBE_RUN_FILTER?
$ DEFMT_DISPLAY_FILTER=krate::module=info cargo run --bin my-app
0.000000 INFO  message1
└─ krate::module::function1 @ src/module/foo.rs:8
0.000001 INFO  message2
└─ krate::module::function2 @ src/module/bar.rs:9
(..)

Detect when the `rt` feature was not enabled

I'm not sure if this can be detected, but if it can, we should totally try to do it, since everyone forgets to enable the "rt" feature from time to time and the symptoms are just "stuff's broken yo", which isn't very easy to debug.

ST-Link v2.1 crashing?

Describe the bug
I'm using a ST-Link v2.1 with an ATSAMD21, this combination has been working fine for a few weeks with probe-run and defmt. The first time I do probe-run --verbose --chip ATSAMD21G18AU path/to/firmware, it flashes and successfully opens up the defmt-rtt console successfully. After about 20 seconds, probe-run exits with:

<normal defmt RTT output>
RTT error: Error communicating with probe: An error with the usage of the probe occured
Error: An error with the usage of the probe occured

Caused by:
    0: An error specific to a probe type occured
    1: Command failed with status JtagNoDeviceConnected

Once this failure has happened, subsequent probe-run invocations give:

  (HOST) DEBUG RAM region: 0x20000000-0x20007FFF
└─ probe_run @ src/main.rs:144
  (HOST) WARN  insufficient DWARF info; compile your program with `debug = 2` to enable location info
└─ probe_run @ src/main.rs:169
  (HOST) DEBUG section `.data` is in RAM at 0x20000000-0x20000147
└─ probe_run @ src/main.rs:204
  (HOST) DEBUG section `.bss` is in RAM at 0x20000150-0x20004C07
└─ probe_run @ src/main.rs:204
  (HOST) DEBUG section `.uninit` is in RAM at 0x20004C08-0x20005007
└─ probe_run @ src/main.rs:204
  (HOST) DEBUG vector table: VectorTable { location: 0, initial_sp: 20008000, reset: b1, hard_fault: 55a9 }
└─ probe_run @ src/main.rs:268
  (HOST) DEBUG found 1 probes
└─ probe_run @ src/main.rs:298
  (HOST) DEBUG opened probe
└─ probe_run @ src/main.rs:303
Error: An error with the usage of the probe occured

Caused by:
    0: An error specific to a probe type occured
    1: Command failed with status JtagNoDeviceConnected

To get a successful flash, disconnecting and reconnecting the USB to the ST-Link seems necessary.

Expected and observed behavior
I'd expect the session to not fail, but if it did I would expect to get some more detailed logging out with the --verbose flag specified, to be able to dig deeper in to the issue.

config.toml

[build]
target = "thumbv6m-none-eabi"

[target.thumbv6m-none-eabi]
runner = "probe-run --verbose --chip ATSAMD21G18AU"
rustflags = [
  "-C", "link-arg=-Tlink.x",
  "-C", "link-arg=-Tdefmt.x"
]

Probe details
ST-Link v2.1, just updated to firmware v2j37m26 which appears to be the latest, upgrade didn't change symptoms.

probe-rs-cli list
The following devices were found:
[0]: STLink V2-1 (VID: 0483, PID: 3752, Serial: 0670FF505055877267123015, STLink)

Operating System:
Ubuntu 20.04.1 LTS

Check the selected processor and target for compatability.

After spending an inordinate amount of time trying to work out why RTT wasn't working, I discovered that I had set the wrong target.

As probe-run knows both the source target (through the path) and the target IC, it should be possible to show a warning if the two aren't compatible with each other.

stack trace infinite loop

I'm just getting started using probe-run, testing a threading crate I'm building.

So (on Cortex-M), the thread stacks are populated with a frame like an exception would do, [r0-r4, r12, LR, PC, APSR].

LR is set to the location of a cleanup(), which does some house-keeping, then triggers the scheduler to switch away, then does a loop {}, which is practically unreachable.

Now when I run something with probe-run, the resulting stack trace endlessly repeats in cleanup():

[...]
    Finished dev [optimized + debuginfo] target(s) in 0.01s              
     Running `probe-run --chip nRF52840_xxAA /home/kaspar/src/own/rust/riot_core/target/thumbv7em-none-eabi/debug/examples/bench_lock`             
flashing program ..                                                      
^[[CDONE                                                                 
resetting device                                                         
stack backtrace:                                                         
   0: 0x00001752 - <unknown>                                             
   1: 0x000016b6 - cortex_m_semihosting::hio::hstdout
   2: 0x00001650 - cortex_m_semihosting::export::hstdout_fmt::{{closure}}                                                                          
   3: 0x00001558 - cortex_m::interrupt::free                             
   4: 0x00001638 - cortex_m_semihosting::export::hstdout_fmt
   5: 0x000007b6 - user_main                                             
   6: 0x0000112a - riot_core::main_trampoline                            
   7: 0x00000d20 - riot_core::thread::cleanup                                                                                                      
   8: 0x00000d20 - riot_core::thread::cleanup                            
   9: 0x00000d20 - riot_core::thread::cleanup       
  10: 0x00000d20 - riot_core::thread::cleanup                            
  11: 0x00000d20 - riot_core::thread::cleanup            
  12: 0x00000d20 - riot_core::thread::cleanup
  13: 0x00000d20 - riot_core::thread::cleanup
[...]

The lines <N>: 0x00000d20 - riot_core::thread::cleanup repeat extremely fast, and the process cannot be cancelled with CTRL-C.

While I might have messed up something on the stack to make it invalid and look like this to probe-run, I'd expect it to stop after maybe the second iteration, letting the user know that this would repeat.

(I'm assuming that probe-run's rtt support uses a different BKPT scheme than traditional semihosting, and that's why this exits on the first hprintln!(), but that is a unrelated to this issue.)

This is on probe-run 0.1.3 installed today via "cargo install probe-run".

backtrace: report real path to core / std source code

if the rust-std component is installed.

currently we report the build machine paths:

   2: core::panicking::panic_fmt
        at /rustc/04488afe34512aa4c33566eb16d8c912a3ae04f9/src/libcore/panicking.rs:85
   3: core::panicking::panic
        at /rustc/04488afe34512aa4c33566eb16d8c912a3ae04f9/src/libcore/panicking.rs:50

but we could do what the standard library does and report the path to $(rustc --print sysroot)

  11: std::panicking::begin_panic
             at /home/japaric/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:456

the goal is to make VS code's "open file location in editor" work

add flag / env-var to select the probe by serial number

This is helpful when you want to cargo-run firmware on two or more different devices in parallel.

$ # terminal 1
$ cd path/to/firmware
$ PROBE_RUN_SN=abcdef012345 cargo run --bin radio-tx

$ # terminal 2
$ cd path/to/firmware
$ PROBE_RUN_SN=012345abcdef cargo run --bin radio-rx

In the above case the firmware can live in the same Cargo project.

When the firmware lives in different Cargo projects you can use the flag version.

$ # terminal 1
$ cd path/to/firmware-a
$ head .cargo/config
[target.thumbv7em-none-eabihf]
runner = "probe-run --serial-number abcdef012345 --chip nrf52"

$ cargo run --bin radio-tx

$ # terminal 2
$ cd path/to/firmware-b
$ head .cargo/config
[target.thumbv7em-none-eabihf]
runner = "probe-run --serial-number 012345abcdef --chip nrf52"

$ cargo run --bin radio-rx

Report defmt decoder errors

Decoding failure is currently ignored by probe-run, which is problematic. It makes it look like the program stops outputting anything.

Error: `_defmt_*` symbol not found

> probe-run --chip STM32H743BITx --defmt .\target\thumbv7em-none-eabihf\debug\mainboardfw-rs
Error: `_defmt_*` symbol not found

Probably related: knurling-rs/defmt#132

Using defmt HEAD.

I'm building probe-run HEAD with probe-rs HEAD to work around #15.

[patch.crates-io]
probe-rs = { git = "https://github.com/probe-rs/probe-rs", rev = "0f3a2856365304dd6c04fc8c28dc82f8ac06e8bb" }
probe-rs-rtt = { git = "https://github.com/probe-rs/probe-rs-rtt" }

My firmware is linked with GCC like so:

[build]
target = "thumbv7em-none-eabihf"
rustflags = [
  "-C", "inline-threshold=225",
  "-C", "linker=arm-none-eabi-gcc",
  "-C", "link-arg=-Wl,-Tlink.x",
  "-C", "link-arg=-Wl,-Tdefmt.x",
  "-C", "link-arg=-nostartfiles",
  "-C", "link-arg=-specs=nano.specs",
  "-C", "link-arg=-lc",
  "-C", "link-arg=-mcpu=cortex-m7",
  "-C", "link-arg=-mfpu=fpv5-d16",
  "-C", "link-arg=-mfloat-abi=hard",
  "-C", "link-arg=-mthumb",
]

The symbols do seem to be present:

> arm-none-eabi-readelf.exe --sections --symbols .\target\thumbv7em-none-eabihf\debug\mainboardfw-rs | grep -i defmt
  [13] .defmt            PROGBITS        20001f1c 020218 00001f 00      0   0  1
  7363: 08006941   302 FUNC    LOCAL  DEFAULT    2 _ZN50_$LT$defmt_rtt..Logg
  7370: 08000993    82 FUNC    LOCAL  DEFAULT    2 _ZN5defmt9Formatter3fmt17
  7371: 08006903    62 FUNC    LOCAL  DEFAULT    2 _ZN5defmt9Formatter4istr1
  7372: 08006857   172 FUNC    LOCAL  DEFAULT    2 _ZN5defmt9Formatter5leb64
  7384: 2000021d     1 OBJECT  LOCAL  DEFAULT    5 _ZN9defmt_rtt17INTERRUPTS
  7385: 2000021c     1 OBJECT  LOCAL  DEFAULT    5 _ZN9defmt_rtt5TAKEN17h13d
  7386: 20001b1c  1024 OBJECT  LOCAL  DEFAULT   12 _ZN9defmt_rtt6handle6BUFF
  8134: 20001f28     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_info_start
  8135: 20001f1c     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_error_start
  8153: 20001f31     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_trace_start
  8163: 20001f28     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_warn_end
  8168: 20001f1d     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_version_ = 82dd53f
  8221: 080010c3    36 FUNC    GLOBAL DEFAULT    2 _defmt_timestamp
  8247: 08006a71   102 FUNC    GLOBAL DEFAULT    2 _defmt_acquire
  8269: 20001f27     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_warn_start
  8293: 20001f33     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_trace_end
  8354: 08006ad7    32 FUNC    GLOBAL DEFAULT    2 _defmt_release
  8363: 20001f2b     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_debug_start
  8412: 20001f27     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_error_end
  8428: 20001f31     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_debug_end
  8515: 20001f2b     0 NOTYPE  GLOBAL DEFAULT   13 _defmt_info_end

Going to try searching for the source of the error message.

Build failure with defmt on current main head

Describe the bug
Since last night I can't compile it because of some issues with defmt code it calls.

This is on OSX, probe-run hash 4ee681e

To Reproduce

cargo install probe-run --git https://github.com/knurling-rs/probe-run.git --branch main -f --features defmt

Output:

 ... all fine until here ...
  Compiling probe-rs-t2rust v0.6.0
   Compiling defmt-elf2table v0.1.0 (https://github.com/knurling-rs/defmt?branch=main#91f33fc4)
   Compiling probe-rs v0.8.0
   Compiling probe-rs-rtt v0.3.0
   Compiling probe-run v0.1.3 (/Users/daschl/.cargo/git/checkouts/probe-run-31a04fec2ca67672/4ee681e)
error[E0425]: cannot find function `parse` in crate `defmt_elf2table`
   --> src/main.rs:140:38
    |
140 |         let table = defmt_elf2table::parse(&bytes)?;
    |                                      ^^^^^ not found in `defmt_elf2table`

error[E0425]: cannot find function `get_locations` in crate `defmt_elf2table`
   --> src/main.rs:150:41
    |
150 |             let locs = defmt_elf2table::get_locations(&bytes, table)?;
    |                                         ^^^^^^^^^^^^^ not found in `defmt_elf2table`

error[E0603]: enum `Level` is private
  --> src/logger.rs:32:24
   |
32 |         defmt_decoder::Level::Trace => Level::Trace,
   |                        ^^^^^ private enum
   |
note: the enum `Level` is defined here
  --> /Users/daschl/.cargo/git/checkouts/defmt-7f5b74b4e6ff55d4/91f33fc/decoder/src/lib.rs:21:30
   |
21 | use defmt_parser::{Fragment, Level, Type};
   |                              ^^^^^

error[E0603]: enum `Level` is private
  --> src/logger.rs:33:24
   |
33 |         defmt_decoder::Level::Debug => Level::Debug,
   |                        ^^^^^ private enum
   |
note: the enum `Level` is defined here
  --> /Users/daschl/.cargo/git/checkouts/defmt-7f5b74b4e6ff55d4/91f33fc/decoder/src/lib.rs:21:30
   |
21 | use defmt_parser::{Fragment, Level, Type};
   |                              ^^^^^

error[E0603]: enum `Level` is private
  --> src/logger.rs:34:24
   |
34 |         defmt_decoder::Level::Info => Level::Info,
   |                        ^^^^^ private enum
   |
note: the enum `Level` is defined here
  --> /Users/daschl/.cargo/git/checkouts/defmt-7f5b74b4e6ff55d4/91f33fc/decoder/src/lib.rs:21:30
   |
21 | use defmt_parser::{Fragment, Level, Type};
   |                              ^^^^^

error[E0603]: enum `Level` is private
  --> src/logger.rs:35:24
   |
35 |         defmt_decoder::Level::Warn => Level::Warn,
   |                        ^^^^^ private enum
   |
note: the enum `Level` is defined here
  --> /Users/daschl/.cargo/git/checkouts/defmt-7f5b74b4e6ff55d4/91f33fc/decoder/src/lib.rs:21:30
   |
21 | use defmt_parser::{Fragment, Level, Type};
   |                              ^^^^^

error[E0603]: enum `Level` is private
  --> src/logger.rs:36:24
   |
36 |         defmt_decoder::Level::Error => Level::Error,
   |                        ^^^^^ private enum
   |
note: the enum `Level` is defined here
  --> /Users/daschl/.cargo/git/checkouts/defmt-7f5b74b4e6ff55d4/91f33fc/decoder/src/lib.rs:21:30
   |
21 | use defmt_parser::{Fragment, Level, Type};
   |                              ^^^^^

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0425, E0603.
For more information about an error, try `rustc --explain E0425`.
error: failed to compile `probe-run v0.1.3 (https://github.com/knurling-rs/probe-run.git?branch=main#4ee681e6)`, intermediate artifacts can be found at `/var/folders/2t/p_gqr4sn1qb75zjtt673kx000000gr/T/cargo-installLdrOuP`

Caused by:
  could not compile `probe-run`.

To learn more, run the command again with --verbose.

Unable to flash STM32H7 MCU

Running `probe-run --chip STM32H743BITx --defmt target\thumbv7em-none-eabihf\release\mainboardfw-rs`
flashing program ..
Error: Error while flashing

Caused by:
    No flash memory contains the entire requested memory range 0x8000000..0x8005904.

This is caused by probe-rs having an incorrect memory map for the flash, which was fixed in probe-rs/probe-rs#314.

Approximated stack overflow detection via stack canaries

While it is possible to link an embedded app in a way that will detect stack overflows immediately and (mostly) reliably, few people actually do this as it requires using a linker wrapper to link the app twice. cortex-m-rt also doesn't do it by default at the moment.

However, we can still do our best to help out when no built-in stack overflow protection is used: After uploading the program, but before starting it, we can fill the space in RAM right after the data used by ELF sections with a unique pattern. Then, after the program exits (or even while it still runs), we scan the filled area and look for bytes that were changed from our pattern. If we find any changed bytes, there is a high probability that the program has used too much stack and overwrote its own data sections.

There are a few things to keep in mind here:

  • When "real" stack overflow protection is used, the ELF sections will be at the end of RAM, and our canary won't fit anywhere (but is also unnecessary).
  • This is all relying on luck and is a post-mortem technique: The program state is already undefined when we detect the stack overflow.
  • We need to fill "enough" RAM with the canary to get a high chance of detecting the overflow, but only as much RAM as is needed (otherwise, even regular stack usage will trip the canary).
  • It is currently unclear how this interacts with program that use the heap. It probably has to be disabled then, as the heap usually starts right after the fixed ELF sections.
  • While this feature has both false positives and negatives, I believe it can be enabled by default if the message is worded right. Something like "program has used at least N bytes of stack space, collision with data segments is likely". This can be worded differently based on where in the canary the modification was detected.

Diagnose probable lack of linker script

It's a common problem that users forget to pass -Tlink.x to the linker, since this currently needs to be done in every embedded application. The result is an ELF that is missing most sections. I think we do currently catch that, but we should try to include the likely cause and a suggestion in the error message.

WFI/WFE after print results in the same message printed multiple times

I'm implementing an embedded async runtime on an stm32f103. Inside a future I am calling defmt::info!, before waiting on a timer (via an interrupt). Therefore, the future returns Poll::Pending and I call asm::wfi() to sleep the CPU.
Then, the message printed before the wait gets sent a ton of times, all with the same timestamp. Is this expected? How does your printing mechanism interact with sleep modes?

I've tried setting the DBGMCU_CR.DEBUG_SLEEP flag but it doesn't do anything.

This is on Windows 10 with an STLink v2. I don't have a small reproducer at the moment because the code is tied into all sorts of unrelated stuff. Maybe there's an underlying reason this doesn't work and you don't need an example, let me know.

Allow GDB connection

I was wondering whether it will be possible to include gdb-server stub from probe-rs to probe-run. The idea is to allow GDB connection and use regular debugging while maintain display of defmt log messages.

When the probe-run is running it is not possible to access the st-link probe from the gdb-server nor OpenOCD. So to allow this to work a GDB session has to be somehow integrated into the probe-run.

backtrace can infinte-loop.

I'm seeing this behavior with -C force-frame-pointers=no.

I think it's to be expected that backtracing doesn't work correctly with it, but I think at least this should be detected and fail with error: the stack appears to be corrupted beyond this point instead of looping forever.

If there's interest I can try cooking a binary that reproduces this.

stack backtrace:
   0: HardFaultTrampoline
      <exception entry>
   1: tester_gwc::sys::__cortex_m_rt_WDT
        at ak/src/bin/../sys.rs:556
   2: WDT
        at ak/src/bin/../sys.rs:553
      <exception entry>
   3: <futures_util::future::select::Select<A,B> as core::future::future::Future>::poll
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.8/src/future/select.rs:95
   4: tester_gwc::common::abort_on_keypress::{{closure}}
        at ak/src/bin/../tester_common.rs:26
   5: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
        at /home/dirbaio/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:80
   6: tester_gwc::test_network::{{closure}}
        at ak/src/bin/tester_gwc.rs:61
   7: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
        at /home/dirbaio/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:80
   8: tester_gwc::main::{{closure}}
        at ak/src/bin/tester_gwc.rs:43
   9: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
  10: tester_gwc::sys::main_task::task::{{closure}}
        at ak/src/bin/../sys.rs:196
  11: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
        at /home/dirbaio/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:80
  12: embassy::executor::Task<F>::poll
        at /home/dirbaio/akiles/embassy/embassy/src/executor/mod.rs:132
  13: core::cell::Cell<T>::get
        at /home/dirbaio/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:432
  14: embassy::executor::timer_queue::TimerQueue::update
        at /home/dirbaio/akiles/embassy/embassy/src/executor/timer_queue.rs:34
  15: embassy::executor::Executor::run::{{closure}}
        at /home/dirbaio/akiles/embassy/embassy/src/executor/mod.rs:241
  16: embassy::executor::run_queue::RunQueue::dequeue_all
        at /home/dirbaio/akiles/embassy/embassy/src/executor/run_queue.rs:65
  17: embassy::executor::Executor::run
        at /home/dirbaio/akiles/embassy/embassy/src/executor/mod.rs:223
  18: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  19: real_main
        at ak/src/bin/../sys.rs:478
  20: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  21: real_main
        at ak/src/bin/../sys.rs:478
  22: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  23: real_main
        at ak/src/bin/../sys.rs:478
  24: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  25: real_main
        at ak/src/bin/../sys.rs:478
  26: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  27: real_main
        at ak/src/bin/../sys.rs:478
  28: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  29: real_main
        at ak/src/bin/../sys.rs:478
  30: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  31: real_main
        at ak/src/bin/../sys.rs:478
  32: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  33: real_main
        at ak/src/bin/../sys.rs:478
  34: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  35: real_main
        at ak/src/bin/../sys.rs:478
  36: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  37: real_main
        at ak/src/bin/../sys.rs:478
  38: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  39: real_main
        at ak/src/bin/../sys.rs:478
  40: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  41: real_main
        at ak/src/bin/../sys.rs:478
  42: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  43: real_main
        at ak/src/bin/../sys.rs:478
  44: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  45: real_main
        at ak/src/bin/../sys.rs:478
  46: cortex_m::asm::wfe
        at /home/dirbaio/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:117
  47: real_main
        at ak/src/bin/../sys.rs:478
... this goes on forever

Decorate backtrace with location information (file+line)

The libstd implementation prints file and line number for each (non-inlined) call in the backtrace. We should do the same, as it makes finding the relevant locations easier.

If the format is right, VS Code should even make the locations clickable.

What would it take to support Teensy 3 & 4?

What would it take to support the Teensy series of chips - especially the newer 3.x and 4.x families based on Cortex M families?

  • Teensy 4.0 and 4.1: "an ARM Cortex-M7 processor at 600 MHz, with a NXP iMXRT1062 chip, the fastest microcontroller available today"
  • Teensy 3.6: "a 32 bit 180 MHz ARM Cortex-M4 processor with floating point unit"
  • Teensy 3.5: "a 32 bit 120 MHz ARM Cortex-M4 processor with floating point unit"
  • (Teensy 3.1 and 3.2: "a 32 bit ARM processor")
  • (Teensy 2.0: AVR)

Some possibly-relevant work e.g.

  • teensy 4
  • teensy 3.5, 3.6 ?
  • teensy 3.1, 3.2 "This crate is meant to be consumed by a binary for a PJRC Teensy 3.1 or 3.2. Support for Teensy 3.0, 3.5, and 3.6 boards is planned, but not implemented."

The newer Teensy chips provide a fun amount of compute power not commonly seen in other boards, I'd love to see better Rust support for these boards ❤️

What would it take to allow debugging?

Hi,
thank you for the runner, it is something I've been waiting for a long time.

I ma just wondering what would need to be done to allow for debugging with standard IDEs, such as CLion, or VS code, in the past the runner was configured to arm-none-eabi-gdb.

I've seen that there are limitations in running RTT alongside with GDB in probe-rs, but I do not know enough to figure out the consequences for the runner.

Thanks!
I'll gladly contribute if the implementation will be something I can handle.

Runner hangs at resetting device when using async-embedded.

Hi,
I know that async is extremely experimental, however when exprimenting with it, I stumbled upon the problem that when I was trying to run the code wit probe-run nothing was printed using RTT, but when I ran it using cargo embed, RTT work normally.
The code with respective outputs is here:

#![no_std]
#![no_main]

use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics

use cortex_m::asm::bkpt;
use cortex_m_rt::entry;
use rtt_target::{rprintln,rtt_init_print};
use async_embedded::task;

#[entry]
fn main() -> ! {
    rtt_init_print!();
    rprintln!("Hello, world!");

    task::spawn(async move {```
        loop {
            rprintln!("a");
            task::r#yield().await;
        }
    });

    task::block_on(async {
        loop {
            rprintln!("b");
            task::r#yield().await;
        }
    })
}

probe-run (when stopped):

flashing program ..
DONE
resetting device
stack backtrace:
   0: 0x08000410 - core::future::get_context
   1: 0x08000a8c - async_embedded::task::yield::{{closure}}
   2: 0x0800092c - <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
   3: 0x080015a2 - runner_test::__cortex_m_rt_main::{{closure}}
   4: 0x080008c8 - <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
   5: 0x08000c60 - async_embedded::executor::Node<dyn core::future::future::Future+Output = ()>::new::{{closure}}
   6: 0x08000864 - <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
   7: 0x08000f84 - async_embedded::executor::Executor::block_on
   8: 0x08000b48 - async_embedded::task::block_on
   9: 0x08001254 - runner_test::__cortex_m_rt_main
  10: 0x080010a8 - main
  11: 0x08003c76 - ResetTrampoline
  12: 0x08003c6c - Reset
Error: RTT control block not found in target memory. Make sure RTT is initialized on the target.

Process finished with exit code 1

Cargo embed: correctly showing alternating 'a' and 'b'.

blocking rtt hangs process

Any thoughts against servicing the rtt buffer the entire time? Im trying to print large buffers on exit, but theyre either truncated because the buffer is full (and youd hate to set the rtt buffer to 10k or something) or in rtt blocking deadlock because the buffer inst serviced until the breakpoint is reached.

Any architectural reasons or?

backtrace: Shorten paths to crates/libcore

It would be nice to shorten long paths to rust libraries or published dependency crate versions, so your backtrace lines are better human-readable:

For core/alloc/std libraries, a format stating the version of the compiler used in a format similar to rust-toolchain file specifications would be good

[stable-1.46.0]/lib/rustlib/src/foo.rs

For published library dependencies, it would be good to use a similar format, with `$crate_name-$crate_version:

[heapless-0.5.2]/src/vec.rs

I think it would be reasonable to make this an option (perhaps the default?), as it may interfere with vscode's ability to jump to source. However, this would drastically reduce line lengths when that functionality is not needed.

--features defmt precludes running firmware without it

When probe-run has the defmt feature enabled, using it to run a firmware that uses rtt-target results in Error: defmt version symbol not found then probe-run exits.

To Reproduce
Steps to reproduce the behavior:

  1. Install probe-run with --features defmt
  2. Build an ELF that uses RTT, but not defmt
  3. probe-run elf_from_step_2 --chip SOMECHIP

Expected and observed behavior
I'd expect to see either the same behaviour as when probe-run is not built with --features defmt, perhaps with a warning to the effect of "defmt version symbol not found, falling back to raw RTT". Actually, an error message is displayed and probe-run exits.

config.toml

[build]
target = "thumbv6m-none-eabi"

[target.thumbv6m-none-eabi]
runner = "probe-run --chip ATSAMD21G18AU"
rustflags = [
  "-C", "link-arg=-Tlink.x",
]

Probe details

main git:((aba2ddc...)) ✗ probe-run --list-probes
The following devices were found:
[0]: STLink V2-1 (VID: 0483, PID: 374b, Serial: 0670FF505055877267123015, STLink)

Operating System:
Linux (Ubuntu 20.04)

ELF file (attachment)
codecraft_demo.zip

Additional context
I'm totally digging probe-run and defmt, thanks for making and sharing it!

JtagGetIdcodeError

Hi. Where should I start debugging this? On STM32F3, and switching from openocd:

    Finished release [optimized + debuginfo] target(s) in 23.16s
     Running `probe-run --chip STM32F303CCTx target\thumbv7em-none-eabihf\release\anyleaf_watermonitor`
Error: An error with the usage of the probe occured

Caused by:
    0: An error specific to a probe type occured
    1: Command failed with status JtagGetIdcodeError
error: process didn't exit successfully: `probe-run --chip STM32F303CCTx target\thumbv7em-none-eabihf\release\anyleaf_watermonitor` (exit code:
 1)

./cargo/config:

[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-run --chip STM32F303CCTx" # to list chips, run `probe-run --list-chips.`
rustflags = [
  "-C", "link-arg=-Tlink.x",
]

[build]
target = "thumbv7em-none-eabihf"

edit: After removing the

rustflags = [
  "-C", "link-arg=-Tlink.x",
]

line, the error is Error: .vector_table section is missing.

Text not printed with rprint without newline

I have a strange bug where rprint!(".") doesn't print anything until I print a newline \n later. For instance rprint!(".\n"); works, rprint!("."); rprint!("\n"); works too, and of course rprintln!("."); works. Characters are not missed, it's just as if some buffer is flushed only when newline is met.

This doesn't happen with cargo-embed so I created the issue here

Freeze with RTIC pend

I have tried basic example from RTIC, just updated to use defmt and hardware that I have available and it freezes on the pend call for some reason. Any idea what might be wrong?

#[app(device = stm32l0x1_minihal::pac)]
const APP: () = {
    #[init]
    fn init(_: init::Context) {
        rtic::pend(Interrupt::USART1);

        defmt::debug!("Init!");
    }

    #[idle]
    fn idle(_: idle::Context) -> ! {
        defmt::debug!("Idle!");

        rtic::pend(Interrupt::USART1);

        l0::exit();

        loop {
            cortex_m::asm::nop();
        }
    }

    #[task(binds = USART1)]
    fn uart0(_: uart0::Context) {
        static mut TIMES: u32 = 0;

        *TIMES += 1;
        defmt::debug!("Called: {:u32}", TIMES);
    }
};

The output from cargo-run is:

Finished dev [optimized + debuginfo] target(s) in 0.03s
     Running `probe-run --chip STM32L031K6Tx --defmt target/thumbv6m-none-eabi/debug/l0`
  (HOST) INFO  flashing program
  (HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
0.000000 DEBUG Init!
└─ l0::init @ src/bin/main.rs:67

Stack backtrace is printed after shell prompt

...
0.000000 INFO  (7/10) running `filter_list32_std`...
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:73
0.000000 INFO  (8/10) running `filter_list32_ext`...
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:73
0.000000 INFO  (9/10) running `dequeue_lower_priority_frame`...
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:73
0.000000 INFO  (10/10) running `ext_roundtrip`...
└─ integration::tests::__defmt_test_entry @ tests/integration.rs:73
^C⏎
~/dev/bxcan/testsuite *master> stack backtrace:
   0: core::ptr::read_volatile
        at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1042
   1: vcell::VolatileCell<T>::get
        at /home/jonas/.cargo/registry/src/github.com-1ecc6299db9ec823/vcell-0.1.2/src/lib.rs:32
   2: bxcan::pac::generic::Reg<U,REG>::read
        at /home/jonas/dev/bxcan/src/pac/generic.rs:52
   3: bxcan::Tx<I>::is_idle
        at /home/jonas/dev/bxcan/src/lib.rs:589
   4: bxcan::Can<I>::is_transmitter_idle
        at /home/jonas/dev/bxcan/src/lib.rs:385
   5: integration::tests::ext_roundtrip
        at tests/integration.rs:417
   6: main
        at tests/integration.rs:73
   7: Reset
        at /home/jonas/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:526

Note how the shell prompt shows up between the defmt output and the stacktrace. Not really sure what causes this behavior, but we might need to add a flush somewhere?

virtual unwind support for hard-float targets

general comment: the Thumb targets are backwards compatible. Both thumbv7em-none-eabi and thumbv7em-none-eabihf work fine on Cortex-M4F devices. If you are not doing floating point operations (f32 math) then you can use the thumbv7em-none-eabi target, which is supported by probe-run, without any performance degradation.


The virtual unwinder doesn't expect floating pointer (FP) registers to be pushed on exception entry.

The Cortex-M is smart about this: it only pushes FP registers if the preempted context was using them.
The unwinder will need to compute at runtime whether the FP registers were pushed or not (there should be some flag/register pushed onto the stack that contains this info) and update the per-frame SP value accordingly while walking up the stack.

Semihosting support

Semihosting provides a canonical way to exit the program with a firmware-controlled exit status. This could replace our current scheme, where we terminate the program after any breakpoint was hit, and look at the stack backtrace to determine whether to use an exit status that indicates failure (being in the HardFault exception handler is treated as a failure).

Using semihosting seems more robust and flexible to me.

Using probe-run with bootloader

Hi Guys!

I am attempting to use probe-run to run my application on top of a custom bootloader.. It flashes successfully, and the application boots as expected. I don't expect to have defmt logging from both the bootloader and the application at the same time, as they are two different ELF files.

Looking at my application, i can verify that it looks to be built correctly:

➜  release git:(master) ✗ arm-none-eabi-nm -CSn output | head -n 30                                                                                                                                                                                                                                        [20/08/26|8:45:41]
00000000 00000001 N {:u32}
00000001 N _defmt_error_start
00000001 A "_defmt_version_ = 5a1047ba740398184fbe26b58fe504c0b918c6bb"
00000001 00000001 N panicked at {:str}:{:u32}:{:u32}
00000002 00000001 N Network init
00000003 00000001 N Failed to obtain time!
00000004 00000001 N Failed to obtain time!
00000005 00000001 N Abort error
00000006 00000001 N Failed to obtain ntp time!
00000007 00000001 N Buffer too small!!!
00000008 N _defmt_error_end
00000008 N _defmt_warn_start
00000008 00000001 N OTA Job removed!
00000009 00000001 N @#25 bytes(5709..5726)
00000009 N _defmt_info_start
00000009 N _defmt_warn_end
0000000a 00000001 N Copyright Mathias Koch 2020
0000000b 00000001 N Network initialized!
0000000c 00000001 N Time delta: {:?} ms
0000000d 00000001 N Re-attaching!
0000000e 00000001 N Re-registering & attaching!
0000000f N _defmt_debug_end
0000000f N _defmt_debug_start
0000000f N _defmt_info_end
0000000f N _defmt_trace_end
0000000f N _defmt_trace_start
08004404 00000004 R __RESET_VECTOR
08004408 00000038 R __EXCEPTIONS
08004408 R __reset_vector
08004440 R __eexceptions
...

And running RUST_LOG=info probe-run --chip STM32L475VGTx --defmt output flashes the device and ends up with:

[2020-08-26T06:42:31Z INFO  probe_run] flashed program
[2020-08-26T06:42:31Z INFO  probe_run] attached to core
DONE
resetting device
[2020-08-26T06:42:31Z INFO  probe_run] Could not attach because the target's RTT control block isn't initialized (yet). retrying
[2020-08-26T06:42:31Z INFO  probe_run] Successfully attached RTT

Then nothing more happens. I can verify that the application is running as expected, so only the logging is missing.. (built with default = ["defmt-default"])

Searching some more, it seems to be caused by this piece:

for try_index in 0..=NUM_RETRIES {
    rtt_res = Rtt::attach_region(sess.clone(), &ScanRegion::Exact(rtt_addr_res));
    match rtt_res {
        Ok(_) => {
            log::info!("Successfully attached RTT");
            break;
        }
        Err(probe_rs_rtt::Error::ControlBlockNotFound) => {
            if try_index < NUM_RETRIES {
                log::info!("Could not attach because the target's RTT control block isn't initialized (yet). retrying");
            } else {
                log::info!("Max number of RTT attach retries exceeded.");
                return Err(anyhow!(probe_rs_rtt::Error::ControlBlockNotFound));
            }
        }
        Err(e) => {
            return Err(anyhow!(e));
        }
    }
}

not delaying enough for the bootloader to jump to application before giving up on the RTT attachment.

A simple 1 second sleep between retries seems to fix my issue.

Could not compile probe-run v0.1.6 on macOS 10.15.7

So far I have installed probe-run without problems on macOS (x86_64) with:

cargo install --git https://github.com/knurling-rs/probe-run --branch main --features defmt

Now I tried to install release version with:

cargo install probe-run

And got following error:

  = note: Undefined symbols for architecture x86_64:
            "_NSAppKitVersionNumber", referenced from:
                _hid_init in libhidapi-6c82a0d52f552184.rlib(hid.o)
                _hid_enumerate in libhidapi-6c82a0d52f552184.rlib(hid.o)
                _hid_open_path in libhidapi-6c82a0d52f552184.rlib(hid.o)
          ld: symbol(s) not found for architecture x86_64
          clang: error: linker command failed with exit code 1 (use -v to see invocation)


error: aborting due to previous error

error: failed to compile `probe-run v0.1.6 (https://github.com/knurling-rs/probe-run?branch=main#013c0bd3)`, intermediate artifacts can be found at `/var/folders/5b/jlxfj70x1fb_n2l6qh21xxfh0000gn/T/cargo-installcEziMp`

Caused by:
  could not compile `probe-run`.

To learn more, run the command again with --verbose.

Full log

Rust version:

rustc 1.46.0 (04488afe3 2020-08-24)

STM32F407VGTx Do not have unwind info for the given address

Do we think its a configuration error or unsupported arch somewhere?

$ cargo run --release --example cycle_count
    Finished release [optimized] target(s) in 0.01s
     Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/release/examples/cycle_count`
flashing program ..
DONE
resetting device
ticks: 16800059
stack backtrace:
   0: 0x0800132e - <unknown>
Error: Do not have unwind info for the given address.

include module path info in the output

depends on knurling-rs/defmt#151
Example input:

// src/bin/hello.rs
fn main() -> ! {
    defmt::info!("program start");
    // ..
}
// src/hal.rs
fn init() {
    defmt::debug!("initializing the HAL");
    // ..
}

Example output:

0.000000 INFO  [my_app::hello::main] program start
└─ src/bin/hello.rs:8
0.000001 DEBUG [my_app::hal::init] initializing the HAL
└─ src/hal.rs:8

`<exception entry>` printed twice on UDF

STR

#[cortex_m_rt::entry]
fn main() -> ! {
    cortex_m::asm::udf();
}
$ cargo rb abort
stack backtrace:
   0: 0x000003e0 - HardFaultTrampoline
      <exception entry>
      <exception entry>
   1: 0x00000140 - __udf
   2: 0x00000118 - cortex_m::asm::udf
   3: 0x0000012c - abort::__cortex_m_rt_main
   4: 0x00000122 - main
   5: 0x000000fa - Reset

Add --connect-under-reset option

Describe the bug
probe-run is not able to connect to device if wfi is used.
It was tested with stlink v2 and stm32f411.

To Reproduce
Lets say I have following program where TIM5 fires with 1 Hz.

    #[idle]
    fn idle(_: idle::Context) -> ! {
        loop {
            // cannot connect if wfi is used
            cortex_m::asm::wfi();
            // this works
            //cortex_m::asm::nop();
        }
    }
    
    #[task(binds = TIM5, resources = [led, timer])]
    fn timer5_tick(ctx: timer5_tick::Context) {
        defmt::info!("tick");
        ctx.resources.timer.clear_interrupt(Event::TimeOut);
        ctx.resources.led.toggle().unwrap();
    }

It is only possible to reflash device using --connect-under-reset option which uses external reset pin.

cargo flash --chip STM32F411CEUx --release --bin app  --connect-under-reset

config.toml defines:

runner = "probe-run --chip STM32F411CEUx --defmt"

The problem is that probe-run does not have similar option like --connect-under-reset and therefore it fails to connect to target:

>cargo rrb app                                                                                                                                                                                                                                                                                           
    Finished release [optimized + debuginfo] target(s) in 0.04s
     Running `probe-run --chip STM32F411CEUx --defmt target/thumbv7em-none-eabihf/release/app`
Error: An error with the usage of the probe occured

Caused by:
    0: An error specific to a probe type occured
    1: Command failed with status JtagNoDeviceConnected

Error with STM32F723IEKx

Here's what i get when i try using the provided "app-template" with the stm32f723 disco board via the onboard ST-LINK/V2-1

probe-run --chip STM32F723IEKx --defmt target/thumbv7em-none-eabihf/debug/hello`
flashing program ..
DONE
resetting device
Error: Error communicating with probe: A core architecture specific error occured

Caused by:
    0: A core architecture specific error occured
    1: Failed to read register DRW at address 0x0000000c because: An error specific to a probe type occured
    2: An error specific to a probe type occured
    3: Command failed with status SwdDpFault

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.