This is more straight forward refactor of the startup sequence that reverts parts ofba29e60f9a. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in087a5d2ec7I think we've narrowed down the main source of test instability that motivated the startup sequence change.
245 lines
8.9 KiB
Python
245 lines
8.9 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)
|
|
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"
|
|
)
|
|
|
|
@skipIfWindows
|
|
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)")
|
|
|
|
@skipIfWindows
|
|
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")
|