1 """Test stepping through ObjC method dispatch in various forms.""" 2 3 import os, time 4 import unittest2 5 import lldb 6 import lldbutil 7 from lldbtest import * 8 9 class TestObjCStepping(TestBase): 10 11 def getCategories (self): 12 return ['basic_process'] 13 14 mydir = os.path.join("lang", "objc", "objc-stepping") 15 16 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 17 @python_api_test 18 @dsym_test 19 def test_with_dsym_and_python_api(self): 20 """Test stepping through ObjC method dispatch in various forms.""" 21 self.buildDsym() 22 self.objc_stepping() 23 24 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 25 @python_api_test 26 @dwarf_test 27 def test_with_dwarf_and_python_api(self): 28 """Test stepping through ObjC method dispatch in various forms.""" 29 self.buildDwarf() 30 self.objc_stepping() 31 32 def setUp(self): 33 # Call super's setUp(). 34 TestBase.setUp(self) 35 # Find the line numbers that we will step to in main: 36 self.main_source = "stepping-tests.m" 37 self.source_randomMethod_line = line_number (self.main_source, '// Source randomMethod start line.') 38 self.sourceBase_randomMethod_line = line_number (self.main_source, '// SourceBase randomMethod start line.') 39 self.source_returnsStruct_start_line = line_number (self.main_source, '// Source returnsStruct start line.') 40 self.sourceBase_returnsStruct_start_line = line_number (self.main_source, '// SourceBase returnsStruct start line.') 41 self.stepped_past_nil_line = line_number (self.main_source, '// Step over nil should stop here.') 42 43 def objc_stepping(self): 44 """Use Python APIs to test stepping into ObjC methods.""" 45 exe = os.path.join(os.getcwd(), "a.out") 46 47 target = self.dbg.CreateTarget(exe) 48 self.assertTrue(target, VALID_TARGET) 49 50 self.main_source_spec = lldb.SBFileSpec (self.main_source) 51 52 breakpoints_to_disable = [] 53 54 break1 = target.BreakpointCreateBySourceRegex ("// Set first breakpoint here.", self.main_source_spec) 55 self.assertTrue(break1, VALID_BREAKPOINT) 56 breakpoints_to_disable.append (break1) 57 58 break2 = target.BreakpointCreateBySourceRegex ("// Set second breakpoint here.", self.main_source_spec) 59 self.assertTrue(break2, VALID_BREAKPOINT) 60 breakpoints_to_disable.append (break2) 61 62 break3 = target.BreakpointCreateBySourceRegex ('// Set third breakpoint here.', self.main_source_spec) 63 self.assertTrue(break3, VALID_BREAKPOINT) 64 breakpoints_to_disable.append (break3) 65 66 break4 = target.BreakpointCreateBySourceRegex ('// Set fourth breakpoint here.', self.main_source_spec) 67 self.assertTrue(break4, VALID_BREAKPOINT) 68 breakpoints_to_disable.append (break4) 69 70 break5 = target.BreakpointCreateBySourceRegex ('// Set fifth breakpoint here.', self.main_source_spec) 71 self.assertTrue(break5, VALID_BREAKPOINT) 72 breakpoints_to_disable.append (break5) 73 74 break_returnStruct_call_super = target.BreakpointCreateBySourceRegex ('// Source returnsStruct call line.', self.main_source_spec) 75 self.assertTrue(break_returnStruct_call_super, VALID_BREAKPOINT) 76 breakpoints_to_disable.append (break_returnStruct_call_super) 77 78 break_step_nil = target.BreakpointCreateBySourceRegex ('// Set nil step breakpoint here.', self.main_source_spec) 79 self.assertTrue(break_step_nil, VALID_BREAKPOINT) 80 81 # Now launch the process, and do not stop at entry point. 82 process = target.LaunchSimple (None, None, os.getcwd()) 83 84 self.assertTrue(process, PROCESS_IS_VALID) 85 86 # The stop reason of the thread should be breakpoint. 87 threads = lldbutil.get_threads_stopped_at_breakpoint (process, break1) 88 if len(threads) != 1: 89 self.fail ("Failed to stop at breakpoint 1.") 90 91 thread = threads[0] 92 93 mySource = thread.GetFrameAtIndex(0).FindVariable("mySource") 94 self.assertTrue(mySource, "Found mySource local variable.") 95 mySource_isa = mySource.GetChildMemberWithName ("isa") 96 self.assertTrue(mySource_isa, "Found mySource->isa local variable.") 97 className = mySource_isa.GetSummary () 98 99 if self.TraceOn(): 100 print mySource_isa 101 102 # Lets delete mySource so we can check that after stepping a child variable 103 # with no parent persists and is useful. 104 del (mySource) 105 106 # Now step in, that should leave us in the Source randomMethod: 107 thread.StepInto() 108 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 109 self.assertTrue (line_number == self.source_randomMethod_line, "Stepped into Source randomMethod.") 110 111 # Now step in again, through the super call, and that should leave us in the SourceBase randomMethod: 112 thread.StepInto() 113 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 114 self.assertTrue (line_number == self.sourceBase_randomMethod_line, "Stepped through super into SourceBase randomMethod.") 115 116 threads = lldbutil.continue_to_breakpoint (process, break2) 117 self.assertTrue (len(threads) == 1, "Continued to second breakpoint in main.") 118 119 # Again, step in twice gets us to a stret method and a stret super call: 120 thread = threads[0] 121 thread.StepInto() 122 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 123 self.assertTrue (line_number == self.source_returnsStruct_start_line, "Stepped into Source returnsStruct.") 124 125 threads = lldbutil.continue_to_breakpoint (process, break_returnStruct_call_super) 126 self.assertTrue (len(threads) == 1, "Stepped to the call super line in Source returnsStruct.") 127 thread = threads[0] 128 129 thread.StepInto() 130 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 131 self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct.") 132 133 # Cool now continue to get past the call that intializes the Observer, and then do our steps in again to see that 134 # we can find our way when we're stepping through a KVO swizzled object. 135 136 threads = lldbutil.continue_to_breakpoint (process, break3) 137 self.assertTrue (len(threads) == 1, "Continued to third breakpoint in main, our object should now be swizzled.") 138 139 newClassName = mySource_isa.GetSummary () 140 141 if self.TraceOn(): 142 print mySource_isa 143 144 self.assertTrue (newClassName != className, "The isa did indeed change, swizzled!") 145 146 # Now step in, that should leave us in the Source randomMethod: 147 thread = threads[0] 148 thread.StepInto() 149 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 150 self.assertTrue (line_number == self.source_randomMethod_line, "Stepped into Source randomMethod in swizzled object.") 151 152 # Now step in again, through the super call, and that should leave us in the SourceBase randomMethod: 153 thread.StepInto() 154 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 155 self.assertTrue (line_number == self.sourceBase_randomMethod_line, "Stepped through super into SourceBase randomMethod in swizzled object.") 156 157 threads = lldbutil.continue_to_breakpoint (process, break4) 158 self.assertTrue (len(threads) == 1, "Continued to fourth breakpoint in main.") 159 thread = threads[0] 160 161 # Again, step in twice gets us to a stret method and a stret super call: 162 thread.StepInto() 163 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 164 self.assertTrue (line_number == self.source_returnsStruct_start_line, "Stepped into Source returnsStruct in swizzled object.") 165 166 threads = lldbutil.continue_to_breakpoint(process, break_returnStruct_call_super) 167 self.assertTrue (len(threads) == 1, "Stepped to the call super line in Source returnsStruct - second time.") 168 thread = threads[0] 169 170 thread.StepInto() 171 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 172 self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct in swizzled object.") 173 174 for bkpt in breakpoints_to_disable: 175 bkpt.SetEnabled(False) 176 177 threads = lldbutil.continue_to_breakpoint (process, break_step_nil) 178 self.assertTrue (len(threads) == 1, "Continued to step nil breakpoint.") 179 180 thread.StepInto() 181 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 182 self.assertTrue (line_number == self.stepped_past_nil_line, "Step in over dispatch to nil stepped over.") 183 184 if __name__ == '__main__': 185 import atexit 186 lldb.SBDebugger.Initialize() 187 atexit.register(lambda: lldb.SBDebugger.Terminate()) 188 unittest2.main() 189