199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtUse lldb Python API to test dynamic values in ObjC
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht
699451b44SJordan Rupprecht
799451b44SJordan Rupprechtimport lldb
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprechtclass ObjCDynamicValueTestCase(TestBase):
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht    mydir = TestBase.compute_mydir(__file__)
1699451b44SJordan Rupprecht
1799451b44SJordan Rupprecht    def setUp(self):
1899451b44SJordan Rupprecht        # Call super's setUp().
1999451b44SJordan Rupprecht        TestBase.setUp(self)
2099451b44SJordan Rupprecht
2199451b44SJordan Rupprecht        # Find the line number to break for main.c.
2299451b44SJordan Rupprecht
2399451b44SJordan Rupprecht        self.source_name = 'dynamic-value.m'
2499451b44SJordan Rupprecht        self.set_property_line = line_number(
2599451b44SJordan Rupprecht            self.source_name,
2699451b44SJordan Rupprecht            '// This is the line in setProperty, make sure we step to here.')
2799451b44SJordan Rupprecht        self.handle_SourceBase = line_number(
2899451b44SJordan Rupprecht            self.source_name, '// Break here to check dynamic values.')
2999451b44SJordan Rupprecht        self.main_before_setProperty_line = line_number(
3099451b44SJordan Rupprecht            self.source_name, '// Break here to see if we can step into real method.')
3199451b44SJordan Rupprecht
3299451b44SJordan Rupprecht    @add_test_categories(['pyapi'])
3399451b44SJordan Rupprecht    @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107")
3499451b44SJordan Rupprecht    def test_get_objc_dynamic_vals(self):
3599451b44SJordan Rupprecht        """Test fetching ObjC dynamic values."""
3699451b44SJordan Rupprecht        if self.getArchitecture() == 'i386':
3799451b44SJordan Rupprecht            # rdar://problem/9946499
3899451b44SJordan Rupprecht            self.skipTest("Dynamic types for ObjC V1 runtime not implemented")
3999451b44SJordan Rupprecht
4099451b44SJordan Rupprecht        self.build()
4199451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
4299451b44SJordan Rupprecht
4399451b44SJordan Rupprecht        # Create a target from the debugger.
4499451b44SJordan Rupprecht
4599451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
4699451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
4799451b44SJordan Rupprecht
4899451b44SJordan Rupprecht        # Set up our breakpoints:
4999451b44SJordan Rupprecht
5099451b44SJordan Rupprecht        handle_SourceBase_bkpt = target.BreakpointCreateByLocation(
5199451b44SJordan Rupprecht            self.source_name, self.handle_SourceBase)
5299451b44SJordan Rupprecht        self.assertTrue(handle_SourceBase_bkpt and
5399451b44SJordan Rupprecht                        handle_SourceBase_bkpt.GetNumLocations() == 1,
5499451b44SJordan Rupprecht                        VALID_BREAKPOINT)
5599451b44SJordan Rupprecht
5699451b44SJordan Rupprecht        main_before_setProperty_bkpt = target.BreakpointCreateByLocation(
5799451b44SJordan Rupprecht            self.source_name, self.main_before_setProperty_line)
5899451b44SJordan Rupprecht        self.assertTrue(main_before_setProperty_bkpt and
5999451b44SJordan Rupprecht                        main_before_setProperty_bkpt.GetNumLocations() == 1,
6099451b44SJordan Rupprecht                        VALID_BREAKPOINT)
6199451b44SJordan Rupprecht
6299451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
6399451b44SJordan Rupprecht        process = target.LaunchSimple(
6499451b44SJordan Rupprecht            None, None, self.get_process_working_directory())
6599451b44SJordan Rupprecht
66*ce825e46SJonas Devlieghere        self.assertState(process.GetState(), lldb.eStateStopped,
6799451b44SJordan Rupprecht                         PROCESS_STOPPED)
6899451b44SJordan Rupprecht
6999451b44SJordan Rupprecht        threads = lldbutil.get_threads_stopped_at_breakpoint(
7099451b44SJordan Rupprecht            process, main_before_setProperty_bkpt)
71b3a0c4d7SRaphael Isemann        self.assertEquals(len(threads), 1)
7299451b44SJordan Rupprecht        thread = threads[0]
7399451b44SJordan Rupprecht
7499451b44SJordan Rupprecht        #
7599451b44SJordan Rupprecht        #  At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
7699451b44SJordan Rupprecht        #  make sure we can get that properly:
7799451b44SJordan Rupprecht
7899451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
7999451b44SJordan Rupprecht        myObserver = frame.FindVariable(
8099451b44SJordan Rupprecht            'myObserver', lldb.eDynamicCanRunTarget)
8199451b44SJordan Rupprecht        self.assertTrue(myObserver)
8299451b44SJordan Rupprecht        myObserver_source = myObserver.GetChildMemberWithName(
8399451b44SJordan Rupprecht            '_source', lldb.eDynamicCanRunTarget)
8499451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(myObserver_source)
8599451b44SJordan Rupprecht
8699451b44SJordan Rupprecht        #
8799451b44SJordan Rupprecht        # Make sure a static value can be correctly turned into a dynamic
8899451b44SJordan Rupprecht        # value.
8999451b44SJordan Rupprecht
9099451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
9199451b44SJordan Rupprecht        myObserver_static = frame.FindVariable(
9299451b44SJordan Rupprecht            'myObserver', lldb.eNoDynamicValues)
9399451b44SJordan Rupprecht        self.assertTrue(myObserver_static)
9499451b44SJordan Rupprecht        myObserver = myObserver_static.GetDynamicValue(
9599451b44SJordan Rupprecht            lldb.eDynamicCanRunTarget)
9699451b44SJordan Rupprecht        myObserver_source = myObserver.GetChildMemberWithName(
9799451b44SJordan Rupprecht            '_source', lldb.eDynamicCanRunTarget)
9899451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(myObserver_source)
9999451b44SJordan Rupprecht
10099451b44SJordan Rupprecht        # The "frame var" code uses another path to get into children, so let's
10199451b44SJordan Rupprecht        # make sure that works as well:
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        result = lldb.SBCommandReturnObject()
10499451b44SJordan Rupprecht
10599451b44SJordan Rupprecht        self.expect(
10699451b44SJordan Rupprecht            'frame var -d run-target myObserver->_source',
10799451b44SJordan Rupprecht            'frame var finds its way into a child member',
10899451b44SJordan Rupprecht            patterns=['\(SourceDerived \*\)'])
10999451b44SJordan Rupprecht
11099451b44SJordan Rupprecht        # check that our ObjC GetISA() does a good job at hiding KVO swizzled
11199451b44SJordan Rupprecht        # classes
11299451b44SJordan Rupprecht
11399451b44SJordan Rupprecht        self.expect(
11499451b44SJordan Rupprecht            'frame var -d run-target myObserver->_source -T',
11599451b44SJordan Rupprecht            'the KVO-ed class is hidden',
11699451b44SJordan Rupprecht            substrs=['SourceDerived'])
11799451b44SJordan Rupprecht
11899451b44SJordan Rupprecht        self.expect(
11999451b44SJordan Rupprecht            'frame var -d run-target myObserver->_source -T',
12099451b44SJordan Rupprecht            'the KVO-ed class is hidden',
12199451b44SJordan Rupprecht            matching=False,
12299451b44SJordan Rupprecht            substrs=['NSKVONotify'])
12399451b44SJordan Rupprecht
12499451b44SJordan Rupprecht        # This test is not entirely related to the main thrust of this test case, but since we're here,
12599451b44SJordan Rupprecht        # try stepping into setProperty, and make sure we get into the version
12699451b44SJordan Rupprecht        # in Source:
12799451b44SJordan Rupprecht
12899451b44SJordan Rupprecht        thread.StepInto()
12999451b44SJordan Rupprecht
13099451b44SJordan Rupprecht        threads = lldbutil.get_stopped_threads(
13199451b44SJordan Rupprecht            process, lldb.eStopReasonPlanComplete)
132b3a0c4d7SRaphael Isemann        self.assertEquals(len(threads), 1)
13399451b44SJordan Rupprecht        line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()
13499451b44SJordan Rupprecht
13599451b44SJordan Rupprecht        self.assertEqual(line_entry.GetLine(), self.set_property_line)
13699451b44SJordan Rupprecht        self.assertEqual(
13799451b44SJordan Rupprecht            line_entry.GetFileSpec().GetFilename(),
13899451b44SJordan Rupprecht            self.source_name)
13999451b44SJordan Rupprecht
14099451b44SJordan Rupprecht        # Okay, back to the main business.  Continue to the handle_SourceBase
14199451b44SJordan Rupprecht        # and make sure we get the correct dynamic value.
14299451b44SJordan Rupprecht
14399451b44SJordan Rupprecht        threads = lldbutil.continue_to_breakpoint(
14499451b44SJordan Rupprecht            process, handle_SourceBase_bkpt)
145b3a0c4d7SRaphael Isemann        self.assertEquals(len(threads), 1)
14699451b44SJordan Rupprecht        thread = threads[0]
14799451b44SJordan Rupprecht
14899451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
14999451b44SJordan Rupprecht
15099451b44SJordan Rupprecht        # Get "object" using FindVariable:
15199451b44SJordan Rupprecht
15299451b44SJordan Rupprecht        noDynamic = lldb.eNoDynamicValues
15399451b44SJordan Rupprecht        useDynamic = lldb.eDynamicCanRunTarget
15499451b44SJordan Rupprecht
15599451b44SJordan Rupprecht        object_static = frame.FindVariable('object', noDynamic)
15699451b44SJordan Rupprecht        object_dynamic = frame.FindVariable('object', useDynamic)
15799451b44SJordan Rupprecht
15899451b44SJordan Rupprecht        # Delete this object to make sure that this doesn't cause havoc with
15999451b44SJordan Rupprecht        # the dynamic object that depends on it.
16099451b44SJordan Rupprecht        del (object_static)
16199451b44SJordan Rupprecht
16299451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
16399451b44SJordan Rupprecht
16499451b44SJordan Rupprecht        # Get "this" using FindValue, make sure that works too:
16599451b44SJordan Rupprecht        object_static = frame.FindValue(
16699451b44SJordan Rupprecht            'object', lldb.eValueTypeVariableArgument, noDynamic)
16799451b44SJordan Rupprecht        object_dynamic = frame.FindValue(
16899451b44SJordan Rupprecht            'object', lldb.eValueTypeVariableArgument, useDynamic)
16999451b44SJordan Rupprecht        del (object_static)
17099451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
17199451b44SJordan Rupprecht
17299451b44SJordan Rupprecht        # Get "this" using the EvaluateExpression:
17399451b44SJordan Rupprecht        object_static = frame.EvaluateExpression('object', noDynamic)
17499451b44SJordan Rupprecht        object_dynamic = frame.EvaluateExpression('object', useDynamic)
17599451b44SJordan Rupprecht        del (object_static)
17699451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
17799451b44SJordan Rupprecht
17899451b44SJordan Rupprecht        # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
17999451b44SJordan Rupprecht        # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
18099451b44SJordan Rupprecht        # its isa pointer points to SourceBase not NSKVOSourceBase or
18199451b44SJordan Rupprecht        # whatever...
18299451b44SJordan Rupprecht
18399451b44SJordan Rupprecht        threads = lldbutil.continue_to_breakpoint(
18499451b44SJordan Rupprecht            process, handle_SourceBase_bkpt)
185b3a0c4d7SRaphael Isemann        self.assertEquals(len(threads), 1)
18699451b44SJordan Rupprecht        thread = threads[0]
18799451b44SJordan Rupprecht
18899451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
18999451b44SJordan Rupprecht
19099451b44SJordan Rupprecht        # Get "object" using FindVariable:
19199451b44SJordan Rupprecht
19299451b44SJordan Rupprecht        object_static = frame.FindVariable('object', noDynamic)
19399451b44SJordan Rupprecht        object_dynamic = frame.FindVariable('object', useDynamic)
19499451b44SJordan Rupprecht
19599451b44SJordan Rupprecht        # Delete this object to make sure that this doesn't cause havoc with
19699451b44SJordan Rupprecht        # the dynamic object that depends on it.
19799451b44SJordan Rupprecht        del (object_static)
19899451b44SJordan Rupprecht
19999451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
20099451b44SJordan Rupprecht
20199451b44SJordan Rupprecht    def examine_SourceDerived_ptr(self, object):
20299451b44SJordan Rupprecht        self.assertTrue(object)
203b3a0c4d7SRaphael Isemann        self.assertNotEqual(object.GetTypeName().find('SourceDerived'), -1)
20499451b44SJordan Rupprecht        derivedValue = object.GetChildMemberWithName('_derivedValue')
20599451b44SJordan Rupprecht        self.assertTrue(derivedValue)
206b3a0c4d7SRaphael Isemann        self.assertEquals(int(derivedValue.GetValue(), 0), 30)
207