xref: /llvm-project/lldb/test/API/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py (revision 80fcecb13c388ff087a27a4b0e7ca3dd8c98eaa4)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtUse lldb Python API to test dynamic values in ObjC
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht
699451b44SJordan Rupprechtimport lldb
799451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
899451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
999451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1099451b44SJordan Rupprecht
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprechtclass ObjCDynamicValueTestCase(TestBase):
1399451b44SJordan Rupprecht    def setUp(self):
1499451b44SJordan Rupprecht        # Call super's setUp().
1599451b44SJordan Rupprecht        TestBase.setUp(self)
1699451b44SJordan Rupprecht
1799451b44SJordan Rupprecht        # Find the line number to break for main.c.
1899451b44SJordan Rupprecht
192238dcc3SJonas Devlieghere        self.source_name = "dynamic-value.m"
2099451b44SJordan Rupprecht        self.set_property_line = line_number(
2199451b44SJordan Rupprecht            self.source_name,
222238dcc3SJonas Devlieghere            "// This is the line in setProperty, make sure we step to here.",
232238dcc3SJonas Devlieghere        )
2499451b44SJordan Rupprecht        self.handle_SourceBase = line_number(
252238dcc3SJonas Devlieghere            self.source_name, "// Break here to check dynamic values."
262238dcc3SJonas Devlieghere        )
2799451b44SJordan Rupprecht        self.main_before_setProperty_line = line_number(
282238dcc3SJonas Devlieghere            self.source_name, "// Break here to see if we can step into real method."
292238dcc3SJonas Devlieghere        )
3099451b44SJordan Rupprecht
312238dcc3SJonas Devlieghere    @add_test_categories(["pyapi"])
3299451b44SJordan Rupprecht    @expectedFailureDarwin("llvm.org/pr20271 rdar://18684107")
3399451b44SJordan Rupprecht    def test_get_objc_dynamic_vals(self):
3499451b44SJordan Rupprecht        """Test fetching ObjC dynamic values."""
352238dcc3SJonas Devlieghere        if self.getArchitecture() == "i386":
3699451b44SJordan Rupprecht            # rdar://problem/9946499
3799451b44SJordan Rupprecht            self.skipTest("Dynamic types for ObjC V1 runtime not implemented")
3899451b44SJordan Rupprecht
3999451b44SJordan Rupprecht        self.build()
4099451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
4199451b44SJordan Rupprecht
4299451b44SJordan Rupprecht        # Create a target from the debugger.
4399451b44SJordan Rupprecht
4499451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
4599451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
4699451b44SJordan Rupprecht
4799451b44SJordan Rupprecht        # Set up our breakpoints:
4899451b44SJordan Rupprecht
4999451b44SJordan Rupprecht        handle_SourceBase_bkpt = target.BreakpointCreateByLocation(
502238dcc3SJonas Devlieghere            self.source_name, self.handle_SourceBase
512238dcc3SJonas Devlieghere        )
522238dcc3SJonas Devlieghere        self.assertTrue(
532238dcc3SJonas Devlieghere            handle_SourceBase_bkpt and handle_SourceBase_bkpt.GetNumLocations() == 1,
542238dcc3SJonas Devlieghere            VALID_BREAKPOINT,
552238dcc3SJonas Devlieghere        )
5699451b44SJordan Rupprecht
5799451b44SJordan Rupprecht        main_before_setProperty_bkpt = target.BreakpointCreateByLocation(
582238dcc3SJonas Devlieghere            self.source_name, self.main_before_setProperty_line
592238dcc3SJonas Devlieghere        )
602238dcc3SJonas Devlieghere        self.assertTrue(
612238dcc3SJonas Devlieghere            main_before_setProperty_bkpt
622238dcc3SJonas Devlieghere            and main_before_setProperty_bkpt.GetNumLocations() == 1,
632238dcc3SJonas Devlieghere            VALID_BREAKPOINT,
642238dcc3SJonas Devlieghere        )
6599451b44SJordan Rupprecht
6699451b44SJordan Rupprecht        # Now launch the process, and do not stop at the entry point.
672238dcc3SJonas Devlieghere        process = target.LaunchSimple(None, None, self.get_process_working_directory())
6899451b44SJordan Rupprecht
692238dcc3SJonas Devlieghere        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
7099451b44SJordan Rupprecht
7199451b44SJordan Rupprecht        threads = lldbutil.get_threads_stopped_at_breakpoint(
722238dcc3SJonas Devlieghere            process, main_before_setProperty_bkpt
732238dcc3SJonas Devlieghere        )
74*80fcecb1SJonas Devlieghere        self.assertEqual(len(threads), 1)
7599451b44SJordan Rupprecht        thread = threads[0]
7699451b44SJordan Rupprecht
7799451b44SJordan Rupprecht        #
7899451b44SJordan Rupprecht        #  At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
7999451b44SJordan Rupprecht        #  make sure we can get that properly:
8099451b44SJordan Rupprecht
8199451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
822238dcc3SJonas Devlieghere        myObserver = frame.FindVariable("myObserver", lldb.eDynamicCanRunTarget)
8399451b44SJordan Rupprecht        self.assertTrue(myObserver)
8499451b44SJordan Rupprecht        myObserver_source = myObserver.GetChildMemberWithName(
852238dcc3SJonas Devlieghere            "_source", lldb.eDynamicCanRunTarget
862238dcc3SJonas Devlieghere        )
8799451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(myObserver_source)
8899451b44SJordan Rupprecht
8999451b44SJordan Rupprecht        #
9099451b44SJordan Rupprecht        # Make sure a static value can be correctly turned into a dynamic
9199451b44SJordan Rupprecht        # value.
9299451b44SJordan Rupprecht
9399451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
942238dcc3SJonas Devlieghere        myObserver_static = frame.FindVariable("myObserver", lldb.eNoDynamicValues)
9599451b44SJordan Rupprecht        self.assertTrue(myObserver_static)
962238dcc3SJonas Devlieghere        myObserver = myObserver_static.GetDynamicValue(lldb.eDynamicCanRunTarget)
9799451b44SJordan Rupprecht        myObserver_source = myObserver.GetChildMemberWithName(
982238dcc3SJonas Devlieghere            "_source", lldb.eDynamicCanRunTarget
992238dcc3SJonas Devlieghere        )
10099451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(myObserver_source)
10199451b44SJordan Rupprecht
10299451b44SJordan Rupprecht        # The "frame var" code uses another path to get into children, so let's
10399451b44SJordan Rupprecht        # make sure that works as well:
10499451b44SJordan Rupprecht
10599451b44SJordan Rupprecht        result = lldb.SBCommandReturnObject()
10699451b44SJordan Rupprecht
10799451b44SJordan Rupprecht        self.expect(
1082238dcc3SJonas Devlieghere            "frame var -d run-target myObserver->_source",
1092238dcc3SJonas Devlieghere            "frame var finds its way into a child member",
1102238dcc3SJonas Devlieghere            patterns=["\(SourceDerived \*\)"],
1112238dcc3SJonas Devlieghere        )
11299451b44SJordan Rupprecht
11399451b44SJordan Rupprecht        # check that our ObjC GetISA() does a good job at hiding KVO swizzled
11499451b44SJordan Rupprecht        # classes
11599451b44SJordan Rupprecht
11699451b44SJordan Rupprecht        self.expect(
1172238dcc3SJonas Devlieghere            "frame var -d run-target myObserver->_source -T",
1182238dcc3SJonas Devlieghere            "the KVO-ed class is hidden",
1192238dcc3SJonas Devlieghere            substrs=["SourceDerived"],
1202238dcc3SJonas Devlieghere        )
12199451b44SJordan Rupprecht
12299451b44SJordan Rupprecht        self.expect(
1232238dcc3SJonas Devlieghere            "frame var -d run-target myObserver->_source -T",
1242238dcc3SJonas Devlieghere            "the KVO-ed class is hidden",
12599451b44SJordan Rupprecht            matching=False,
1262238dcc3SJonas Devlieghere            substrs=["NSKVONotify"],
1272238dcc3SJonas Devlieghere        )
12899451b44SJordan Rupprecht
12999451b44SJordan Rupprecht        # This test is not entirely related to the main thrust of this test case, but since we're here,
13099451b44SJordan Rupprecht        # try stepping into setProperty, and make sure we get into the version
13199451b44SJordan Rupprecht        # in Source:
13299451b44SJordan Rupprecht
13399451b44SJordan Rupprecht        thread.StepInto()
13499451b44SJordan Rupprecht
1352238dcc3SJonas Devlieghere        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
136*80fcecb1SJonas Devlieghere        self.assertEqual(len(threads), 1)
13799451b44SJordan Rupprecht        line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()
13899451b44SJordan Rupprecht
13999451b44SJordan Rupprecht        self.assertEqual(line_entry.GetLine(), self.set_property_line)
1402238dcc3SJonas Devlieghere        self.assertEqual(line_entry.GetFileSpec().GetFilename(), self.source_name)
14199451b44SJordan Rupprecht
14299451b44SJordan Rupprecht        # Okay, back to the main business.  Continue to the handle_SourceBase
14399451b44SJordan Rupprecht        # and make sure we get the correct dynamic value.
14499451b44SJordan Rupprecht
1452238dcc3SJonas Devlieghere        threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt)
146*80fcecb1SJonas Devlieghere        self.assertEqual(len(threads), 1)
14799451b44SJordan Rupprecht        thread = threads[0]
14899451b44SJordan Rupprecht
14999451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
15099451b44SJordan Rupprecht
15199451b44SJordan Rupprecht        # Get "object" using FindVariable:
15299451b44SJordan Rupprecht
15399451b44SJordan Rupprecht        noDynamic = lldb.eNoDynamicValues
15499451b44SJordan Rupprecht        useDynamic = lldb.eDynamicCanRunTarget
15599451b44SJordan Rupprecht
1562238dcc3SJonas Devlieghere        object_static = frame.FindVariable("object", noDynamic)
1572238dcc3SJonas Devlieghere        object_dynamic = frame.FindVariable("object", useDynamic)
15899451b44SJordan Rupprecht
15999451b44SJordan Rupprecht        # Delete this object to make sure that this doesn't cause havoc with
16099451b44SJordan Rupprecht        # the dynamic object that depends on it.
1612238dcc3SJonas Devlieghere        del object_static
16299451b44SJordan Rupprecht
16399451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
16499451b44SJordan Rupprecht
16599451b44SJordan Rupprecht        # Get "this" using FindValue, make sure that works too:
16699451b44SJordan Rupprecht        object_static = frame.FindValue(
1672238dcc3SJonas Devlieghere            "object", lldb.eValueTypeVariableArgument, noDynamic
1682238dcc3SJonas Devlieghere        )
16999451b44SJordan Rupprecht        object_dynamic = frame.FindValue(
1702238dcc3SJonas Devlieghere            "object", lldb.eValueTypeVariableArgument, useDynamic
1712238dcc3SJonas Devlieghere        )
1722238dcc3SJonas Devlieghere        del object_static
17399451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
17499451b44SJordan Rupprecht
17599451b44SJordan Rupprecht        # Get "this" using the EvaluateExpression:
1762238dcc3SJonas Devlieghere        object_static = frame.EvaluateExpression("object", noDynamic)
1772238dcc3SJonas Devlieghere        object_dynamic = frame.EvaluateExpression("object", useDynamic)
1782238dcc3SJonas Devlieghere        del object_static
17999451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
18099451b44SJordan Rupprecht
18199451b44SJordan Rupprecht        # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
18299451b44SJordan Rupprecht        # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
18399451b44SJordan Rupprecht        # its isa pointer points to SourceBase not NSKVOSourceBase or
18499451b44SJordan Rupprecht        # whatever...
18599451b44SJordan Rupprecht
1862238dcc3SJonas Devlieghere        threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt)
187*80fcecb1SJonas Devlieghere        self.assertEqual(len(threads), 1)
18899451b44SJordan Rupprecht        thread = threads[0]
18999451b44SJordan Rupprecht
19099451b44SJordan Rupprecht        frame = thread.GetFrameAtIndex(0)
19199451b44SJordan Rupprecht
19299451b44SJordan Rupprecht        # Get "object" using FindVariable:
19399451b44SJordan Rupprecht
1942238dcc3SJonas Devlieghere        object_static = frame.FindVariable("object", noDynamic)
1952238dcc3SJonas Devlieghere        object_dynamic = frame.FindVariable("object", useDynamic)
19699451b44SJordan Rupprecht
19799451b44SJordan Rupprecht        # Delete this object to make sure that this doesn't cause havoc with
19899451b44SJordan Rupprecht        # the dynamic object that depends on it.
1992238dcc3SJonas Devlieghere        del object_static
20099451b44SJordan Rupprecht
20199451b44SJordan Rupprecht        self.examine_SourceDerived_ptr(object_dynamic)
20299451b44SJordan Rupprecht
20399451b44SJordan Rupprecht    def examine_SourceDerived_ptr(self, object):
20499451b44SJordan Rupprecht        self.assertTrue(object)
2052238dcc3SJonas Devlieghere        self.assertNotEqual(object.GetTypeName().find("SourceDerived"), -1)
2062238dcc3SJonas Devlieghere        derivedValue = object.GetChildMemberWithName("_derivedValue")
20799451b44SJordan Rupprecht        self.assertTrue(derivedValue)
208*80fcecb1SJonas Devlieghere        self.assertEqual(int(derivedValue.GetValue(), 0), 30)
209