Description
Currently, we represent thin references and pointers with DW_TAG_pointer_type
DIEs and fat pointers (slices and trait objects) as DW_TAG_struct
DIEs with fields representing payload and metadata pointers. This is not ideal and with debuggers knowing about Rust, we can do better. The question is, what exactly do we want the representation for these kinds of types to look like.
Some things seem pretty straightforward to me:
- Rust references should be
DW_TAG_reference_type
DIEs. - Rust raw pointers should be
DW_TAG_pointer_type
DIEs.
But beyond that, there are some decisions to be made:
(1) How do we represent mutability?
The C++ version of DWARF represents a const pointer like const char *
with three separate type entries:
0:
DW_TAG_base_type
DW_AT_name "char"
...
1:
DW_TAG_const_type
DW_AT_type: ref to <0>
2:
DW_TAG_pointer_type
DW_AT_type: ref to <1>
I think this is a bit verbose and I'm not sure it is entirely appropriate for Rust. Do we really have const
and mut
types? That is, does Rust have the concept of a mut i32
at the type level, for example? I mean there are mutable and immutable slots/memory locations and we have "mutable" and "shared" references, but those two things seem kind of different to me.
As an alternative to using DW_TAG_const_type
for representing mutability, we could re-use the DW_AT_mutable
attribute that is already defined in DWARF. In C++ DWARF it is used for mutable
fields. We could use it for reference type and local variable DIEs:
0: // char
DW_TAG_base_type
DW_AT_name "char"
...
1: // &mut char
DW_TAG_reference_type
DW_AT_type: ref to <0>
DW_AT_mutable: true
2: // &char
DW_TAG_reference_type
DW_AT_type: ref to <0>
DW_AT_mutable: false // or just leave it off
3:
DW_TAG_variable
DW_AT_name: "foo"
DW_AT_type: ref to <0>
DW_AT_mutable: true
...
(2) How to represent fat pointers?
The pointer types in C/C++ DWARF don't have DW_TAG_member
sub-DIEs, since they are always just values. Fat pointers in Rust are different: they have one field that is a pointer to the data, and another field that holds additional information, either the size of a slice or the pointer to a vtable. These need to be described somehow.
I see a few options:
- A fat-pointer type is described by a
DW_TAG_pointer_type
orDW_TAG_reference_type
DIE with two fields that are described byDW_TAG_member
sub-DIEs, both having theDW_AT_artificial
attribute. @tromey once suggested for slices that the field entries have no name and the debugger determines which is which by the type (the size is always an integer type, the data is always a pointer type). This could also be extended for trait objects, since the data pointer will always be a pointer to a trait and the vtable-pointer will always be something else. - Treat trait objects and slices differently. Have a new
DW_TAG_slice_type
DIE that follows the encoding above and borrow some other attributes for trait objects: aDW_AT_vtable_elem_location
attribute holds the offset of the vtable field within the fat-pointer value, and aDW_AT_object_pointer
attribute does the same for the data pointer. This is distinctly not how these attributes are used in a C++ context but it would be a nice fit, I think. - Mix of the above with
DW_AT_object_pointer
indicating data pointer field
Another questions is: Should fat-pointers (and thin pointers too, maybe) have a DW_AT_byte_size
attribute that specifies their size explicitly?
cc @tromey, @Manishearth
See also #33073