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