Debugging Rust with rust-lldb
Tags: rust, debug, lldb
Published: 2020-01-20 04:19:38

This is a quick and dirty primer to debugging rust applications with `rust-lldb`.

## Start the Debugger
Assuming you are using `cargo` to build your executable, the first problem you'll run into is that you cannot debug `target/debug/BIN`; instead, you need to debug `target/debug/deps/BIN-HASH` where `BIN` is the name of your program, and `HASH` is a random hash... you'll probably have a ton of builds in the `deps` directory; just use the latest (something like `ls -lt target/debug/deps/BIN-*` should help you find the latest).

If you're trying to debug an example program, they'll live under `target/debug/examples/BIN` - no hash nonsense.

Ok, now you can start the debugger:

```
rust-lldb target/debug/deps/BIN-HASH -- arg1 arg2 ...
```

Where `arg1 arg2 ...` are command line arguments to your application. If your application needs no arguments you can just leave them off.

## Breakpoints
You are now in the lldb debugger. You'll probably want to set some breakpoints before your program starts: you do that with the `breakpoint set` command (shorthand: `b`). There are lots of ways to set your breakpoint (specific file and line number, function name, etc). Type `help breakpoint set` to see documentation. The shorthand, `b`, actually accepts a simpler syntax from which it will guess the right thing to do. For example:

```
breakpoint set --name func
b func
```

These two commands will do the same thing. So will:

```
breakpoint set -f src/path/to/file.rs -l linenr
b src/path/to/file.rs:linenr
```

Run `help b` to see the simplified syntax.

You can see a list of your breakpoints with `breakpoint list`. There are additional things you can do with breakpoints: see `help breakpoint`.

## Running
Once you've set your breakpoints, you can start the program with `run` (shortcut `r`). Execution will continue until a breakpoint is hit or the program ends (intentionally or not).

## Examining Program State
Ok, so your program is running and it hits a breakpoint. Now what? You'll probably want to examine the state of your program to get an idea of what's going on. Here are some commands to get you started:

`frame variable` will show you all the variables in the current "frame"; ie, variables in scope.

`expression <expr>` (shortcut `expr` or just `p`) will execute `<expr>` and display the result. This can be used to examine the value of a variable or execute some code to see what the result is.

You may have noticed when execution first paused that a listing of your code is shown, pointing to the current line that execution paused on. You can get that listing back with `list` (shortcut `l`).

`n` will "step over" the current line, ie, the current line will execute and then the program will pause again.

`s` will "step into" the current line, ie, the innermost function will be called and execution will pause at the start of that function.

`c` will continue execution until another breakpoint is reached or the program exits.

Finally, if you're debugging a program that interops with another language (ffi), it might be useful to examine specific memory addresses. That can be done with `x <addr>`. This will show a hex-dump of memory at that address.

## Some Other Helpful Things
If you would normally invoke your program by piping something into stdin (ie, `cat file.txt | my-program`), you won't be able to do that when running your program under rust-lldb. Instead, run rust-lldb with your program (ie, `rust-lldb my-program`) and then run:

```
settings set target.input-path <path-to-file>
```

## Conclusion
This is just barely scratching the surface of debugging. lldb is very powerful; judicious use of `help` is encouraged. But hopefully this little primer will get you started!