| """ | |
| Test lldb process crash info. | |
| """ | |
| import os | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test import lldbutil | |
| from lldbsuite.test import lldbtest | |
| class PlatformProcessCrashInfoTestCase(TestBase): | |
| def setUp(self): | |
| TestBase.setUp(self) | |
| self.runCmd("settings set auto-confirm true") | |
| self.source = "main.c" | |
| self.line = line_number(self.source, "// break here") | |
| def tearDown(self): | |
| self.runCmd("settings clear auto-confirm") | |
| TestBase.tearDown(self) | |
| def containsLibmallocError(self, output): | |
| for error in [ | |
| "pointer being freed was not allocated", | |
| "not an allocated block", | |
| "MTE tag mismatch", | |
| ]: | |
| if error in output: | |
| return True | |
| return False | |
| @skipIfAsan # The test process intentionally double-frees. | |
| @skipUnlessDarwin | |
| def test_cli(self): | |
| """Test that `process status --verbose` fetches the extended crash | |
| information dictionary from the command-line properly.""" | |
| self.build() | |
| exe = self.getBuildArtifact("a.out") | |
| self.expect("file " + exe, patterns=["Current executable set to .*a.out"]) | |
| self.expect("process launch", patterns=["Process .* launched: .*a.out"]) | |
| result = lldb.SBCommandReturnObject() | |
| self.dbg.GetCommandInterpreter().HandleCommand( | |
| "process status --verbose", result | |
| ) | |
| self.assertIn("Extended Crash Information", result.GetOutput()) | |
| self.assertIn("Crash-Info Annotations", result.GetOutput()) | |
| self.assertTrue(self.containsLibmallocError(result.GetOutput())) | |
| @skipIfAsan # The test process intentionally hits a memory bug. | |
| @skipUnlessDarwin | |
| def test_api(self): | |
| """Test that lldb can fetch a crashed process' extended crash information | |
| dictionary from the api properly.""" | |
| self.build() | |
| target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) | |
| self.assertTrue(target, VALID_TARGET) | |
| target.LaunchSimple(None, None, os.getcwd()) | |
| stream = lldb.SBStream() | |
| self.assertTrue(stream) | |
| process = target.GetProcess() | |
| self.assertTrue(process) | |
| crash_info = process.GetExtendedCrashInformation() | |
| error = crash_info.GetAsJSON(stream) | |
| self.assertSuccess(error) | |
| self.assertTrue(crash_info.IsValid()) | |
| self.assertTrue(self.containsLibmallocError(stream.GetData())) | |
| # dyld leaves permanent crash_info records when testing on device. | |
| @skipIfDarwinEmbedded | |
| def test_on_sane_process(self): | |
| """Test that lldb doesn't fetch the extended crash information | |
| dictionary from a 'sane' stopped process.""" | |
| self.build() | |
| target, _, _, _ = lldbutil.run_to_line_breakpoint( | |
| self, lldb.SBFileSpec(self.source), self.line | |
| ) | |
| stream = lldb.SBStream() | |
| self.assertTrue(stream) | |
| process = target.GetProcess() | |
| self.assertTrue(process) | |
| crash_info = process.GetExtendedCrashInformation() | |
| error = crash_info.GetAsJSON(stream) | |
| self.assertFalse(error.Success()) | |
| self.assertIn("No structured data.", error.GetCString()) |