199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtUse lldb Python API to test dynamic values in ObjC 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprecht 699451b44SJordan Rupprecht 799451b44SJordan Rupprechtimport lldb 899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 1199451b44SJordan Rupprecht 1299451b44SJordan Rupprecht 1399451b44SJordan Rupprechtclass ObjCDynamicValueTestCase(TestBase): 1499451b44SJordan Rupprecht 1599451b44SJordan Rupprecht mydir = TestBase.compute_mydir(__file__) 1699451b44SJordan Rupprecht 1799451b44SJordan Rupprecht def setUp(self): 1899451b44SJordan Rupprecht # Call super's setUp(). 1999451b44SJordan Rupprecht TestBase.setUp(self) 2099451b44SJordan Rupprecht 2199451b44SJordan Rupprecht # Find the line number to break for main.c. 2299451b44SJordan Rupprecht 2399451b44SJordan Rupprecht self.source_name = 'dynamic-value.m' 2499451b44SJordan Rupprecht self.set_property_line = line_number( 2599451b44SJordan Rupprecht self.source_name, 2699451b44SJordan Rupprecht '// This is the line in setProperty, make sure we step to here.') 2799451b44SJordan Rupprecht self.handle_SourceBase = line_number( 2899451b44SJordan Rupprecht self.source_name, '// Break here to check dynamic values.') 2999451b44SJordan Rupprecht self.main_before_setProperty_line = line_number( 3099451b44SJordan Rupprecht self.source_name, '// Break here to see if we can step into real method.') 3199451b44SJordan Rupprecht 3299451b44SJordan Rupprecht @add_test_categories(['pyapi']) 3399451b44SJordan Rupprecht @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107") 3499451b44SJordan Rupprecht def test_get_objc_dynamic_vals(self): 3599451b44SJordan Rupprecht """Test fetching ObjC dynamic values.""" 3699451b44SJordan Rupprecht if self.getArchitecture() == 'i386': 3799451b44SJordan Rupprecht # rdar://problem/9946499 3899451b44SJordan Rupprecht self.skipTest("Dynamic types for ObjC V1 runtime not implemented") 3999451b44SJordan Rupprecht 4099451b44SJordan Rupprecht self.build() 4199451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 4299451b44SJordan Rupprecht 4399451b44SJordan Rupprecht # Create a target from the debugger. 4499451b44SJordan Rupprecht 4599451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 4699451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 4799451b44SJordan Rupprecht 4899451b44SJordan Rupprecht # Set up our breakpoints: 4999451b44SJordan Rupprecht 5099451b44SJordan Rupprecht handle_SourceBase_bkpt = target.BreakpointCreateByLocation( 5199451b44SJordan Rupprecht self.source_name, self.handle_SourceBase) 5299451b44SJordan Rupprecht self.assertTrue(handle_SourceBase_bkpt and 5399451b44SJordan Rupprecht handle_SourceBase_bkpt.GetNumLocations() == 1, 5499451b44SJordan Rupprecht VALID_BREAKPOINT) 5599451b44SJordan Rupprecht 5699451b44SJordan Rupprecht main_before_setProperty_bkpt = target.BreakpointCreateByLocation( 5799451b44SJordan Rupprecht self.source_name, self.main_before_setProperty_line) 5899451b44SJordan Rupprecht self.assertTrue(main_before_setProperty_bkpt and 5999451b44SJordan Rupprecht main_before_setProperty_bkpt.GetNumLocations() == 1, 6099451b44SJordan Rupprecht VALID_BREAKPOINT) 6199451b44SJordan Rupprecht 6299451b44SJordan Rupprecht # Now launch the process, and do not stop at the entry point. 6399451b44SJordan Rupprecht process = target.LaunchSimple( 6499451b44SJordan Rupprecht None, None, self.get_process_working_directory()) 6599451b44SJordan Rupprecht 66*ce825e46SJonas Devlieghere self.assertState(process.GetState(), lldb.eStateStopped, 6799451b44SJordan Rupprecht PROCESS_STOPPED) 6899451b44SJordan Rupprecht 6999451b44SJordan Rupprecht threads = lldbutil.get_threads_stopped_at_breakpoint( 7099451b44SJordan Rupprecht process, main_before_setProperty_bkpt) 71b3a0c4d7SRaphael Isemann self.assertEquals(len(threads), 1) 7299451b44SJordan Rupprecht thread = threads[0] 7399451b44SJordan Rupprecht 7499451b44SJordan Rupprecht # 7599451b44SJordan Rupprecht # At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived 7699451b44SJordan Rupprecht # make sure we can get that properly: 7799451b44SJordan Rupprecht 7899451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 7999451b44SJordan Rupprecht myObserver = frame.FindVariable( 8099451b44SJordan Rupprecht 'myObserver', lldb.eDynamicCanRunTarget) 8199451b44SJordan Rupprecht self.assertTrue(myObserver) 8299451b44SJordan Rupprecht myObserver_source = myObserver.GetChildMemberWithName( 8399451b44SJordan Rupprecht '_source', lldb.eDynamicCanRunTarget) 8499451b44SJordan Rupprecht self.examine_SourceDerived_ptr(myObserver_source) 8599451b44SJordan Rupprecht 8699451b44SJordan Rupprecht # 8799451b44SJordan Rupprecht # Make sure a static value can be correctly turned into a dynamic 8899451b44SJordan Rupprecht # value. 8999451b44SJordan Rupprecht 9099451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 9199451b44SJordan Rupprecht myObserver_static = frame.FindVariable( 9299451b44SJordan Rupprecht 'myObserver', lldb.eNoDynamicValues) 9399451b44SJordan Rupprecht self.assertTrue(myObserver_static) 9499451b44SJordan Rupprecht myObserver = myObserver_static.GetDynamicValue( 9599451b44SJordan Rupprecht lldb.eDynamicCanRunTarget) 9699451b44SJordan Rupprecht myObserver_source = myObserver.GetChildMemberWithName( 9799451b44SJordan Rupprecht '_source', lldb.eDynamicCanRunTarget) 9899451b44SJordan Rupprecht self.examine_SourceDerived_ptr(myObserver_source) 9999451b44SJordan Rupprecht 10099451b44SJordan Rupprecht # The "frame var" code uses another path to get into children, so let's 10199451b44SJordan Rupprecht # make sure that works as well: 10299451b44SJordan Rupprecht 10399451b44SJordan Rupprecht result = lldb.SBCommandReturnObject() 10499451b44SJordan Rupprecht 10599451b44SJordan Rupprecht self.expect( 10699451b44SJordan Rupprecht 'frame var -d run-target myObserver->_source', 10799451b44SJordan Rupprecht 'frame var finds its way into a child member', 10899451b44SJordan Rupprecht patterns=['\(SourceDerived \*\)']) 10999451b44SJordan Rupprecht 11099451b44SJordan Rupprecht # check that our ObjC GetISA() does a good job at hiding KVO swizzled 11199451b44SJordan Rupprecht # classes 11299451b44SJordan Rupprecht 11399451b44SJordan Rupprecht self.expect( 11499451b44SJordan Rupprecht 'frame var -d run-target myObserver->_source -T', 11599451b44SJordan Rupprecht 'the KVO-ed class is hidden', 11699451b44SJordan Rupprecht substrs=['SourceDerived']) 11799451b44SJordan Rupprecht 11899451b44SJordan Rupprecht self.expect( 11999451b44SJordan Rupprecht 'frame var -d run-target myObserver->_source -T', 12099451b44SJordan Rupprecht 'the KVO-ed class is hidden', 12199451b44SJordan Rupprecht matching=False, 12299451b44SJordan Rupprecht substrs=['NSKVONotify']) 12399451b44SJordan Rupprecht 12499451b44SJordan Rupprecht # This test is not entirely related to the main thrust of this test case, but since we're here, 12599451b44SJordan Rupprecht # try stepping into setProperty, and make sure we get into the version 12699451b44SJordan Rupprecht # in Source: 12799451b44SJordan Rupprecht 12899451b44SJordan Rupprecht thread.StepInto() 12999451b44SJordan Rupprecht 13099451b44SJordan Rupprecht threads = lldbutil.get_stopped_threads( 13199451b44SJordan Rupprecht process, lldb.eStopReasonPlanComplete) 132b3a0c4d7SRaphael Isemann self.assertEquals(len(threads), 1) 13399451b44SJordan Rupprecht line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry() 13499451b44SJordan Rupprecht 13599451b44SJordan Rupprecht self.assertEqual(line_entry.GetLine(), self.set_property_line) 13699451b44SJordan Rupprecht self.assertEqual( 13799451b44SJordan Rupprecht line_entry.GetFileSpec().GetFilename(), 13899451b44SJordan Rupprecht self.source_name) 13999451b44SJordan Rupprecht 14099451b44SJordan Rupprecht # Okay, back to the main business. Continue to the handle_SourceBase 14199451b44SJordan Rupprecht # and make sure we get the correct dynamic value. 14299451b44SJordan Rupprecht 14399451b44SJordan Rupprecht threads = lldbutil.continue_to_breakpoint( 14499451b44SJordan Rupprecht process, handle_SourceBase_bkpt) 145b3a0c4d7SRaphael Isemann self.assertEquals(len(threads), 1) 14699451b44SJordan Rupprecht thread = threads[0] 14799451b44SJordan Rupprecht 14899451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 14999451b44SJordan Rupprecht 15099451b44SJordan Rupprecht # Get "object" using FindVariable: 15199451b44SJordan Rupprecht 15299451b44SJordan Rupprecht noDynamic = lldb.eNoDynamicValues 15399451b44SJordan Rupprecht useDynamic = lldb.eDynamicCanRunTarget 15499451b44SJordan Rupprecht 15599451b44SJordan Rupprecht object_static = frame.FindVariable('object', noDynamic) 15699451b44SJordan Rupprecht object_dynamic = frame.FindVariable('object', useDynamic) 15799451b44SJordan Rupprecht 15899451b44SJordan Rupprecht # Delete this object to make sure that this doesn't cause havoc with 15999451b44SJordan Rupprecht # the dynamic object that depends on it. 16099451b44SJordan Rupprecht del (object_static) 16199451b44SJordan Rupprecht 16299451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 16399451b44SJordan Rupprecht 16499451b44SJordan Rupprecht # Get "this" using FindValue, make sure that works too: 16599451b44SJordan Rupprecht object_static = frame.FindValue( 16699451b44SJordan Rupprecht 'object', lldb.eValueTypeVariableArgument, noDynamic) 16799451b44SJordan Rupprecht object_dynamic = frame.FindValue( 16899451b44SJordan Rupprecht 'object', lldb.eValueTypeVariableArgument, useDynamic) 16999451b44SJordan Rupprecht del (object_static) 17099451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 17199451b44SJordan Rupprecht 17299451b44SJordan Rupprecht # Get "this" using the EvaluateExpression: 17399451b44SJordan Rupprecht object_static = frame.EvaluateExpression('object', noDynamic) 17499451b44SJordan Rupprecht object_dynamic = frame.EvaluateExpression('object', useDynamic) 17599451b44SJordan Rupprecht del (object_static) 17699451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 17799451b44SJordan Rupprecht 17899451b44SJordan Rupprecht # Continue again to the handle_SourceBase and make sure we get the correct dynamic value. 17999451b44SJordan Rupprecht # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so 18099451b44SJordan Rupprecht # its isa pointer points to SourceBase not NSKVOSourceBase or 18199451b44SJordan Rupprecht # whatever... 18299451b44SJordan Rupprecht 18399451b44SJordan Rupprecht threads = lldbutil.continue_to_breakpoint( 18499451b44SJordan Rupprecht process, handle_SourceBase_bkpt) 185b3a0c4d7SRaphael Isemann self.assertEquals(len(threads), 1) 18699451b44SJordan Rupprecht thread = threads[0] 18799451b44SJordan Rupprecht 18899451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(0) 18999451b44SJordan Rupprecht 19099451b44SJordan Rupprecht # Get "object" using FindVariable: 19199451b44SJordan Rupprecht 19299451b44SJordan Rupprecht object_static = frame.FindVariable('object', noDynamic) 19399451b44SJordan Rupprecht object_dynamic = frame.FindVariable('object', useDynamic) 19499451b44SJordan Rupprecht 19599451b44SJordan Rupprecht # Delete this object to make sure that this doesn't cause havoc with 19699451b44SJordan Rupprecht # the dynamic object that depends on it. 19799451b44SJordan Rupprecht del (object_static) 19899451b44SJordan Rupprecht 19999451b44SJordan Rupprecht self.examine_SourceDerived_ptr(object_dynamic) 20099451b44SJordan Rupprecht 20199451b44SJordan Rupprecht def examine_SourceDerived_ptr(self, object): 20299451b44SJordan Rupprecht self.assertTrue(object) 203b3a0c4d7SRaphael Isemann self.assertNotEqual(object.GetTypeName().find('SourceDerived'), -1) 20499451b44SJordan Rupprecht derivedValue = object.GetChildMemberWithName('_derivedValue') 20599451b44SJordan Rupprecht self.assertTrue(derivedValue) 206b3a0c4d7SRaphael Isemann self.assertEquals(int(derivedValue.GetValue(), 0), 30) 207