summaryrefslogtreecommitdiffstats
path: root/lldb/test/lang/objc
diff options
context:
space:
mode:
authorJohnny Chen <johnny.chen@apple.com>2011-06-25 20:16:38 +0000
committerJohnny Chen <johnny.chen@apple.com>2011-06-25 20:16:38 +0000
commit33e89de95a6be2bd6482fd4aeb62e177d1a70956 (patch)
tree61dafeb3a9b1a48e243a058bc74276a25a0a28cc /lldb/test/lang/objc
parent53af50ac56c3e74edcba4074a27b3f27865a6edf (diff)
downloadbcm5719-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/Makefile6
-rw-r--r--lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py165
-rw-r--r--lldb/test/lang/objc/objc-dynamic-value/dynamic-value.m147
-rw-r--r--lldb/test/lang/objc/objc-ivar-offsets/Makefile6
-rw-r--r--lldb/test/lang/objc/objc-ivar-offsets/TestObjCIvarOffsets.py75
-rw-r--r--lldb/test/lang/objc/objc-ivar-offsets/main.m13
-rw-r--r--lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.h23
-rw-r--r--lldb/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.m19
-rw-r--r--lldb/test/lang/objc/objc-optimized/Makefile8
-rw-r--r--lldb/test/lang/objc/objc-optimized/TestObjcOptimized.py63
-rw-r--r--lldb/test/lang/objc/objc-optimized/main.m44
-rw-r--r--lldb/test/lang/objc/objc-stepping/Makefile6
-rw-r--r--lldb/test/lang/objc/objc-stepping/TestObjCStepping.py165
-rw-r--r--lldb/test/lang/objc/objc-stepping/stepping-tests.m133
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;
+
+}
OpenPOWER on IntegriCloud