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