
This PR changes how we treat the launch sequence in lldb-dap. - Send the initialized event after we finish handling the initialize request, rather than after we finish attaching or launching. - Delay handling the launch and attach request until we have handled the configurationDone request. The latter is now largely a NO-OP and only exists to signal lldb-dap that it can handle the launch and attach requests. - Delay handling the initial threads requests until we have handled the launch or attach request. - Make all attaching and launching synchronous, including when we have attach or launch commands. This removes the need to synchronize between the request and event thread. Background: https://discourse.llvm.org/t/reliability-of-the-lldb-dap-tests/86125
243 lines
8.8 KiB
Python
243 lines
8.8 KiB
Python
"""
|
|
Test lldb-dap stackTrace request
|
|
"""
|
|
|
|
import os
|
|
|
|
import lldbdap_testcase
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
|
|
|
|
class TestDAP_stackTrace(lldbdap_testcase.DAPTestCaseBase):
|
|
name_key_path = ["name"]
|
|
source_key_path = ["source", "path"]
|
|
line_key_path = ["line"]
|
|
|
|
# stackTrace additioanl frames for paginated traces
|
|
page_size = 20
|
|
|
|
def verify_stackFrames(self, start_idx, stackFrames):
|
|
frame_idx = start_idx
|
|
for stackFrame in stackFrames:
|
|
# Don't care about frame above main
|
|
if frame_idx > 40:
|
|
return
|
|
self.verify_stackFrame(frame_idx, stackFrame)
|
|
frame_idx += 1
|
|
|
|
def verify_stackFrame(self, frame_idx, stackFrame):
|
|
frame_name = self.get_dict_value(stackFrame, self.name_key_path)
|
|
frame_source = self.get_dict_value(stackFrame, self.source_key_path)
|
|
frame_line = self.get_dict_value(stackFrame, self.line_key_path)
|
|
if frame_idx == 0:
|
|
expected_line = self.recurse_end
|
|
expected_name = "recurse"
|
|
elif frame_idx < 40:
|
|
expected_line = self.recurse_call
|
|
expected_name = "recurse"
|
|
else:
|
|
expected_line = self.recurse_invocation
|
|
expected_name = "main"
|
|
self.assertEqual(
|
|
frame_name,
|
|
expected_name,
|
|
'frame #%i name "%s" == "%s"' % (frame_idx, frame_name, expected_name),
|
|
)
|
|
self.assertEqual(
|
|
frame_source,
|
|
self.source_path,
|
|
'frame #%i source "%s" == "%s"'
|
|
% (frame_idx, frame_source, self.source_path),
|
|
)
|
|
self.assertEqual(
|
|
frame_line,
|
|
expected_line,
|
|
"frame #%i line %i == %i" % (frame_idx, frame_line, expected_line),
|
|
)
|
|
|
|
def test_stackTrace(self):
|
|
"""
|
|
Tests the 'stackTrace' packet and all its variants.
|
|
"""
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program, stopOnEntry=True)
|
|
source = "main.c"
|
|
self.source_path = os.path.join(os.getcwd(), source)
|
|
self.recurse_end = line_number(source, "recurse end")
|
|
self.recurse_call = line_number(source, "recurse call")
|
|
self.recurse_invocation = line_number(source, "recurse invocation")
|
|
|
|
lines = [self.recurse_end]
|
|
|
|
# Set breakpoint at a point of deepest recuusion
|
|
breakpoint_ids = self.set_source_breakpoints(source, lines)
|
|
self.assertEqual(
|
|
len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
|
|
)
|
|
|
|
self.continue_to_breakpoints(breakpoint_ids)
|
|
startFrame = 0
|
|
# Verify we get all stack frames with no arguments
|
|
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount()
|
|
frameCount = len(stackFrames)
|
|
self.assertGreaterEqual(
|
|
frameCount, 40, "verify we get at least 40 frames for all frames"
|
|
)
|
|
self.assertEqual(
|
|
totalFrames,
|
|
frameCount,
|
|
"verify total frames returns a speculative page size",
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Verify totalFrames contains a speculative page size of additional frames with startFrame = 0 and levels = 0
|
|
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
|
|
startFrame=0, levels=10
|
|
)
|
|
self.assertEqual(len(stackFrames), 10, "verify we get levels=10 frames")
|
|
self.assertEqual(
|
|
totalFrames,
|
|
len(stackFrames) + self.page_size,
|
|
"verify total frames returns a speculative page size",
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Verify all stack frames by specifying startFrame = 0 and levels not
|
|
# specified
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame)
|
|
self.assertEqual(
|
|
frameCount,
|
|
len(stackFrames),
|
|
("verify same number of frames with startFrame=%i") % (startFrame),
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Verify all stack frames by specifying startFrame = 0 and levels = 0
|
|
levels = 0
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
|
|
self.assertEqual(
|
|
frameCount,
|
|
len(stackFrames),
|
|
("verify same number of frames with startFrame=%i and" " levels=%i")
|
|
% (startFrame, levels),
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Get only the first stack frame by sepcifying startFrame = 0 and
|
|
# levels = 1
|
|
levels = 1
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
|
|
self.assertEqual(
|
|
levels,
|
|
len(stackFrames),
|
|
("verify one frame with startFrame=%i and" " levels=%i")
|
|
% (startFrame, levels),
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Get only the first 3 stack frames by sepcifying startFrame = 0 and
|
|
# levels = 3
|
|
levels = 3
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
|
|
self.assertEqual(
|
|
levels,
|
|
len(stackFrames),
|
|
("verify %i frames with startFrame=%i and" " levels=%i")
|
|
% (levels, startFrame, levels),
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Get only the first 15 stack frames by sepcifying startFrame = 5 and
|
|
# levels = 16
|
|
startFrame = 5
|
|
levels = 16
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
|
|
self.assertEqual(
|
|
levels,
|
|
len(stackFrames),
|
|
("verify %i frames with startFrame=%i and" " levels=%i")
|
|
% (levels, startFrame, levels),
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Verify we cap things correctly when we ask for too many frames
|
|
startFrame = 5
|
|
levels = 1000
|
|
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
|
|
startFrame=startFrame, levels=levels
|
|
)
|
|
self.assertEqual(
|
|
len(stackFrames),
|
|
frameCount - startFrame,
|
|
("verify less than 1000 frames with startFrame=%i and" " levels=%i")
|
|
% (startFrame, levels),
|
|
)
|
|
self.assertEqual(
|
|
totalFrames,
|
|
frameCount,
|
|
"verify we get correct value for totalFrames count "
|
|
"when requested frames not from 0 index",
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Verify level=0 works with non-zerp start frame
|
|
startFrame = 5
|
|
levels = 0
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
|
|
self.assertEqual(
|
|
len(stackFrames),
|
|
frameCount - startFrame,
|
|
("verify less than 1000 frames with startFrame=%i and" " levels=%i")
|
|
% (startFrame, levels),
|
|
)
|
|
self.verify_stackFrames(startFrame, stackFrames)
|
|
|
|
# Verify we get not frames when startFrame is too high
|
|
startFrame = 1000
|
|
levels = 1
|
|
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
|
|
self.assertEqual(
|
|
0, len(stackFrames), "verify zero frames with startFrame out of bounds"
|
|
)
|
|
|
|
def test_functionNameWithArgs(self):
|
|
"""
|
|
Test that the stack frame without a function name is given its pc in the response.
|
|
"""
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program, customFrameFormat="${function.name-with-args}")
|
|
source = "main.c"
|
|
|
|
self.set_source_breakpoints(source, [line_number(source, "recurse end")])
|
|
|
|
self.continue_to_next_stop()
|
|
frame = self.get_stackFrames()[0]
|
|
self.assertEqual(frame["name"], "recurse(x=1)")
|
|
|
|
def test_StackFrameFormat(self):
|
|
"""
|
|
Test the StackFrameFormat.
|
|
"""
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program)
|
|
source = "main.c"
|
|
|
|
self.set_source_breakpoints(source, [line_number(source, "recurse end")])
|
|
|
|
self.continue_to_next_stop()
|
|
frame = self.get_stackFrames(format={"parameters": True})[0]
|
|
self.assertEqual(frame["name"], "recurse(x=1)")
|
|
|
|
frame = self.get_stackFrames(format={"parameterNames": True})[0]
|
|
self.assertEqual(frame["name"], "recurse(x=1)")
|
|
|
|
frame = self.get_stackFrames(format={"parameterValues": True})[0]
|
|
self.assertEqual(frame["name"], "recurse(x=1)")
|
|
|
|
frame = self.get_stackFrames(format={"parameters": False, "line": True})[0]
|
|
self.assertEqual(frame["name"], "main.c:5:5 recurse")
|
|
|
|
frame = self.get_stackFrames(format={"parameters": False, "module": True})[0]
|
|
self.assertEqual(frame["name"], "a.out recurse")
|