208 lines
7.4 KiB
Python
208 lines
7.4 KiB
Python
"""
|
|
Use lldb Python API to test dynamic values in ObjC
|
|
"""
|
|
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
class ObjCDynamicValueTestCase(TestBase):
|
|
def setUp(self):
|
|
# Call super's setUp().
|
|
TestBase.setUp(self)
|
|
|
|
# Find the line number to break for main.c.
|
|
|
|
self.source_name = "dynamic-value.m"
|
|
self.set_property_line = line_number(
|
|
self.source_name,
|
|
"// This is the line in setProperty, make sure we step to here.",
|
|
)
|
|
self.handle_SourceBase = line_number(
|
|
self.source_name, "// Break here to check dynamic values."
|
|
)
|
|
self.main_before_setProperty_line = line_number(
|
|
self.source_name, "// Break here to see if we can step into real method."
|
|
)
|
|
|
|
@add_test_categories(["pyapi"])
|
|
@expectedFailureDarwin("llvm.org/pr20271 rdar://18684107")
|
|
def test_get_objc_dynamic_vals(self):
|
|
"""Test fetching ObjC dynamic values."""
|
|
if self.getArchitecture() == "i386":
|
|
# rdar://problem/9946499
|
|
self.skipTest("Dynamic types for ObjC V1 runtime not implemented")
|
|
|
|
self.build()
|
|
exe = self.getBuildArtifact("a.out")
|
|
|
|
# Create a target from the debugger.
|
|
|
|
target = self.dbg.CreateTarget(exe)
|
|
self.assertTrue(target, VALID_TARGET)
|
|
|
|
# Set up our breakpoints:
|
|
|
|
handle_SourceBase_bkpt = target.BreakpointCreateByLocation(
|
|
self.source_name, self.handle_SourceBase
|
|
)
|
|
self.assertTrue(
|
|
handle_SourceBase_bkpt and handle_SourceBase_bkpt.GetNumLocations() == 1,
|
|
VALID_BREAKPOINT,
|
|
)
|
|
|
|
main_before_setProperty_bkpt = target.BreakpointCreateByLocation(
|
|
self.source_name, self.main_before_setProperty_line
|
|
)
|
|
self.assertTrue(
|
|
main_before_setProperty_bkpt
|
|
and main_before_setProperty_bkpt.GetNumLocations() == 1,
|
|
VALID_BREAKPOINT,
|
|
)
|
|
|
|
# Now launch the process, and do not stop at the entry point.
|
|
process = target.LaunchSimple(None, None, self.get_process_working_directory())
|
|
|
|
self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
|
|
|
|
threads = lldbutil.get_threads_stopped_at_breakpoint(
|
|
process, main_before_setProperty_bkpt
|
|
)
|
|
self.assertEquals(len(threads), 1)
|
|
thread = threads[0]
|
|
|
|
#
|
|
# At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
|
|
# make sure we can get that properly:
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
myObserver = frame.FindVariable("myObserver", lldb.eDynamicCanRunTarget)
|
|
self.assertTrue(myObserver)
|
|
myObserver_source = myObserver.GetChildMemberWithName(
|
|
"_source", lldb.eDynamicCanRunTarget
|
|
)
|
|
self.examine_SourceDerived_ptr(myObserver_source)
|
|
|
|
#
|
|
# Make sure a static value can be correctly turned into a dynamic
|
|
# value.
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
myObserver_static = frame.FindVariable("myObserver", lldb.eNoDynamicValues)
|
|
self.assertTrue(myObserver_static)
|
|
myObserver = myObserver_static.GetDynamicValue(lldb.eDynamicCanRunTarget)
|
|
myObserver_source = myObserver.GetChildMemberWithName(
|
|
"_source", lldb.eDynamicCanRunTarget
|
|
)
|
|
self.examine_SourceDerived_ptr(myObserver_source)
|
|
|
|
# The "frame var" code uses another path to get into children, so let's
|
|
# make sure that works as well:
|
|
|
|
result = lldb.SBCommandReturnObject()
|
|
|
|
self.expect(
|
|
"frame var -d run-target myObserver->_source",
|
|
"frame var finds its way into a child member",
|
|
patterns=["\(SourceDerived \*\)"],
|
|
)
|
|
|
|
# check that our ObjC GetISA() does a good job at hiding KVO swizzled
|
|
# classes
|
|
|
|
self.expect(
|
|
"frame var -d run-target myObserver->_source -T",
|
|
"the KVO-ed class is hidden",
|
|
substrs=["SourceDerived"],
|
|
)
|
|
|
|
self.expect(
|
|
"frame var -d run-target myObserver->_source -T",
|
|
"the KVO-ed class is hidden",
|
|
matching=False,
|
|
substrs=["NSKVONotify"],
|
|
)
|
|
|
|
# This test is not entirely related to the main thrust of this test case, but since we're here,
|
|
# try stepping into setProperty, and make sure we get into the version
|
|
# in Source:
|
|
|
|
thread.StepInto()
|
|
|
|
threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
|
|
self.assertEquals(len(threads), 1)
|
|
line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()
|
|
|
|
self.assertEqual(line_entry.GetLine(), self.set_property_line)
|
|
self.assertEqual(line_entry.GetFileSpec().GetFilename(), self.source_name)
|
|
|
|
# Okay, back to the main business. Continue to the handle_SourceBase
|
|
# and make sure we get the correct dynamic value.
|
|
|
|
threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt)
|
|
self.assertEquals(len(threads), 1)
|
|
thread = threads[0]
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
|
|
# Get "object" using FindVariable:
|
|
|
|
noDynamic = lldb.eNoDynamicValues
|
|
useDynamic = lldb.eDynamicCanRunTarget
|
|
|
|
object_static = frame.FindVariable("object", noDynamic)
|
|
object_dynamic = frame.FindVariable("object", useDynamic)
|
|
|
|
# Delete this object to make sure that this doesn't cause havoc with
|
|
# the dynamic object that depends on it.
|
|
del object_static
|
|
|
|
self.examine_SourceDerived_ptr(object_dynamic)
|
|
|
|
# Get "this" using FindValue, make sure that works too:
|
|
object_static = frame.FindValue(
|
|
"object", lldb.eValueTypeVariableArgument, noDynamic
|
|
)
|
|
object_dynamic = frame.FindValue(
|
|
"object", lldb.eValueTypeVariableArgument, useDynamic
|
|
)
|
|
del object_static
|
|
self.examine_SourceDerived_ptr(object_dynamic)
|
|
|
|
# Get "this" using the EvaluateExpression:
|
|
object_static = frame.EvaluateExpression("object", noDynamic)
|
|
object_dynamic = frame.EvaluateExpression("object", useDynamic)
|
|
del object_static
|
|
self.examine_SourceDerived_ptr(object_dynamic)
|
|
|
|
# Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
|
|
# This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
|
|
# its isa pointer points to SourceBase not NSKVOSourceBase or
|
|
# whatever...
|
|
|
|
threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt)
|
|
self.assertEquals(len(threads), 1)
|
|
thread = threads[0]
|
|
|
|
frame = thread.GetFrameAtIndex(0)
|
|
|
|
# Get "object" using FindVariable:
|
|
|
|
object_static = frame.FindVariable("object", noDynamic)
|
|
object_dynamic = frame.FindVariable("object", useDynamic)
|
|
|
|
# Delete this object to make sure that this doesn't cause havoc with
|
|
# the dynamic object that depends on it.
|
|
del object_static
|
|
|
|
self.examine_SourceDerived_ptr(object_dynamic)
|
|
|
|
def examine_SourceDerived_ptr(self, object):
|
|
self.assertTrue(object)
|
|
self.assertNotEqual(object.GetTypeName().find("SourceDerived"), -1)
|
|
derivedValue = object.GetChildMemberWithName("_derivedValue")
|
|
self.assertTrue(derivedValue)
|
|
self.assertEquals(int(derivedValue.GetValue(), 0), 30)
|