Bug 18846 – VisualD - show vtable in debugger

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P1
Component
visuald
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-05-09T21:32:44Z
Last change time
2018-06-06T05:01:56Z
Assigned to
No Owner
Creator
Manu

Comments

Comment #0 by turkeyman — 2018-05-09T21:32:44Z
Compile and debug this code (using Mago): ----------------------------------- C++: ---- #include <stdio.h> class Something { public: virtual void x(); int data = 10; }; void Something::x() { printf("X"); } void dfunc(Something*); void main() { Something s; dfunc(&s); } ----------------------------------- D: -- extern(C++) class Something { abstract void x(); int data; } extern(C++) void dfunc(Something s) { s.x(); } ----------------------------------- Put a breakpoint in dfunc(). If you inspect 's' in C++, you will see "__vfptr ..." and "data = 10" If you inspect 's' from D, you will only see "data = 10" In C++, __vfptr is an array of "void*" that you can open and see a list of all the virtual functions. I really want to be able to see __vfptr from D's debuginfo too. At very least, it will help to debug mis-alignments between C++ and extern(C++) vtables. It's very easy to create a vtable mismatch from D. If the debuginfo doesn't want to emit this member (it should), then I think it might also be possible to fabricate its appearance with the natvis?
Comment #1 by r.sagitario — 2018-05-19T20:46:24Z
I've implemented this, but allow disabling it with an option on the Debugger->Mago page. You can try it in https://ci.appveyor.com/project/rainers/visuald/build/job/sd42f639wlwh77qc/artifacts It doesn't show symbol names, though, just raw pointer values. I'm not sure that's good enough.
Comment #2 by turkeyman — 2018-05-19T22:16:43Z
Right, I've noticed that our pointers don't seem to show symbol names like C++ does... why is that? Is that possible to fix? The experience should match C++.
Comment #3 by turkeyman — 2018-05-20T01:00:53Z
I just installed that build. I can see an item in place of the vtable: -tclass 0x02D20000 Source.Base + [Source.Derived] 0x02D20000 Source.Derived object.Object D0006: Error: Type resolve failed x 10 int y 20 int It seems there's an object.Object item there, which fails to evaluate correctly. It should be void** (or rather, void*[N] to inspect properly) right?
Comment #4 by r.sagitario — 2018-05-20T06:47:56Z
It seems I've messed up the defaults between Visual D and mago: you have to enable it in Tools->Options->Debugger->Mago. I think that being disabled is actually the better default as the vtable yields no additional information for most people. Unfortunately that build is also broken, as it tries to show [0] multiple times and fails.
Comment #5 by turkeyman — 2018-05-20T06:57:23Z
Even if we can't see the symbol names, seeing the pointers might help matching values and confirm function order against C++ code that you can also see in the debugger.
Comment #6 by r.sagitario — 2018-05-20T15:41:07Z
The build was ok, I just looked at the class instance before it was initialized. I've now added symbol names (no demangling yet). One gotcha: if you are linking with /INCREMENTAL, the linker relocates symbols through a series of jumps and that confuses the symbol display.
Comment #7 by turkeyman — 2018-05-20T18:24:50Z
Haha, oh man. Everything is always so hard! ;) I turned it off and everything works great! Sadly, /INCREMENTAL is overwhelmingly common, and also the default... basically nobody will ever turn that off :/
Comment #8 by turkeyman — 2018-05-20T18:51:30Z
I just noticed a minor issue... Mago is displaying hex with A-F in CAPS. VS debugger displays hex with a-f in lower case. I'm finding it surprisingly jarring when calling in/out of D, because a pointer that I was just looking at *looks* different, and I think the value has changed. Can we make Mago match VS with lower case hex?
Comment #9 by turkeyman — 2018-05-20T20:06:29Z
Also, another super-minor detail. In C++, it shows the derived type member at the top, then __vfptr (ie, first member), then the normal member listing. In Mago, it's showing __vfptr at the top, then the derived type member, then the normal members. Can we swap those top 2 items to match C++? __vfptr is really just the first member, and it feels strange when it's disconnected from the other members (separated by the derived accessor) that way.
Comment #10 by r.sagitario — 2018-05-21T07:55:39Z
Ok, I changed hex values to lower letters. The order of the class view is [derived type] __vfptr base-types The base types (multiple with interfaces) are part of the "field list" in the debug info, so a bit harder to mock fields. Unfortunately I noticed two more cases where the display fails: - with interfaces, the vtable contains pointers to thunks, but these have no symbols attached. - LDC does not emit any vtable information at all, so nothing to be shown there.
Comment #11 by turkeyman — 2018-05-21T08:45:02Z
Well this is all great progress. This experience is starting to feel pretty tight!
Comment #12 by r.sagitario — 2018-05-24T07:07:23Z
Next build also works with /INCREMENTAL.
Comment #13 by turkeyman — 2018-05-25T02:39:43Z
Wow! Works on all my tests! Thanks again! I wonder if this feature should be turned on by default now :P
Comment #14 by turkeyman — 2018-05-25T02:50:07Z
I'm noticing C++ symbols in the vtable don't demangle (ie, DMD). Is there a way to call the C++ demangler that VS uses (to make sure the demangle is identical)?
Comment #15 by r.sagitario — 2018-05-25T05:59:31Z
demangling C++ is easy, helper functions everywhere... ;-)
Comment #16 by turkeyman — 2018-05-25T06:21:58Z
Sure, except that it needs to demangle EXACTLY like the MSVC tools, so you don't see 2 errors from C++ and from D next to eachother and get confused as if they're different symbols, and then spend minutes figuring out that they're actually the same symbol, just piped through 2 different demanglers! ;)
Comment #17 by turkeyman — 2018-05-25T06:23:55Z
Or if you're looking at a symbol in the watch window let's say, and you step from D <-> C, and the symbol appears to suddenly change name in the crossing :P I'm doing a lot of watching vtables as I step back and fourth.
Comment #18 by r.sagitario — 2018-05-25T06:45:58Z
I use the demangler supplied by the debugger with flags as they seem to be used in C++. That doesn't prepend the module name, though. But looking at the vtable isn't too common and is probably rather special to your current work. I also do it sometimes to figure the dynamic type if the debugger fails to do it.
Comment #19 by turkeyman — 2018-05-25T06:50:40Z
extern(C++) in D is fraught with perils. When working on a multi-language program, you really need those symbols and the vtable is super useful to know everything's in good state.
Comment #20 by turkeyman — 2018-06-06T05:01:56Z
Seems to be working well!