Skip to content
Open
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
32 changes: 30 additions & 2 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) };
let subscripts = &[subrange];

let di_node = unsafe {
let mut di_node = unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
size.bits(),
Expand All @@ -128,6 +128,22 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
)
};

if cpp_like_debuginfo(cx.tcx) {
Copy link
Copy Markdown
Member

@Enselic Enselic Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies, but I still don't understand why we need to change both fn build_pointer_or_reference_di_node() and fn build_fixed_size_array_di_node() in the same PR. They seem completely orthogonal to me. So far I've only looked at the change in the former.

View changes since the review

let array_type_name = compute_debuginfo_type_name(cx.tcx, array_type, false);
di_node = unsafe {
llvm::LLVMDIBuilderCreateTypedef(
DIB(cx),
di_node,
array_type_name.as_ptr(),
array_type_name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
None,
0,
)
};
}

DINodeCreationResult::new(di_node, false)
}

Expand Down Expand Up @@ -177,8 +193,20 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
pointer_align.abi,
&ptr_type_debuginfo_name,
);
let typedefed_ptr = unsafe {
Copy link
Copy Markdown
Member

@Enselic Enselic Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I've dug deeper, I've discovered that this program:

fn foo(f: &usize) {
    println!("Value: {}", f);
}

fn main() {
    let x = 5;
    foo(&x);
}

with plain gdb (not rust-gdb) says that the type of f is *mut usize:

$ rustc -g /home/martin/src/main.rs && gdb -ex "b main::foo" -ex "run" -ex "ptype f" --args main
Breakpoint 1, main::foo (f=0x7fffffffe2b0) at /home/martin/src/main.rs:2
2           println!("Value: {}", f);
type = *mut usize

I've debugged gdb with gdb, and the reason is that gdb doesn't think the type have a name in this part of gdb code:

    case TYPE_CODE_PTR:
      {
        if (type->name () != nullptr)
          gdb_puts (type->name (), stream);
        else
          {
            /* We currently can't distinguish between pointers and
               references.  */
            gdb_puts ("*mut ", stream);
            type_print (type->target_type (), "", stream, 0);
          }
      }
(For reference, here is the top of the gdb stacktrace to reach that code)
#0  rust_internal_print_type (type=0x555556522700, varstring=0x555555dae803 "", stream=0x55555640c390, show=1, level=0, flags=0x7fffffffdfc0, for_rust_enum=false, podata=0x7fffffffdf3c)
    at rust-lang.c:1114
#1  0x0000555555abd054 in rust_language::print_type (this=this@entry=0x555556148730 <rust_language_defn>, type=type@entry=0x555556522780, varstring=varstring@entry=0x555555dae803 "",
    stream=0x55555640c390, show=show@entry=1, level=level@entry=0, flags=0x7fffffffdfc0) at rust-lang.c:1834
#2  0x0000555555babc66 in whatis_exp (exp=<optimized out>, show=1) at typeprint.c:497
#3  0x0000555555796ee5 in cmd_func (cmd=<optimized out>, args=<optimized out>, from_tty=<optimized out>) at cli/cli-decode.c:2810
#4  0x0000555555b75065 in execute_command (p=<optimized out>, p@entry=0x55555616c030 "ptype f", from_tty=<optimized out>) at top.c:632

But with dwarfdump main, the type info looks correct:

< 3><0x00000872>        DW_TAG_formal_parameter
                          DW_AT_location              len 0x0002: 0x9108: 
                              DW_OP_fbreg 8
                          DW_AT_name                  f
                          DW_AT_decl_file             0x00000009 /home/martin/src/main.rs
                          DW_AT_decl_line             0x00000001
                          DW_AT_type                  <0x00000723>
< 1><0x00000723>    DW_TAG_typedef
                      DW_AT_type                  <0x0000072c>
                      DW_AT_name                  &usize
< 1><0x0000072c>    DW_TAG_pointer_type
                      DW_AT_type                  <0x000000a8>
                      DW_AT_name                  &usize
                      DW_AT_address_class         0x00000000
< 1><0x000000a8>    DW_TAG_base_type
                      DW_AT_name                  usize
                      DW_AT_encoding              DW_ATE_unsigned
                      DW_AT_byte_size             0x00000008

So it looks like gdb wants to work well with Rust without any Python scripts.

To me, it seems better to focus on getting the basics right, than to stack workarounds on top of each other.

So, before we go ahead with something like this, I'd like to understand why gdb is not already working well for this case.

Disclaimer: There might very well be decisions or context I am missing. But this is where I stand right now.

View changes since the review

llvm::LLVMDIBuilderCreateTypedef(
DIB(cx),
di_node,
ptr_type_debuginfo_name.as_ptr(),
ptr_type_debuginfo_name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
None,
0,
)
};

