1"""Test stepping through ObjC method dispatch in various forms.""" 2 3import lldb 4from lldbsuite.test.decorators import * 5from lldbsuite.test.lldbtest import * 6from lldbsuite.test import lldbutil 7 8 9class TestObjCStepping(TestBase): 10 def setUp(self): 11 # Call super's setUp(). 12 TestBase.setUp(self) 13 # Find the line numbers that we will step to in main: 14 self.main_source = "stepping-tests.m" 15 self.source_randomMethod_line = line_number( 16 self.main_source, "// Source randomMethod start line." 17 ) 18 self.sourceBase_randomMethod_line = line_number( 19 self.main_source, "// SourceBase randomMethod start line." 20 ) 21 self.source_returnsStruct_start_line = line_number( 22 self.main_source, "// Source returnsStruct start line." 23 ) 24 self.sourceBase_returnsStruct_start_line = line_number( 25 self.main_source, "// SourceBase returnsStruct start line." 26 ) 27 self.stepped_past_nil_line = line_number( 28 self.main_source, "// Step over nil should stop here." 29 ) 30 31 @add_test_categories(["pyapi", "basic_process"]) 32 def test_with_python_api(self): 33 """Test stepping through ObjC method dispatch in various forms.""" 34 self.build() 35 exe = self.getBuildArtifact("a.out") 36 37 target = self.dbg.CreateTarget(exe) 38 self.assertTrue(target, VALID_TARGET) 39 40 self.main_source_spec = lldb.SBFileSpec(self.main_source) 41 42 breakpoints_to_disable = [] 43 44 break1 = target.BreakpointCreateBySourceRegex( 45 "// Set first breakpoint here.", self.main_source_spec 46 ) 47 self.assertTrue(break1, VALID_BREAKPOINT) 48 breakpoints_to_disable.append(break1) 49 50 break2 = target.BreakpointCreateBySourceRegex( 51 "// Set second breakpoint here.", self.main_source_spec 52 ) 53 self.assertTrue(break2, VALID_BREAKPOINT) 54 breakpoints_to_disable.append(break2) 55 56 break3 = target.BreakpointCreateBySourceRegex( 57 "// Set third breakpoint here.", self.main_source_spec 58 ) 59 self.assertTrue(break3, VALID_BREAKPOINT) 60 breakpoints_to_disable.append(break3) 61 62 break4 = target.BreakpointCreateBySourceRegex( 63 "// Set fourth breakpoint here.", self.main_source_spec 64 ) 65 self.assertTrue(break4, VALID_BREAKPOINT) 66 breakpoints_to_disable.append(break4) 67 68 break5 = target.BreakpointCreateBySourceRegex( 69 "// Set fifth breakpoint here.", self.main_source_spec 70 ) 71 self.assertTrue(break5, VALID_BREAKPOINT) 72 breakpoints_to_disable.append(break5) 73 74 break_returnStruct_call_super = target.BreakpointCreateBySourceRegex( 75 "// Source returnsStruct call line.", self.main_source_spec 76 ) 77 self.assertTrue(break_returnStruct_call_super, VALID_BREAKPOINT) 78 breakpoints_to_disable.append(break_returnStruct_call_super) 79 80 break_step_nil = target.BreakpointCreateBySourceRegex( 81 "// Set nil step breakpoint here.", self.main_source_spec 82 ) 83 self.assertTrue(break_step_nil, VALID_BREAKPOINT) 84 85 # Now launch the process, and do not stop at entry point. 86 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 87 88 self.assertTrue(process, PROCESS_IS_VALID) 89 90 # The stop reason of the thread should be breakpoint. 91 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break1) 92 if len(threads) != 1: 93 self.fail("Failed to stop at breakpoint 1.") 94 95 thread = threads[0] 96 97 mySource = thread.GetFrameAtIndex(0).FindVariable("mySource") 98 self.assertTrue(mySource, "Found mySource local variable.") 99 mySource_isa = mySource.GetChildMemberWithName("isa") 100 self.assertTrue(mySource_isa, "Found mySource->isa local variable.") 101 className = mySource_isa.GetSummary() 102 103 if self.TraceOn(): 104 print(mySource_isa) 105 106 # Lets delete mySource so we can check that after stepping a child variable 107 # with no parent persists and is useful. 108 del mySource 109 110 # Now step in, that should leave us in the Source randomMethod: 111 thread.StepInto() 112 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 113 self.assertEqual( 114 line_number, 115 self.source_randomMethod_line, 116 "Stepped into Source randomMethod.", 117 ) 118 119 # Now step in again, through the super call, and that should leave us 120 # in the SourceBase randomMethod: 121 thread.StepInto() 122 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 123 self.assertEqual( 124 line_number, 125 self.sourceBase_randomMethod_line, 126 "Stepped through super into SourceBase randomMethod.", 127 ) 128 129 threads = lldbutil.continue_to_breakpoint(process, break2) 130 self.assertEqual(len(threads), 1, "Continued to second breakpoint in main.") 131 132 # Again, step in twice gets us to a stret method and a stret super 133 # call: 134 thread = threads[0] 135 thread.StepInto() 136 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 137 self.assertEqual( 138 line_number, 139 self.source_returnsStruct_start_line, 140 "Stepped into Source returnsStruct.", 141 ) 142 143 threads = lldbutil.continue_to_breakpoint( 144 process, break_returnStruct_call_super 145 ) 146 self.assertEqual( 147 len(threads), 1, "Stepped to the call super line in Source returnsStruct." 148 ) 149 thread = threads[0] 150 151 thread.StepInto() 152 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 153 self.assertEqual( 154 line_number, 155 self.sourceBase_returnsStruct_start_line, 156 "Stepped through super into SourceBase returnsStruct.", 157 ) 158 159 # Cool now continue to get past the call that initializes the Observer, and then do our steps in again to see that 160 # we can find our way when we're stepping through a KVO swizzled 161 # object. 162 163 threads = lldbutil.continue_to_breakpoint(process, break3) 164 self.assertEqual( 165 len(threads), 166 1, 167 "Continued to third breakpoint in main, our object should now be swizzled.", 168 ) 169 170 newClassName = mySource_isa.GetSummary() 171 172 if self.TraceOn(): 173 print("className is %s, newClassName is %s" % (className, newClassName)) 174 print(mySource_isa) 175 176 self.assertNotEqual( 177 newClassName, className, "The isa did indeed change, swizzled!" 178 ) 179 180 # Now step in, that should leave us in the Source randomMethod: 181 thread = threads[0] 182 thread.StepInto() 183 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 184 self.assertEqual( 185 line_number, 186 self.source_randomMethod_line, 187 "Stepped into Source randomMethod in swizzled object.", 188 ) 189 190 # Now step in again, through the super call, and that should leave us 191 # in the SourceBase randomMethod: 192 thread.StepInto() 193 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 194 self.assertEqual( 195 line_number, 196 self.sourceBase_randomMethod_line, 197 "Stepped through super into SourceBase randomMethod in swizzled object.", 198 ) 199 200 threads = lldbutil.continue_to_breakpoint(process, break4) 201 self.assertEqual(len(threads), 1, "Continued to fourth breakpoint in main.") 202 thread = threads[0] 203 204 # Again, step in twice gets us to a stret method and a stret super 205 # call: 206 thread.StepInto() 207 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 208 self.assertEqual( 209 line_number, 210 self.source_returnsStruct_start_line, 211 "Stepped into Source returnsStruct in swizzled object.", 212 ) 213 214 threads = lldbutil.continue_to_breakpoint( 215 process, break_returnStruct_call_super 216 ) 217 self.assertEqual( 218 len(threads), 219 1, 220 "Stepped to the call super line in Source returnsStruct - second time.", 221 ) 222 thread = threads[0] 223 224 thread.StepInto() 225 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 226 self.assertEqual( 227 line_number, 228 self.sourceBase_returnsStruct_start_line, 229 "Stepped through super into SourceBase returnsStruct in swizzled object.", 230 ) 231 232 for bkpt in breakpoints_to_disable: 233 bkpt.SetEnabled(False) 234 235 threads = lldbutil.continue_to_breakpoint(process, break_step_nil) 236 self.assertEqual(len(threads), 1, "Continued to step nil breakpoint.") 237 238 thread.StepInto() 239 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() 240 self.assertEqual( 241 line_number, 242 self.stepped_past_nil_line, 243 "Step in over dispatch to nil stepped over.", 244 ) 245