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