1# encoding: utf-8 2""" 3Test lldb Obj-C exception support. 4""" 5 6 7 8import lldb 9from lldbsuite.test.decorators import * 10from lldbsuite.test.lldbtest import * 11from lldbsuite.test import lldbutil 12 13 14class ObjCExceptionsTestCase(TestBase): 15 16 mydir = TestBase.compute_mydir(__file__) 17 18 @skipUnlessDarwin 19 def test_objc_exceptions_at_throw(self): 20 self.build() 21 22 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 23 self.assertTrue(target, VALID_TARGET) 24 25 launch_info = lldb.SBLaunchInfo(["a.out", "0"]) 26 lldbutil.run_to_name_breakpoint(self, "objc_exception_throw", launch_info=launch_info) 27 28 self.expect("thread list", 29 substrs=['stopped', 'stop reason = hit Objective-C exception']) 30 31 self.expect('thread exception', substrs=[ 32 '(NSException *) exception = ', 33 '"SomeReason"', 34 ]) 35 36 target = self.dbg.GetSelectedTarget() 37 thread = target.GetProcess().GetSelectedThread() 38 frame = thread.GetSelectedFrame() 39 40 opts = lldb.SBVariablesOptions() 41 opts.SetIncludeRecognizedArguments(True) 42 variables = frame.GetVariables(opts) 43 44 self.assertEqual(variables.GetSize(), 1) 45 self.assertEqual(variables.GetValueAtIndex(0).name, "exception") 46 self.assertEqual(variables.GetValueAtIndex(0).GetValueType(), lldb.eValueTypeVariableArgument) 47 48 lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", lldb.SBFileSpec("main.mm"), launch_info=launch_info) 49 50 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 51 substrs=['stopped', 'stop reason = breakpoint']) 52 53 target = self.dbg.GetSelectedTarget() 54 thread = target.GetProcess().GetSelectedThread() 55 frame = thread.GetSelectedFrame() 56 57 # No exception being currently thrown/caught at this point 58 self.assertFalse(thread.GetCurrentException().IsValid()) 59 self.assertFalse(thread.GetCurrentExceptionBacktrace().IsValid()) 60 61 self.expect( 62 'frame variable e1', 63 substrs=[ 64 '(NSException *) e1 = ', 65 '"SomeReason"' 66 ]) 67 68 self.expect( 69 'frame variable --dynamic-type no-run-target *e1', 70 substrs=[ 71 '(NSException) *e1 = ', 72 'name = ', '"ExceptionName"', 73 'reason = ', '"SomeReason"', 74 'userInfo = ', '1 key/value pair', 75 'reserved = ', 'nil', 76 ]) 77 78 e1 = frame.FindVariable("e1") 79 self.assertTrue(e1) 80 self.assertEqual(e1.type.name, "NSException *") 81 self.assertEqual(e1.GetSummary(), '"SomeReason"') 82 self.assertEqual(e1.GetChildMemberWithName("name").description, "ExceptionName") 83 self.assertEqual(e1.GetChildMemberWithName("reason").description, "SomeReason") 84 userInfo = e1.GetChildMemberWithName("userInfo").dynamic 85 self.assertEqual(userInfo.summary, "1 key/value pair") 86 self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(0).description, "some_key") 87 self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(1).description, "some_value") 88 self.assertEqual(e1.GetChildMemberWithName("reserved").description, "<nil>") 89 90 self.expect( 91 'frame variable e2', 92 substrs=[ 93 '(NSException *) e2 = ', 94 '"SomeReason"' 95 ]) 96 97 self.expect( 98 'frame variable --dynamic-type no-run-target *e2', 99 substrs=[ 100 '(NSException) *e2 = ', 101 'name = ', '"ThrownException"', 102 'reason = ', '"SomeReason"', 103 'userInfo = ', '1 key/value pair', 104 'reserved = ', 105 ]) 106 107 e2 = frame.FindVariable("e2") 108 self.assertTrue(e2) 109 self.assertEqual(e2.type.name, "NSException *") 110 self.assertEqual(e2.GetSummary(), '"SomeReason"') 111 self.assertEqual(e2.GetChildMemberWithName("name").description, "ThrownException") 112 self.assertEqual(e2.GetChildMemberWithName("reason").description, "SomeReason") 113 userInfo = e2.GetChildMemberWithName("userInfo").dynamic 114 self.assertEqual(userInfo.summary, "1 key/value pair") 115 self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(0).description, "some_key") 116 self.assertEqual(userInfo.GetChildAtIndex(0).GetChildAtIndex(1).description, "some_value") 117 reserved = e2.GetChildMemberWithName("reserved").dynamic 118 self.assertGreater(reserved.num_children, 0) 119 callStackReturnAddresses = [reserved.GetChildAtIndex(i).GetChildAtIndex(1) for i in range(0, reserved.GetNumChildren()) 120 if reserved.GetChildAtIndex(i).GetChildAtIndex(0).description == "callStackReturnAddresses"][0].dynamic 121 children = [callStackReturnAddresses.GetChildAtIndex(i) for i in range(0, callStackReturnAddresses.num_children)] 122 123 pcs = [i.unsigned for i in children] 124 names = [target.ResolveSymbolContextForAddress(lldb.SBAddress(pc, target), lldb.eSymbolContextSymbol).GetSymbol().name for pc in pcs] 125 for n in ["objc_exception_throw", "foo(int)", "main"]: 126 self.assertTrue(n in names, "%s is in the exception backtrace (%s)" % (n, names)) 127 128 @skipUnlessDarwin 129 def test_objc_exceptions_at_abort(self): 130 self.build() 131 132 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 133 self.assertTrue(target, VALID_TARGET) 134 135 self.runCmd("run 0") 136 137 # We should be stopped at pthread_kill because of an unhandled exception 138 self.expect("thread list", 139 substrs=['stopped', 'stop reason = signal SIGABRT']) 140 141 self.expect('thread exception', substrs=[ 142 '(NSException *) exception = ', 143 '"SomeReason"', 144 'libobjc.A.dylib`objc_exception_throw', 145 'a.out`foo', 'at main.mm:16', 146 'a.out`rethrow', 'at main.mm:27', 147 'a.out`main', 148 ]) 149 150 process = self.dbg.GetSelectedTarget().process 151 thread = process.GetSelectedThread() 152 153 # There is an exception being currently processed at this point 154 self.assertTrue(thread.GetCurrentException().IsValid()) 155 self.assertTrue(thread.GetCurrentExceptionBacktrace().IsValid()) 156 157 history_thread = thread.GetCurrentExceptionBacktrace() 158 self.assertGreaterEqual(history_thread.num_frames, 4) 159 for n in ["objc_exception_throw", "foo(int)", "rethrow(int)", "main"]: 160 self.assertEqual(len([f for f in history_thread.frames if f.GetFunctionName() == n]), 1) 161 162 self.runCmd("kill") 163 164 self.runCmd("run 1") 165 # We should be stopped at pthread_kill because of an unhandled exception 166 self.expect("thread list", 167 substrs=['stopped', 'stop reason = signal SIGABRT']) 168 169 self.expect('thread exception', substrs=[ 170 '(MyCustomException *) exception = ', 171 'libobjc.A.dylib`objc_exception_throw', 172 'a.out`foo', 'at main.mm:18', 173 'a.out`rethrow', 'at main.mm:27', 174 'a.out`main', 175 ]) 176 177 process = self.dbg.GetSelectedTarget().process 178 thread = process.GetSelectedThread() 179 180 history_thread = thread.GetCurrentExceptionBacktrace() 181 self.assertGreaterEqual(history_thread.num_frames, 4) 182 for n in ["objc_exception_throw", "foo(int)", "rethrow(int)", "main"]: 183 self.assertEqual(len([f for f in history_thread.frames if f.GetFunctionName() == n]), 1) 184 185 @skipUnlessDarwin 186 def test_cxx_exceptions_at_abort(self): 187 self.build() 188 189 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) 190 self.assertTrue(target, VALID_TARGET) 191 192 self.runCmd("run 2") 193 194 # We should be stopped at pthread_kill because of an unhandled exception 195 self.expect("thread list", 196 substrs=['stopped', 'stop reason = signal SIGABRT']) 197 198 self.expect('thread exception', substrs=['exception =']) 199 200 process = self.dbg.GetSelectedTarget().process 201 thread = process.GetSelectedThread() 202 203 self.assertTrue(thread.GetCurrentException().IsValid()) 204 205 # C++ exception backtraces are not exposed in the API (yet). 206 self.assertFalse(thread.GetCurrentExceptionBacktrace().IsValid()) 207