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