| """ | |
| Test that the built in ObjC exception throw recognizer works | |
| """ | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| import lldbsuite.test.lldbutil as lldbutil | |
| from lldbsuite.test.lldbtest import * | |
| class TestObjCRecognizer(TestBase): | |
| NO_DEBUG_INFO_TESTCASE = True | |
| @skipUnlessDarwin | |
| def test_exception_recognizer_sub_class(self): | |
| """There can be many tests in a test case - describe this test here.""" | |
| self.build() | |
| self.main_source_file = lldb.SBFileSpec("main.m") | |
| self.objc_recognizer_test(True) | |
| @skipUnlessDarwin | |
| def test_exception_recognizer_plain(self): | |
| """There can be many tests in a test case - describe this test here.""" | |
| self.build() | |
| self.main_source_file = lldb.SBFileSpec("main.m") | |
| self.objc_recognizer_test(False) | |
| def objc_recognizer_test(self, sub_class): | |
| """Make sure we stop at the exception and get all the fields out of the recognizer. | |
| If sub_class is True, we make a subclass of NSException and throw that.""" | |
| if sub_class: | |
| bkpt_string = "Set a breakpoint here for MyException" | |
| else: | |
| bkpt_string = "Set a breakpoint here for plain exception" | |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( | |
| self, bkpt_string, self.main_source_file | |
| ) | |
| # Now turn on the ObjC Exception breakpoint and continue to hit it: | |
| exception_bkpt = target.BreakpointCreateForException( | |
| lldb.eLanguageTypeObjC, False, True | |
| ) | |
| self.assertGreater( | |
| exception_bkpt.GetNumLocations(), 0, "Got some exception locations" | |
| ) | |
| threads = lldbutil.continue_to_breakpoint(process, exception_bkpt) | |
| self.assertEqual(len(threads), 1, "One thread hit exception breakpoint") | |
| frame = threads[0].frame[0] | |
| var_opts = lldb.SBVariablesOptions() | |
| var_opts.SetIncludeRecognizedArguments(True) | |
| var_opts.SetUseDynamic(True) | |
| vars = frame.GetVariables(var_opts) | |
| self.assertEqual(len(vars), 1, "Got the synthetic argument") | |
| self.assertTrue(vars[0].IsValid(), "Got a valid Exception variable") | |
| # This will be a pointer | |
| ns_exception_children = [ | |
| ValueCheck(type="NSObject"), | |
| ValueCheck(name="name", summary='"NSException"'), | |
| ValueCheck(name="reason", summary='"Simple Reason"'), | |
| ValueCheck(name="userInfo"), | |
| ValueCheck(name="reserved"), | |
| ] | |
| ns_exception = ValueCheck(type="NSException", children=ns_exception_children) | |
| if not sub_class: | |
| simple_check = ValueCheck(name="exception", dereference=ns_exception) | |
| simple_check.check_value(self, vars[0], "Simple exception is right") | |
| else: | |
| my_exception_children = [ | |
| ns_exception, | |
| ValueCheck(name="extra_info", type="int", value="100"), | |
| ] | |
| my_exception = ValueCheck( | |
| type="MyException", children=my_exception_children | |
| ) | |
| sub_check = ValueCheck( | |
| name="exception", type="MyException *", dereference=my_exception | |
| ) | |
| sub_check.check_value(self, vars[0], "Subclass exception is right") |