Add debug representation of trait objects
Updated descrption
Trait objects (~T and @T where T is a trait) are objects that hide their implementation and carry a virtual method dispatch table (i.e. vtable).
So, two things:
- Debuggers will want to be able to bypass the abstraction barrier and see the hidden implementation.
- They are also likely to want to be able to see the vtable.
- I am not sure how flexible the debug format is for gdb, but newer versions of gdb do support printing the vtable for C++ objects (via
info vtblor perhapsinfo vtable). It would be cool if we could massage our debug info so that gdb can just print out our vtables too, the same way.
- I am not sure how flexible the debug format is for gdb, but newer versions of gdb do support printing the vtable for C++ objects (via
Original description
There is none.
What would a debug representation of a Trait be? I think of a Trait as a purely compile-time entity that is erased by the time you get to runtime.
@jdm Is this specifically for @Trait objects (in which case, yes, I agree we would want to expose the vtable to the debugger?) If so, then I'll clear up the bug title and description.
Felix S Klock II at 2013-06-18 12:31:56
Yes, I think scoping this to cover trait objects (of the ~ and @ variety) would be fine.
Josh Matthews at 2013-06-18 12:53:00
According to
middle/trans/debuginfo.rs:cx.sess.span_note(span, "debuginfo for trait NYI");i.e. this is still valid, properly tagged and milestoned, 2013-06-19.
Graydon Hoare at 2013-06-19 18:42:32
Triage visit; deferring to @michaelwoerister.
Huon Wilson at 2013-08-05 08:23:44
Triage visit; deferring to @michaelwoerister.
It is still NYI but should be tackled some time this month.
Michael Woerister at 2013-08-05 08:46:31
Update:
As of PR #9168 there is some basic support for trait objects. A trait object pointer is described as a struct with the correct size (two pointers) and the correct name ({sigil}{mutability}{trait name}) and is placed in the correct namespace. The interior of this "fat pointer" is not described any further yet. What is missing is the description of the trait's methods. I don't know enough about how they are actually implemented to say much about that.
Michael Woerister at 2013-09-16 13:44:11
Not 1.0, but high
Tim Chevalier at 2013-10-17 17:59:15
@michaelwoerister: By the way, the new vtable layout is
[drop_glue, method, method2, method3, ...]. I'm sure this will change in the future somehow when supertrait methods become callable on trait objects.Daniel Micay at 2014-04-01 11:56:42
This has got more complicated with DST since you can have objects like
Fat<Trait>whereFatis a DST struct. The stub code for trait objects has got a little bit more broken, but I don't want to fix it since it is just a stub. I left a FIXME there.Nick Cameron at 2014-08-25 00:12:14
Triage bump: unsure what the status is of this today.
Steve Klabnik at 2015-01-20 17:55:11
still needs doing
Nick Cameron at 2015-01-20 17:57:25
We could do the following: (1) Create a type descriptions for each trait that contains the methods it defines. Since there are no traits in the DWARF standard yet, using
DW_AT_interfacewould make the most sense. But maybe usingDW_AT_structis more compatible with our C-oriented debuggers.(2) Describe trait pointers (
&Traitet al) as tuples of type(*(), *OpaqueVTable<Trait>).(3) Implement custom GDB/LLDB commands in Python that, given a fat pointer, use the pointer value and type information to print the vtable.
That's not perfect but could be done with the current means available. The symbol names of the functions pointed to by the vtable should also indicate the actual runtime type of the trait object.
Michael Woerister at 2015-03-26 16:23:25
Only in builds with debug info (i.e., not release builds) and only by a pretty tiny amount
Nick Cameron at 2015-06-29 20:51:25
Triage: still needs doing. cc @Manishearth @tromey P-low
Brian Anderson at 2016-07-14 16:52:45
This is both
P-lowandP-mediumnowJonas Schievink at 2016-07-14 17:54:14
Removing P-medium
Alex Crichton at 2016-07-14 18:05:04
I looked into this a bit recently. What I hope to do is:
- Emit some DWARF describing each vtable that is emitted. This would describe the vtable's type (as a struct of pointers-to-function), the vtable's location, and the concrete type represented by that vtable (maybe
DW_AT_containing_typecan be repurposed for this). - Further describe the interior of a trait object pointer. Currently I think this has to be done via a bit of a hack, because while DWARF describes a way to compute a given function's vtable slot, it doesn't seem to have a way to indicate "this member of the object is the vtable".
Then a debugger can do the following to print a trait object pointer: if a value's type has a vtable, fetch the vtable from the inferior, look up the vtable's address in the DWARF to find the vtable type, and then use the concrete type to decode the payload pointer.
Tom Tromey at 2017-05-06 15:51:24
- Emit some DWARF describing each vtable that is emitted. This would describe the vtable's type (as a struct of pointers-to-function), the vtable's location, and the concrete type represented by that vtable (maybe
I'm working on this. I have an LLVM patch to let rustc emit a small DWARF extension (the
DW_AT_containing_type) idea; a rustc patch to emit the basics of the vtable (address and containing type, not emit the methods), and most of a gdb patch to read it all and makeprintwork.Tom Tromey at 2017-10-06 21:03:15
First success today:
(gdb) p tu $1 = traitobjtest::&T {pointer: 0x7fffffffe047 "\027\070\340\377\377\377\177\000", vtable: 0x5555555c34e8 <vtable> "\360\253UUUU\000"} (gdb) p *tu $2 = 23Tom Tromey at 2017-10-09 20:11:34
Exciting!
Michael Woerister at 2017-10-10 08:34:15
LLVM patch is here: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20171016/495458.html
Tom Tromey at 2017-10-25 17:16:52
Moved to phabricator; might be simpler to follow there as well: https://reviews.llvm.org/D39503
Tom Tromey at 2017-11-01 20:53:54
gdb patch for printing trait objects is here: https://sourceware.org/ml/gdb-patches/2017-11/msg00289.html
Tom Tromey at 2017-11-15 21:29:25
Part 2 can be done by describing the fields of the vtable. I haven't looked at the rustc bits to see how difficult this is yet. The
info vtblbits in gdb aren't hard, mostly just virtualizing the existing command a bit more. With correct field names in there, it seems like implementing method calls on trait objects should also be straightforward.Tom Tromey at 2017-11-15 22:13:40
Version 2 of the gdb patch is here: https://sourceware.org/ml/gdb-patches/2017-11/msg00369.html
Tom Tromey at 2017-11-17 19:26:51
The gdb patch is in now, but I think this issue should be left open, as there's still the other vtable task to implement.
Tom Tromey at 2017-11-17 21:50:03
@tromey does the "vtable task" require gdb changes or just rustc changes?
AJ Gardner at 2018-01-24 04:11:44
@tromey does the "vtable task" require gdb changes or just rustc changes?
Ideally I think it would require both; however just doing the rustc bits would be a good start (and this has to come first anyhow). The task here is to have rustc emit a full description of the vtable in the DWARF -- so, the type and name of each member.
Tom Tromey at 2018-01-24 16:07:23
Visited during wg-debugging triage. As far as we're aware, @tromey's update above is still correct and the next step is to update rustc to generate full descriptions of the vtable in DWARF.
Wesley Wiser at 2022-08-15 14:11:22
This is actually almost entirely complete. The only issue that remains is that the emitted vtable struct has names like
__method3rather than the actual method name.Kyle Huey at 2022-08-15 14:31:24
Using the actual method name inside vtable debuginfo is only blocked on coming up with a clean way for handling multiple methods of the same name, I think. For example, a vtable might contain methods of traits
FooandBar, and both traits have a method with the namequux, then we would end up with two "fields" with the namequuxin vtable debuginfo, with no easy way of telling which of them belongs to which trait. Since traits can also have the same name (e.g.foo::Fooandbar::Foo), qualifying method names just by their unqualified trait name is not unambiguous either.Michael Woerister at 2022-08-15 15:15:39
The same problem probably exists with C++. How is it solved there?
Deleted user at 2022-08-15 16:46:56
vtables in C++ aren't "flattened" the way they are in Rust. In the multiple inheritance case the object actually contains multiple vtable pointers, and in the single inheritance case a method with the same (mangled) name overrides an earlier one. So this problem doesn't actually exist in C++.
Kyle Huey at 2022-08-15 23:04:41
That's good to know. Is this possible with Rust too? Or is it maybe possible to add a mapping of Foo:: method to _method3?
Sorry, I know nothing about compilers and debuggers so these may are ignorant questions. In my mind there should be a some kind of mapping from unmangled to mangled. Like in the .map in JavaScript that's generated after minifying the code.
Deleted user at 2022-08-17 09:19:19
Since traits can also have the same name (e.g. foo::Foo and bar::Foo), qualifying method names just by their unqualified trait name is not unambiguous either.
"crate_foo::foo::Foo::quux", "crate_bar::bar::Foo::quux",Looks awful (yet there are different crate versions - look how compiler encodes symbols) but it depends on how debuggers resolve the vtable debug info: if there's a way to link the symbol name "crate_foo::foo::Foo::quux" to its function body
crate_foo::foo::Foo::quuxthen why not.pravic at 2022-08-17 10:33:04