Skip to content

Commit 6490f6f

Browse files
ashgtiJDevlieghere
authored andcommitted
Reapply "[lldb-dap] Re-land refactor of DebugCommunication. (llvm#147787)" (llvm#154832)
This reverts commit 0f33b90 and includes a fix for the added test that was submitted between my last update and pull. (cherry picked from commit 36d07ad)
1 parent 963e1f2 commit 6490f6f

File tree

15 files changed

+581
-469
lines changed

15 files changed

+581
-469
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 459 additions & 347 deletions
Large diffs are not rendered by default.

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
import time
3-
from typing import Optional
3+
from typing import Optional, Callable, Any, List, Union
44
import uuid
55

66
import dap_server
@@ -67,7 +67,10 @@ def set_source_breakpoints_assembly(
6767
self, source_reference, lines, data=None, wait_for_resolve=True
6868
):
6969
return self.set_source_breakpoints_from_source(
70-
Source(source_reference=source_reference), lines, data, wait_for_resolve
70+
Source.build(source_reference=source_reference),
71+
lines,
72+
data,
73+
wait_for_resolve,
7174
)
7275

7376
def set_source_breakpoints_from_source(
@@ -120,11 +123,19 @@ def wait_for_breakpoints_to_resolve(
120123
f"Expected to resolve all breakpoints. Unresolved breakpoint ids: {unresolved_breakpoints}",
121124
)
122125

123-
def waitUntil(self, condition_callback):
124-
for _ in range(20):
125-
if condition_callback():
126+
def wait_until(
127+
self,
128+
predicate: Callable[[], bool],
129+
delay: float = 0.5,
130+
timeout: float = DEFAULT_TIMEOUT,
131+
) -> bool:
132+
"""Repeatedly run the predicate until either the predicate returns True
133+
or a timeout has occurred."""
134+
deadline = time.monotonic() + timeout
135+
while deadline > time.monotonic():
136+
if predicate():
126137
return True
127-
time.sleep(0.5)
138+
time.sleep(delay)
128139
return False
129140

130141
def assertCapabilityIsSet(self, key: str, msg: Optional[str] = None) -> None:
@@ -137,13 +148,16 @@ def assertCapabilityIsNotSet(self, key: str, msg: Optional[str] = None) -> None:
137148
if key in self.dap_server.capabilities:
138149
self.assertEqual(self.dap_server.capabilities[key], False, msg)
139150

140-
def verify_breakpoint_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
151+
def verify_breakpoint_hit(
152+
self, breakpoint_ids: List[Union[int, str]], timeout: float = DEFAULT_TIMEOUT
153+
):
141154
"""Wait for the process we are debugging to stop, and verify we hit
142155
any breakpoint location in the "breakpoint_ids" array.
143156
"breakpoint_ids" should be a list of breakpoint ID strings
144157
(["1", "2"]). The return value from self.set_source_breakpoints()
145158
or self.set_function_breakpoints() can be passed to this function"""
146159
stopped_events = self.dap_server.wait_for_stopped(timeout)
160+
normalized_bp_ids = [str(b) for b in breakpoint_ids]
147161
for stopped_event in stopped_events:
148162
if "body" in stopped_event:
149163
body = stopped_event["body"]
@@ -154,22 +168,16 @@ def verify_breakpoint_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
154168
and body["reason"] != "instruction breakpoint"
155169
):
156170
continue
157-
if "description" not in body:
171+
if "hitBreakpointIds" not in body:
158172
continue
159-
# Descriptions for breakpoints will be in the form
160-
# "breakpoint 1.1", so look for any description that matches
161-
# ("breakpoint 1.") in the description field as verification
162-
# that one of the breakpoint locations was hit. DAP doesn't
163-
# allow breakpoints to have multiple locations, but LLDB does.
164-
# So when looking at the description we just want to make sure
165-
# the right breakpoint matches and not worry about the actual
166-
# location.
167-
description = body["description"]
168-
for breakpoint_id in breakpoint_ids:
169-
match_desc = f"breakpoint {breakpoint_id}."
170-
if match_desc in description:
173+
hit_breakpoint_ids = body["hitBreakpointIds"]
174+
for bp in hit_breakpoint_ids:
175+
if str(bp) in normalized_bp_ids:
171176
return
172-
self.assertTrue(False, f"breakpoint not hit, stopped_events={stopped_events}")
177+
self.assertTrue(
178+
False,
179+
f"breakpoint not hit, wanted breakpoint_ids {breakpoint_ids} in stopped_events {stopped_events}",
180+
)
173181

174182
def verify_all_breakpoints_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
175183
"""Wait for the process we are debugging to stop, and verify we hit
@@ -213,7 +221,7 @@ def verify_stop_exception_info(self, expected_description, timeout=DEFAULT_TIMEO
213221
return True
214222
return False
215223

216-
def verify_commands(self, flavor, output, commands):
224+
def verify_commands(self, flavor: str, output: str, commands: list[str]):
217225
self.assertTrue(output and len(output) > 0, "expect console output")
218226
lines = output.splitlines()
219227
prefix = "(lldb) "
@@ -226,10 +234,11 @@ def verify_commands(self, flavor, output, commands):
226234
found = True
227235
break
228236
self.assertTrue(
229-
found, "verify '%s' found in console output for '%s'" % (cmd, flavor)
237+
found,
238+
f"Command '{flavor}' - '{cmd}' not found in output: {output}",
230239
)
231240

232-
def get_dict_value(self, d, key_path):
241+
def get_dict_value(self, d: dict, key_path: list[str]) -> Any:
233242
"""Verify each key in the key_path array is in contained in each
234243
dictionary within "d". Assert if any key isn't in the
235244
corresponding dictionary. This is handy for grabbing values from VS
@@ -298,28 +307,34 @@ def get_source_and_line(self, threadId=None, frameIndex=0):
298307
return (source["path"], stackFrame["line"])
299308
return ("", 0)
300309

301-
def get_stdout(self, timeout=0.0):
302-
return self.dap_server.get_output("stdout", timeout=timeout)
310+
def get_stdout(self):
311+
return self.dap_server.get_output("stdout")
303312

304-
def get_console(self, timeout=0.0):
305-
return self.dap_server.get_output("console", timeout=timeout)
313+
def get_console(self):
314+
return self.dap_server.get_output("console")
306315

307-
def get_important(self, timeout=0.0):
308-
return self.dap_server.get_output("important", timeout=timeout)
316+
def get_important(self):
317+
return self.dap_server.get_output("important")
309318

310-
def collect_stdout(self, timeout_secs, pattern=None):
319+
def collect_stdout(
320+
self, timeout: float = DEFAULT_TIMEOUT, pattern: Optional[str] = None
321+
) -> str:
311322
return self.dap_server.collect_output(
312-
"stdout", timeout_secs=timeout_secs, pattern=pattern
323+
"stdout", timeout=timeout, pattern=pattern
313324
)
314325

315-
def collect_console(self, timeout_secs, pattern=None):
326+
def collect_console(
327+
self, timeout: float = DEFAULT_TIMEOUT, pattern: Optional[str] = None
328+
) -> str:
316329
return self.dap_server.collect_output(
317-
"console", timeout_secs=timeout_secs, pattern=pattern
330+
"console", timeout=timeout, pattern=pattern
318331
)
319332

320-
def collect_important(self, timeout_secs, pattern=None):
333+
def collect_important(
334+
self, timeout: float = DEFAULT_TIMEOUT, pattern: Optional[str] = None
335+
) -> str:
321336
return self.dap_server.collect_output(
322-
"important", timeout_secs=timeout_secs, pattern=pattern
337+
"important", timeout=timeout, pattern=pattern
323338
)
324339

325340
def get_local_as_int(self, name, threadId=None):

lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def test_commands(self):
153153
breakpoint_ids = self.set_function_breakpoints(functions)
154154
self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint")
155155
self.continue_to_breakpoints(breakpoint_ids)
156-
output = self.collect_console(timeout_secs=10, pattern=stopCommands[-1])
156+
output = self.collect_console(timeout=10, pattern=stopCommands[-1])
157157
self.verify_commands("stopCommands", output, stopCommands)
158158

159159
# Continue after launch and hit the "pause()" call and stop the target.
@@ -163,7 +163,7 @@ def test_commands(self):
163163
time.sleep(0.5)
164164
self.dap_server.request_pause()
165165
self.dap_server.wait_for_stopped()
166-
output = self.collect_console(timeout_secs=10, pattern=stopCommands[-1])
166+
output = self.collect_console(timeout=10, pattern=stopCommands[-1])
167167
self.verify_commands("stopCommands", output, stopCommands)
168168

169169
# Continue until the program exits
@@ -172,7 +172,7 @@ def test_commands(self):
172172
# "exitCommands" that were run after the second breakpoint was hit
173173
# and the "terminateCommands" due to the debugging session ending
174174
output = self.collect_console(
175-
timeout_secs=10.0,
175+
timeout=10.0,
176176
pattern=terminateCommands[0],
177177
)
178178
self.verify_commands("exitCommands", output, exitCommands)
@@ -223,7 +223,7 @@ def test_terminate_commands(self):
223223
# "terminateCommands"
224224
self.dap_server.request_disconnect(terminateDebuggee=True)
225225
output = self.collect_console(
226-
timeout_secs=1.0,
226+
timeout=1.0,
227227
pattern=terminateCommands[0],
228228
)
229229
self.verify_commands("terminateCommands", output, terminateCommands)

lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
Test lldb-dap setBreakpoints request in assembly source references.
33
"""
44

5-
65
from lldbsuite.test.decorators import *
76
from dap_server import Source
87
import lldbdap_testcase
@@ -52,7 +51,7 @@ def test_break_on_invalid_source_reference(self):
5251

5352
# Verify that setting a breakpoint on an invalid source reference fails
5453
response = self.dap_server.request_setBreakpoints(
55-
Source(source_reference=-1), [1]
54+
Source.build(source_reference=-1), [1]
5655
)
5756
self.assertIsNotNone(response)
5857
breakpoints = response["body"]["breakpoints"]
@@ -69,7 +68,7 @@ def test_break_on_invalid_source_reference(self):
6968

7069
# Verify that setting a breakpoint on a source reference that is not created fails
7170
response = self.dap_server.request_setBreakpoints(
72-
Source(source_reference=200), [1]
71+
Source.build(source_reference=200), [1]
7372
)
7473
self.assertIsNotNone(response)
7574
breakpoints = response["body"]["breakpoints"]
@@ -116,7 +115,7 @@ def test_persistent_assembly_breakpoint(self):
116115

117116
persistent_breakpoint_source = self.dap_server.resolved_breakpoints[
118117
persistent_breakpoint_ids[0]
119-
].source()
118+
]["source"]
120119
self.assertIn(
121120
"adapterData",
122121
persistent_breakpoint_source,
@@ -139,7 +138,7 @@ def test_persistent_assembly_breakpoint(self):
139138
self.dap_server.request_initialize()
140139
self.dap_server.request_launch(program)
141140
new_session_breakpoints_ids = self.set_source_breakpoints_from_source(
142-
Source(raw_dict=persistent_breakpoint_source),
141+
Source(persistent_breakpoint_source),
143142
[persistent_breakpoint_line],
144143
)
145144

lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def test_breakpoint_events(self):
5858
# Set breakpoints and verify that they got set correctly
5959
dap_breakpoint_ids = []
6060
response = self.dap_server.request_setBreakpoints(
61-
Source(main_source_path), [main_bp_line]
61+
Source.build(path=main_source_path), [main_bp_line]
6262
)
6363
self.assertTrue(response["success"])
6464
breakpoints = response["body"]["breakpoints"]
@@ -70,7 +70,7 @@ def test_breakpoint_events(self):
7070
)
7171

7272
response = self.dap_server.request_setBreakpoints(
73-
Source(foo_source_path), [foo_bp1_line]
73+
Source.build(path=foo_source_path), [foo_bp1_line]
7474
)
7575
self.assertTrue(response["success"])
7676
breakpoints = response["body"]["breakpoints"]

lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
Test lldb-dap setBreakpoints request
33
"""
44

5-
65
from dap_server import Source
76
import shutil
87
from lldbsuite.test.decorators import *
@@ -58,7 +57,7 @@ def test_source_map(self):
5857

5958
# breakpoint in main.cpp
6059
response = self.dap_server.request_setBreakpoints(
61-
Source(new_main_path), [main_line]
60+
Source.build(path=new_main_path), [main_line]
6261
)
6362
breakpoints = response["body"]["breakpoints"]
6463
self.assertEqual(len(breakpoints), 1)
@@ -70,7 +69,7 @@ def test_source_map(self):
7069

7170
# 2nd breakpoint, which is from a dynamically loaded library
7271
response = self.dap_server.request_setBreakpoints(
73-
Source(new_other_path), [other_line]
72+
Source.build(path=new_other_path), [other_line]
7473
)
7574
breakpoints = response["body"]["breakpoints"]
7675
breakpoint = breakpoints[0]
@@ -85,7 +84,7 @@ def test_source_map(self):
8584

8685
# 2nd breakpoint again, which should be valid at this point
8786
response = self.dap_server.request_setBreakpoints(
88-
Source(new_other_path), [other_line]
87+
Source.build(path=new_other_path), [other_line]
8988
)
9089
breakpoints = response["body"]["breakpoints"]
9190
breakpoint = breakpoints[0]
@@ -129,7 +128,9 @@ def test_set_and_clear(self):
129128
self.build_and_launch(program)
130129

131130
# Set 3 breakpoints and verify that they got set correctly
132-
response = self.dap_server.request_setBreakpoints(Source(self.main_path), lines)
131+
response = self.dap_server.request_setBreakpoints(
132+
Source.build(path=self.main_path), lines
133+
)
133134
line_to_id = {}
134135
breakpoints = response["body"]["breakpoints"]
135136
self.assertEqual(
@@ -154,7 +155,9 @@ def test_set_and_clear(self):
154155
lines.remove(second_line)
155156
# Set 2 breakpoints and verify that the previous breakpoints that were
156157
# set above are still set.
157-
response = self.dap_server.request_setBreakpoints(Source(self.main_path), lines)
158+
response = self.dap_server.request_setBreakpoints(
159+
Source.build(path=self.main_path), lines
160+
)
158161
breakpoints = response["body"]["breakpoints"]
159162
self.assertEqual(
160163
len(breakpoints),
@@ -199,7 +202,9 @@ def test_set_and_clear(self):
199202
# Now clear all breakpoints for the source file by passing down an
200203
# empty lines array
201204
lines = []
202-
response = self.dap_server.request_setBreakpoints(Source(self.main_path), lines)
205+
response = self.dap_server.request_setBreakpoints(
206+
Source.build(path=self.main_path), lines
207+
)
203208
breakpoints = response["body"]["breakpoints"]
204209
self.assertEqual(
205210
len(breakpoints),
@@ -219,7 +224,9 @@ def test_set_and_clear(self):
219224
# Now set a breakpoint again in the same source file and verify it
220225
# was added.
221226
lines = [second_line]
222-
response = self.dap_server.request_setBreakpoints(Source(self.main_path), lines)
227+
response = self.dap_server.request_setBreakpoints(
228+
Source.build(path=self.main_path), lines
229+
)
223230
if response:
224231
breakpoints = response["body"]["breakpoints"]
225232
self.assertEqual(
@@ -270,7 +277,9 @@ def test_clear_breakpoints_unset_breakpoints(self):
270277
self.build_and_launch(program)
271278

272279
# Set one breakpoint and verify that it got set correctly.
273-
response = self.dap_server.request_setBreakpoints(Source(self.main_path), lines)
280+
response = self.dap_server.request_setBreakpoints(
281+
Source.build(path=self.main_path), lines
282+
)
274283
line_to_id = {}
275284
breakpoints = response["body"]["breakpoints"]
276285
self.assertEqual(
@@ -286,7 +295,9 @@ def test_clear_breakpoints_unset_breakpoints(self):
286295
# Now clear all breakpoints for the source file by not setting the
287296
# lines array.
288297
lines = None
289-
response = self.dap_server.request_setBreakpoints(Source(self.main_path), lines)
298+
response = self.dap_server.request_setBreakpoints(
299+
Source.build(path=self.main_path), lines
300+
)
290301
breakpoints = response["body"]["breakpoints"]
291302
self.assertEqual(len(breakpoints), 0, "expect no source breakpoints")
292303

@@ -362,7 +373,7 @@ def test_column_breakpoints(self):
362373
# Set two breakpoints on the loop line at different columns.
363374
columns = [13, 39]
364375
response = self.dap_server.request_setBreakpoints(
365-
Source(self.main_path),
376+
Source.build(path=self.main_path),
366377
[loop_line, loop_line],
367378
list({"column": c} for c in columns),
368379
)

0 commit comments

Comments
 (0)