-
Notifications
You must be signed in to change notification settings - Fork 8
User Guide Debugging and Inspection
RTICX applications are written with a set of attributes (#[<distro>::app],
#[task], #[sw_task], …) that are expanded into a large amount of generated
Rust code. The rticx-expand cargo tool expands an application into a
plain, compilable Rust file so you can:
- Step-debug with GDB through the generated code (entry point, dispatchers, interrupt handlers, resource proxies) instead of the attribute syntax.
- Inspect and security-vet exactly what the framework generates: no macro magic left between you and the code that actually runs on the device.
- Debug your own compilation passes by dumping the intermediate syntax after each pipeline stage (distribution developers, see Writing Compilation Passes).
cargo install rticx-expand
# or from local source
cargo install --path path/to/rticx-expandThis installs the cargo-rticx-expand binary, invocable as
cargo rticx-expand ….
Run from your application crate (the one whose Cargo.toml depends on the
distribution):
cargo rticx-expand --example hello_rtic --features swtasksLike cargo expand, this prints the expanded application to stdout. The
output is the complete, compilable file: the expanded module spliced into
your original source, so everything around it (#![no_std], #![no_main],
imports, statics, and any code after the module) is preserved. Pipe it into a file and it stays executable:
cargo rticx-expand --example hello_rtic --features swtasks > expanded.rsTo debug the generated code with GDB, replace the #[…::app] module in your
source file with the expansion:
cargo rticx-expand --example hello_rtic --features swtasks --mergeThe tool finds the file containing the #[<distro>::app] module
automatically (or use --file if your app module lives in a separate file),
keeps the original as <file>.old, and replaces the attribute and its module
with the expanded code: all other code in the file (#![no_std], imports,
statics, trailing items) stays untouched. The resulting file is a plain Rust
file: set your GDB breakpoints anywhere in it and build/flash as usual.
The tool runs
cargo checkand reports its result, but the merge happens even when checking fails (for example because of an error in your task bodies), the expansion is still useful for inspection. If the macro itself panics or the crate fails to compile before reaching it, no expansion can be produced; the tool prints the cargo output and leaves your sources untouched.
Any build flag you would pass to cargo check works:
cargo rticx-expand --bin hello_rtic --target thumbv7m-none-eabi \
--features swtasks --no-default-featuresIf the package has several binaries/examples, specify the one to expand with
--bin <name> or --example <name>.
When you are done debugging after a --merge, use:
cargo rticx-expand restoreThis replaces the merged file with its .old backup (auto-detected; use
--file to disambiguate) and, with --remove-expansions, deletes the
expansion directory. You can then rebuild the original RTICX sources.
Snapshot the module after every pipeline stage (each compilation pass and the core pass) into a directory of your choice:
cargo rticx-expand --example hello_rtic --features swtasks --expand-passes target/passesThe directory receives one file per stage, named so lexical order equals pipeline order:
target/passes/00_original.rs # the module exactly as you wrote it
target/passes/01_SoftwareTasks.rs # after the software tasks pass
target/passes/02_core.rs # after the core pass (the final expansion)Now point your diff tool at consecutive files to see exactly what each stage changed: no need to re-run with different pass selections:
diff -u target/passes/00_original.rs target/passes/01_SoftwareTasks.rs # what the pass did
diff -u target/passes/01_SoftwareTasks.rs target/passes/02_core.rs # what the core pass did
# or compare the whole chain side by side:
meld target/passes| File | Contents |
|---|---|
00_original.rs |
The module exactly as received, before any pass |
NN_<Pass>.rs |
Module state after the pass at pipeline position N
|
NN_<Pass>_input.rs |
State the failing pass received (only when a pass errors) |
NN_core.rs |
The full, final expansion after the core pass |
NN_post_passes.rs |
State after all passes (only when core parsing fails) |