https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/214960
In the Microsoft ABI, the offset to a virtual base we read from the v(b)table is relative to the vbptr (pointer to vbtable). Unlike on Itanium, where the offset is relative to the start of the record. This makes a difference when the virtual base isn't the first one. Because then the `vbptr` is offset. For example in the test I added, the record layout for `UserUser` looks like this (https://godbolt.org/z/TYnMW5hcs): ``` class UserUser size(48): +--- 0 | +--- (base class Padding4) 0 | | member | +--- 8 | +--- (base class User) 8 | | +--- (base class Padding3) 8 | | | member | | +--- 16 | | {vbptr} 24 | | member | | <alignment member> (size=6) | | <alignment member> (size=4) | +--- 32 | +--- (base class Padding5) 32 | | member | +--- 34 | member | <alignment member> (size=4) | <alignment member> (size=4) +--- +--- (virtual base VBase1) 40 | member +--- +--- (virtual base VBase2) 42 | member +--- UserUser::$vbtable@: 0 | -8 1 | 24 (UserUserd(User+8)VBase1) 2 | 26 (UserUserd(User+8)VBase2) ``` When trying to read the virtual base in `User`, we'd read the `vbtable` at offset 1 and get 24 as the offset (-> 16 + 24 = 40). In our tests, the virtual base was always the first one, so this never showed up. >From d92087117ad8322327f5cfcf3e10ecfa61266f28 Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Sat, 8 Aug 2026 13:50:28 +0200 Subject: [PATCH] [lldb] Read virtual bases relative to vbptr on MS ABI --- .../TypeSystem/Clang/TypeSystemClang.cpp | 4 ++ lldb/test/API/lang/cpp/virtual-bases/Makefile | 3 ++ .../cpp/virtual-bases/TestCppVirtualBases.py | 49 +++++++++++++++++++ lldb/test/API/lang/cpp/virtual-bases/main.cpp | 30 ++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 lldb/test/API/lang/cpp/virtual-bases/Makefile create mode 100644 lldb/test/API/lang/cpp/virtual-bases/TestCppVirtualBases.py create mode 100644 lldb/test/API/lang/cpp/virtual-bases/main.cpp diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 4a637f0817759..806042e009059 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -313,6 +313,10 @@ static bool GetVBaseBitOffset(VTableContextBase &vtable_ctx, if (base_offset == INT64_MAX) return false; + // In the Microsoft ABI, the offset we read in the vtable is relative to the + // vbptr in the type itself, not relative to the start of the record. + if (vtable_ctx.isMicrosoft()) + base_offset += record_layout.getVBPtrOffset().getQuantity(); bit_offset = base_offset * 8; return true; diff --git a/lldb/test/API/lang/cpp/virtual-bases/Makefile b/lldb/test/API/lang/cpp/virtual-bases/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/lang/cpp/virtual-bases/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/virtual-bases/TestCppVirtualBases.py b/lldb/test/API/lang/cpp/virtual-bases/TestCppVirtualBases.py new file mode 100644 index 0000000000000..141dd0321bb77 --- /dev/null +++ b/lldb/test/API/lang/cpp/virtual-bases/TestCppVirtualBases.py @@ -0,0 +1,49 @@ +""" +Test reading virtual bases through the vtable. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestCppVirtualBases(TestBase): + @no_debug_info_test + def test(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "// break here", lldb.SBFileSpec("main.cpp") + ) + + children = [ + ValueCheck( + type="Padding4", + children=[ValueCheck(type="short", name="member", value="4")], + ), + ValueCheck( + type="User", + children=[ + ValueCheck( + type="Padding3", + children=[ValueCheck(type="short", name="member", value="3")], + ), + ValueCheck( + type="VBase1", + children=[ValueCheck(type="short", name="member", value="1")], + ), + ValueCheck( + type="VBase2", + children=[ValueCheck(type="short", name="member", value="2")], + ), + ValueCheck(type="short", name="member", value="6"), + ], + ), + ValueCheck( + type="Padding5", + children=[ValueCheck(type="short", name="member", value="5")], + ), + ValueCheck(type="short", name="member", value="7"), + ] + self.expect_expr("useruser", result_type="UserUser", result_children=children) + self.expect_var_path("useruser", type="UserUser", children=children) diff --git a/lldb/test/API/lang/cpp/virtual-bases/main.cpp b/lldb/test/API/lang/cpp/virtual-bases/main.cpp new file mode 100644 index 0000000000000..8addd388dfcb2 --- /dev/null +++ b/lldb/test/API/lang/cpp/virtual-bases/main.cpp @@ -0,0 +1,30 @@ +struct VBase1 { + short member = 1; +}; +struct VBase2 { + short member = 2; +}; + +struct Padding3 { + short member = 3; +}; +struct Padding4 { + short member = 4; +}; +struct Padding5 { + short member = 5; +}; + +struct User : public Padding3, public virtual VBase1, public virtual VBase2 { + short member = 6; +}; + +struct UserUser : public Padding4, public User, public Padding5 { + short member = 7; +}; + +int main() { + UserUser useruser; + + return 0; // break here +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
