| """ |
| 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") |