🎓 A1Learner
🔍

Rust Using a Debugger

A debugger is a tool that pauses a running program on a marked line. Every value sits within reach while the program is paused.

Start the debugger

Build first. Then hand the debug binary to the starter command:

// in your terminal:
// $ cargo build
// $ rust-gdb target/debug/marks

Mark a line, then run

Inside the debugger you type short commands at its prompt. break marks the line. run starts the program:

// at the (gdb) prompt:
// break main
// run

Read values while paused

print shows any value in reach, in its Rust shape. Ask for the inputs. Ask for the half-finished answer:

// at the (gdb) prompt:
// print scores
// print total

Step, do not leap

next runs one line and steps over calls. step runs one line and dives into a call. continue runs on to the next breakpoint:

// at the (gdb) prompt:
// next
// step
// continue

The editor drives the same session

The Debug label above main starts this same debugger inside your editor. Breakpoints become red dots in the margin. The values panel is print, without the typing:

fn main() {
    let answer = sum_to(4);
    println!("sum 1..=4 = {answer}");
}

Example

fn sum_to(limit: i32) -> i32 {
    let mut total = 0;
    let mut n = 1;
    while n <= limit {
        total += n;
        n += 1;
    }
    total
}

fn main() {
    let answer = sum_to(4);
    println!("sum 1..=4 = {answer}");
}

Key points

  • A debugger trades speed for sight: the program stops, and every value can be read.
  • A breakpoint is a line that is marked: the running program pauses just before that line runs
  • Use rust-gdb to start the gdb debugger on a Rust program.
  • Use rust-lldb for the lldb debugger, the common one on macOS.
  • Both starters load Rust pretty-printers.
  • A Vec shows its items.
  • A String shows its text.
  • Neither shows raw memory.
  • The everyday moves are few.
  • run starts the program.
  • next runs one line.
  • step dives into a call.
  • print shows a value.
  • continue runs to the next breakpoint.
  • Use a debug build for debugging.
  • Its debug info maps the running program back to the source lines.
  • An optimised build can report a value as optimised out.

In this example, sum_to adds the numbers from 1 up to the limit. A debugger session on it could go like this. Put a breakpoint on the total += n line. Run, and the program pauses with n = 1 and total = 0. Continue, and it pauses again with n = 2 and total = 1. Four pauses walk the loop by hand. The last one leaves total = 10, and main prints sum 1..=4 = 10.

Note

A debugger freezes time.

Some bugs hate being frozen and vanish.

If a bug hides whenever the program pauses, dbg! and logging are the better tools.

Prints never stop the clock.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

The debugger reports a key value as "optimised out". What went wrong?