xref: /llvm-project/lldb/test/API/functionalities/vtable/TestVTableValue.py (revision abb6919a63c7ef017bb4f9c86057adcdb8129964)
17fbd427fSGreg Clayton"""
27fbd427fSGreg ClaytonMake sure the getting a variable path works and doesn't crash.
37fbd427fSGreg Clayton"""
47fbd427fSGreg Clayton
57fbd427fSGreg Claytonimport lldb
67fbd427fSGreg Claytonimport lldbsuite.test.lldbutil as lldbutil
77fbd427fSGreg Claytonfrom lldbsuite.test.decorators import *
87fbd427fSGreg Claytonfrom lldbsuite.test.lldbtest import *
97fbd427fSGreg Clayton
10096c530aSJonas Devlieghere
117fbd427fSGreg Claytonclass TestVTableValue(TestBase):
127fbd427fSGreg Clayton    # If your test case doesn't stress debug info, then
137fbd427fSGreg Clayton    # set this to true.  That way it won't be run once for
147fbd427fSGreg Clayton    # each debug info format.
157fbd427fSGreg Clayton    NO_DEBUG_INFO_TESTCASE = True
167fbd427fSGreg Clayton
17876bd794SMichael Buch    @skipIf(compiler="clang", compiler_version=["<", "9.0"])
187fbd427fSGreg Clayton    @skipUnlessPlatform(["linux", "macosx"])
197fbd427fSGreg Clayton    def test_vtable(self):
207fbd427fSGreg Clayton        self.build()
217fbd427fSGreg Clayton        lldbutil.run_to_source_breakpoint(
227fbd427fSGreg Clayton            self, "At the end", lldb.SBFileSpec("main.cpp")
237fbd427fSGreg Clayton        )
247fbd427fSGreg Clayton
257fbd427fSGreg Clayton        # Test a shape instance to make sure we get the vtable correctly.
267fbd427fSGreg Clayton        shape = self.frame().FindVariable("shape")
277fbd427fSGreg Clayton        vtable = shape.GetVTable()
2880fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetName(), "vtable for Shape")
2980fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetTypeName(), "vtable for Shape")
307fbd427fSGreg Clayton        # Make sure we have the right number of virtual functions in our vtable
317fbd427fSGreg Clayton        # for the shape class.
3280fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetNumChildren(), 4)
337fbd427fSGreg Clayton
347fbd427fSGreg Clayton        # Verify vtable address
357fbd427fSGreg Clayton        vtable_addr = vtable.GetValueAsUnsigned(0)
367fbd427fSGreg Clayton        expected_addr = self.expected_vtable_addr(shape)
3780fcecb1SJonas Devlieghere        self.assertEqual(vtable_addr, expected_addr)
387fbd427fSGreg Clayton
39096c530aSJonas Devlieghere        for idx, vtable_entry in enumerate(vtable.children):
407fbd427fSGreg Clayton            self.verify_vtable_entry(vtable_entry, vtable_addr, idx)
417fbd427fSGreg Clayton
427fbd427fSGreg Clayton        # Test a shape reference to make sure we get the vtable correctly.
437fbd427fSGreg Clayton        shape = self.frame().FindVariable("shape_ref")
447fbd427fSGreg Clayton        vtable = shape.GetVTable()
4580fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetName(), "vtable for Shape")
4680fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetTypeName(), "vtable for Shape")
477fbd427fSGreg Clayton        # Make sure we have the right number of virtual functions in our vtable
487fbd427fSGreg Clayton        # for the shape class.
4980fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetNumChildren(), 4)
507fbd427fSGreg Clayton
517fbd427fSGreg Clayton        # Verify vtable address
527fbd427fSGreg Clayton        vtable_addr = vtable.GetValueAsUnsigned(0)
537fbd427fSGreg Clayton        expected_addr = self.expected_vtable_addr(shape)
5480fcecb1SJonas Devlieghere        self.assertEqual(vtable_addr, expected_addr)
557fbd427fSGreg Clayton
56096c530aSJonas Devlieghere        for idx, vtable_entry in enumerate(vtable.children):
577fbd427fSGreg Clayton            self.verify_vtable_entry(vtable_entry, vtable_addr, idx)
587fbd427fSGreg Clayton
597fbd427fSGreg Clayton        # Test we get the right vtable for the Rectangle instance.
607fbd427fSGreg Clayton        rect = self.frame().FindVariable("rect")
617fbd427fSGreg Clayton        vtable = rect.GetVTable()
6280fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetName(), "vtable for Rectangle")
6380fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetTypeName(), "vtable for Rectangle")
647fbd427fSGreg Clayton
657fbd427fSGreg Clayton        # Make sure we have the right number of virtual functions in our vtable
667fbd427fSGreg Clayton        # with the extra virtual function added by the Rectangle class
6780fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetNumChildren(), 5)
687fbd427fSGreg Clayton
697fbd427fSGreg Clayton        # Verify vtable address
707fbd427fSGreg Clayton        vtable_addr = vtable.GetValueAsUnsigned()
717fbd427fSGreg Clayton        expected_addr = self.expected_vtable_addr(rect)
7280fcecb1SJonas Devlieghere        self.assertEqual(vtable_addr, expected_addr)
737fbd427fSGreg Clayton
74096c530aSJonas Devlieghere        for idx, vtable_entry in enumerate(vtable.children):
757fbd427fSGreg Clayton            self.verify_vtable_entry(vtable_entry, vtable_addr, idx)
767fbd427fSGreg Clayton
77d08d9cf5SMichael Buch    @skipIf(compiler="clang", compiler_version=["<", "9.0"])
787fbd427fSGreg Clayton    @skipUnlessPlatform(["linux", "macosx"])
797fbd427fSGreg Clayton    def test_base_class_ptr(self):
807fbd427fSGreg Clayton        self.build()
817fbd427fSGreg Clayton        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
827fbd427fSGreg Clayton            self, "Shape is Rectangle", lldb.SBFileSpec("main.cpp")
837fbd427fSGreg Clayton        )
847fbd427fSGreg Clayton
857fbd427fSGreg Clayton        shape = self.frame().FindVariable("shape")
867fbd427fSGreg Clayton        rect = self.frame().FindVariable("rect")
877fbd427fSGreg Clayton
887fbd427fSGreg Clayton        shape_ptr = self.frame().FindVariable("shape_ptr")
897fbd427fSGreg Clayton        shape_ptr_vtable = shape_ptr.GetVTable()
9080fcecb1SJonas Devlieghere        self.assertEqual(shape_ptr_vtable.GetName(), "vtable for Rectangle")
9180fcecb1SJonas Devlieghere        self.assertEqual(shape_ptr_vtable.GetNumChildren(), 5)
9280fcecb1SJonas Devlieghere        self.assertEqual(shape_ptr.GetValueAsUnsigned(0), rect.GetLoadAddress())
937fbd427fSGreg Clayton        lldbutil.continue_to_source_breakpoint(
947fbd427fSGreg Clayton            self, process, "Shape is Shape", lldb.SBFileSpec("main.cpp")
957fbd427fSGreg Clayton        )
9680fcecb1SJonas Devlieghere        self.assertEqual(shape_ptr.GetValueAsUnsigned(0), shape.GetLoadAddress())
9780fcecb1SJonas Devlieghere        self.assertEqual(shape_ptr_vtable.GetNumChildren(), 4)
9880fcecb1SJonas Devlieghere        self.assertEqual(shape_ptr_vtable.GetName(), "vtable for Shape")
997fbd427fSGreg Clayton
1007fbd427fSGreg Clayton    @skipUnlessPlatform(["linux", "macosx"])
1017fbd427fSGreg Clayton    def test_no_vtable(self):
1027fbd427fSGreg Clayton        self.build()
1037fbd427fSGreg Clayton        lldbutil.run_to_source_breakpoint(
1047fbd427fSGreg Clayton            self, "At the end", lldb.SBFileSpec("main.cpp")
1057fbd427fSGreg Clayton        )
1067fbd427fSGreg Clayton
1077fbd427fSGreg Clayton        var = self.frame().FindVariable("not_virtual")
108096c530aSJonas Devlieghere        self.assertEqual(
109096c530aSJonas Devlieghere            var.GetVTable().GetError().GetCString(),
110096c530aSJonas Devlieghere            'type "NotVirtual" doesn\'t have a vtable',
111096c530aSJonas Devlieghere        )
1127fbd427fSGreg Clayton
1137fbd427fSGreg Clayton        var = self.frame().FindVariable("argc")
114096c530aSJonas Devlieghere        self.assertEqual(
115096c530aSJonas Devlieghere            var.GetVTable().GetError().GetCString(),
116096c530aSJonas Devlieghere            'no language runtime support for the language "c"',
117096c530aSJonas Devlieghere        )
1187fbd427fSGreg Clayton
1197fbd427fSGreg Clayton    @skipUnlessPlatform(["linux", "macosx"])
1207fbd427fSGreg Clayton    def test_overwrite_vtable(self):
1217fbd427fSGreg Clayton        self.build()
1227fbd427fSGreg Clayton        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
1237fbd427fSGreg Clayton            self, "At the end", lldb.SBFileSpec("main.cpp")
1247fbd427fSGreg Clayton        )
1257fbd427fSGreg Clayton
1267fbd427fSGreg Clayton        # Test a shape instance to make sure we get the vtable correctly.
1277fbd427fSGreg Clayton        shape = self.frame().FindVariable("shape")
1287fbd427fSGreg Clayton        vtable = shape.GetVTable()
12980fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetName(), "vtable for Shape")
13080fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetTypeName(), "vtable for Shape")
1317fbd427fSGreg Clayton        # Make sure we have the right number of virtual functions in our vtable
1327fbd427fSGreg Clayton        # for the shape class.
13380fcecb1SJonas Devlieghere        self.assertEqual(vtable.GetNumChildren(), 4)
1347fbd427fSGreg Clayton
1357fbd427fSGreg Clayton        # Overwrite the first entry in the vtable and make sure we can still
1367fbd427fSGreg Clayton        # see the bogus value which should have no summary
1377fbd427fSGreg Clayton        vtable_addr = vtable.GetValueAsUnsigned()
1384be8a7bdSDavid Spickett
1394be8a7bdSDavid Spickett        is_64bit = self.process().GetAddressByteSize() == 8
1404be8a7bdSDavid Spickett        data = str(
1414be8a7bdSDavid Spickett            "\x01\x01\x01\x01\x01\x01\x01\x01" if is_64bit else "\x01\x01\x01\x01"
1424be8a7bdSDavid Spickett        )
1437fbd427fSGreg Clayton        error = lldb.SBError()
144*abb6919aSAlex Langford        bytes_written = process.WriteMemory(vtable_addr, data, error)
145*abb6919aSAlex Langford
146*abb6919aSAlex Langford        self.assertSuccess(error)
147*abb6919aSAlex Langford        self.assertGreater(
148*abb6919aSAlex Langford            bytes_written, 0, "Failed to overwrite first entry in vtable"
149*abb6919aSAlex Langford        )
1507fbd427fSGreg Clayton
1517fbd427fSGreg Clayton        scribbled_child = vtable.GetChildAtIndex(0)
15280fcecb1SJonas Devlieghere        self.assertEqual(
1534be8a7bdSDavid Spickett            scribbled_child.GetValueAsUnsigned(0),
1544be8a7bdSDavid Spickett            0x0101010101010101 if is_64bit else 0x01010101,
1554be8a7bdSDavid Spickett        )
15680fcecb1SJonas Devlieghere        self.assertEqual(scribbled_child.GetSummary(), None)
1577fbd427fSGreg Clayton
1587fbd427fSGreg Clayton    def expected_vtable_addr(self, var: lldb.SBValue) -> int:
1597fbd427fSGreg Clayton        load_addr = var.GetLoadAddress()
1607fbd427fSGreg Clayton        read_from_memory_error = lldb.SBError()
1617fbd427fSGreg Clayton        vtable_addr = self.process().ReadPointerFromMemory(
1627fbd427fSGreg Clayton            load_addr, read_from_memory_error
1637fbd427fSGreg Clayton        )
1647fbd427fSGreg Clayton        self.assertTrue(read_from_memory_error.Success())
1657fbd427fSGreg Clayton        return vtable_addr
1667fbd427fSGreg Clayton
1677fbd427fSGreg Clayton    def expected_vtable_entry_func_ptr(self, vtable_addr: int, idx: int):
1687fbd427fSGreg Clayton        vtable_entry_addr = vtable_addr + idx * self.process().GetAddressByteSize()
1697fbd427fSGreg Clayton        read_func_ptr_error = lldb.SBError()
170096c530aSJonas Devlieghere        func_ptr = self.process().ReadPointerFromMemory(
171096c530aSJonas Devlieghere            vtable_entry_addr, read_func_ptr_error
172096c530aSJonas Devlieghere        )
1737fbd427fSGreg Clayton        self.assertTrue(read_func_ptr_error.Success())
1747fbd427fSGreg Clayton        return func_ptr
1757fbd427fSGreg Clayton
176096c530aSJonas Devlieghere    def verify_vtable_entry(
177096c530aSJonas Devlieghere        self, vtable_entry: lldb.SBValue, vtable_addr: int, idx: int
178096c530aSJonas Devlieghere    ):
1797fbd427fSGreg Clayton        """Verify the vtable entry looks something like:
1807fbd427fSGreg Clayton
1817fbd427fSGreg Clayton        (double ()) [0] = 0x0000000100003a10 a.out`Rectangle::Area() at main.cpp:14
1827fbd427fSGreg Clayton
1837fbd427fSGreg Clayton        """
1847fbd427fSGreg Clayton        # Check function ptr
1857fbd427fSGreg Clayton        vtable_entry_func_ptr = vtable_entry.GetValueAsUnsigned(0)
18680fcecb1SJonas Devlieghere        self.assertEqual(
1877fbd427fSGreg Clayton            vtable_entry_func_ptr,
1887fbd427fSGreg Clayton            self.expected_vtable_entry_func_ptr(vtable_addr, idx),
1897fbd427fSGreg Clayton        )
1907fbd427fSGreg Clayton
1917fbd427fSGreg Clayton        sb_addr = self.target().ResolveLoadAddress(vtable_entry_func_ptr)
1927fbd427fSGreg Clayton        sym_ctx = sb_addr.GetSymbolContext(lldb.eSymbolContextEverything)
1937fbd427fSGreg Clayton
1947fbd427fSGreg Clayton        # Make sure the type is the same as the function type
1957fbd427fSGreg Clayton        func_type = sym_ctx.GetFunction().GetType()
1967fbd427fSGreg Clayton        if func_type.IsValid():
19780fcecb1SJonas Devlieghere            self.assertEqual(vtable_entry.GetType(), func_type.GetPointerType())
1987fbd427fSGreg Clayton
1997fbd427fSGreg Clayton        # The summary should be the address description of the function pointer
2007fbd427fSGreg Clayton        summary = vtable_entry.GetSummary()
20180fcecb1SJonas Devlieghere        self.assertEqual(str(sb_addr), summary)
202