1""" 2Use lldb Python API to test dynamic values in ObjC 3""" 4 5 6 7import lldb 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11 12 13class ObjCDynamicValueTestCase(TestBase): 14 15 def setUp(self): 16 # Call super's setUp(). 17 TestBase.setUp(self) 18 19 # Find the line number to break for main.c. 20 21 self.source_name = 'dynamic-value.m' 22 self.set_property_line = line_number( 23 self.source_name, 24 '// This is the line in setProperty, make sure we step to here.') 25 self.handle_SourceBase = line_number( 26 self.source_name, '// Break here to check dynamic values.') 27 self.main_before_setProperty_line = line_number( 28 self.source_name, '// Break here to see if we can step into real method.') 29 30 @add_test_categories(['pyapi']) 31 @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107") 32 def test_get_objc_dynamic_vals(self): 33 """Test fetching ObjC dynamic values.""" 34 if self.getArchitecture() == 'i386': 35 # rdar://problem/9946499 36 self.skipTest("Dynamic types for ObjC V1 runtime not implemented") 37 38 self.build() 39 exe = self.getBuildArtifact("a.out") 40 41 # Create a target from the debugger. 42 43 target = self.dbg.CreateTarget(exe) 44 self.assertTrue(target, VALID_TARGET) 45 46 # Set up our breakpoints: 47 48 handle_SourceBase_bkpt = target.BreakpointCreateByLocation( 49 self.source_name, self.handle_SourceBase) 50 self.assertTrue(handle_SourceBase_bkpt and 51 handle_SourceBase_bkpt.GetNumLocations() == 1, 52 VALID_BREAKPOINT) 53 54 main_before_setProperty_bkpt = target.BreakpointCreateByLocation( 55 self.source_name, self.main_before_setProperty_line) 56 self.assertTrue(main_before_setProperty_bkpt and 57 main_before_setProperty_bkpt.GetNumLocations() == 1, 58 VALID_BREAKPOINT) 59 60 # Now launch the process, and do not stop at the entry point. 61 process = target.LaunchSimple( 62 None, None, self.get_process_working_directory()) 63 64 self.assertState(process.GetState(), lldb.eStateStopped, 65 PROCESS_STOPPED) 66 67 threads = lldbutil.get_threads_stopped_at_breakpoint( 68 process, main_before_setProperty_bkpt) 69 self.assertEquals(len(threads), 1) 70 thread = threads[0] 71 72 # 73 # At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived 74 # make sure we can get that properly: 75 76 frame = thread.GetFrameAtIndex(0) 77 myObserver = frame.FindVariable( 78 'myObserver', lldb.eDynamicCanRunTarget) 79 self.assertTrue(myObserver) 80 myObserver_source = myObserver.GetChildMemberWithName( 81 '_source', lldb.eDynamicCanRunTarget) 82 self.examine_SourceDerived_ptr(myObserver_source) 83 84 # 85 # Make sure a static value can be correctly turned into a dynamic 86 # value. 87 88 frame = thread.GetFrameAtIndex(0) 89 myObserver_static = frame.FindVariable( 90 'myObserver', lldb.eNoDynamicValues) 91 self.assertTrue(myObserver_static) 92 myObserver = myObserver_static.GetDynamicValue( 93 lldb.eDynamicCanRunTarget) 94 myObserver_source = myObserver.GetChildMemberWithName( 95 '_source', lldb.eDynamicCanRunTarget) 96 self.examine_SourceDerived_ptr(myObserver_source) 97 98 # The "frame var" code uses another path to get into children, so let's 99 # make sure that works as well: 100 101 result = lldb.SBCommandReturnObject() 102 103 self.expect( 104 'frame var -d run-target myObserver->_source', 105 'frame var finds its way into a child member', 106 patterns=['\(SourceDerived \*\)']) 107 108 # check that our ObjC GetISA() does a good job at hiding KVO swizzled 109 # classes 110 111 self.expect( 112 'frame var -d run-target myObserver->_source -T', 113 'the KVO-ed class is hidden', 114 substrs=['SourceDerived']) 115 116 self.expect( 117 'frame var -d run-target myObserver->_source -T', 118 'the KVO-ed class is hidden', 119 matching=False, 120 substrs=['NSKVONotify']) 121 122 # This test is not entirely related to the main thrust of this test case, but since we're here, 123 # try stepping into setProperty, and make sure we get into the version 124 # in Source: 125 126 thread.StepInto() 127 128 threads = lldbutil.get_stopped_threads( 129 process, lldb.eStopReasonPlanComplete) 130 self.assertEquals(len(threads), 1) 131 line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry() 132 133 self.assertEqual(line_entry.GetLine(), self.set_property_line) 134 self.assertEqual( 135 line_entry.GetFileSpec().GetFilename(), 136 self.source_name) 137 138 # Okay, back to the main business. Continue to the handle_SourceBase 139 # and make sure we get the correct dynamic value. 140 141 threads = lldbutil.continue_to_breakpoint( 142 process, handle_SourceBase_bkpt) 143 self.assertEquals(len(threads), 1) 144 thread = threads[0] 145 146 frame = thread.GetFrameAtIndex(0) 147 148 # Get "object" using FindVariable: 149 150 noDynamic = lldb.eNoDynamicValues 151 useDynamic = lldb.eDynamicCanRunTarget 152 153 object_static = frame.FindVariable('object', noDynamic) 154 object_dynamic = frame.FindVariable('object', useDynamic) 155 156 # Delete this object to make sure that this doesn't cause havoc with 157 # the dynamic object that depends on it. 158 del (object_static) 159 160 self.examine_SourceDerived_ptr(object_dynamic) 161 162 # Get "this" using FindValue, make sure that works too: 163 object_static = frame.FindValue( 164 'object', lldb.eValueTypeVariableArgument, noDynamic) 165 object_dynamic = frame.FindValue( 166 'object', lldb.eValueTypeVariableArgument, useDynamic) 167 del (object_static) 168 self.examine_SourceDerived_ptr(object_dynamic) 169 170 # Get "this" using the EvaluateExpression: 171 object_static = frame.EvaluateExpression('object', noDynamic) 172 object_dynamic = frame.EvaluateExpression('object', useDynamic) 173 del (object_static) 174 self.examine_SourceDerived_ptr(object_dynamic) 175 176 # Continue again to the handle_SourceBase and make sure we get the correct dynamic value. 177 # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so 178 # its isa pointer points to SourceBase not NSKVOSourceBase or 179 # whatever... 180 181 threads = lldbutil.continue_to_breakpoint( 182 process, handle_SourceBase_bkpt) 183 self.assertEquals(len(threads), 1) 184 thread = threads[0] 185 186 frame = thread.GetFrameAtIndex(0) 187 188 # Get "object" using FindVariable: 189 190 object_static = frame.FindVariable('object', noDynamic) 191 object_dynamic = frame.FindVariable('object', useDynamic) 192 193 # Delete this object to make sure that this doesn't cause havoc with 194 # the dynamic object that depends on it. 195 del (object_static) 196 197 self.examine_SourceDerived_ptr(object_dynamic) 198 199 def examine_SourceDerived_ptr(self, object): 200 self.assertTrue(object) 201 self.assertNotEqual(object.GetTypeName().find('SourceDerived'), -1) 202 derivedValue = object.GetChildMemberWithName('_derivedValue') 203 self.assertTrue(derivedValue) 204 self.assertEquals(int(derivedValue.GetValue(), 0), 30) 205