diff options
author | Johnny Chen <johnny.chen@apple.com> | 2011-06-25 20:16:38 +0000 |
---|---|---|
committer | Johnny Chen <johnny.chen@apple.com> | 2011-06-25 20:16:38 +0000 |
commit | 33e89de95a6be2bd6482fd4aeb62e177d1a70956 (patch) | |
tree | 61dafeb3a9b1a48e243a058bc74276a25a0a28cc /lldb/test/lang/objc | |
parent | 53af50ac56c3e74edcba4074a27b3f27865a6edf (diff) | |
download | bcm5719-llvm-33e89de95a6be2bd6482fd4aeb62e177d1a70956.tar.gz bcm5719-llvm-33e89de95a6be2bd6482fd4aeb62e177d1a70956.zip |
Move objc-related test directories to now reside under lang/objc.
llvm-svn: 133877
Diffstat (limited to 'lldb/test/lang/objc')
-rw-r--r-- | lldb/test/lang/objc/objc-dynamic-value/Makefile | 6 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py | 165 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-dynamic-value/dynamic-value.m | 147 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-ivar-offsets/Makefile | 6 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-ivar-offsets/TestObjCIvarOffsets.py | 75 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-ivar-offsets/main.m | 13 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.h | 23 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.m | 19 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-optimized/Makefile | 8 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-optimized/TestObjcOptimized.py | 63 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-optimized/main.m | 44 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-stepping/Makefile | 6 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-stepping/TestObjCStepping.py | 165 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-stepping/stepping-tests.m | 133 |
14 files changed, 873 insertions, 0 deletions
diff --git a/lldb/test/lang/objc/objc-dynamic-value/Makefile b/lldb/test/lang/objc/objc-dynamic-value/Makefile new file mode 100644 index 00000000000..a981f4b9035 --- /dev/null +++ b/lldb/test/lang/objc/objc-dynamic-value/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +OBJC_SOURCES := dynamic-value.m +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py b/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py new file mode 100644 index 00000000000..1a5547bccce --- /dev/null +++ b/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py @@ -0,0 +1,165 @@ +""" +Use lldb Python API to test dynamic values in ObjC +""" + +import os, time +import re +import unittest2 +import lldb, lldbutil +from lldbtest import * + +class ObjCDynamicValueTestCase(TestBase): + + mydir = os.path.join("lang", "objc", "objc-dynamic-value") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @python_api_test + def test_get_dynamic_objc_vals_with_dsym(self): + """Test fetching ObjC dynamic values.""" + self.buildDsym() + self.do_get_dynamic_vals() + + @python_api_test + def test_get_objc_dynamic_vals_with_dwarf(self): + """Test fetching ObjC dynamic values.""" + self.buildDwarf() + self.do_get_dynamic_vals() + + 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.') + + 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) + + def do_get_dynamic_vals(self): + """Make sure we get dynamic values correctly both for compiled in classes and dynamic ones""" + exe = os.path.join(os.getcwd(), "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, os.getcwd()) + + 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) + + # 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 \*\)']) + + # 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.assertTrue (line_entry.GetLine() == self.set_property_line) + self.assertTrue (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: + # These tests fail for now because EvaluateExpression doesn't currently support dynamic typing... + #object_static = frame.EvaluateExpression ('object', noDynamic) + #object_dynamic = frame.EvaluateExpression ('object', useDynamic) + #self.examine_value_object_of_object_ptr (object_static, object_dynamic, myB_loc) + + # 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) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/lang/objc/objc-dynamic-value/dynamic-value.m b/lldb/test/lang/objc/objc-dynamic-value/dynamic-value.m new file mode 100644 index 00000000000..60a506efd8e --- /dev/null +++ b/lldb/test/lang/objc/objc-dynamic-value/dynamic-value.m @@ -0,0 +1,147 @@ +#import <Foundation/Foundation.h> + +// SourceBase will be the base class of Source. We'll pass a Source object into a +// function as a SourceBase, and then see if the dynamic typing can get us through the KVO +// goo and all the way back to Source. + +@interface SourceBase: NSObject +{ + uint32_t _value; +} +- (SourceBase *) init; +- (uint32_t) getValue; +@end + +@implementation SourceBase +- (SourceBase *) init +{ + [super init]; + _value = 10; + return self; +} +- (uint32_t) getValue +{ + return _value; +} +@end + +// Source is a class that will be observed by the Observer class below. +// When Observer sets itself up to observe this property (in initWithASource) +// the KVO system will overwrite the "isa" pointer of the object with the "kvo'ed" +// one. + +@interface Source : SourceBase +{ + int _property; +} +- (Source *) init; +- (void) setProperty: (int) newValue; +@end + +@implementation Source +- (Source *) init +{ + [super init]; + _property = 20; + return self; +} +- (void) setProperty: (int) newValue +{ + _property = newValue; // This is the line in setProperty, make sure we step to here. +} +@end + +@interface SourceDerived : Source +{ + int _derivedValue; +} +- (SourceDerived *) init; +- (uint32_t) getValue; +@end + +@implementation SourceDerived +- (SourceDerived *) init +{ + [super init]; + _derivedValue = 30; + return self; +} +- (uint32_t) getValue +{ + return _derivedValue; +} +@end + +// Observer is the object that will watch Source and cause KVO to swizzle it... + +@interface Observer : NSObject +{ + Source *_source; +} ++ (Observer *) observerWithSource: (Source *) source; +- (Observer *) initWithASource: (Source *) source; +- (void) observeValueForKeyPath: (NSString *) path + ofObject: (id) object + change: (NSDictionary *) change + context: (void *) context; +@end + +@implementation Observer + ++ (Observer *) observerWithSource: (Source *) inSource; +{ + Observer *retval; + + retval = [[Observer alloc] initWithASource: inSource]; + return retval; +} + +- (Observer *) initWithASource: (Source *) source +{ + [super init]; + _source = source; + [_source addObserver: self + forKeyPath: @"property" + options: (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) + context: NULL]; + return self; +} + +- (void) observeValueForKeyPath: (NSString *) path + ofObject: (id) object + change: (NSDictionary *) change + context: (void *) context +{ + printf ("Observer function called.\n"); + return; +} +@end + +uint32_t +handle_SourceBase (SourceBase *object) +{ + return [object getValue]; // Break here to check dynamic values. +} + +int main () +{ + SourceDerived *mySource; + Observer *myObserver; + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + mySource = [[SourceDerived alloc] init]; + myObserver = [Observer observerWithSource: mySource]; + + [mySource setProperty: 5]; // Break here to see if we can step into real method. + + uint32_t return_value = handle_SourceBase (mySource); + + SourceDerived *unwatchedSource = [[SourceDerived alloc] init]; + + return_value = handle_SourceBase (unwatchedSource); + + [pool release]; + return 0; + +} diff --git a/lldb/test/lang/objc/objc-ivar-offsets/Makefile b/lldb/test/lang/objc/objc-ivar-offsets/Makefile new file mode 100644 index 00000000000..fdd3b5ebfa9 --- /dev/null +++ b/lldb/test/lang/objc/objc-ivar-offsets/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +OBJC_SOURCES := objc-ivar-offsets.m main.m +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/objc/objc-ivar-offsets/TestObjCIvarOffsets.py b/lldb/test/lang/objc/objc-ivar-offsets/TestObjCIvarOffsets.py new file mode 100644 index 00000000000..066e9e4f899 --- /dev/null +++ b/lldb/test/lang/objc/objc-ivar-offsets/TestObjCIvarOffsets.py @@ -0,0 +1,75 @@ +"""Test printing ObjC objects that use unbacked properties - so that the static ivar offsets are incorrect.""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class TestObjCIvarOffsets(TestBase): + + mydir = os.path.join("lang", "objc", "objc-ivar-offsets") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @python_api_test + def test_with_dsym_and_python_api(self): + """Test printing ObjC objects that use unbacked properties""" + self.buildDsym() + self.objc_ivar_offsets() + + @python_api_test + def test_with_dwarf_and_python_api(self): + """Test printing ObjC objects that use unbacked properties""" + self.buildDwarf() + self.objc_ivar_offsets() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line numbers to break inside main(). + self.main_source = "main.m" + self.stop_line = line_number(self.main_source, '// Set breakpoint here.') + + def objc_ivar_offsets(self): + """Use Python APIs to test stepping into ObjC methods.""" + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + breakpoint = target.BreakpointCreateByLocation(self.main_source, self.stop_line) + self.assertTrue(breakpoint, VALID_BREAKPOINT) + + process = target.LaunchSimple (None, None, os.getcwd()) + self.assertTrue (process, "Created a process.") + self.assertTrue (process.GetState() == lldb.eStateStopped, "Stopped it too.") + + thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) + self.assertTrue (len(thread_list) == 1) + thread = thread_list[0] + + frame = thread.GetFrameAtIndex(0) + self.assertTrue (frame, "frame 0 is valid") + + mine = thread.GetFrameAtIndex(0).FindVariable("mine") + self.assertTrue(mine, "Found local variable mine.") + + # Test the value object value for BaseClass->_backed_int + + mine_backed_int = mine.GetChildMemberWithName ("_backed_int") + self.assertTrue(mine_backed_int, "Found mine->backed_int local variable.") + backed_value = int (mine_backed_int.GetValue (frame), 0) + self.assertTrue (backed_value == 1111) + + # Test the value object value for DerivedClass->_derived_backed_int + + mine_derived_backed_int = mine.GetChildMemberWithName ("_derived_backed_int") + self.assertTrue(mine_derived_backed_int, "Found mine->derived_backed_int local variable.") + derived_backed_value = int (mine_derived_backed_int.GetValue (frame), 0) + self.assertTrue (derived_backed_value == 3333) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/lang/objc/objc-ivar-offsets/main.m b/lldb/test/lang/objc/objc-ivar-offsets/main.m new file mode 100644 index 00000000000..206255f6a21 --- /dev/null +++ b/lldb/test/lang/objc/objc-ivar-offsets/main.m @@ -0,0 +1,13 @@ +#include "objc-ivar-offsets.h" + +int +main () +{ + DerivedClass *mine = [[DerivedClass alloc] init]; + mine.backed_int = 1111; + mine.unbacked_int = 2222; + mine.derived_backed_int = 3333; + mine.derived_unbacked_int = 4444; + + return 0; // Set breakpoint here. +} diff --git a/lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.h b/lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.h new file mode 100644 index 00000000000..9dff95e0839 --- /dev/null +++ b/lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.h @@ -0,0 +1,23 @@ +#import <Foundation/Foundation.h> + +@interface BaseClass : NSObject +{ + int _backed_int; +#if !__OBJC2__ + int _unbacked_int; +#endif +} +@property int backed_int; +@property int unbacked_int; +@end + +@interface DerivedClass : BaseClass +{ + int _derived_backed_int; +#if !__OBJC2__ + int _unbacked_int; +#endif +} +@property int derived_backed_int; +@property int derived_unbacked_int; +@end diff --git a/lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.m b/lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.m new file mode 100644 index 00000000000..db87adea3d1 --- /dev/null +++ b/lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.m @@ -0,0 +1,19 @@ +#import "objc-ivar-offsets.h" + +@implementation BaseClass +@synthesize backed_int = _backed_int; +#if __OBJC2__ +@synthesize unbacked_int; +#else +@synthesize unbacked_int = _unbacked_int; +#endif +@end + +@implementation DerivedClass +@synthesize derived_backed_int = _derived_backed_int; +#if __OBJC2__ +@synthesize derived_unbacked_int; +#else +@synthesize derived_unbacked_int = _derived_unbacked_int; +#endif +@end diff --git a/lldb/test/lang/objc/objc-optimized/Makefile b/lldb/test/lang/objc/objc-optimized/Makefile new file mode 100644 index 00000000000..a8cf6b98194 --- /dev/null +++ b/lldb/test/lang/objc/objc-optimized/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../../make + +OBJC_SOURCES := main.m + +CFLAGS ?= -arch $(ARCH) -gdwarf-2 -O2 +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/objc/objc-optimized/TestObjcOptimized.py b/lldb/test/lang/objc/objc-optimized/TestObjcOptimized.py new file mode 100644 index 00000000000..bbdf5854849 --- /dev/null +++ b/lldb/test/lang/objc/objc-optimized/TestObjcOptimized.py @@ -0,0 +1,63 @@ +""" +Test that objective-c expression parser continues to work for optimized build. + +http://llvm.org/viewvc/llvm-project?rev=126973&view=rev +Fixed a bug in the expression parser where the 'this' +or 'self' variable was not properly read if the compiler +optimized it into a register. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * + +# rdar://problem/9087739 +# test failure: objc_optimized does not work for "-C clang -A i386" +@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") +class ObjcOptimizedTestCase(TestBase): + + mydir = os.path.join("lang", "objc", "objc-optimized") + myclass = "MyClass" + mymethod = "description" + method_spec = "-[%s %s]" % (myclass, mymethod) + + def test_break_with_dsym(self): + """Test 'expr member' continues to work for optimized build.""" + self.buildDsym() + self.objc_optimized() + + def test_break_with_dwarf(self): + """Test 'expr member' continues to work for optimized build.""" + self.buildDwarf() + self.objc_optimized() + + def objc_optimized(self): + """Test 'expr member' continues to work for optimized build.""" + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + self.expect("breakpoint set -n '%s'" % self.method_spec, + BREAKPOINT_CREATED, + startstr = "Breakpoint created: 1: name = '%s', locations = 1" % self.method_spec) + + self.runCmd("run", RUN_SUCCEEDED) + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs = ["stop reason = breakpoint"], + patterns = ["frame.*0:.*%s %s" % (self.myclass, self.mymethod)]) + + self.expect('expression member', + startstr = "(int) $0 = 5") + + self.expect('expression self', + startstr = "(%s *) $1 = " % self.myclass) + + self.expect('expression self->non_member', error=True, + substrs = ["does not have a member named 'non_member'"]) + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/lang/objc/objc-optimized/main.m b/lldb/test/lang/objc/objc-optimized/main.m new file mode 100644 index 00000000000..df88eea0f86 --- /dev/null +++ b/lldb/test/lang/objc/objc-optimized/main.m @@ -0,0 +1,44 @@ +#import <Foundation/Foundation.h> + +@interface MyClass : NSObject { + int member; +} + +- (id)initWithMember:(int)_member; +- (NSString*)description; +@end + +@implementation MyClass + +- (id)initWithMember:(int)_member +{ + if (self = [super init]) + { + member = _member; + } + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + +// Set a breakpoint on '-[MyClass description]' and test expressions: expr member +- (NSString *)description +{ + return [NSString stringWithFormat:@"%d", member]; +} +@end + +int main (int argc, char const *argv[]) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + MyClass *my_object = [[MyClass alloc] initWithMember:5]; + + NSLog(@"MyObject %@", [my_object description]); + + [pool release]; + return 0; +} diff --git a/lldb/test/lang/objc/objc-stepping/Makefile b/lldb/test/lang/objc/objc-stepping/Makefile new file mode 100644 index 00000000000..b097fe65fce --- /dev/null +++ b/lldb/test/lang/objc/objc-stepping/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +OBJC_SOURCES := stepping-tests.m +LDFLAGS = $(CFLAGS) -lobjc -framework Foundation + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/objc/objc-stepping/TestObjCStepping.py b/lldb/test/lang/objc/objc-stepping/TestObjCStepping.py new file mode 100644 index 00000000000..9db97908e71 --- /dev/null +++ b/lldb/test/lang/objc/objc-stepping/TestObjCStepping.py @@ -0,0 +1,165 @@ +"""Test stepping through ObjC method dispatch in various forms.""" + +import os, time +import unittest2 +import lldb +from lldbtest import * + +class TestObjCStepping(TestBase): + + mydir = os.path.join("lang", "objc", "objc-stepping") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @python_api_test + def test_with_dsym_and_python_api(self): + """Test stepping through ObjC method dispatch in various forms.""" + self.buildDsym() + self.objc_stepping() + + @python_api_test + def test_with_dwarf_and_python_api(self): + """Test stepping through ObjC method dispatch in various forms.""" + self.buildDwarf() + self.objc_stepping() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line numbers to break inside main(). + self.main_source = "stepping-tests.m" + self.line1 = line_number(self.main_source, '// Set first breakpoint here.') + self.line2 = line_number(self.main_source, '// Set second breakpoint here.') + self.line3 = line_number(self.main_source, '// Set third breakpoint here.') + self.line4 = line_number(self.main_source, '// Set fourth breakpoint here.') + self.line5 = line_number(self.main_source, '// Set fifth breakpoint here.') + self.source_randomMethod_line = line_number (self.main_source, '// Source randomMethod start line.') + self.sourceBase_randomMethod_line = line_number (self.main_source, '// SourceBase randomMethod start line.') + self.source_returnsStruct_start_line = line_number (self.main_source, '// Source returnsStruct start line.') + self.source_returnsStruct_call_line = line_number (self.main_source, '// Source returnsStruct call line.') + self.sourceBase_returnsStruct_start_line = line_number (self.main_source, '// SourceBase returnsStruct start line.') + + def objc_stepping(self): + """Use Python APIs to test stepping into ObjC methods.""" + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + break1 = target.BreakpointCreateByLocation(self.main_source, self.line1) + self.assertTrue(break1, VALID_BREAKPOINT) + + break2 = target.BreakpointCreateByLocation(self.main_source, self.line2) + self.assertTrue(break2, VALID_BREAKPOINT) + + break3 = target.BreakpointCreateByLocation(self.main_source, self.line3) + self.assertTrue(break3, VALID_BREAKPOINT) + + break4 = target.BreakpointCreateByLocation(self.main_source, self.line4) + self.assertTrue(break4, VALID_BREAKPOINT) + + break5 = target.BreakpointCreateByLocation(self.main_source, self.line5) + self.assertTrue(break5, VALID_BREAKPOINT) + + break_returnStruct_call_super = target.BreakpointCreateByLocation(self.main_source, self.source_returnsStruct_call_line) + self.assertTrue(break_returnStruct_call_super, VALID_BREAKPOINT) + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple (None, None, os.getcwd()) + + self.assertTrue(process, PROCESS_IS_VALID) + + # The stop reason of the thread should be breakpoint. + thread = process.GetThreadAtIndex(0) + if thread.GetStopReason() != lldb.eStopReasonBreakpoint: + from lldbutil import stop_reason_to_str + self.fail(STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS % + stop_reason_to_str(thread.GetStopReason())) + + # Make sure we stopped at the first breakpoint. + + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.line1, "Hit the first breakpoint.") + + mySource = thread.GetFrameAtIndex(0).FindVariable("mySource") + self.assertTrue(mySource, "Found mySource local variable.") + mySource_isa = mySource.GetChildMemberWithName ("isa") + self.assertTrue(mySource_isa, "Found mySource->isa local variable.") + mySource_isa.GetValue (thread.GetFrameAtIndex(0)) + + # Lets delete mySource so we can check that after stepping a child variable + # with no parent persists and is useful. + del (mySource) + + # Now step in, that should leave us in the Source randomMethod: + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.source_randomMethod_line, "Stepped into Source randomMethod.") + + # Now step in again, through the super call, and that should leave us in the SourceBase randomMethod: + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.sourceBase_randomMethod_line, "Stepped through super into SourceBase randomMethod.") + + process.Continue() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.line2, "Continued to second breakpoint in main.") + + # Again, step in twice gets us to a stret method and a stret super call: + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.source_returnsStruct_start_line, "Stepped into Source returnsStruct.") + + process.Continue() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.source_returnsStruct_call_line, "Stepped to the call super line in Source returnsStruct.") + + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct.") + + # Cool now continue to get past the call that intializes the Observer, and then do our steps in again to see that + # we can find our way when we're stepping through a KVO swizzled object. + + process.Continue() + frame = thread.GetFrameAtIndex(0) + line_number = frame.GetLineEntry().GetLine() + self.assertTrue (line_number == self.line3, "Continued to third breakpoint in main, our object should now be swizzled.") + + mySource_isa.GetValue (frame) + did_change = mySource_isa.GetValueDidChange (frame) + + self.assertTrue (did_change, "The isa did indeed change, swizzled!") + + # Now step in, that should leave us in the Source randomMethod: + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.source_randomMethod_line, "Stepped into Source randomMethod in swizzled object.") + + # Now step in again, through the super call, and that should leave us in the SourceBase randomMethod: + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.sourceBase_randomMethod_line, "Stepped through super into SourceBase randomMethod in swizzled object.") + + process.Continue() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.line4, "Continued to fourth breakpoint in main.") + + # Again, step in twice gets us to a stret method and a stret super call: + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.source_returnsStruct_start_line, "Stepped into Source returnsStruct in swizzled object.") + + process.Continue() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.source_returnsStruct_call_line, "Stepped to the call super line in Source returnsStruct - second time.") + + thread.StepInto() + line_number = thread.GetFrameAtIndex(0).GetLineEntry().GetLine() + self.assertTrue (line_number == self.sourceBase_returnsStruct_start_line, "Stepped through super into SourceBase returnsStruct in swizzled object.") + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/lang/objc/objc-stepping/stepping-tests.m b/lldb/test/lang/objc/objc-stepping/stepping-tests.m new file mode 100644 index 00000000000..cc62dc251ce --- /dev/null +++ b/lldb/test/lang/objc/objc-stepping/stepping-tests.m @@ -0,0 +1,133 @@ +#import <Foundation/Foundation.h> +#include <stdio.h> + +struct return_me +{ + int first; + int second; +}; + +@interface SourceBase: NSObject +{ + struct return_me my_return; +} +- (SourceBase *) initWithFirst: (int) first andSecond: (int) second; +- (void) randomMethod; +- (struct return_me) returnsStruct; +@end + +@implementation SourceBase +- (void) randomMethod +{ + printf ("Called in SourceBase version of randomMethod.\n"); // SourceBase randomMethod start line. +} + +- (struct return_me) returnsStruct +{ + return my_return; // SourceBase returnsStruct start line. +} + +- (SourceBase *) initWithFirst: (int) first andSecond: (int) second +{ + my_return.first = first; + my_return.second = second; + + return self; +} +@end + +@interface Source : SourceBase +{ + int _property; +} +- (void) setProperty: (int) newValue; +- (void) randomMethod; +- (struct return_me) returnsStruct; +@end + +@implementation Source +- (void) setProperty: (int) newValue +{ + _property = newValue; +} + +- (void) randomMethod +{ + [super randomMethod]; // Source randomMethod start line. + printf ("Called in Source version of random method."); +} + +- (struct return_me) returnsStruct +{ + printf ("Called in Source version of returnsStruct.\n"); // Source returnsStruct start line. + return [super returnsStruct]; // Source returnsStruct call line. +} + +@end + +@interface Observer : NSObject +{ + Source *_source; +} ++ (Observer *) observerWithSource: (Source *) source; +- (Observer *) initWithASource: (Source *) source; +- (void) observeValueForKeyPath: (NSString *) path + ofObject: (id) object + change: (NSDictionary *) change + context: (void *) context; +@end + +@implementation Observer + ++ (Observer *) observerWithSource: (Source *) inSource; +{ + Observer *retval; + + retval = [[Observer alloc] initWithASource: inSource]; + return retval; +} + +- (Observer *) initWithASource: (Source *) source +{ + [super init]; + _source = source; + [_source addObserver: self + forKeyPath: @"property" + options: (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) + context: NULL]; + return self; +} + +- (void) observeValueForKeyPath: (NSString *) path + ofObject: (id) object + change: (NSDictionary *) change + context: (void *) context +{ + printf ("Observer function called.\n"); + return; +} +@end + +int main () +{ + Source *mySource; + Observer *myObserver; + struct return_me ret_val; + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + mySource = [[Source alloc] init]; + + [mySource randomMethod]; // Set first breakpoint here. + ret_val = [mySource returnsStruct]; // Set second breakpoint here. + + myObserver = [Observer observerWithSource: mySource]; + + [mySource randomMethod]; // Set third breakpoint here. + ret_val = [mySource returnsStruct]; // Set fourth breakpoint here. + [mySource setProperty: 5]; // Set fifth breakpoint here. + + [pool release]; + return 0; + +} |