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