summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile9
-rw-r--r--lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py90
-rw-r--r--lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m36
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSException.cpp45
4 files changed, 172 insertions, 8 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile
new file mode 100644
index 00000000000..9f7fb1ca623
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/Makefile
@@ -0,0 +1,9 @@
+LEVEL = ../../../make
+
+OBJC_SOURCES := main.m
+
+CFLAGS_EXTRAS += -w
+
+include $(LEVEL)/Makefile.rules
+
+LDFLAGS += -framework Foundation
diff --git a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
new file mode 100644
index 00000000000..423776cd115
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py
@@ -0,0 +1,90 @@
+# encoding: utf-8
+"""
+Test lldb Obj-C exception support.
+"""
+
+from __future__ import print_function
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ObjCExceptionsTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipUnlessDarwin
+ def test_objc_exceptions_1(self):
+ self.build()
+
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(target, VALID_TARGET)
+
+ lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", lldb.SBFileSpec("main.m"))
+
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs=['stopped', 'stop reason = breakpoint'])
+
+ thread = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread()
+ frame = thread.GetSelectedFrame()
+
+ self.expect(
+ 'frame variable e1',
+ substrs=[
+ '(NSException *) e1 = ',
+ 'name: @"ExceptionName" - reason: @"SomeReason"'
+ ])
+
+ self.expect(
+ 'frame variable --dynamic-type no-run-target *e1',
+ substrs=[
+ '(NSException) *e1 = ',
+ 'name = ', '@"ExceptionName"',
+ 'reason = ', '@"SomeReason"',
+ 'userInfo = ', '1 key/value pair',
+ 'reserved = ', 'nil',
+ ])
+
+ e1 = frame.FindVariable("e1")
+ self.assertTrue(e1)
+ self.assertEqual(e1.type.name, "NSException *")
+ 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
+ self.assertEqual(userInfo.summary, "1 key/value pair")
+ self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(0).description, "some_key")
+ self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(1).description, "some_value")
+ self.assertEqual(e1.GetChildMemberWithName("reserved").description, "<nil>")
+
+ self.expect(
+ 'frame variable e2',
+ substrs=[
+ '(NSException *) e2 = ',
+ 'name: @"ThrownException" - reason: @"SomeReason"'
+ ])
+
+ self.expect(
+ 'frame variable --dynamic-type no-run-target *e2',
+ substrs=[
+ '(NSException) *e2 = ',
+ 'name = ', '@"ThrownException"',
+ 'reason = ', '@"SomeReason"',
+ 'userInfo = ', '1 key/value pair',
+ 'reserved = ',
+ ])
+
+ e2 = frame.FindVariable("e2")
+ self.assertTrue(e2)
+ self.assertEqual(e2.type.name, "NSException *")
+ 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
+ self.assertEqual(userInfo.summary, "1 key/value pair")
+ self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(0).description, "some_key")
+ self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(1).description, "some_value")
+ self.assertGreater(e2.GetChildMemberWithName("reserved").dynamic.num_children, 0)
diff --git a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m
new file mode 100644
index 00000000000..93ad7266256
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/main.m
@@ -0,0 +1,36 @@
+//===-- main.m ------------------------------------------------*- ObjC -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#import <Foundation/Foundation.h>
+
+void foo()
+{
+ NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:@"some_value", @"some_key", nil];
+ @throw [[NSException alloc] initWithName:@"ThrownException" reason:@"SomeReason" userInfo:info];
+}
+
+int main (int argc, const char * argv[])
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:@"some_value", @"some_key", nil];
+ NSException *e1 = [[NSException alloc] initWithName:@"ExceptionName" reason:@"SomeReason" userInfo:info];
+ NSException *e2;
+
+ @try {
+ foo();
+ } @catch(NSException *e) {
+ e2 = e;
+ }
+
+ NSLog(@"1"); // Set break point at this line.
+ [pool drain];
+ return 0;
+}
+
diff --git a/lldb/source/Plugins/Language/ObjC/NSException.cpp b/lldb/source/Plugins/Language/ObjC/NSException.cpp
index 66be60ffcb9..bb0bcb94688 100644
--- a/lldb/source/Plugins/Language/ObjC/NSException.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSException.cpp
@@ -30,8 +30,8 @@ using namespace lldb_private;
using namespace lldb_private::formatters;
static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
- ValueObjectSP *reason_sp,
- ValueObjectSP *userinfo_sp) {
+ ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp,
+ ValueObjectSP *reserved_sp) {
ProcessSP process_sp(valobj.GetProcessSP());
if (!process_sp)
return false;
@@ -61,10 +61,14 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
auto userinfo = process_sp->ReadPointerFromMemory(ptr + 3 * ptr_size, error);
if (error.Fail() || userinfo == LLDB_INVALID_ADDRESS)
return false;
+ auto reserved = process_sp->ReadPointerFromMemory(ptr + 4 * ptr_size, error);
+ if (error.Fail() || reserved == LLDB_INVALID_ADDRESS)
+ return false;
InferiorSizedWord name_isw(name, *process_sp);
InferiorSizedWord reason_isw(reason, *process_sp);
InferiorSizedWord userinfo_isw(userinfo, *process_sp);
+ InferiorSizedWord reserved_isw(reserved, *process_sp);
CompilerType voidstar = process_sp->GetTarget()
.GetScratchClangASTContext()
@@ -83,6 +87,10 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
*userinfo_sp = ValueObject::CreateValueObjectFromData(
"userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
valobj.GetExecutionContextRef(), voidstar);
+ if (reserved_sp)
+ *reserved_sp = ValueObject::CreateValueObjectFromData(
+ "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
+ valobj.GetExecutionContextRef(), voidstar);
return true;
}
@@ -91,7 +99,7 @@ bool lldb_private::formatters::NSException_SummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
lldb::ValueObjectSP name_sp;
lldb::ValueObjectSP reason_sp;
- if (!ExtractFields(valobj, &name_sp, &reason_sp, nullptr))
+ if (!ExtractFields(valobj, &name_sp, &reason_sp, nullptr, nullptr))
return false;
if (!name_sp || !reason_sp)
@@ -117,19 +125,27 @@ public:
~NSExceptionSyntheticFrontEnd() override = default;
size_t CalculateNumChildren() override {
- return 1;
+ return 4;
}
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
switch (idx) {
- case 0: return m_userinfo_sp;
+ case 0: return m_name_sp;
+ case 1: return m_reason_sp;
+ case 2: return m_userinfo_sp;
+ case 3: return m_reserved_sp;
}
return lldb::ValueObjectSP();
}
bool Update() override {
+ m_name_sp.reset();
+ m_reason_sp.reset();
m_userinfo_sp.reset();
- if (!ExtractFields(m_backend, nullptr, nullptr, &m_userinfo_sp)) {
+ m_reserved_sp.reset();
+
+ if (!ExtractFields(m_backend, &m_name_sp, &m_reason_sp, &m_userinfo_sp,
+ &m_reserved_sp)) {
return false;
}
return true;
@@ -138,14 +154,27 @@ public:
bool MightHaveChildren() override { return true; }
size_t GetIndexOfChildWithName(const ConstString &name) override {
+ // NSException has 4 members:
+ // NSString *name;
+ // NSString *reason;
+ // NSDictionary *userInfo;
+ // id reserved;
+ static ConstString g___name("name");
+ static ConstString g___reason("reason");
static ConstString g___userInfo("userInfo");
- if (name == g___userInfo)
- return 0;
+ static ConstString g___reserved("reserved");
+ if (name == g___name) return 0;
+ if (name == g___reason) return 1;
+ if (name == g___userInfo) return 2;
+ if (name == g___reserved) return 3;
return UINT32_MAX;
}
private:
+ ValueObjectSP m_name_sp;
+ ValueObjectSP m_reason_sp;
ValueObjectSP m_userinfo_sp;
+ ValueObjectSP m_reserved_sp;
};
SyntheticChildrenFrontEnd *
OpenPOWER on IntegriCloud