llvm-project/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py
John Harrison 13eca5248c
[lldb-dap] Re-land refactor of DebugCommunication. (#147787)
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.
2025-08-21 10:20:01 -07:00

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