-
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) |