Skip to content

Commit

Permalink
Auto merge of #96316 - michaelwoerister:debuginfo-fix-unit-msvc, r=we…
Browse files Browse the repository at this point in the history
…sleywiser

debuginfo: Emit ZST struct debuginfo for unit type when CPP-like debuginfo is enabled

As already discovered in 24a728a, PDB does not play well with custom basic types. This PR extends to the fix to `()`: Instead of a custom basic type, we treat it like an empty tuple (i.e. it is described as a struct which happens to have no fields).

Before this change anything with a `()` in it would cause trouble, which is especially bad for `*const ()` and `*mut ()` which are often used for opaque pointers. E.g. the test case added in this PR would look like:
```
0:000>  dx _ref
Error: Unable to bind name '_ref'
0:000>  dx _ptr
Error: Unable to bind name '_ptr'
0:000>  dx _local
Error: Unable to bind name '_local'
0:000>  dx _field,d
_field,d         [Type: unit_type::_TypeContainingUnitField]
    [+0x008] _a               : 123 [Type: unsigned int]
    [+0x000] _unit            : Unexpected failure to dereference object
    [+0x000] _b               : 456 [Type: unsigned __int64]
0:000>  dx ((__int64 *)_ptr),x
Error: Unable to bind name '_ptr'
```

With the PR it produces the expected output:
```
0:000>  dx _ref
_ref             : 0x7ff6f2012230 : () [Type: tuple$<> *]
0:000>  dx _ptr
_ptr             : 0x7e8ddffc20 : () [Type: tuple$<> *]
0:000>  dx _local
_local           : () [Type: tuple$<>]
0:000>  dx _field,d
_field,d         [Type: unit_type::_TypeContainingUnitField]
    [+0x008] _a               : 123 [Type: unsigned int]
    [+0x000] _unit            : () [Type: tuple$<>]
    [+0x000] _b               : 456 [Type: unsigned __int64]
0:000>  dx ((__int64 *)_ptr),x
((__int64 *)_ptr),x : 0x7e8ddffc20 : 0x1122334455667788 [Type: __int64 *]
```

r? `@wesleywiser`
  • Loading branch information
bors committed Apr 23, 2022
2 parents 64c5deb + 8b23008 commit 09064a2
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 9 deletions.
25 changes: 16 additions & 9 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,11 +437,9 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D

let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
}
ty::Tuple(elements) if elements.is_empty() => {
DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
build_basic_type_di_node(cx, t)
}
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
Expand Down Expand Up @@ -640,7 +638,10 @@ impl MsvcBasicName for ty::FloatTy {
}
}

fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
fn build_basic_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
t: Ty<'tcx>,
) -> DINodeCreationResult<'ll> {
debug!("build_basic_type_di_node: {:?}", t);

// When targeting MSVC, emit MSVC style type names for compatibility with
Expand All @@ -649,7 +650,13 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -

let (name, encoding) = match t.kind() {
ty::Never => ("!", DW_ATE_unsigned),
ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
ty::Tuple(elements) if elements.is_empty() => {
if cpp_like_debuginfo {
return build_tuple_type_di_node(cx, UniqueTypeId::for_ty(cx.tcx, t));
} else {
("()", DW_ATE_unsigned)
}
}
ty::Bool => ("bool", DW_ATE_boolean),
ty::Char => ("char", DW_ATE_UTF),
ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
Expand All @@ -672,14 +679,14 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
};

if !cpp_like_debuginfo {
return ty_di_node;
return DINodeCreationResult::new(ty_di_node, false);
}

let typedef_name = match t.kind() {
ty::Int(int_ty) => int_ty.name_str(),
ty::Uint(uint_ty) => uint_ty.name_str(),
ty::Float(float_ty) => float_ty.name_str(),
_ => return ty_di_node,
_ => return DINodeCreationResult::new(ty_di_node, false),
};

let typedef_di_node = unsafe {
Expand All @@ -694,7 +701,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -
)
};

typedef_di_node
DINodeCreationResult::new(typedef_di_node, false)
}

fn build_foreign_type_di_node<'ll, 'tcx>(
Expand Down
71 changes: 71 additions & 0 deletions src/test/debuginfo/unit-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// compile-flags:-g

// We only test Rust-aware versions of GDB:
// min-gdb-version: 8.2

// === GDB TESTS ===================================================================================

// gdb-command: run

// gdb-command: print _ref
// gdb-check: $1 = (*mut ()) 0x[...]

// gdb-command: print _ptr
// gdb-check: $2 = (*mut ()) 0x[...]

// gdb-command: print _local
// gdb-check: $3 = ()

// gdb-command: print _field
// gdb-check: $4 = unit_type::_TypeContainingUnitField {_a: 123, _unit: (), _b: 456}

// Check that we can cast "void pointers" to their actual type in the debugger
// gdb-command: print /x *(_ptr as *const u64)
// gdb-check: $5 = 0x1122334455667788

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

// cdb-command: g
// cdb-check: Breakpoint 0 hit

// cdb-command: dx _ref
// cdb-check: _ref : 0x[...] : () [Type: tuple$<> *]

// cdb-command: dx _ptr
// cdb-check: _ptr : 0x[...] : () [Type: tuple$<> *]

// cdb-command: dx _local
// cdb-check: _local : () [Type: tuple$<>]

// cdb-command: dx _field,d
// cdb-check: _field,d [Type: unit_type::_TypeContainingUnitField]
// cdb-check: [+0x[...]] _a : 123 [Type: unsigned int]
// cdb-check: [+0x[...]] _unit : () [Type: tuple$<>]
// cdb-check: [+0x[...]] _b : 456 [Type: unsigned __int64]

// Check that we can cast "void pointers" to their actual type in the debugger
// cdb-command: dx ((__int64 *)_ptr),x
// cdb-check: ((__int64 *)_ptr),x : 0x[...] : 0x1122334455667788 [Type: __int64 *]
// cdb-check: 0x1122334455667788 [Type: __int64]

struct _TypeContainingUnitField {
_a: u32,
_unit: (),
_b: u64,
}

fn foo(_ref: &(), _ptr: *const ()) {
let _local = ();
let _field = _TypeContainingUnitField { _a: 123, _unit: (), _b: 456 };

zzz(); // #break
}

fn main() {
let pointee = 0x1122_3344_5566_7788i64;

foo(&(), &pointee as *const i64 as *const ());
}

#[inline(never)]
fn zzz() {}

0 comments on commit 09064a2

Please sign in to comment.