1 """Test stepping through ObjC method dispatch in various forms."""
3 from __future__ import print_function
9 from lldbsuite.test.decorators import *
10 from lldbsuite.test.lldbtest import *
11 from lldbsuite.test import lldbutil
14 class TestObjCStepping(TestBase):
16 def getCategories(self):
17 return ['basic_process']
19 mydir = TestBase.compute_mydir(__file__)
22 # Call super's setUp().
24 # Find the line numbers that we will step to in main:
25 self.main_source = "stepping-tests.m"
26 self.source_randomMethod_line = line_number(
27 self.main_source, '// Source randomMethod start line.')
28 self.sourceBase_randomMethod_line = line_number(
29 self.main_source, '// SourceBase randomMethod start line.')
30 self.source_returnsStruct_start_line = line_number(
31 self.main_source, '// Source returnsStruct start line.')
32 self.sourceBase_returnsStruct_start_line = line_number(
33 self.main_source, '// SourceBase returnsStruct start line.')
34 self.stepped_past_nil_line = line_number(
35 self.main_source, '// Step over nil should stop here.')
38 @add_test_categories(['pyapi'])
39 def test_with_python_api(self):
40 """Test stepping through ObjC method dispatch in various forms."""
42 exe = os.path.join(os.getcwd(), "a.out")
44 target = self.dbg.CreateTarget(exe)
45 self.assertTrue(target, VALID_TARGET)
47 self.main_source_spec = lldb.SBFileSpec(self.main_source)
49 breakpoints_to_disable = []
51 break1 = target.BreakpointCreateBySourceRegex(
52 "// Set first breakpoint here.", self.main_source_spec)
53 self.assertTrue(break1, VALID_BREAKPOINT)
54 breakpoints_to_disable.append(break1)
56 break2 = target.BreakpointCreateBySourceRegex(
57 "// Set second breakpoint here.", self.main_source_spec)
58 self.assertTrue(break2, VALID_BREAKPOINT)
59 breakpoints_to_disable.append(break2)
61 break3 = target.BreakpointCreateBySourceRegex(
62 '// Set third breakpoint here.', self.main_source_spec)
63 self.assertTrue(break3, VALID_BREAKPOINT)
64 breakpoints_to_disable.append(break3)
66 break4 = target.BreakpointCreateBySourceRegex(
67 '// Set fourth breakpoint here.', self.main_source_spec)
68 self.assertTrue(break4, VALID_BREAKPOINT)
69 breakpoints_to_disable.append(break4)
71 break5 = target.BreakpointCreateBySourceRegex(
72 '// Set fifth breakpoint here.', self.main_source_spec)
73 self.assertTrue(break5, VALID_BREAKPOINT)
74 breakpoints_to_disable.append(break5)
76 break_returnStruct_call_super = target.BreakpointCreateBySourceRegex(
77 '// Source returnsStruct call line.', self.main_source_spec)
78 self.assertTrue(break_returnStruct_call_super, VALID_BREAKPOINT)
79 breakpoints_to_disable.append(break_returnStruct_call_super)
81 break_step_nil = target.BreakpointCreateBySourceRegex(
82 '// Set nil step breakpoint here.', self.main_source_spec)
83 self.assertTrue(break_step_nil, VALID_BREAKPOINT)
85 # Now launch the process, and do not stop at entry point.
86 process = target.LaunchSimple(
87 None, None, self.get_process_working_directory())
89 self.assertTrue(process, PROCESS_IS_VALID)
91 # The stop reason of the thread should be breakpoint.
92 threads = lldbutil.get_threads_stopped_at_breakpoint(process, break1)
94 self.fail("Failed to stop at breakpoint 1.")
98 mySource = thread.GetFrameAtIndex(0).FindVariable("mySource")
99 self.assertTrue(mySource, "Found mySource local variable.")
100 mySource_isa = mySource.GetChildMemberWithName("isa")
101 self.assertTrue(mySource_isa, "Found mySource->isa local variable.")
102 className = mySource_isa.GetSummary()
107 # Lets delete mySource so we can check that after stepping a child variable
108 # with no parent persists and is useful.
111 # Now step in, that should leave us in the Source randomMethod:
113 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
115 line_number == self.source_randomMethod_line,
116 "Stepped into Source randomMethod.")
118 # Now step in again, through the super call, and that should leave us
119 # in the SourceBase randomMethod:
121 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
123 line_number == self.sourceBase_randomMethod_line,
124 "Stepped through super into SourceBase randomMethod.")
126 threads = lldbutil.continue_to_breakpoint(process, break2)
129 "Continued to second breakpoint in main.")
131 # Again, step in twice gets us to a stret method and a stret super
135 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
137 line_number == self.source_returnsStruct_start_line,
138 "Stepped into Source returnsStruct.")
140 threads = lldbutil.continue_to_breakpoint(
141 process, break_returnStruct_call_super)
144 "Stepped to the call super line in Source returnsStruct.")
148 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
150 line_number == self.sourceBase_returnsStruct_start_line,
151 "Stepped through super into SourceBase returnsStruct.")
153 # Cool now continue to get past the call that initializes the Observer, and then do our steps in again to see that
154 # we can find our way when we're stepping through a KVO swizzled
157 threads = lldbutil.continue_to_breakpoint(process, break3)
160 "Continued to third breakpoint in main, our object should now be swizzled.")
162 newClassName = mySource_isa.GetSummary()
168 newClassName != className,
169 "The isa did indeed change, swizzled!")
171 # Now step in, that should leave us in the Source randomMethod:
174 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
176 line_number == self.source_randomMethod_line,
177 "Stepped into Source randomMethod in swizzled object.")
179 # Now step in again, through the super call, and that should leave us
180 # in the SourceBase randomMethod:
182 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
184 line_number == self.sourceBase_randomMethod_line,
185 "Stepped through super into SourceBase randomMethod in swizzled object.")
187 threads = lldbutil.continue_to_breakpoint(process, break4)
190 "Continued to fourth breakpoint in main.")
193 # Again, step in twice gets us to a stret method and a stret super
196 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
198 line_number == self.source_returnsStruct_start_line,
199 "Stepped into Source returnsStruct in swizzled object.")
201 threads = lldbutil.continue_to_breakpoint(
202 process, break_returnStruct_call_super)
205 "Stepped to the call super line in Source returnsStruct - second time.")
209 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
211 line_number == self.sourceBase_returnsStruct_start_line,
212 "Stepped through super into SourceBase returnsStruct in swizzled object.")
214 for bkpt in breakpoints_to_disable:
215 bkpt.SetEnabled(False)
217 threads = lldbutil.continue_to_breakpoint(process, break_step_nil)
218 self.assertTrue(len(threads) == 1, "Continued to step nil breakpoint.")
221 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
223 line_number == self.stepped_past_nil_line,
224 "Step in over dispatch to nil stepped over.")