xref: /llvm-project/lldb/test/API/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py (revision b3a0c4d7dcfa252be17ef5f5b63ffaaa83e01a2b)
1"""
2Use lldb Python API to test dynamic values in ObjC
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11
12
13class ObjCDynamicValueTestCase(TestBase):
14
15    mydir = TestBase.compute_mydir(__file__)
16
17    def setUp(self):
18        # Call super's setUp().
19        TestBase.setUp(self)
20
21        # Find the line number to break for main.c.
22
23        self.source_name = 'dynamic-value.m'
24        self.set_property_line = line_number(
25            self.source_name,
26            '// This is the line in setProperty, make sure we step to here.')
27        self.handle_SourceBase = line_number(
28            self.source_name, '// Break here to check dynamic values.')
29        self.main_before_setProperty_line = line_number(
30            self.source_name, '// Break here to see if we can step into real method.')
31
32    @skipUnlessDarwin
33    @add_test_categories(['pyapi'])
34    @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107")
35    def test_get_objc_dynamic_vals(self):
36        """Test fetching ObjC dynamic values."""
37        if self.getArchitecture() == 'i386':
38            # rdar://problem/9946499
39            self.skipTest("Dynamic types for ObjC V1 runtime not implemented")
40
41        self.build()
42        exe = self.getBuildArtifact("a.out")
43
44        # Create a target from the debugger.
45
46        target = self.dbg.CreateTarget(exe)
47        self.assertTrue(target, VALID_TARGET)
48
49        # Set up our breakpoints:
50
51        handle_SourceBase_bkpt = target.BreakpointCreateByLocation(
52            self.source_name, self.handle_SourceBase)
53        self.assertTrue(handle_SourceBase_bkpt and
54                        handle_SourceBase_bkpt.GetNumLocations() == 1,
55                        VALID_BREAKPOINT)
56
57        main_before_setProperty_bkpt = target.BreakpointCreateByLocation(
58            self.source_name, self.main_before_setProperty_line)
59        self.assertTrue(main_before_setProperty_bkpt and
60                        main_before_setProperty_bkpt.GetNumLocations() == 1,
61                        VALID_BREAKPOINT)
62
63        # Now launch the process, and do not stop at the entry point.
64        process = target.LaunchSimple(
65            None, None, self.get_process_working_directory())
66
67        self.assertEquals(process.GetState(), lldb.eStateStopped,
68                        PROCESS_STOPPED)
69
70        threads = lldbutil.get_threads_stopped_at_breakpoint(
71            process, main_before_setProperty_bkpt)
72        self.assertEquals(len(threads), 1)
73        thread = threads[0]
74
75        #
76        #  At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
77        #  make sure we can get that properly:
78
79        frame = thread.GetFrameAtIndex(0)
80        myObserver = frame.FindVariable(
81            'myObserver', lldb.eDynamicCanRunTarget)
82        self.assertTrue(myObserver)
83        myObserver_source = myObserver.GetChildMemberWithName(
84            '_source', lldb.eDynamicCanRunTarget)
85        self.examine_SourceDerived_ptr(myObserver_source)
86
87        #
88        # Make sure a static value can be correctly turned into a dynamic
89        # value.
90
91        frame = thread.GetFrameAtIndex(0)
92        myObserver_static = frame.FindVariable(
93            'myObserver', lldb.eNoDynamicValues)
94        self.assertTrue(myObserver_static)
95        myObserver = myObserver_static.GetDynamicValue(
96            lldb.eDynamicCanRunTarget)
97        myObserver_source = myObserver.GetChildMemberWithName(
98            '_source', lldb.eDynamicCanRunTarget)
99        self.examine_SourceDerived_ptr(myObserver_source)
100
101        # The "frame var" code uses another path to get into children, so let's
102        # make sure that works as well:
103
104        result = lldb.SBCommandReturnObject()
105
106        self.expect(
107            'frame var -d run-target myObserver->_source',
108            'frame var finds its way into a child member',
109            patterns=['\(SourceDerived \*\)'])
110
111        # check that our ObjC GetISA() does a good job at hiding KVO swizzled
112        # classes
113
114        self.expect(
115            'frame var -d run-target myObserver->_source -T',
116            'the KVO-ed class is hidden',
117            substrs=['SourceDerived'])
118
119        self.expect(
120            'frame var -d run-target myObserver->_source -T',
121            'the KVO-ed class is hidden',
122            matching=False,
123            substrs=['NSKVONotify'])
124
125        # This test is not entirely related to the main thrust of this test case, but since we're here,
126        # try stepping into setProperty, and make sure we get into the version
127        # in Source:
128
129        thread.StepInto()
130
131        threads = lldbutil.get_stopped_threads(
132            process, lldb.eStopReasonPlanComplete)
133        self.assertEquals(len(threads), 1)
134        line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()
135
136        self.assertEqual(line_entry.GetLine(), self.set_property_line)
137        self.assertEqual(
138            line_entry.GetFileSpec().GetFilename(),
139            self.source_name)
140
141        # Okay, back to the main business.  Continue to the handle_SourceBase
142        # and make sure we get the correct dynamic value.
143
144        threads = lldbutil.continue_to_breakpoint(
145            process, handle_SourceBase_bkpt)
146        self.assertEquals(len(threads), 1)
147        thread = threads[0]
148
149        frame = thread.GetFrameAtIndex(0)
150
151        # Get "object" using FindVariable:
152
153        noDynamic = lldb.eNoDynamicValues
154        useDynamic = lldb.eDynamicCanRunTarget
155
156        object_static = frame.FindVariable('object', noDynamic)
157        object_dynamic = frame.FindVariable('object', useDynamic)
158
159        # Delete this object to make sure that this doesn't cause havoc with
160        # the dynamic object that depends on it.
161        del (object_static)
162
163        self.examine_SourceDerived_ptr(object_dynamic)
164
165        # Get "this" using FindValue, make sure that works too:
166        object_static = frame.FindValue(
167            'object', lldb.eValueTypeVariableArgument, noDynamic)
168        object_dynamic = frame.FindValue(
169            'object', lldb.eValueTypeVariableArgument, useDynamic)
170        del (object_static)
171        self.examine_SourceDerived_ptr(object_dynamic)
172
173        # Get "this" using the EvaluateExpression:
174        object_static = frame.EvaluateExpression('object', noDynamic)
175        object_dynamic = frame.EvaluateExpression('object', useDynamic)
176        del (object_static)
177        self.examine_SourceDerived_ptr(object_dynamic)
178
179        # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
180        # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
181        # its isa pointer points to SourceBase not NSKVOSourceBase or
182        # whatever...
183
184        threads = lldbutil.continue_to_breakpoint(
185            process, handle_SourceBase_bkpt)
186        self.assertEquals(len(threads), 1)
187        thread = threads[0]
188
189        frame = thread.GetFrameAtIndex(0)
190
191        # Get "object" using FindVariable:
192
193        object_static = frame.FindVariable('object', noDynamic)
194        object_dynamic = frame.FindVariable('object', useDynamic)
195
196        # Delete this object to make sure that this doesn't cause havoc with
197        # the dynamic object that depends on it.
198        del (object_static)
199
200        self.examine_SourceDerived_ptr(object_dynamic)
201
202    def examine_SourceDerived_ptr(self, object):
203        self.assertTrue(object)
204        self.assertNotEqual(object.GetTypeName().find('SourceDerived'), -1)
205        derivedValue = object.GetChildMemberWithName('_derivedValue')
206        self.assertTrue(derivedValue)
207        self.assertEquals(int(derivedValue.GetValue(), 0), 30)
208