Sounds like this is what https://github.com/llvm/llvm-project/pull/130255 is trying to achieve? If we could simplify that part of LLDB that'd be great!
On Wed, 23 Apr 2025 at 16:32, Kyle Huey via Dwarf-discuss <dwarf-discuss@lists.dwarfstd.org> wrote: > > Consider the following C++ program > > #include <stdio.h> > > class Base { > public: > virtual const char* method1() = 0; > void method2() { > printf("%s\n", method1()); > } > }; > > class DerivedOne : public Base { > virtual const char* method1() override { > return "DerivedOne"; > } > }; > > template<typename T> > class DerivedTwo : public Base { > public: > DerivedTwo(T t) : t(t) {} > private: > virtual const char* method1() override { > return t; > } > T t; > }; > > template<typename T> > class DerivedThree : public Base { > public: > DerivedThree(T t) : t(t) {} > private: > virtual const char* method1() override { > return t(); > } > T t; > }; > > int main() { > DerivedOne d1; > DerivedTwo d2("DerivedTwo"); > DerivedThree d3([]() { > return "DerivedThree"; > }); > d1.method2(); > d2.method2(); > d3.method2(); > return 0; > } > > If a debugger stops at method1, the DW_TAG_formal_parameter will tell > the debugger the type of `this` is Base. Downcasting to the derived > type is very useful for the programmer though, so both gdb and lldb > contain a feature to downcast based on the vtable pointer (the "print > object" and the "target.prefer-dynamic" settings in the respective > debuggers). > > The first part of this is straightforward. The DWARF for Base will > contain a member for the vtable pointer, and that plus knowledge of > how the ABI lays out vtables allows the debugger to effectively do a > dynamic_cast<void*> to obtain a pointer to the most derived object. > From there the vtable address is compared against the ELF symbol table > to find the mangled name of the vtable symbol. > > Then things begin to get hairy, the debugger demangles the mangled > name that exists in the ELF symbol table, chops off the "vtable for " > prefix on the demangled name, and searches for the type by name in the > DWARF. If it finds the type, it adjusts the type of the value and > prints it accordingly. But this text based matching doesn't always > work. There are no mangled names for types so the debugger's > demangling has to match the compiler's output character for character. > > In the example program I've provided, when using the respective > compilers, gdb can successfully downcast DerivedOne and DerivedThree > but not DerivedTwo. gdb fails because gcc emits the DW_TAG_class_type > with a DW_AT_name "DerivedTwo<main()::<lambda()> >" but libiberty > demangles the vtable symbol to "vtable for > DerivedTwo<main::{lambda()#1}>" and those do not match. lldb can only > successfully downcast DerivedOne. lldb appears to not handle classes > with template parameters correctly at all. And even if all of that > were fixed, libiberty and llvm disagree about how to demangle the > symbol for DerivedTwo's vtable, so the two ecosystems would not be > interoperable. > > Perhaps these are merely quality of implementation issues and belong > on the respective bug trackers, however, better representations are > possible. Rustc, for example, does not rely on the ELF symbol table > and demangled string matching. It emits a global variable in the DWARF > whose location is the address of the vtable. That variable has a > DW_AT_type pointing to a DW_TAG_class_type that describes the layout > of the vtable, and that type has a DW_AT_containing_type that points > to the type making use of that vtable. > > Any thoughts? > > - Kyle > -- > Dwarf-discuss mailing list > Dwarf-discuss@lists.dwarfstd.org > https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss -- Dwarf-discuss mailing list Dwarf-discuss@lists.dwarfstd.org https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss