1""" 2Test calling a function that throws an ObjC exception, make sure that it doesn't propagate the exception. 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11 12class ExprCommandWithThrowTestCase(TestBase): 13 def setUp(self): 14 # Call super's setUp(). 15 TestBase.setUp(self) 16 17 self.main_source = "call-throws.m" 18 self.main_source_spec = lldb.SBFileSpec(self.main_source) 19 20 @add_test_categories(["objc"]) 21 def test(self): 22 """Test calling a function that throws and ObjC exception.""" 23 self.build() 24 self.call_function() 25 26 def check_after_call(self): 27 # Check that we are back where we were before: 28 frame = self.thread.GetFrameAtIndex(0) 29 self.assertEqual( 30 self.orig_frame_pc, frame.GetPC(), "Restored the zeroth frame correctly" 31 ) 32 33 def call_function(self): 34 """Test calling function that throws.""" 35 (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint( 36 self, "I am about to throw.", self.main_source_spec 37 ) 38 39 options = lldb.SBExpressionOptions() 40 options.SetUnwindOnError(True) 41 42 frame = self.thread.GetFrameAtIndex(0) 43 # Store away the PC to check that the functions unwind to the right 44 # place after calls 45 self.orig_frame_pc = frame.GetPC() 46 47 value = frame.EvaluateExpression("[my_class callMeIThrow]", options) 48 self.assertTrue(value.IsValid()) 49 self.assertFalse(value.GetError().Success()) 50 51 self.check_after_call() 52 53 # Okay, now try with a breakpoint in the called code in the case where 54 # we are ignoring breakpoint hits. 55 handler_bkpt = target.BreakpointCreateBySourceRegex( 56 "I felt like it", self.main_source_spec 57 ) 58 self.assertGreater(handler_bkpt.GetNumLocations(), 0) 59 options.SetIgnoreBreakpoints(True) 60 options.SetUnwindOnError(True) 61 62 value = frame.EvaluateExpression("[my_class callMeIThrow]", options) 63 64 self.assertTrue(value.IsValid() and not value.GetError().Success()) 65 self.check_after_call() 66 67 # Now set the ObjC language breakpoint and make sure that doesn't 68 # interfere with the call: 69 exception_bkpt = target.BreakpointCreateForException( 70 lldb.eLanguageTypeObjC, False, True 71 ) 72 self.assertGreater(exception_bkpt.GetNumLocations(), 0) 73 74 options.SetIgnoreBreakpoints(True) 75 options.SetUnwindOnError(True) 76 77 value = frame.EvaluateExpression("[my_class callMeIThrow]", options) 78 79 self.assertTrue(value.IsValid() and not value.GetError().Success()) 80 self.check_after_call() 81 82 # Now turn off exception trapping, and call a function that catches the exceptions, 83 # and make sure the function actually completes, and we get the right 84 # value: 85 options.SetTrapExceptions(False) 86 value = frame.EvaluateExpression("[my_class iCatchMyself]", options) 87 self.assertTrue(value.IsValid()) 88 self.assertSuccess(value.GetError()) 89 self.assertEqual(value.GetValueAsUnsigned(), 57) 90 self.check_after_call() 91 options.SetTrapExceptions(True) 92 93 # Now set this unwind on error to false, and make sure that we stop 94 # where the exception was thrown 95 options.SetUnwindOnError(False) 96 value = frame.EvaluateExpression("[my_class callMeIThrow]", options) 97 98 self.assertTrue(value.IsValid() and not value.GetError().Success()) 99 self.check_after_call() 100