Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve debuginfo for closures and async functions on Windows MSVC #83941

Merged
merged 1 commit into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 39 additions & 15 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_middle::ty;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, Span};
use rustc_target::abi::{LayoutOf, Size};
use rustc_target::abi::Size;

use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
Expand Down Expand Up @@ -265,33 +265,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
None => continue,
};

let mut layout = base.layout;
let mut direct_offset = Size::ZERO;
// FIXME(eddyb) use smallvec here.
let mut indirect_offsets = vec![];
let mut place = base;

for elem in &var.projection[..] {
match *elem {
mir::ProjectionElem::Deref => {
indirect_offsets.push(Size::ZERO);
layout = bx.cx().layout_of(
layout
.ty
.builtin_deref(true)
.unwrap_or_else(|| {
span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty)
})
.ty,
);
place = place.project_deref(bx);
}
mir::ProjectionElem::Field(field, _) => {
let i = field.index();
let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
*offset += layout.fields.offset(i);
layout = layout.field(bx.cx(), i);
*offset += place.layout.fields.offset(i);
place = place.project_field(bx, i);
}
mir::ProjectionElem::Downcast(_, variant) => {
layout = layout.for_variant(bx.cx(), variant);
place = place.project_downcast(bx, variant);
}
_ => span_bug!(
var.source_info.span,
Expand All @@ -301,7 +293,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}

bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
// When targeting MSVC, create extra allocas for arguments instead of pointing multiple
// dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
// not DWARF and LLVM doesn't support translating the resulting
// [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView.
// Creating extra allocas on the stack makes the resulting debug info simple enough
// that LLVM can generate correct CodeView records and thus the values appear in the
// debugger. (#83709)
let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
&& self.mir.local_kind(local) == mir::LocalKind::Arg
// LLVM can handle simple things but anything more complex than just a direct
// offset or one indirect offset of 0 is too complex for it to generate CV records
// correctly.
&& (direct_offset != Size::ZERO
|| !matches!(&indirect_offsets[..], [Size::ZERO] | []));

if should_create_individual_allocas {
// Create a variable which will be a pointer to the actual value
let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut {
mutbl: mir::Mutability::Mut,
ty: place.layout.ty,
}));
let ptr_layout = bx.layout_of(ptr_ty);
let alloca = PlaceRef::alloca(bx, ptr_layout);
bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill"));

// Write the pointer to the variable
bx.store(place.llval, alloca.llval, alloca.align);

// Point the debug info to `*alloca` for the current variable
bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]);
} else {
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
downcast
}

pub fn project_deref<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) -> Self {
let target_ty = self.layout.ty.builtin_deref(true).expect("failed to deref");
let layout = bx.layout_of(target_ty.ty);

PlaceRef {
llval: bx.load(self.llval, self.align),
llextra: None,
layout,
align: layout.align.abi,
}
}

pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
bx.lifetime_start(self.llval, self.layout.size);
}
Expand Down
49 changes: 49 additions & 0 deletions src/test/debuginfo/var-captured-in-nested-closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,55 @@
// lldbr-check:(isize) closure_local = 8
// lldb-command:continue


// === CDB TESTS ===================================================================================

// cdb-command: g

// cdb-command: dx variable
// cdb-check:variable : 1 [Type: [...]]
// cdb-command: dx constant
// cdb-check:constant : 2 [Type: [...]]
// cdb-command: dx a_struct
// cdb-check:a_struct [Type: var_captured_in_nested_closure::Struct]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx struct_ref
// cdb-check:struct_ref : 0x[...] [Type: var_captured_in_nested_closure::Struct *]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx owned
// cdb-check:owned : 0x[...] : 6 [Type: [...] *]
// cdb-check: 6 [Type: [...]]
// cdb-command: dx closure_local
// cdb-check:closure_local : 8 [Type: [...]]
// cdb-command: dx nested_closure
// cdb-check:nested_closure [Type: var_captured_in_nested_closure::main::{{closure}}::closure-0]

// cdb-command: g

// cdb-command: dx variable
// cdb-check:variable : 1 [Type: [...]]
// cdb-command: dx constant
// cdb-check:constant : 2 [Type: [...]]
// cdb-command: dx a_struct
// cdb-check:a_struct [Type: var_captured_in_nested_closure::Struct]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx struct_ref
// cdb-check:struct_ref : 0x[...] [Type: var_captured_in_nested_closure::Struct *]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx owned
// cdb-check:owned : 0x[...] : 6 [Type: [...] *]
// cdb-check: 6 [Type: [...]]
// cdb-command: dx closure_local
// cdb-check:closure_local : 8 [Type: [...]]

#![allow(unused_variables)]
#![feature(box_syntax)]
#![feature(omit_gdb_pretty_printer_section)]
Expand Down
42 changes: 42 additions & 0 deletions src/test/debuginfo/var-captured-in-stack-closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,48 @@
// lldbg-check:[...]$9 = 6
// lldbr-check:(isize) *owned = 6


// === CDB TESTS ===================================================================================

// cdb-command: g

// cdb-command: dx variable
// cdb-check:variable : 1 [Type: [...]]
// cdb-command: dx constant
// cdb-check:constant : 2 [Type: [...]]
// cdb-command: dx a_struct
// cdb-check:a_struct [Type: var_captured_in_stack_closure::Struct]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx struct_ref
// cdb-check:struct_ref : 0x[...] [Type: var_captured_in_stack_closure::Struct *]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx owned
// cdb-check:owned : 0x[...] : 6 [Type: [...] *]


// cdb-command: g

// cdb-command: dx variable
// cdb-check:variable : 2 [Type: [...]]
// cdb-command: dx constant
// cdb-check:constant : 2 [Type: [...]]
// cdb-command: dx a_struct
// cdb-check:a_struct [Type: var_captured_in_stack_closure::Struct]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx struct_ref
// cdb-check:struct_ref : 0x[...] [Type: var_captured_in_stack_closure::Struct *]
// cdb-check: [+0x[...]] a : -3 [Type: [...]]
// cdb-check: [+0x[...]] b : 4.500000 [Type: [...]]
// cdb-check: [+0x[...]] c : 0x5 [Type: unsigned [...]]
// cdb-command: dx owned
// cdb-check:owned : 0x[...] : 6 [Type: [...] *]

#![feature(box_syntax)]
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
Expand Down