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
13 class TestObjCStepping(TestBase):
15 def getCategories (self):
16 return ['basic_process']
18 mydir = TestBase.compute_mydir(__file__)
21 # Call super's setUp().
23 # Find the line numbers that we will step to in main:
24 self.main_source = "stepping-tests.m"
25 self.source_randomMethod_line = line_number (self.main_source, '// Source randomMethod start line.')
26 self.sourceBase_randomMethod_line = line_number (self.main_source, '// SourceBase randomMethod start line.')
27 self.source_returnsStruct_start_line = line_number (self.main_source, '// Source returnsStruct start line.')
28 self.sourceBase_returnsStruct_start_line = line_number (self.main_source, '// SourceBase returnsStruct start line.')
29 self.stepped_past_nil_line = line_number (self.main_source, '// Step over nil should stop here.')
32 @add_test_categories(['pyapi'])
33 def test_with_python_api(self):
34 """Test stepping through ObjC method dispatch in various forms."""
36 exe = os.path.join(os.getcwd(), "a.out")
38 target = self.dbg.CreateTarget(exe)
39 self.assertTrue(target, VALID_TARGET)
41 self.main_source_spec = lldb.SBFileSpec (self.main_source)
43 breakpoints_to_disable = []
45 break1 = target.BreakpointCreateBySourceRegex ("// Set first breakpoint here.", self.main_source_spec)
46 self.assertTrue(break1, VALID_BREAKPOINT)
47 breakpoints_to_disable.append (break1)
49 break2 = target.BreakpointCreateBySourceRegex ("// Set second breakpoint here.", self.main_source_spec)
50 self.assertTrue(break2, VALID_BREAKPOINT)
51 breakpoints_to_disable.append (break2)
53 break3 = target.BreakpointCreateBySourceRegex ('// Set third breakpoint here.', self.main_source_spec)
54 self.assertTrue(break3, VALID_BREAKPOINT)
55 breakpoints_to_disable.append (break3)
57 break4 = target.BreakpointCreateBySourceRegex ('// Set fourth breakpoint here.', self.main_source_spec)
58 self.assertTrue(break4, VALID_BREAKPOINT)
59 breakpoints_to_disable.append (break4)
61 break5 = target.BreakpointCreateBySourceRegex ('// Set fifth breakpoint here.', self.main_source_spec)
62 self.assertTrue(break5, VALID_BREAKPOINT)
63 breakpoints_to_disable.append (break5)
65 break_returnStruct_call_super = target.BreakpointCreateBySourceRegex ('// Source returnsStruct call line.', self.main_source_spec)
66 self.assertTrue(break_returnStruct_call_super, VALID_BREAKPOINT)
67 breakpoints_to_disable.append (break_returnStruct_call_super)
69 break_step_nil = target.BreakpointCreateBySourceRegex ('// Set nil step breakpoint here.', self.main_source_spec)
70 self.assertTrue(break_step_nil, VALID_BREAKPOINT)
72 # Now launch the process, and do not stop at entry point.
73 process = target.LaunchSimple (None, None, self.get_process_working_directory())
75 self.assertTrue(process, PROCESS_IS_VALID)
77 # The stop reason of the thread should be breakpoint.
78 threads = lldbutil.get_threads_stopped_at_breakpoint (process, break1)
80 self.fail ("Failed to stop at breakpoint 1.")
84 mySource = thread.GetFrameAtIndex(0).FindVariable("mySource")
85 self.assertTrue(mySource, "Found mySource local variable.")
86 mySource_isa = mySource.GetChildMemberWithName ("isa")
87 self.assertTrue(mySource_isa, "Found mySource->isa local variable.")
88 className = mySource_isa.GetSummary ()
93 # Lets delete mySource so we can check that after stepping a child variable
94 # with no parent persists and is useful.
97 # Now step in, that should leave us in the Source randomMethod:
99 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
100 self.assertTrue (line_number == self.source_randomMethod_line, "Stepped into Source randomMethod.")
102 # Now step in again, through the super call, and that should leave us in the SourceBase randomMethod:
104 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
105 self.assertTrue (line_number == self.sourceBase_randomMethod_line, "Stepped through super into SourceBase randomMethod.")
107 threads = lldbutil.continue_to_breakpoint (process, break2)
108 self.assertTrue (len(threads) == 1, "Continued to second breakpoint in main.")
110 # Again, step in twice gets us to a stret method and a stret super call:
113 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
114 self.assertTrue (line_number == self.source_returnsStruct_start_line, "Stepped into Source returnsStruct.")
116 threads = lldbutil.continue_to_breakpoint (process, break_returnStruct_call_super)
117 self.assertTrue (len(threads) == 1, "Stepped to the call super line in Source returnsStruct.")
121 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
122 self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct.")
124 # Cool now continue to get past the call that initializes the Observer, and then do our steps in again to see that
125 # we can find our way when we're stepping through a KVO swizzled object.
127 threads = lldbutil.continue_to_breakpoint (process, break3)
128 self.assertTrue (len(threads) == 1, "Continued to third breakpoint in main, our object should now be swizzled.")
130 newClassName = mySource_isa.GetSummary ()
135 self.assertTrue (newClassName != className, "The isa did indeed change, swizzled!")
137 # Now step in, that should leave us in the Source randomMethod:
140 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
141 self.assertTrue (line_number == self.source_randomMethod_line, "Stepped into Source randomMethod in swizzled object.")
143 # Now step in again, through the super call, and that should leave us in the SourceBase randomMethod:
145 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
146 self.assertTrue (line_number == self.sourceBase_randomMethod_line, "Stepped through super into SourceBase randomMethod in swizzled object.")
148 threads = lldbutil.continue_to_breakpoint (process, break4)
149 self.assertTrue (len(threads) == 1, "Continued to fourth breakpoint in main.")
152 # Again, step in twice gets us to a stret method and a stret super call:
154 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
155 self.assertTrue (line_number == self.source_returnsStruct_start_line, "Stepped into Source returnsStruct in swizzled object.")
157 threads = lldbutil.continue_to_breakpoint(process, break_returnStruct_call_super)
158 self.assertTrue (len(threads) == 1, "Stepped to the call super line in Source returnsStruct - second time.")
162 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
163 self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct in swizzled object.")
165 for bkpt in breakpoints_to_disable:
166 bkpt.SetEnabled(False)
168 threads = lldbutil.continue_to_breakpoint (process, break_step_nil)
169 self.assertTrue (len(threads) == 1, "Continued to step nil breakpoint.")
172 line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine()
173 self.assertTrue (line_number == self.stepped_past_nil_line, "Step in over dispatch to nil stepped over.")