summaryrefslogtreecommitdiffstats
path: root/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
diff options
context:
space:
mode:
authorKuba Mracek <mracek@apple.com>2018-12-20 02:01:59 +0000
committerKuba Mracek <mracek@apple.com>2018-12-20 02:01:59 +0000
commitc9e1190a27864868324c20aabd8fa648a8247c5a (patch)
tree9c4c52e8ff57572eb2db84a2ea0a2e6b2869b105 /lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
parent17e705129eeffdefe148ecafdd0268ba463ac876 (diff)
downloadbcm5719-llvm-c9e1190a27864868324c20aabd8fa648a8247c5a.tar.gz
bcm5719-llvm-c9e1190a27864868324c20aabd8fa648a8247c5a.zip
[lldb] Retrieve currently handled Obj-C exception via __cxa_current_exception_type and add GetCurrentExceptionBacktrace SB ABI
This builds on https://reviews.llvm.org/D43884 and https://reviews.llvm.org/D43886 and extends LLDB support of Obj-C exceptions to also look for a "current exception" for a thread in the C++ exception handling runtime metadata (via call to __cxa_current_exception_type). We also construct an actual historical SBThread/ThreadSP that contains frames from the backtrace in the Obj-C exception object. The high level goal this achieves is that when we're already crashed (because an unhandled exception occurred), we can still access the exception object and retrieve the backtrace from the throw point. In Obj-C, this is particularly useful because a catch+rethrow is very common and in those cases you currently don't have any access to the throw point backtrace. Differential Revision: https://reviews.llvm.org/D44072 llvm-svn: 349718
Diffstat (limited to 'lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py')
-rw-r--r--lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py108
1 files changed, 96 insertions, 12 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
index 6959f2ef75d..b5511549fd5 100644
--- a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
@@ -17,13 +17,14 @@ class ObjCExceptionsTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@skipUnlessDarwin
- def test_objc_exceptions_1(self):
+ def test_objc_exceptions_at_throw(self):
self.build()
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.assertTrue(target, VALID_TARGET)
- lldbutil.run_to_name_breakpoint(self, "objc_exception_throw")
+ launch_info = lldb.SBLaunchInfo(["a.out", "0"])
+ lldbutil.run_to_name_breakpoint(self, "objc_exception_throw", launch_info=launch_info)
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs=['stopped', 'stop reason = breakpoint'])
@@ -33,7 +34,7 @@ class ObjCExceptionsTestCase(TestBase):
'name: "ThrownException" - reason: "SomeReason"',
])
- lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", lldb.SBFileSpec("main.m"))
+ lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", lldb.SBFileSpec("main.mm"), launch_info=launch_info)
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs=['stopped', 'stop reason = breakpoint'])
@@ -42,19 +43,23 @@ class ObjCExceptionsTestCase(TestBase):
thread = target.GetProcess().GetSelectedThread()
frame = thread.GetSelectedFrame()
+ # No exception being currently thrown/caught at this point
+ self.assertFalse(thread.GetCurrentException().IsValid())
+ self.assertFalse(thread.GetCurrentExceptionBacktrace().IsValid())
+
self.expect(
'frame variable e1',
substrs=[
'(NSException *) e1 = ',
- 'name: @"ExceptionName" - reason: @"SomeReason"'
+ 'name: "ExceptionName" - reason: "SomeReason"'
])
self.expect(
'frame variable --dynamic-type no-run-target *e1',
substrs=[
'(NSException) *e1 = ',
- 'name = ', '@"ExceptionName"',
- 'reason = ', '@"SomeReason"',
+ 'name = ', '"ExceptionName"',
+ 'reason = ', '"SomeReason"',
'userInfo = ', '1 key/value pair',
'reserved = ', 'nil',
])
@@ -62,7 +67,7 @@ class ObjCExceptionsTestCase(TestBase):
e1 = frame.FindVariable("e1")
self.assertTrue(e1)
self.assertEqual(e1.type.name, "NSException *")
- self.assertEqual(e1.GetSummary(), 'name: @"ExceptionName" - reason: @"SomeReason"')
+ self.assertEqual(e1.GetSummary(), 'name: "ExceptionName" - reason: "SomeReason"')
self.assertEqual(e1.GetChildMemberWithName("name").description, "ExceptionName")
self.assertEqual(e1.GetChildMemberWithName("reason").description, "SomeReason")
userInfo = e1.GetChildMemberWithName("userInfo").dynamic
@@ -75,15 +80,15 @@ class ObjCExceptionsTestCase(TestBase):
'frame variable e2',
substrs=[
'(NSException *) e2 = ',
- 'name: @"ThrownException" - reason: @"SomeReason"'
+ 'name: "ThrownException" - reason: "SomeReason"'
])
self.expect(
'frame variable --dynamic-type no-run-target *e2',
substrs=[
'(NSException) *e2 = ',
- 'name = ', '@"ThrownException"',
- 'reason = ', '@"SomeReason"',
+ 'name = ', '"ThrownException"',
+ 'reason = ', '"SomeReason"',
'userInfo = ', '1 key/value pair',
'reserved = ',
])
@@ -91,7 +96,7 @@ class ObjCExceptionsTestCase(TestBase):
e2 = frame.FindVariable("e2")
self.assertTrue(e2)
self.assertEqual(e2.type.name, "NSException *")
- self.assertEqual(e2.GetSummary(), 'name: @"ThrownException" - reason: @"SomeReason"')
+ self.assertEqual(e2.GetSummary(), 'name: "ThrownException" - reason: "SomeReason"')
self.assertEqual(e2.GetChildMemberWithName("name").description, "ThrownException")
self.assertEqual(e2.GetChildMemberWithName("reason").description, "SomeReason")
userInfo = e2.GetChildMemberWithName("userInfo").dynamic
@@ -106,5 +111,84 @@ class ObjCExceptionsTestCase(TestBase):
pcs = [i.unsigned for i in children]
names = [target.ResolveSymbolContextForAddress(lldb.SBAddress(pc, target), lldb.eSymbolContextSymbol).GetSymbol().name for pc in pcs]
- for n in ["objc_exception_throw", "foo", "main"]:
+ for n in ["objc_exception_throw", "foo(int)", "main"]:
self.assertTrue(n in names, "%s is in the exception backtrace (%s)" % (n, names))
+
+ @skipUnlessDarwin
+ def test_objc_exceptions_at_abort(self):
+ self.build()
+
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(target, VALID_TARGET)
+
+ self.runCmd("run 0")
+
+ # We should be stopped at pthread_kill because of an unhandled exception
+ self.expect("thread list",
+ substrs=['stopped', 'stop reason = signal SIGABRT'])
+
+ self.expect('thread exception', substrs=[
+ '(NSException *) exception = ',
+ 'name: "ThrownException" - reason: "SomeReason"',
+ 'libobjc.A.dylib`objc_exception_throw',
+ 'a.out`foo', 'at main.mm:25',
+ 'a.out`rethrow', 'at main.mm:36',
+ 'a.out`main',
+ ])
+
+ process = self.dbg.GetSelectedTarget().process
+ thread = process.GetSelectedThread()
+
+ # There is an exception being currently processed at this point
+ self.assertTrue(thread.GetCurrentException().IsValid())
+ self.assertTrue(thread.GetCurrentExceptionBacktrace().IsValid())
+
+ history_thread = thread.GetCurrentExceptionBacktrace()
+ self.assertGreaterEqual(history_thread.num_frames, 4)
+ for n in ["objc_exception_throw", "foo(int)", "rethrow(int)", "main"]:
+ self.assertEqual(len([f for f in history_thread.frames if f.GetFunctionName() == n]), 1)
+
+ self.runCmd("kill")
+
+ self.runCmd("run 1")
+ # We should be stopped at pthread_kill because of an unhandled exception
+ self.expect("thread list",
+ substrs=['stopped', 'stop reason = signal SIGABRT'])
+
+ self.expect('thread exception', substrs=[
+ '(MyCustomException *) exception = ',
+ 'libobjc.A.dylib`objc_exception_throw',
+ 'a.out`foo', 'at main.mm:27',
+ 'a.out`rethrow', 'at main.mm:36',
+ 'a.out`main',
+ ])
+
+ process = self.dbg.GetSelectedTarget().process
+ thread = process.GetSelectedThread()
+
+ history_thread = thread.GetCurrentExceptionBacktrace()
+ self.assertGreaterEqual(history_thread.num_frames, 4)
+ for n in ["objc_exception_throw", "foo(int)", "rethrow(int)", "main"]:
+ self.assertEqual(len([f for f in history_thread.frames if f.GetFunctionName() == n]), 1)
+
+ @skipUnlessDarwin
+ def test_cxx_exceptions_at_abort(self):
+ self.build()
+
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(target, VALID_TARGET)
+
+ self.runCmd("run 2")
+
+ # We should be stopped at pthread_kill because of an unhandled exception
+ self.expect("thread list",
+ substrs=['stopped', 'stop reason = signal SIGABRT'])
+
+ self.expect('thread exception', substrs=[])
+
+ process = self.dbg.GetSelectedTarget().process
+ thread = process.GetSelectedThread()
+
+ # C++ exceptions are not exposed in the API (yet).
+ self.assertFalse(thread.GetCurrentException().IsValid())
+ self.assertFalse(thread.GetCurrentExceptionBacktrace().IsValid())
OpenPOWER on IntegriCloud