DINodeCreationResult { di_node, already_stored_in_typemap: false }
DINodeCreationResult { di_node: typedefed_ptr, already_stored_in_typemap: false }
}
Some(wide_pointer_kind) => {
type_map::build_type_with_children(
Expand Down
13 changes: 9 additions & 4 deletions src/etc/gdb_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ def unwrap_unique_or_non_null(unique_or_nonnull):
# BACKCOMPAT: rust 1.60
# https://github.com/rust-lang/rust/commit/2a91eeac1a2d27dd3de1bf55515d765da20fd86f
ptr = unique_or_nonnull["pointer"]
if ptr.type.code == gdb.TYPE_CODE_TYPEDEF:
ptr = ptr.cast(ptr.type.strip_typedefs())

return ptr if ptr.type.code == gdb.TYPE_CODE_PTR else ptr[ptr.type.fields()[0]]


Expand Down Expand Up @@ -147,8 +150,9 @@ def __init__(self, valobj):
self._valobj = valobj
self._length = int(valobj["len"])
self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"])
ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0))
self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty)
self._data_ptr = self._data_ptr.cast(self._data_ptr.type.strip_typedefs())
ptr_ty = valobj.type.template_argument(0).pointer()
self._data_ptr = self._data_ptr.cast(ptr_ty)

def to_string(self):
return "Vec(size={})".format(self._length)
Expand Down Expand Up @@ -177,8 +181,9 @@ def __init__(self, valobj):
cap = cap[ZERO_FIELD]
self._cap = int(cap)
self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"])
ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0))
self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty)
self._data_ptr = self._data_ptr.cast(self._data_ptr.type.strip_typedefs())
ptr_ty = valobj.type.template_argument(0).pointer()
self._data_ptr = self._data_ptr.cast(ptr_ty)

def to_string(self):
return "VecDeque(size={})".format(self._size)
Expand Down
18 changes: 10 additions & 8 deletions tests/codegen-llvm/debug-vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,39 @@

// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize"
// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
// MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >"
// NONMSVC: ![[PTR_TYPEDEF:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "*const ()", file: {{.*}}, baseType: ![[PTR:[0-9]+]])
// MSVC: ![[PTR_TYPEDEF:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "ptr_const$<tuple$<> >", file: {{.*}}, baseType: ![[PTR:[0-9]+]])
// NONMSVC: ![[PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
// MSVC: ![[PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >"

// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"

// NONMSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable_type}", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]],
// MSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable_type$", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]],
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR_TYPEDEF]], size: {{64|32}}, align: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR_TYPEDEF]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR_TYPEDEF]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}})
// CHECK: ![[FOO_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo",

// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"

// NONMSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable_type}", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
// MSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable_type$", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR_TYPEDEF]], size: {{64|32}}, align: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR_TYPEDEF]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})

// NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
// MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"

// NONMSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as _>::{vtable_type}", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
// MSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, _>::vtable_type$", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR_TYPEDEF]], size: {{64|32}}, align: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})

Expand Down
6 changes: 3 additions & 3 deletions tests/debuginfo/basic-types-metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
//@ gdb-check: type = struct basic_types_metadata::main::{closure_env#0}
//@ gdb-command:ptype closure_1
//@ gdb-check: type = struct basic_types_metadata::main::{closure_env#1} {
//@ gdb-check: *mut bool,
//@ gdb-check: _ref__b: &bool,
//@ gdb-check: }
//@ gdb-command:ptype closure_2
//@ gdb-check: type = struct basic_types_metadata::main::{closure_env#2} {
//@ gdb-check: *mut bool,
//@ gdb-check: *mut isize,
//@ gdb-check: _ref__b: &bool,
//@ gdb-check: _ref__i: &isize,
//@ gdb-check: }

//@ gdb-command:continue
Expand Down
2 changes: 1 addition & 1 deletion tests/debuginfo/function-call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//@ gdb-command:print fun(444, false)
//@ gdb-check:$2 = false

//@ gdb-command:print r.get_x()
//@ gdb-command: print function_call::RegularStruct::get_x(&r)
//@ gdb-check:$3 = 4

#![allow(dead_code, unused_variables)]
Expand Down
6 changes: 3 additions & 3 deletions tests/debuginfo/function-names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@

// Closure
//@ gdb-command:info functions -q function_names::.*::{closure.*
//@ gdb-check:[...]static fn function_names::generic_func::{closure#0}<i32>(*mut function_names::generic_func::{closure_env#0}<i32>);
//@ gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure_env#0});
//@ gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}<i32, i32>(*mut function_names::{impl#2}::impl_function::{closure_env#0}<i32, i32>);
//@ gdb-check:[...]static fn function_names::generic_func::{closure#0}<i32>(&function_names::generic_func::{closure_env#0}<i32>);
//@ gdb-check:[...]static fn function_names::main::{closure#0}(&function_names::main::{closure_env#0});
//@ gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}<i32, i32>(&function_names::{impl#2}::impl_function::{closure_env#0}<i32, i32>);

// Coroutine
// Coroutines don't seem to appear in GDB's symbol table.
Expand Down
4 changes: 2 additions & 2 deletions tests/debuginfo/type-names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@

// FOREIGN TYPES
//@ gdb-command:whatis foreign1
//@ gdb-check:type = *mut type_names::{extern#0}::ForeignType1
//@ gdb-check:type = *const type_names::{extern#0}::ForeignType1

//@ gdb-command:whatis foreign2
//@ gdb-check:type = *mut type_names::mod1::{extern#0}::ForeignType2
//@ gdb-check:type = *const type_names::mod1::{extern#0}::ForeignType2

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

Expand Down
4 changes: 2 additions & 2 deletions tests/debuginfo/unit-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
//@ gdb-command: run

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

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

//@ gdb-command: print _local
//@ gdb-check: $3 = ()
Expand Down
Loading