PDB debugging information has bad variable valid ranges
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.2k
- PR merge metrics
- PR metrics pending
Description
On windows, with this repro case, compiled with cargo rustc (--emit=asm,llvm-ir)
fn main() {
foobar(5);
}
fn foobar(n: usize) -> () {
let foo = if n == 5 {
0
} else {
1
};
let bar = if n == 6 {
1
} else {
2
};
}
I expected to see this happen: When stepping through code source line-by-line (in either WinDbg, or the LLDB-based RustRover debugger), I'd expect the value of foo to be available and shown in the locals window once we reach line 12 (let bar = ...).
Instead, this happened: Instead, the value is only available when stepping past that location, either to the next line, or even to the next assembly instruction.
The ultimate reason for this is that the emitted debuginfo is inaccurate: (from the asm output)
.def _ZN20rust_debuginfo_repro6foobar17h5720b41e41166300E;
.scl 3;
.type 32;
.endef
.section .text,"xr",one_only,_ZN20rust_debuginfo_repro6foobar17h5720b41e41166300E,unique,1
.p2align 4
_ZN20rust_debuginfo_repro6foobar17h5720b41e41166300E:
.Lfunc_begin1:
.cv_func_id 1
.cv_loc 1 1 5 0
.seh_proc _ZN20rust_debuginfo_repro6foobar17h5720b41e41166300E
subq $24, %rsp
.seh_stackalloc 24
.seh_endprologue
movq %rcx, (%rsp)
movq %rcx, 16(%rsp)
.Ltmp2:
.cv_loc 1 1 6 0
cmpq $5, %rcx
jne .LBB1_2
.cv_loc 1 1 7 0
movl $0, 8(%rsp)
.cv_loc 1 1 6 0
jmp .LBB1_3
.LBB1_2:
.cv_loc 1 1 9 0
movl $1, 8(%rsp)
.LBB1_3:
.cv_loc 1 1 12 0
movq (%rsp), %rax # <- Line 12 breakpoint/stepping stops here
.Ltmp3: # <- "foo" valid starting from here (see debug record at the end)
cmpq $6, %rax
jne .LBB1_5
.cv_loc 1 1 13 0
movl $1, 12(%rsp)
.cv_loc 1 1 12 0
jmp .LBB1_6
.LBB1_5:
.cv_loc 1 1 15 0
movl $2, 12(%rsp)
.Ltmp4:
.LBB1_6:
.cv_loc 1 1 17 0
.seh_startepilogue
addq $24, %rsp
.seh_endepilogue
retq
.Ltmp5:
.Lfunc_end1:
.seh_endproc
# later...
# Debug record for "foo" variable
.asciz "foo"
.p2align 2, 0x0
.Ltmp49:
.cv_def_range .Ltmp3 .Ltmp4, frame_ptr_rel, 8 # Valid from .Ltmp3 to .Ltmp4
Interestingly, I compared the debug output generated for DWARF (https://godbolt.org/z/4b9T8fvvs) and while it appears to have the same validity range as the CodeView version, it rather assigns the source locations differently:
.LBB0_2:
.loc 1 9 9
mov dword ptr [rsp - 16], 1
.LBB0_3:
.loc 1 0 9 is_stmt 0 # <- Marked as line 12 in PDB, but "no line" here
mov rax, qword ptr [rsp - 24]
.Ltmp1: # <- "foo" validity starts here
.loc 1 12 18 is_stmt 1
cmp rax, 6
jne .LBB0_5
This means that a breakpoint on that line ends up stopping at the cmp instead, and "foo" is visible as expected. (Even though, in reality, the value on the stack was already available on the previous instruction, but this is much less of an issue.)
Meta
rustc --version --verbose:
rustc 1.93.0-beta.6 (7bea8c6cf 2026-01-09)
binary: rustc
commit-hash: 7bea8c6cf1ccce6b06c26d9a435e85cd0b9113bb
commit-date: 2026-01-09
host: x86_64-pc-windows-msvc
release: 1.93.0-beta.6
LLVM version: 21.1.8
I found similar reports in the RustRover bug tracker going back several years, so this is unlikely to be a recent regression: RUST-15126 RUST-6821
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the Windows case with cargo rustc --emit=asm,llvm-ir using the foobar example, then inspect the emitted CodeView/PDB records around .cv_loc and .cv_def_range. Compare the PDB and DWARF source locations and variable ranges; done means foo is visible when execution reaches line 12 in the debugger without stepping past it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100