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