| """ |
| Test that the FrameRecognizer for __abort_with_payload |
| works properly |
| """ |
| |
| |
| import lldb |
| from lldbsuite.test.decorators import * |
| import lldbsuite.test.lldbutil as lldbutil |
| from lldbsuite.test.lldbtest import * |
| |
| |
| class TestAbortWithPayload(TestBase): |
| NO_DEBUG_INFO_TESTCASE = True |
| |
| @skipUnlessAppleSilicon |
| def test_abort_with_payload(self): |
| """There can be many tests in a test case - describe this test here.""" |
| self.build() |
| self.abort_with_test(True) |
| |
| @skipUnlessAppleSilicon |
| def test_abort_with_reason(self): |
| """There can be many tests in a test case - describe this test here.""" |
| self.build() |
| self.abort_with_test(False) |
| |
| def setUp(self): |
| # Call super's setUp(). |
| TestBase.setUp(self) |
| self.main_source_file = lldb.SBFileSpec("main.c") |
| |
| def abort_with_test(self, with_payload): |
| """If with_payload is True, we test the abort_with_payload call, |
| if false, we test abort_with_reason.""" |
| launch_info = lldb.SBLaunchInfo([]) |
| if not with_payload: |
| launch_info.SetArguments(["use_reason"], True) |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( |
| self, |
| "Stop here before abort", |
| self.main_source_file, |
| launch_info=launch_info, |
| ) |
| |
| frame = thread.GetFrameAtIndex(0) |
| payload_str_var = frame.FindVariable("payload_string") |
| self.assertSuccess(payload_str_var.GetError(), "Got payload string var") |
| payload_var_addr = payload_str_var.unsigned |
| |
| payload_size_var = frame.FindVariable("payload_string_len") |
| self.assertSuccess(payload_size_var.GetError(), "Got payload string len var") |
| payload_size_val = payload_size_var.unsigned |
| |
| # Not let it run to crash: |
| process.Continue() |
| |
| # At this point we should have stopped at the internal function. |
| # Make sure we selected the right thread: |
| sel_thread = process.GetSelectedThread() |
| self.assertEqual(thread, sel_thread, "Selected the original thread") |
| # Make sure the stop reason is right: |
| self.assertEqual( |
| thread.stop_description, |
| "abort with payload or reason", |
| "Description was right", |
| ) |
| frame_0 = thread.frames[0] |
| self.assertEqual(frame_0.name, "__abort_with_payload", "Frame 0 was right") |
| |
| # Now check the recognized argument values and the ExtendedCrashInformation version: |
| options = lldb.SBVariablesOptions() |
| options.SetIncludeRecognizedArguments(True) |
| options.SetIncludeArguments(False) |
| options.SetIncludeLocals(False) |
| options.SetIncludeStatics(False) |
| options.SetIncludeRuntimeSupportValues(False) |
| |
| arguments = frame_0.GetVariables(options) |
| |
| correct_values = { |
| "namespace": 5, |
| "code": 100, |
| "payload_addr": payload_var_addr, |
| "payload_size": payload_size_val, |
| "payload_string": '"This is a payload that happens to be a string"', |
| "reason_string": '"This is the reason string"', |
| "reason_no_quote": "This is the reason string", |
| "flags": 0x85, |
| } |
| |
| # First check the recognized argument values: |
| self.assertEqual(len(arguments), 6, "Got all six values") |
| self.assertEqual(arguments[0].name, "namespace") |
| self.assertEqual( |
| arguments[0].unsigned, |
| correct_values["namespace"], |
| "Namespace value correct", |
| ) |
| |
| self.assertEqual(arguments[1].name, "code") |
| self.assertEqual( |
| arguments[1].unsigned, correct_values["code"], "code value correct" |
| ) |
| |
| # We always stop at __abort_with_payload, regardless of whether the caller |
| # was abort_with_reason or abort_with_payload or any future API that |
| # funnels here. Since I don't want to have to know too much about the |
| # callers, I just always report what is in the function I've |
| # |
| # add the payload ones if it is the payload not the reason function. |
| self.assertEqual(arguments[2].name, "payload_addr") |
| self.assertEqual(arguments[3].name, "payload_size") |
| if with_payload: |
| self.assertEqual( |
| arguments[2].unsigned, |
| correct_values["payload_addr"], |
| "Payload matched variable address", |
| ) |
| # We've made a payload that is a string, try to fetch that: |
| char_ptr_type = target.FindFirstType("char").GetPointerType() |
| self.assertTrue(char_ptr_type.IsValid(), "Got char ptr type") |
| |
| str_val = arguments[2].Cast(char_ptr_type) |
| self.assertEqual( |
| str_val.summary, correct_values["payload_string"], "Got payload string" |
| ) |
| |
| self.assertEqual( |
| arguments[3].unsigned, |
| correct_values["payload_size"], |
| "payload size value correct", |
| ) |
| else: |
| self.assertEqual( |
| arguments[2].unsigned, 0, "Got 0 payload addr for reason call" |
| ) |
| self.assertEqual( |
| arguments[3].unsigned, 0, "Got 0 payload size for reason call" |
| ) |
| |
| self.assertEqual(arguments[4].name, "reason") |
| self.assertEqual( |
| arguments[4].summary, |
| correct_values["reason_string"], |
| "Reason value correct", |
| ) |
| |
| self.assertEqual(arguments[5].name, "flags") |
| self.assertEqual( |
| arguments[5].unsigned, correct_values["flags"], "Flags value correct" |
| ) |
| |
| # Also check that the same info was stored in the ExtendedCrashInformation dict: |
| dict = process.GetExtendedCrashInformation() |
| self.assertTrue(dict.IsValid(), "Got extended crash information dict") |
| self.assertEqual( |
| dict.GetType(), lldb.eStructuredDataTypeDictionary, "It is a dictionary" |
| ) |
| |
| abort_dict = dict.GetValueForKey("abort_with_payload") |
| self.assertTrue(abort_dict.IsValid(), "Got an abort_with_payload dict") |
| self.assertEqual( |
| abort_dict.GetType(), |
| lldb.eStructuredDataTypeDictionary, |
| "It is a dictionary", |
| ) |
| |
| namespace_val = abort_dict.GetValueForKey("namespace") |
| self.assertTrue(namespace_val.IsValid(), "Got a valid namespace") |
| self.assertEqual( |
| namespace_val.GetIntegerValue(0), |
| correct_values["namespace"], |
| "Namespace value correct", |
| ) |
| |
| code_val = abort_dict.GetValueForKey("code") |
| self.assertTrue(code_val.IsValid(), "Got a valid code") |
| self.assertEqual( |
| code_val.GetIntegerValue(0), correct_values["code"], "Code value correct" |
| ) |
| |
| if with_payload: |
| addr_val = abort_dict.GetValueForKey("payload_addr") |
| self.assertTrue(addr_val.IsValid(), "Got a payload_addr") |
| self.assertEqual( |
| addr_val.GetIntegerValue(0), |
| correct_values["payload_addr"], |
| "payload_addr right in dictionary", |
| ) |
| |
| size_val = abort_dict.GetValueForKey("payload_size") |
| self.assertTrue(size_val.IsValid(), "Got a payload size value") |
| self.assertEqual( |
| size_val.GetIntegerValue(0), |
| correct_values["payload_size"], |
| "payload size right in dictionary", |
| ) |
| |
| reason_val = abort_dict.GetValueForKey("reason") |
| self.assertTrue(reason_val.IsValid(), "Got a reason key") |
| self.assertEqual( |
| reason_val.GetStringValue(100), |
| correct_values["reason_no_quote"], |
| "reason right in dictionary", |
| ) |
| |
| flags_val = abort_dict.GetValueForKey("flags") |
| self.assertTrue(flags_val.IsValid(), "Got a flags value") |
| self.assertEqual( |
| flags_val.GetIntegerValue(0), |
| correct_values["flags"], |
| "flags right in dictionary", |
| ) |