Usage of GDB debugger

How to use the GDB debugger with a Raspberry Pi Pico 2 W.

Previous post: Logging with defmt over RTT.

Debugging with GDB

Once you start creating slightly more complicated embedded programs, you might want to:

For this, you need a piece of software called a debugger. The most commonly used debugger for Rust and C is GDB.

Remark: In VS Code, you can install the probe-rs-debug extension to use the probe-rs toolkit for debugging. It uses a different protocol than gdb. See instructions.

Setup of cargo-embed

Adjust the Embed.toml file in the root of this repository if necessary. This file configures the behavior of the cargo embed command when run on your laptop.

For example, if the configuration contains the following, a GDB debug server session will be started, and the loaded program will be reset to the first instruction.

[default.gdb]
enabled = true

[default.reset]
halt_afterwards = true

Prevent lines from being merged or reordered during the build step of your program. These kinds of changes can make it harder for the debugger to stop at the right breakpoints. Add the following to Cargo.toml:

[profile.dev]
debug = 2
opt-level = 0

To be sure the new configuration is used, you can clear the target build cache with cargo clean and then build again:

cargo clean
cargo build --example [BINARY_EXAMPLE_NAME]

Starting a GDB Client

While searching for an appropriate GDB package, look for one that supports the architecture of your target chip. In the case of a Pico 2, gdb needs ARM support built in.

Install the multi-architecture version of gdb:

sudo apt-get install gdb-multiarch

Then run the following command to create and connect a gdb debugging client:

gdb-multiarch target/thumbv8m.main-none-eabi/debug/[BINARY_EXAMPLE_NAME]

Note: The command may also be gdb.

Within the gdb client on your laptop, you have to connect to the running GDB server on the debug Pico probe:

target remote :1337
monitor reset halt # optionally resets to the first instruction
tui enable

Alternatively, you can tell gdb to execute these commands automatically by writing them in a .gdbinit file in the root of this repository.

Common GDB Commands

Breakpoints can be set in the gdb client by using the break command followed by a line number or function name:

break [FUNCTION_NAME]  # Set a breakpoint at a specific function
break [LINE_NUMBER]  # Set a breakpoint at a specific line number
break [FILE_NAME]:[LINE_NUMBER]  # Set a breakpoint at a specific line in a file

You can also write hardware breakpoints directly in your code with cortex_m::asm::bkpt().

To progress through the execution of your debugged program, you can use:

continue  # Continue execution until the next breakpoint is hit
next      # Step to the next line of code

For introspection of variables:

print [VAR_NAME]