
Rust Debugging
- 324 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
Diagnose panics, borrow errors, and runtime failures in Rust crates using lldb/gdb, logging, backtraces, and targeted reproduction steps before release.
About
Guides low-level Rust debugging across native debuggers, structured logging, and backtrace configuration to isolate panics, ownership violations, and concurrency bugs in CLI and systems binaries.
- lldb/gdb workflows for Rust symbols
- backtrace and RUST_BACKTRACE setup
- panic vs Result failure triage
- minimal repro crate patterns
- async/thread deadlock isolation
Rust Debugging by the numbers
- 324 all-time installs (skills.sh)
- +25 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #37 of 121 Rust skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill rust-debuggingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 324 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
What it does
Diagnose panics, borrow errors, and runtime failures in Rust crates using lldb/gdb, logging, backtraces, and targeted reproduction steps before release.
Files
Rust Debugging
Purpose
Guide agents through debugging Rust programs: GDB/LLDB with Rust pretty-printers, backtrace configuration, panic triage, async debugging with tokio-console, and #[no_std] debugging strategies.
Triggers
- "How do I use GDB/LLDB to debug a Rust binary?"
- "How do I get a full backtrace from a Rust panic?"
- "How do I debug async Rust / Tokio?"
- "Rust pretty-printers aren't working in GDB"
- "How do I debug a Rust panic in production?"
- "How do I use dbg! and tracing in Rust?"
Workflow
1. Build for debugging
# Debug build (default) — full debug info, no optimization
cargo build
# Release with debug info (for profiling real workloads)
cargo build --release --profile release-with-debug
# Or configure in Cargo.toml:
# [profile.release-with-debug]
# inherits = "release"
# debug = true
# Run directly
cargo run
cargo run -- arg1 arg22. GDB with Rust pretty-printers
# Use rust-gdb wrapper (sets up pretty-printers automatically)
rust-gdb target/debug/myapp
# Or set up manually in ~/.gdbinit:
# python
# import subprocess, sys
# ...Common GDB session for Rust:
# Basic
(gdb) break main
(gdb) run arg1 arg2
(gdb) next # step over
(gdb) step # step into
(gdb) continue
# Rust-aware inspection
(gdb) print my_string # Shows String content via pretty-printer
(gdb) print my_vec # Shows Vec elements
(gdb) print my_option # Shows Some(value) or None
(gdb) info locals
# Break on panic
(gdb) break rust_panic
(gdb) break core::panicking::panic
# Backtrace
(gdb) bt # Short backtrace
(gdb) bt full # Full with locals3. LLDB with Rust pretty-printers
# Use rust-lldb wrapper
rust-lldb target/debug/myapp
# Manual setup
lldb target/debug/myapp
(lldb) command script import /path/to/rust/lib/rustlib/etc/lldb_lookup.py
(lldb) command source /path/to/rust/lib/rustlib/etc/lldb_commandsCommon LLDB session:
(lldb) b main::main
(lldb) r arg1 arg2
(lldb) n # next (step over)
(lldb) s # step into
(lldb) c # continue
(lldb) frame variable # show locals
(lldb) p my_string # print variable with pretty-printer
(lldb) bt # backtrace
(lldb) bt all # all threads4. Backtrace configuration
# Short backtrace (default on panic)
RUST_BACKTRACE=1 ./myapp
# Full backtrace with all frames
RUST_BACKTRACE=full ./myapp
# With symbols (requires debug build or separate debug info)
RUST_BACKTRACE=full ./target/debug/myapp
# Capture backtrace programmatically
use std::backtrace::Backtrace;
let bt = Backtrace::capture();
eprintln!("{bt}");For release binaries, keep debug symbols in a separate file:
# Build release with debug info
cargo build --release
objcopy --only-keep-debug target/release/myapp target/release/myapp.debug
strip --strip-debug target/release/myapp
objcopy --add-gnu-debuglink=target/release/myapp.debug target/release/myapp5. Panic triage
// Set a custom panic hook for structured logging
use std::panic;
panic::set_hook(Box::new(|info| {
let backtrace = std::backtrace::Backtrace::force_capture();
eprintln!("PANIC: {info}");
eprintln!("{backtrace}");
// Log to file, send to Sentry, etc.
}));Common panic patterns:
| Panic message | Likely cause |
|---|---|
index out of bounds: the len is N but the index is M | Array/vec OOB access |
called Option::unwrap() on a None value | Unwrap on None |
called Result::unwrap() on an Err value | Unwrap on error |
attempt to subtract with overflow | Integer underflow (debug build) |
assertion failed | Failed assert! or assert_eq! |
stack overflow | Infinite recursion |
Use panic = "abort" in release to get a crash dump instead of unwind.
6. The dbg! macro
// dbg! prints file, line, value and returns the value
let result = dbg!(some_computation(x));
// prints: [src/main.rs:15] some_computation(x) = 42
// Chain multiple values
let (a, b) = dbg!((compute_a(), compute_b()));
// Inspect inside iterator chains
let sum: i32 = (0..10)
.filter(|x| dbg!(x % 2 == 0))
.map(|x| dbg!(x * x))
.sum();7. Structured logging with tracing
[dependencies]
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }use tracing::{debug, error, info, instrument, warn};
#[instrument] // Auto-traces function entry/exit with arguments
fn process(id: u64, data: &str) -> Result<(), Error> {
debug!("Processing item");
info!(item_id = id, "Started processing");
if data.is_empty() {
warn!(item_id = id, "Empty data");
return Err(Error::EmptyData);
}
error!(item_id = id, err = ?some_result, "Failed");
Ok(())
}
// Initialize in main
tracing_subscriber::fmt()
.with_env_filter("myapp=debug,warn")
.init();# Control log levels at runtime
RUST_LOG=debug ./myapp
RUST_LOG=myapp::module=trace,warn ./myapp8. Async debugging with tokio-console
[dependencies]
console-subscriber = "0.3"
tokio = { version = "1", features = ["full", "tracing"] }// In main
console_subscriber::init();# Install and run tokio-console
cargo install tokio-console
tokio-console # Connects to running Rust process at port 6669tokio-console shows: task states, waker activity, blocked tasks, poll durations.
For GDB/LLDB command reference and pretty-printer setup, see references/rust-gdb-pretty-printers.md.
Related skills
- Use
skills/rust/rustc-basicsfor debug info flags and build configuration - Use
skills/debuggers/gdbfor GDB fundamentals - Use
skills/debuggers/lldbfor LLDB fundamentals - Use
skills/rust/rust-sanitizers-mirifor memory safety and undefined behaviour
Rust GDB/LLDB Pretty-Printers Reference
GDB Setup
Automatic via rust-gdb
rust-gdb is a wrapper script installed with rustup that sources Rust pretty-printers:
# Find the wrapper
which rust-gdb
# /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rust-gdb
# Use it
rust-gdb ./target/debug/myappManual ~/.gdbinit setup
# ~/.gdbinit
python
import subprocess, sys
# Find rustc sysroot
sysroot = subprocess.check_output(['rustc', '--print', 'sysroot']).decode().strip()
sys.path.insert(0, f'{sysroot}/lib/rustlib/etc')
import gdb_lookup
end
# Enable pretty-printing
set print pretty on
set print array onGDB Commands for Rust
Types
# Print type of expression
(gdb) ptype my_var
(gdb) whatis my_var
# Inspect String
(gdb) p my_string
$1 = "hello world"
# Inspect Vec<T>
(gdb) p my_vec
$2 = vec![1, 2, 3, 4, 5]
(gdb) p my_vec.len
# Inspect Option<T>
(gdb) p my_option
$3 = Some(42)
# Inspect Result<T, E>
(gdb) p my_result
$4 = Ok(42)
# or
$4 = Err(MyError { ... })
# Inspect HashMap
(gdb) p my_map
$5 = HashMap{...}Breakpoints in Rust
# Break on function by full path
(gdb) break myapp::module::function_name
# Break on trait method
(gdb) break '<MyType as MyTrait>::method'
# Break on closure (Rust closures get mangled names)
(gdb) break myapp::module::function_name::{closure#0}
# Break on panic
(gdb) break rust_panic
(gdb) break std::panicking::begin_panic
# Break on specific file:line
(gdb) break src/main.rs:42
# Conditional break
(gdb) break myapp::process if id == 100Thread debugging
# List all threads
(gdb) info threads
# Switch to thread
(gdb) thread 2
# Apply command to all threads
(gdb) thread apply all bt
# Lock scheduler to current thread
(gdb) set scheduler-locking onLLDB Setup
Automatic via rust-lldb
rust-lldb ./target/debug/myappManual setup
# Find Rust LLDB scripts
rustc --print sysroot
# /home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu
# Source scripts in LLDB session
(lldb) command script import ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_lookup.py
(lldb) command source ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_commandsLLDB Commands for Rust
# Set breakpoint
(lldb) b myapp::module::function_name
(lldb) b src/main.rs:42
# Break on panic
(lldb) b rust_panic
# Print variable
(lldb) frame variable my_var
(lldb) p my_vec
# Print specific field
(lldb) p my_struct.field
# All locals
(lldb) frame variable
# Thread list
(lldb) thread list
# Backtrace
(lldb) thread backtrace
(lldb) thread backtrace allVS Code / IDE Integration
CodeLLDB extension (recommended for Rust)
.vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug myapp",
"program": "${workspaceFolder}/target/debug/myapp",
"args": ["--flag", "value"],
"cwd": "${workspaceFolder}",
"env": {
"RUST_BACKTRACE": "1",
"RUST_LOG": "debug"
},
"sourceMap": {
"/rustc/...": "${env:HOME}/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust"
}
},
{
"type": "lldb",
"request": "launch",
"name": "cargo test -- module_name",
"cargo": {
"args": ["test", "--no-run", "--lib"],
"filter": { "name": "myapp", "kind": "lib" }
},
"args": ["module_name"],
"cwd": "${workspaceFolder}"
}
]
}Debugging #[no_std] Binaries
# Connect to embedded target via OpenOCD + GDB
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg &
rust-gdb target/thumbv7em-none-eabihf/debug/firmware \
--ex "target remote localhost:3333"
# Or use probe-rs
cargo install probe-run
probe-run --chip STM32F411CE target/thumbv7em-none-eabihf/debug/firmwareSymbol Demangling
# Demangle Rust symbols manually
echo '_ZN4core4fmt9Formatter9write_fmt17hb4f5d866d07ffa27E' | rustfilt
# core::fmt::Formatter::write_fmt
# Install rustfilt
cargo install rustfilt
# Or use c++filt
echo '_ZN4core4fmt9Formatter9write_fmt17hb4f5d866d07ffa27E' | c++filt