When it comes to debugging Rust in VSCode, the CodeLLDB extension provides a great debugging experience. Until you try to step into some Rust stdlib code and are greeted with assembly.
Of course you can manually add a source map entry for your rust toolchain, which involves finding the current rustc version commit hash and the sysroot path for the source code:
$ rustc --version --verbose
rustc 1.76.0 (07dca489a 2024-02-04)
binary: rustc
commit-hash: 07dca489ac2d933c78d3c5158e3f43beefeb02ce
commit-date: 2024-02-04
host: aarch64-apple-darwin
release: 1.76.0
LLVM version: 17.0.6
$ rust --print sysroot
/Users/USERNAME/.rustup/toolchains/stable-aarch64-apple-darwin
then plugging that into the source map (map from /rustc/{commit-hash}
to {sysroot}/lib/rustlib/src/rust
). However, every time you update your rust toolchain to a new version, these values may have to be updated.
LLDB comes with first-class Python scripting support, so why not have LLDB figure this out for you. CodeLLDB lets you run arbitrary LLDB commands before launching a debug session via the lldb.launch.preRunCommands
setting, so we can set a source map config every time we need to debug.
Plug the following snippet into your VSCode settings.json file and Bob's your uncle:
"lldb.launch.preRunCommands": [
"script import subprocess;rustc=lambda *a: subprocess.run(['rustc',*a],stdout=subprocess.PIPE,check=True,text=True).stdout;sysroot=rustc('--print','sysroot').strip();gitsha=rustc('-vV').partition('commit-hash:')[-1].partition('\\n')[0].strip();lldb.debugger.HandleCommand(f'settings set target.source-map /rustc/{gitsha} \"{sysroot}/lib/rustlib/src/rust\"')"
],
That's quite a mouthfull, so lets break this down a bit.
The command starts with script
, which tells LLDB to interpret the rest of the text as a Python script. The Python code uses ;
to delimit multiple statements. Even though Python is a whitespace-significant language, you can still put multiple statements on a single line provided they are simple statements, e.g. anything that doesn't require an indented block underneath.
Here are those same Python statements, with whitespace and comments added:
import subprocess
# Run the `rustc` command with a given set of arguments as a subprocess,
# and return whatever it outputs to stdout as text (decoded from UTF-8).
rustc = lambda *a: subprocess.run(
['rustc', *a],
stdout=subprocess.PIPE,
check=True,
text=True
).stdout
# Get the current sysroot and commit hash for rustc, producing cleaned strings
sysroot = rustc('--print', 'sysroot').strip()
# `rustc -vV` is shorthand for `rustc --version --verbose`
gitsha = rustc('-vV').partition('commit-hash:')[-1].partition('\n')[0].strip()
# Call back to the LLDB debugger to add a source-map using the rustc
# configuration retrieved above
lldb.debugger.HandleCommand(
f'settings set target.source-map /rustc/{gitsha} "{sysroot}/lib/rustlib/src/rust"
)