4 minute read

Summary

When you debug Rust in VS Code, one of the easiest stacks to understand is rust-analyzer together with CodeLLDB. This post focuses on the most common beginner path inside a Cargo project: entering debug mode, creating launch.json, setting breakpoints, inspecting variables and the call stack, and passing command-line arguments.

The practical takeaway is: create a Cargo project first, install rust-analyzer, add CodeLLDB, and use launch.json to make the debug conditions reproducible.

Document Information

  • Written on: 2026-04-08
  • Verification date: 2026-04-15
  • Document type: tutorial
  • Test environment: Cargo project, VS Code, rust-analyzer, CodeLLDB, Windows-style example paths
  • Test version: VS Code, rust-analyzer, and CodeLLDB versions not fixed
  • Source quality: only official documentation and the upstream repository are used.
  • Note: this post intentionally stays with the rust-analyzer + CodeLLDB path because it is one of the easiest debugger stacks for beginners to follow consistently.

Problem Definition

At the beginning, Rust debugging in VS Code usually feels unclear in four places.

  • It is not obvious whether debugging should be explained around a single file or a Cargo project.
  • The roles of rust-analyzer and CodeLLDB are easy to mix up.
  • launch.json often feels abstract until it is tied to a real executable path and arguments.
  • Breakpoints, variables, the call stack, and argument passing do not always feel like one connected workflow.

This post only covers the basic Cargo-project path needed to reduce that confusion. It does not cover WSL, remote containers, multiple binaries, test debugging, or advanced LLDB settings.

Verified Facts

Directly Confirmed Results

1. A Cargo project was the cleanest debugging baseline

  • Direct result: the flow below matched the debugger setup much better than a single-file example.
cargo new rust-debug-demo
cd rust-debug-demo
code .
  • Direct result: a single-file flow such as rustc hello.rs worked for compilation, but it was a poor fit for the rust-analyzer + CodeLLDB walkthrough used in this post.

2. Installing rust-analyzer made debug entry much easier

  • Direct result: after opening a Cargo project in VS Code and installing rust-analyzer, a Run | Debug button appeared above fn main().

rust-analyzer Run Debug

  • Direct result: that button, or the Rust Analyzer: Debug command, was enough to enter the first debug session.

3. CodeLLDB and launch.json fixed the execution conditions

  • Direct result: in the Run and Debug view, selecting create a launch.json file and then choosing CodeLLDB created the basic debug configuration.

CodeLLDB install Create launch.json Select CodeLLDB

  • Direct result: the simplest Windows example looked like this.
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "lldb",
      "request": "launch",
      "name": "CodeLLDB: Rust Debug",
      "program": "${workspaceFolder}/target/debug/${workspaceFolderBasename}.exe",
      "args": ["abcd", "efgh"],
      "cwd": "${workspaceFolder}"
    }
  ]
}
  • It was easiest to use after building once with:
cargo build

4. Breakpoints, variables, and the call stack were easiest to learn in this order

  • Direct result: the four keys below were enough to understand the basic flow.
  1. F9: set a breakpoint
  2. F5: run or continue
  3. F10: step over
  4. F11: step into
  • Direct result: once a breakpoint was hit, the variables panel and call stack immediately made the current state easier to read.

Breakpoint Variables Call Stack

5. Argument-based debugging was reproducible through args

  • Direct result: putting the code below into src/main.rs and configuring args in launch.json made it easy to verify how command-line arguments entered the program.
fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() > 0 {
        println!("args[0] = {}", args[0]);
    }

    if args.len() > 1 {
        println!("args[1] = {}", args[1]);
    } else {
        println!("args[1] is missing.");
    }

    if args.len() > 2 {
        println!("args[2] = {}", args[2]);
    } else {
        println!("args[2] is missing.");
    }
}
  • The launch.json section looked like this.
"args": ["abcd", "efgh"]
  • Observed result:
args[0] = <executable path>
args[1] = abcd
args[2] = efgh
  • Direct result: args[0] was the executable path, and the values from launch.json appeared starting at args[1] and args[2].

Interpretation / Opinion

  • Opinion: for beginners, it is easier to learn one debugger stack consistently than to mix several debugger extensions at once. rust-analyzer + CodeLLDB is a practical pair for that.
  • Opinion: Cargo projects connect more naturally to Run | Debug, launch.json, and the generated executable path than single-file examples do.
  • Interpretation: launch.json is not just an option file. It is the reproducibility layer that pins down which executable, working directory, and arguments are used during a debug session.

Limits and Exceptions

  • This post is written for local Windows VS Code usage. It does not cover macOS, Linux, WSL, Remote SSH, or Dev Container setups.
  • Button placement, menu labels, and onboarding text can vary across VS Code, rust-analyzer, and CodeLLDB versions.
  • The official VS Code Rust guide sometimes points Windows users to the Microsoft C++ extension first. This post stays with CodeLLDB to keep the walkthrough on one debugger stack.
  • Test debugging, attach mode, multiple binaries, and larger workspace setups are outside the scope of this post.

References

댓글남기기