| """ | |
| Test lldb-dap stackTrace request with an extended backtrace thread. | |
| """ | |
| import os | |
| import lldbdap_testcase | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test.lldbplatformutil import * | |
| class TestDAP_extendedStackTrace(lldbdap_testcase.DAPTestCaseBase): | |
| def build_and_run(self, displayExtendedBacktrace=True): | |
| backtrace_recording_lib = findBacktraceRecordingDylib() | |
| if not backtrace_recording_lib: | |
| self.skipTest( | |
| "Skipped because libBacktraceRecording.dylib was present on the system." | |
| ) | |
| if not os.path.isfile("/usr/lib/system/introspection/libdispatch.dylib"): | |
| self.skipTest( | |
| "Skipped because introspection libdispatch dylib is not present." | |
| ) | |
| program = self.getBuildArtifact("a.out") | |
| self.build_and_launch( | |
| program, | |
| env=[ | |
| "DYLD_LIBRARY_PATH=/usr/lib/system/introspection", | |
| "DYLD_INSERT_LIBRARIES=" + backtrace_recording_lib, | |
| ], | |
| displayExtendedBacktrace=displayExtendedBacktrace, | |
| ) | |
| source = "main.m" | |
| breakpoint = line_number(source, "breakpoint 1") | |
| lines = [breakpoint] | |
| breakpoint_ids = self.set_source_breakpoints(source, lines) | |
| self.assertEqual( | |
| len(breakpoint_ids), len(lines), "expect correct number of breakpoints" | |
| ) | |
| @skipUnlessDarwin | |
| def test_stackTrace(self): | |
| """ | |
| Tests the 'stackTrace' packet on a thread with an extended backtrace. | |
| """ | |
| self.build_and_run() | |
| events = self.continue_to_next_stop() | |
| stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount( | |
| threadId=events[0]["body"]["threadId"] | |
| ) | |
| self.assertGreaterEqual(len(stackFrames), 3, "expect >= 3 frames") | |
| self.assertEqual(len(stackFrames), totalFrames) | |
| self.assertEqual(stackFrames[0]["name"], "one") | |
| self.assertEqual(stackFrames[1]["name"], "two") | |
| self.assertEqual(stackFrames[2]["name"], "three") | |
| stackLabels = [ | |
| (i, frame) | |
| for i, frame in enumerate(stackFrames) | |
| if frame.get("presentationHint", "") == "label" | |
| ] | |
| self.assertEqual(len(stackLabels), 2, "expected two label stack frames") | |
| self.assertRegex( | |
| stackLabels[0][1]["name"], | |
| r"Enqueued from com.apple.root.default-qos \(Thread \d\)", | |
| ) | |
| self.assertRegex( | |
| stackLabels[1][1]["name"], | |
| r"Enqueued from com.apple.main-thread \(Thread \d\)", | |
| ) | |
| for i, frame in stackLabels: | |
| # Ensure requesting startFrame+levels across thread backtraces works as expected. | |
| stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount( | |
| threadId=events[0]["body"]["threadId"], startFrame=i - 1, levels=3 | |
| ) | |
| self.assertEqual(len(stackFrames), 3, "expected 3 frames with levels=3") | |
| self.assertGreaterEqual( | |
| totalFrames, i + 3, "total frames should include a pagination offset" | |
| ) | |
| self.assertEqual(stackFrames[1], frame) | |
| # Ensure requesting startFrame+levels at the beginning of a thread backtraces works as expected. | |
| stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount( | |
| threadId=events[0]["body"]["threadId"], startFrame=i, levels=3 | |
| ) | |
| self.assertEqual(len(stackFrames), 3, "expected 3 frames with levels=3") | |
| self.assertGreaterEqual( | |
| totalFrames, i + 3, "total frames should include a pagination offset" | |
| ) | |
| self.assertEqual(stackFrames[0], frame) | |
| # Ensure requests with startFrame+levels that end precisely on the last frame includes the totalFrames pagination offset. | |
| stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount( | |
| threadId=events[0]["body"]["threadId"], startFrame=i - 1, levels=1 | |
| ) | |
| self.assertEqual(len(stackFrames), 1, "expected 1 frames with levels=1") | |
| self.assertGreaterEqual( | |
| totalFrames, i, "total frames should include a pagination offset" | |
| ) | |
| @skipUnlessDarwin | |
| def test_stackTraceWithFormat(self): | |
| """ | |
| Tests the 'stackTrace' packet on a thread with an extended backtrace using stack trace formats. | |
| """ | |
| self.build_and_run(displayExtendedBacktrace=False) | |
| events = self.continue_to_next_stop() | |
| stackFrames, _ = self.get_stackFrames_and_totalFramesCount( | |
| threadId=events[0]["body"]["threadId"], format={"includeAll": True} | |
| ) | |
| stackLabels = [ | |
| (i, frame) | |
| for i, frame in enumerate(stackFrames) | |
| if frame.get("presentationHint", "") == "label" | |
| ] | |
| self.assertEqual(len(stackLabels), 2, "expected two label stack frames") |