knurling-rs / probe-run Goto Github PK
View Code? Open in Web Editor NEWRun embedded programs just like native ones
License: Apache License 2.0
Run embedded programs just like native ones
License: Apache License 2.0
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'.
We've had folks request the ability to use defmt in a bootloader AND an application, which have unrelated defmt message libraries. Users also seem to want to reuse the same defmt RTT control block and memory space.
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.
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:
Helps identify git installs of probe-run
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
use case: defmt
supports emission filters on the target side (via Cargo features like via the defmt-info
) but these have crate granularityDEFMT_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:
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
(..)
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.
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?
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.
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
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.
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
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
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.
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.
Rust version:
rustc 1.46.0 (04488afe3 2020-08-24)
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".
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.
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.
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.
We should not block CPU execution if there is no debugger attached.
We could make this nonblocking, but we would need to make the defmt line protocol robust enough to handle dropped bytes in the stream.
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.
> 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.
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:
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!
Decoding failure is currently ignored by probe-run, which is problematic. It makes it look like the program stops outputting anything.
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
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
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.
It would be nice to (optionally) display function arguments when displaying the backtrace
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?
Some possibly-relevant work e.g.
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 ❤️
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
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.
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.
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.
...
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?
probe-run implements a lot of ELF magic by itself, but it would be useful to pull that into this repo (presumably into elf2table) so that qemu-run can use and test it.
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
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.
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.
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
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>
The defmt RTT channel is named "defmt", so it can be automatically detected instead of having to pass --defmt
.
When a HardFault is triggered by the UDF instruction, the processor moves to the infinite loop defined in cortex-m crate and the application does not terminate.
Is this the correct behavior?
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
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
we are using 0.6 and latest is 0.8. there were some breaking changes in the API so this may take a bit of work.
The automatic stack canary currently will be disabled when the chip has multiple memory regions. We should try to at least support the case where all but one region are unused by the app.
When probe-run errors because it finds multiple probes, it would be helpful to print the probe list, so that the user can easily specify it without having to run probe-run --list-probes
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
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.