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