2 Use lldb Python API to test dynamic values in ObjC
7 from lldbsuite
.test
.decorators
import *
8 from lldbsuite
.test
.lldbtest
import *
9 from lldbsuite
.test
import lldbutil
12 class ObjCDynamicValueTestCase(TestBase
):
14 # Call super's setUp().
17 # Find the line number to break for main.c.
19 self
.source_name
= "dynamic-value.m"
20 self
.set_property_line
= line_number(
22 "// This is the line in setProperty, make sure we step to here.",
24 self
.handle_SourceBase
= line_number(
25 self
.source_name
, "// Break here to check dynamic values."
27 self
.main_before_setProperty_line
= line_number(
28 self
.source_name
, "// Break here to see if we can step into real method."
31 @add_test_categories(["pyapi"])
32 @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107")
33 def test_get_objc_dynamic_vals(self
):
34 """Test fetching ObjC dynamic values."""
35 if self
.getArchitecture() == "i386":
36 # rdar://problem/9946499
37 self
.skipTest("Dynamic types for ObjC V1 runtime not implemented")
40 exe
= self
.getBuildArtifact("a.out")
42 # Create a target from the debugger.
44 target
= self
.dbg
.CreateTarget(exe
)
45 self
.assertTrue(target
, VALID_TARGET
)
47 # Set up our breakpoints:
49 handle_SourceBase_bkpt
= target
.BreakpointCreateByLocation(
50 self
.source_name
, self
.handle_SourceBase
53 handle_SourceBase_bkpt
and handle_SourceBase_bkpt
.GetNumLocations() == 1,
57 main_before_setProperty_bkpt
= target
.BreakpointCreateByLocation(
58 self
.source_name
, self
.main_before_setProperty_line
61 main_before_setProperty_bkpt
62 and main_before_setProperty_bkpt
.GetNumLocations() == 1,
66 # Now launch the process, and do not stop at the entry point.
67 process
= target
.LaunchSimple(None, None, self
.get_process_working_directory())
69 self
.assertState(process
.GetState(), lldb
.eStateStopped
, PROCESS_STOPPED
)
71 threads
= lldbutil
.get_threads_stopped_at_breakpoint(
72 process
, main_before_setProperty_bkpt
74 self
.assertEquals(len(threads
), 1)
78 # At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
79 # make sure we can get that properly:
81 frame
= thread
.GetFrameAtIndex(0)
82 myObserver
= frame
.FindVariable("myObserver", lldb
.eDynamicCanRunTarget
)
83 self
.assertTrue(myObserver
)
84 myObserver_source
= myObserver
.GetChildMemberWithName(
85 "_source", lldb
.eDynamicCanRunTarget
87 self
.examine_SourceDerived_ptr(myObserver_source
)
90 # Make sure a static value can be correctly turned into a dynamic
93 frame
= thread
.GetFrameAtIndex(0)
94 myObserver_static
= frame
.FindVariable("myObserver", lldb
.eNoDynamicValues
)
95 self
.assertTrue(myObserver_static
)
96 myObserver
= myObserver_static
.GetDynamicValue(lldb
.eDynamicCanRunTarget
)
97 myObserver_source
= myObserver
.GetChildMemberWithName(
98 "_source", lldb
.eDynamicCanRunTarget
100 self
.examine_SourceDerived_ptr(myObserver_source
)
102 # The "frame var" code uses another path to get into children, so let's
103 # make sure that works as well:
105 result
= lldb
.SBCommandReturnObject()
108 "frame var -d run-target myObserver->_source",
109 "frame var finds its way into a child member",
110 patterns
=["\(SourceDerived \*\)"],
113 # check that our ObjC GetISA() does a good job at hiding KVO swizzled
117 "frame var -d run-target myObserver->_source -T",
118 "the KVO-ed class is hidden",
119 substrs
=["SourceDerived"],
123 "frame var -d run-target myObserver->_source -T",
124 "the KVO-ed class is hidden",
126 substrs
=["NSKVONotify"],
129 # This test is not entirely related to the main thrust of this test case, but since we're here,
130 # try stepping into setProperty, and make sure we get into the version
135 threads
= lldbutil
.get_stopped_threads(process
, lldb
.eStopReasonPlanComplete
)
136 self
.assertEquals(len(threads
), 1)
137 line_entry
= threads
[0].GetFrameAtIndex(0).GetLineEntry()
139 self
.assertEqual(line_entry
.GetLine(), self
.set_property_line
)
140 self
.assertEqual(line_entry
.GetFileSpec().GetFilename(), self
.source_name
)
142 # Okay, back to the main business. Continue to the handle_SourceBase
143 # and make sure we get the correct dynamic value.
145 threads
= lldbutil
.continue_to_breakpoint(process
, handle_SourceBase_bkpt
)
146 self
.assertEquals(len(threads
), 1)
149 frame
= thread
.GetFrameAtIndex(0)
151 # Get "object" using FindVariable:
153 noDynamic
= lldb
.eNoDynamicValues
154 useDynamic
= lldb
.eDynamicCanRunTarget
156 object_static
= frame
.FindVariable("object", noDynamic
)
157 object_dynamic
= frame
.FindVariable("object", useDynamic
)
159 # Delete this object to make sure that this doesn't cause havoc with
160 # the dynamic object that depends on it.
163 self
.examine_SourceDerived_ptr(object_dynamic
)
165 # Get "this" using FindValue, make sure that works too:
166 object_static
= frame
.FindValue(
167 "object", lldb
.eValueTypeVariableArgument
, noDynamic
169 object_dynamic
= frame
.FindValue(
170 "object", lldb
.eValueTypeVariableArgument
, useDynamic
173 self
.examine_SourceDerived_ptr(object_dynamic
)
175 # Get "this" using the EvaluateExpression:
176 object_static
= frame
.EvaluateExpression("object", noDynamic
)
177 object_dynamic
= frame
.EvaluateExpression("object", useDynamic
)
179 self
.examine_SourceDerived_ptr(object_dynamic
)
181 # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
182 # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
183 # its isa pointer points to SourceBase not NSKVOSourceBase or
186 threads
= lldbutil
.continue_to_breakpoint(process
, handle_SourceBase_bkpt
)
187 self
.assertEquals(len(threads
), 1)
190 frame
= thread
.GetFrameAtIndex(0)
192 # Get "object" using FindVariable:
194 object_static
= frame
.FindVariable("object", noDynamic
)
195 object_dynamic
= frame
.FindVariable("object", useDynamic
)
197 # Delete this object to make sure that this doesn't cause havoc with
198 # the dynamic object that depends on it.
201 self
.examine_SourceDerived_ptr(object_dynamic
)
203 def examine_SourceDerived_ptr(self
, object):
204 self
.assertTrue(object)
205 self
.assertNotEqual(object.GetTypeName().find("SourceDerived"), -1)
206 derivedValue
= object.GetChildMemberWithName("_derivedValue")
207 self
.assertTrue(derivedValue
)
208 self
.assertEquals(int(derivedValue
.GetValue(), 0), 30)