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