
Originally commited in 362b9d78b4ee9107da2b5e90b3764b0f0fa610fe and then reverted in cb63b75e32a415c9bfc298ed7fdcd67e8d9de54c. This re-lands a subset of the changes to dap_server.py/DebugCommunication and addresses the python3.10 compatibility issue. This includes less type annotations since those were the reason for the failures on that specific version of python. I've done additional testing on python3.8, python3.10 and python3.13 to further validate these changes.
161 lines
6.3 KiB
Python
161 lines
6.3 KiB
Python
"""
|
|
Test lldb-dap setBreakpoints request in assembly source references.
|
|
"""
|
|
|
|
from lldbsuite.test.decorators import *
|
|
from dap_server import Source
|
|
import lldbdap_testcase
|
|
|
|
|
|
class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase):
|
|
# When using PDB, we need to have debug information to break on assembly_func,
|
|
# but this test relies on us not having debug information for that function.
|
|
@skipIfWindows
|
|
def test_can_break_in_source_references(self):
|
|
"""Tests hitting assembly source breakpoints"""
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program)
|
|
|
|
assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"])
|
|
self.continue_to_breakpoints(assmebly_func_breakpoints)
|
|
|
|
assembly_func_frame = self.get_stackFrames()[0]
|
|
self.assertIn(
|
|
"sourceReference",
|
|
assembly_func_frame.get("source"),
|
|
"Expected assembly source frame",
|
|
)
|
|
|
|
line = assembly_func_frame["line"]
|
|
|
|
# Set an assembly breakpoint in the next line and check that it's hit
|
|
source_reference = assembly_func_frame["source"]["sourceReference"]
|
|
assembly_breakpoint_ids = self.set_source_breakpoints_assembly(
|
|
source_reference, [line + 1]
|
|
)
|
|
self.continue_to_breakpoints(assembly_breakpoint_ids)
|
|
|
|
# Continue again and verify it hits in the next function call
|
|
self.continue_to_breakpoints(assmebly_func_breakpoints)
|
|
self.continue_to_breakpoints(assembly_breakpoint_ids)
|
|
|
|
# Clear the breakpoint and then check that the assembly breakpoint does not hit next time
|
|
self.set_source_breakpoints_assembly(source_reference, [])
|
|
self.continue_to_breakpoints(assmebly_func_breakpoints)
|
|
self.continue_to_exit()
|
|
|
|
def test_break_on_invalid_source_reference(self):
|
|
"""Tests hitting assembly source breakpoints"""
|
|
program = self.getBuildArtifact("a.out")
|
|
self.build_and_launch(program)
|
|
|
|
# Verify that setting a breakpoint on an invalid source reference fails
|
|
response = self.dap_server.request_setBreakpoints(
|
|
Source.build(source_reference=-1), [1]
|
|
)
|
|
self.assertIsNotNone(response)
|
|
breakpoints = response["body"]["breakpoints"]
|
|
self.assertEqual(len(breakpoints), 1)
|
|
breakpoint = breakpoints[0]
|
|
self.assertFalse(
|
|
breakpoint["verified"], "Expected breakpoint to not be verified"
|
|
)
|
|
self.assertIn("message", breakpoint, "Expected message to be present")
|
|
self.assertEqual(
|
|
breakpoint["message"],
|
|
"Invalid sourceReference.",
|
|
)
|
|
|
|
# Verify that setting a breakpoint on a source reference that is not created fails
|
|
response = self.dap_server.request_setBreakpoints(
|
|
Source.build(source_reference=200), [1]
|
|
)
|
|
self.assertIsNotNone(response)
|
|
breakpoints = response["body"]["breakpoints"]
|
|
self.assertEqual(len(breakpoints), 1)
|
|
break_point = breakpoints[0]
|
|
self.assertFalse(
|
|
break_point["verified"], "Expected breakpoint to not be verified"
|
|
)
|
|
self.assertIn("message", break_point, "Expected message to be present")
|
|
self.assertEqual(
|
|
break_point["message"],
|
|
"Invalid sourceReference.",
|
|
)
|
|
|
|
@skipIfWindows
|
|
def test_persistent_assembly_breakpoint(self):
|
|
"""Tests that assembly breakpoints are working persistently across sessions"""
|
|
self.build()
|
|
program = self.getBuildArtifact("a.out")
|
|
self.create_debug_adapter()
|
|
|
|
# Run the first session and set a persistent assembly breakpoint
|
|
try:
|
|
self.dap_server.request_initialize()
|
|
self.dap_server.request_launch(program)
|
|
|
|
assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"])
|
|
self.continue_to_breakpoints(assmebly_func_breakpoints)
|
|
|
|
assembly_func_frame = self.get_stackFrames()[0]
|
|
source_reference = assembly_func_frame["source"]["sourceReference"]
|
|
|
|
# Set an assembly breakpoint in the middle of the assembly function
|
|
persistent_breakpoint_line = 4
|
|
persistent_breakpoint_ids = self.set_source_breakpoints_assembly(
|
|
source_reference, [persistent_breakpoint_line]
|
|
)
|
|
|
|
self.assertEqual(
|
|
len(persistent_breakpoint_ids),
|
|
1,
|
|
"Expected one assembly breakpoint to be set",
|
|
)
|
|
|
|
persistent_breakpoint_source = self.dap_server.resolved_breakpoints[
|
|
persistent_breakpoint_ids[0]
|
|
]["source"]
|
|
self.assertIn(
|
|
"adapterData",
|
|
persistent_breakpoint_source,
|
|
"Expected assembly breakpoint to have persistent information",
|
|
)
|
|
self.assertIn(
|
|
"persistenceData",
|
|
persistent_breakpoint_source["adapterData"],
|
|
"Expected assembly breakpoint to have persistent information",
|
|
)
|
|
|
|
self.continue_to_breakpoints(persistent_breakpoint_ids)
|
|
finally:
|
|
self.dap_server.request_disconnect(terminateDebuggee=True)
|
|
self.dap_server.terminate()
|
|
|
|
# Restart the session and verify the breakpoint is still there
|
|
self.create_debug_adapter()
|
|
try:
|
|
self.dap_server.request_initialize()
|
|
self.dap_server.request_launch(program)
|
|
new_session_breakpoints_ids = self.set_source_breakpoints_from_source(
|
|
Source(persistent_breakpoint_source),
|
|
[persistent_breakpoint_line],
|
|
)
|
|
|
|
self.assertEqual(
|
|
len(new_session_breakpoints_ids),
|
|
1,
|
|
"Expected one breakpoint to be set in the new session",
|
|
)
|
|
|
|
self.continue_to_breakpoints(new_session_breakpoints_ids)
|
|
current_line = self.get_stackFrames()[0]["line"]
|
|
self.assertEqual(
|
|
current_line,
|
|
persistent_breakpoint_line,
|
|
"Expected to hit the persistent assembly breakpoint at the same line",
|
|
)
|
|
finally:
|
|
self.dap_server.request_disconnect(terminateDebuggee=True)
|
|
self.dap_server.terminate()
|