199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtUse lldb Python API to test dynamic values in ObjC 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprecht 699451b44SJordan Rupprechtimport lldb 799451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 899451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 999451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 1099451b44SJordan Rupprecht 1199451b44SJordan Rupprecht 1299451b44SJordan Rupprechtclass ObjCDynamicValueTestCase(TestBase): 1399451b44SJordan Rupprecht def setUp(self): 1499451b44SJordan Rupprecht # Call super's setUp(). 1599451b44SJordan Rupprecht TestBase.setUp(self) 1699451b44SJordan Rupprecht 1799451b44SJordan Rupprecht # Find the line number to break for main.c. 1899451b44SJordan Rupprecht 192238dcc3SJonas Devlieghere self.source_name = "dynamic-value.m" 2099451b44SJordan Rupprecht self.set_property_line = line_number( 2199451b44SJordan Rupprecht self.source_name, 222238dcc3SJonas Devlieghere "// This is the line in setProperty, make sure we step to here.", 232238dcc3SJonas Devlieghere ) 2499451b44SJordan Rupprecht self.handle_SourceBase = line_number( 252238dcc3SJonas Devlieghere self.source_name, "// Break here to check dynamic values." 262238dcc3SJonas Devlieghere ) 2799451b44SJordan Rupprecht self.main_before_setProperty_line = line_number( 282238dcc3SJonas Devlieghere self.source_name, "// Break here to see if we can step into real method." 292238dcc3SJonas Devlieghere ) 3099451b44SJordan Rupprecht 312238dcc3SJonas Devlieghere @add_test_categories(["pyapi"]) 3299451b44SJordan Rupprecht @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107") 3399451b44SJordan Rupprecht def test_get_objc_dynamic_vals(self): 3499451b44SJordan Rupprecht """Test fetching ObjC dynamic values.""" 352238dcc3SJonas Devlieghere if self.getArchitecture() == "i386": 3699451b44SJordan Rupprecht # rdar://problem/9946499 3799451b44SJordan Rupprecht self.skipTest("Dynamic types for ObjC V1 runtime not implemented") 3899451b44SJordan Rupprecht 3999451b44SJordan Rupprecht self.build() 4099451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 4199451b44SJordan Rupprecht 4299451b44SJordan Rupprecht # Create a target from the debugger. 4399451b44SJordan Rupprecht 4499451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 4599451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 4699451b44SJordan Rupprecht 4799451b44SJordan Rupprecht # Set up our breakpoints: 4899451b44SJordan Rupprecht 4999451b44SJordan Rupprecht handle_SourceBase_bkpt = target.BreakpointCreateByLocation( 502238dcc3SJonas Devlieghere self.source_name, self.handle_SourceBase 512238dcc3SJonas Devlieghere ) 522238dcc3SJonas Devlieghere self.assertTrue( 532238dcc3SJonas Devlieghere handle_SourceBase_bkpt and handle_SourceBase_bkpt.GetNumLocations() == 1, 542238dcc3SJonas Devlieghere VALID_BREAKPOINT, 552238dcc3SJonas Devlieghere ) 5699451b44SJordan Rupprecht 5799451b44SJordan Rupprecht main_before_setProperty_bkpt = target.BreakpointCreateByLocation( 582238dcc3SJonas Devlieghere self.source_name, self.main_before_setProperty_line 592238dcc3SJonas Devlieghere ) 602238dcc3SJonas Devlieghere self.assertTrue( 612238dcc3SJonas Devlieghere main_before_setProperty_bkpt 622238dcc3SJonas Devlieghere and main_before_setProperty_bkpt.GetNumLocations() == 1, 632238dcc3SJonas Devlieghere VALID_BREAKPOINT, 642238dcc3SJonas Devlieghere ) 6599451b44SJordan Rupprecht 6699451b44SJordan Rupprecht # Now launch the process, and do not stop at the entry point. 672238dcc3SJonas Devlieghere process = target.LaunchSimple(None, None, self.get_process_working_directory()) 6899451b44SJordan Rupprecht 692238dcc3SJonas Devlieghere self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) 7099451b44SJordan Rupprecht 7199451b44SJordan Rupprecht threads = lldbutil.get_threads_stopped_at_breakpoint( 722238dcc3SJonas Devlieghere process, main_before_setProperty_bkpt 732238dcc3SJonas Devlieghere ) 74*80fcecb1SJonas Devlieghere self.assertEqual(len(threads), 1) 7599451b44SJordan Rupprecht thread = threads[0] 7699451b44SJordan Rupprecht 7799451b44SJordan Rupprecht # 7899451b44SJordan Rupprecht # At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived 7999451b44SJordan Rupprecht # make sure we can get that properly: 8099451b44SJordan Rupprecht 8199451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 822238dcc3SJonas Devlieghere myObserver = frame.FindVariable("myObserver", lldb.eDynamicCanRunTarget) 8399451b44SJordan Rupprecht self.assertTrue(myObserver) 8499451b44SJordan Rupprecht myObserver_source = myObserver.GetChildMemberWithName( 852238dcc3SJonas Devlieghere "_source", lldb.eDynamicCanRunTarget 862238dcc3SJonas Devlieghere ) 8799451b44SJordan Rupprecht self.examine_SourceDerived_ptr(myObserver_source) 8899451b44SJordan Rupprecht 8999451b44SJordan Rupprecht # 9099451b44SJordan Rupprecht # Make sure a static value can be correctly turned into a dynamic 9199451b44SJordan Rupprecht # value. 9299451b44SJordan Rupprecht 9399451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 942238dcc3SJonas Devlieghere myObserver_static = frame.FindVariable("myObserver", lldb.eNoDynamicValues) 9599451b44SJordan Rupprecht self.assertTrue(myObserver_static) 962238dcc3SJonas Devlieghere myObserver = myObserver_static.GetDynamicValue(lldb.eDynamicCanRunTarget) 9799451b44SJordan Rupprecht myObserver_source = myObserver.GetChildMemberWithName( 982238dcc3SJonas Devlieghere "_source", lldb.eDynamicCanRunTarget 992238dcc3SJonas Devlieghere ) 10099451b44SJordan Rupprecht self.examine_SourceDerived_ptr(myObserver_source) 10199451b44SJordan Rupprecht 10299451b44SJordan Rupprecht # The "frame var" code uses another path to get into children, so let's 10399451b44SJordan Rupprecht # make sure that works as well: 10499451b44SJordan Rupprecht 10599451b44SJordan Rupprecht result = lldb.SBCommandReturnObject() 10699451b44SJordan Rupprecht 10799451b44SJordan Rupprecht self.expect( 1082238dcc3SJonas Devlieghere "frame var -d run-target myObserver->_source", 1092238dcc3SJonas Devlieghere "frame var finds its way into a child member", 1102238dcc3SJonas Devlieghere patterns=["\(SourceDerived \*\)"], 1112238dcc3SJonas Devlieghere ) 11299451b44SJordan Rupprecht 11399451b44SJordan Rupprecht # check that our ObjC GetISA() does a good job at hiding KVO swizzled 11499451b44SJordan Rupprecht # classes 11599451b44SJordan Rupprecht 11699451b44SJordan Rupprecht self.expect( 1172238dcc3SJonas Devlieghere "frame var -d run-target myObserver->_source -T", 1182238dcc3SJonas Devlieghere "the KVO-ed class is hidden", 1192238dcc3SJonas Devlieghere substrs=["SourceDerived"], 1202238dcc3SJonas Devlieghere ) 12199451b44SJordan Rupprecht 12299451b44SJordan Rupprecht self.expect( 1232238dcc3SJonas Devlieghere "frame var -d run-target myObserver->_source -T", 1242238dcc3SJonas Devlieghere "the KVO-ed class is hidden", 12599451b44SJordan Rupprecht matching=False, 1262238dcc3SJonas Devlieghere substrs=["NSKVONotify"], 1272238dcc3SJonas Devlieghere ) 12899451b44SJordan Rupprecht 12999451b44SJordan Rupprecht # This test is not entirely related to the main thrust of this test case, but since we're here, 13099451b44SJordan Rupprecht # try stepping into setProperty, and make sure we get into the version 13199451b44SJordan Rupprecht # in Source: 13299451b44SJordan Rupprecht 13399451b44SJordan Rupprecht thread.StepInto() 13499451b44SJordan Rupprecht 1352238dcc3SJonas Devlieghere threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) 136*80fcecb1SJonas Devlieghere self.assertEqual(len(threads), 1) 13799451b44SJordan Rupprecht line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry() 13899451b44SJordan Rupprecht 13999451b44SJordan Rupprecht self.assertEqual(line_entry.GetLine(), self.set_property_line) 1402238dcc3SJonas Devlieghere self.assertEqual(line_entry.GetFileSpec().GetFilename(), self.source_name) 14199451b44SJordan Rupprecht 14299451b44SJordan Rupprecht # Okay, back to the main business. Continue to the handle_SourceBase 14399451b44SJordan Rupprecht # and make sure we get the correct dynamic value. 14499451b44SJordan Rupprecht 1452238dcc3SJonas Devlieghere threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt) 146*80fcecb1SJonas Devlieghere self.assertEqual(len(threads), 1) 14799451b44SJordan Rupprecht thread = threads[0] 14899451b44SJordan Rupprecht 14999451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 15099451b44SJordan Rupprecht 15199451b44SJordan Rupprecht # Get "object" using FindVariable: 15299451b44SJordan Rupprecht 15399451b44SJordan Rupprecht noDynamic = lldb.eNoDynamicValues 15499451b44SJordan Rupprecht useDynamic = lldb.eDynamicCanRunTarget 15599451b44SJordan Rupprecht 1562238dcc3SJonas Devlieghere object_static = frame.FindVariable("object", noDynamic) 1572238dcc3SJonas Devlieghere object_dynamic = frame.FindVariable("object", useDynamic) 15899451b44SJordan Rupprecht 15999451b44SJordan Rupprecht # Delete this object to make sure that this doesn't cause havoc with 16099451b44SJordan Rupprecht # the dynamic object that depends on it. 1612238dcc3SJonas Devlieghere del object_static 16299451b44SJordan Rupprecht 16399451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 16499451b44SJordan Rupprecht 16599451b44SJordan Rupprecht # Get "this" using FindValue, make sure that works too: 16699451b44SJordan Rupprecht object_static = frame.FindValue( 1672238dcc3SJonas Devlieghere "object", lldb.eValueTypeVariableArgument, noDynamic 1682238dcc3SJonas Devlieghere ) 16999451b44SJordan Rupprecht object_dynamic = frame.FindValue( 1702238dcc3SJonas Devlieghere "object", lldb.eValueTypeVariableArgument, useDynamic 1712238dcc3SJonas Devlieghere ) 1722238dcc3SJonas Devlieghere del object_static 17399451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 17499451b44SJordan Rupprecht 17599451b44SJordan Rupprecht # Get "this" using the EvaluateExpression: 1762238dcc3SJonas Devlieghere object_static = frame.EvaluateExpression("object", noDynamic) 1772238dcc3SJonas Devlieghere object_dynamic = frame.EvaluateExpression("object", useDynamic) 1782238dcc3SJonas Devlieghere del object_static 17999451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 18099451b44SJordan Rupprecht 18199451b44SJordan Rupprecht # Continue again to the handle_SourceBase and make sure we get the correct dynamic value. 18299451b44SJordan Rupprecht # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so 18399451b44SJordan Rupprecht # its isa pointer points to SourceBase not NSKVOSourceBase or 18499451b44SJordan Rupprecht # whatever... 18599451b44SJordan Rupprecht 1862238dcc3SJonas Devlieghere threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt) 187*80fcecb1SJonas Devlieghere self.assertEqual(len(threads), 1) 18899451b44SJordan Rupprecht thread = threads[0] 18999451b44SJordan Rupprecht 19099451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 19199451b44SJordan Rupprecht 19299451b44SJordan Rupprecht # Get "object" using FindVariable: 19399451b44SJordan Rupprecht 1942238dcc3SJonas Devlieghere object_static = frame.FindVariable("object", noDynamic) 1952238dcc3SJonas Devlieghere object_dynamic = frame.FindVariable("object", useDynamic) 19699451b44SJordan Rupprecht 19799451b44SJordan Rupprecht # Delete this object to make sure that this doesn't cause havoc with 19899451b44SJordan Rupprecht # the dynamic object that depends on it. 1992238dcc3SJonas Devlieghere del object_static 20099451b44SJordan Rupprecht 20199451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 20299451b44SJordan Rupprecht 20399451b44SJordan Rupprecht def examine_SourceDerived_ptr(self, object): 20499451b44SJordan Rupprecht self.assertTrue(object) 2052238dcc3SJonas Devlieghere self.assertNotEqual(object.GetTypeName().find("SourceDerived"), -1) 2062238dcc3SJonas Devlieghere derivedValue = object.GetChildMemberWithName("_derivedValue") 20799451b44SJordan Rupprecht self.assertTrue(derivedValue) 208*80fcecb1SJonas Devlieghere self.assertEqual(int(derivedValue.GetValue(), 0), 30) 209