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