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