blob: e9df6be81cdbdbebb209ab28472c0b660c143979 [file] [log] [blame]
"""
Use lldb Python API to test dynamic values in ObjC
"""
from __future__ import print_function
import os
import time
import re
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class ObjCDynamicValueTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
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.')
@skipUnlessDarwin
@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.assertTrue(process.GetState() == lldb.eStateStopped,
PROCESS_STOPPED)
threads = lldbutil.get_threads_stopped_at_breakpoint(
process, main_before_setProperty_bkpt)
self.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(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.assertTrue(object.GetTypeName().find('SourceDerived') != -1)
derivedValue = object.GetChildMemberWithName('_derivedValue')
self.assertTrue(derivedValue)
self.assertTrue(int(derivedValue.GetValue(), 0) == 30)