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