https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/209936
>From d38347a3796893368da4636484e094d9ba56b6cf Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Wed, 15 Jul 2026 09:32:52 +0100 Subject: [PATCH 1/2] [lldb-dap] Miragte the DAP step and stop hooks tests --- .../API/tools/lldb-dap/step/TestDAP_step.py | 158 +++++++++--------- .../stepInTargets/TestDAP_stepInTargets.py | 118 +++++-------- .../lldb-dap/stop-hooks/TestDAP_stop_hooks.py | 20 ++- 3 files changed, 128 insertions(+), 168 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py index 5c055f679aedc..19bf7e87a235f 100644 --- a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py +++ b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py @@ -2,122 +2,114 @@ Test lldb-dap setBreakpoints request """ +from lldbsuite.test.decorators import skipIfWindows +from lldbsuite.test.lldbtest import line_number +from lldbsuite.test.tools.lldb_dap.types import LaunchArgs +from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase -import dap_server -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil -import lldbdap_testcase - -class TestDAP_step(lldbdap_testcase.DAPTestCaseBase): +class TestDAP_step(DAPTestCaseBase): @skipIfWindows def test_step(self): """ Tests the stepping in/out/over in threads. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program) - source = "main.cpp" - # source_path = os.path.join(os.getcwd(), source) + session = self.build_and_create_session() + source = self.getSourcePath("main.cpp") breakpoint1_line = line_number(source, "// breakpoint 1") lines = [breakpoint1_line] - # Set breakpoint in the thread function so we can step the threads - 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) - threads = self.dap_server.get_threads() - for thread in threads: - if "reason" in thread: - reason = thread["reason"] - if reason == "breakpoint": - # We have a thread that is stopped at our breakpoint. - # Get the value of "x" and get the source file and line. - # These will help us determine if we are stepping - # correctly. If we step a thread correctly we will verify - # the correct falue for x as it progresses through the - # program. - tid = thread["id"] - x1 = self.get_local_as_int("x", threadId=tid) - (src1, line1) = self.get_source_and_line(threadId=tid) - # Now step into the "recurse()" function call again and - # verify, using the new value of "x" and the source file - # and line if we stepped correctly - self.stepIn(threadId=tid, waitForStop=True) - x2 = self.get_local_as_int("x", threadId=tid) - (src2, line2) = self.get_source_and_line(threadId=tid) - self.assertEqual(x1, x2 + 1, "verify step in variable") - self.assertLess(line2, line1, "verify step in line") - self.assertEqual(src1, src2, "verify step in source") + # Set breakpoint in the thread function so we can step the threads. + with session.configure(LaunchArgs(program)) as ctx: + session.resolve_source_breakpoints(source, lines) + process_event = ctx.process_event + stop_event = session.verify_stopped_on_breakpoint(after=process_event) + + # We have a thread that is stopped at our breakpoint. + # Get the value of "x" and get the source file and line. + # These will help us determine if we are stepping + # correctly. If we step a thread correctly we will verify + # the correct value for x as it progresses through the + # program. + thread = session.thread_context_from(stop_event) + top_frame = thread.top_frame() + x1 = top_frame.locals["x"].value_as_int + src1, line1 = top_frame.source_and_line() + + # Now step into the "recurse()" function call again and + # verify, using the new value of "x" and the source file + # and line if we stepped correctly. + thread.step_in() + top_frame = thread.top_frame() + x2 = top_frame.locals["x"].value_as_int + src2, line2 = top_frame.source_and_line() - # Now step out and verify - self.stepOut(threadId=tid, waitForStop=True) - x3 = self.get_local_as_int("x", threadId=tid) - (src3, line3) = self.get_source_and_line(threadId=tid) - self.assertEqual(x1, x3, "verify step out variable") - self.assertGreaterEqual(line3, line1, "verify step out line") - self.assertEqual(src1, src3, "verify step in source") + self.assertEqual(x1, x2 + 1, "verify step in variable") + self.assertLess(line2, line1, "verify step in line") + self.assertEqual(src1, src2, "verify step in source") - # Step over and verify - self.stepOver(threadId=tid, waitForStop=True) - x4 = self.get_local_as_int("x", threadId=tid) - (src4, line4) = self.get_source_and_line(threadId=tid) - self.assertEqual(x4, x3, "verify step over variable") - self.assertGreater(line4, line3, "verify step over line") - self.assertEqual(src1, src4, "verify step over source") + # Now step out and verify. + thread.step_out() + top_frame = thread.top_frame() + x3 = top_frame.locals["x"].value_as_int + (src3, line3) = top_frame.source_and_line() + self.assertEqual(x1, x3, "verify step out variable") + self.assertGreaterEqual(line3, line1, "verify step out line") + self.assertEqual(src1, src3, "verify step in source") - # Step a single assembly instruction. - # Unfortunately, there is no portable way to verify the correct - # stepping behavior here, because the generated assembly code - # depends highly on the compiler, its version, the operating - # system, and many more factors. - self.stepOver( - threadId=tid, waitForStop=True, granularity="instruction" - ) - self.stepIn( - threadId=tid, waitForStop=True, granularity="instruction" - ) + # Step over and verify. + thread.step_over() + top_frame = thread.top_frame() + x4 = top_frame.locals["x"].value_as_int + (src4, line4) = top_frame.source_and_line() + self.assertEqual(x4, x3, "verify step over variable") + self.assertGreater(line4, line3, "verify step over line") + self.assertEqual(src1, src4, "verify step over source") - # only step one thread that is at the breakpoint and stop - break + # Step a single assembly instruction. + # Unfortunately, there is no portable way to verify the correct + # stepping behavior here, because the generated assembly code + # depends highly on the compiler, its version, the operating + # system, and many more factors. + thread.step_over(granularity="instruction") + thread.step_in(granularity="instruction") def test_step_over_inlined_function(self): """ Test stepping over when the program counter is in another file. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program) - source = "main.cpp" + session = self.build_and_create_session() + source = self.getSourcePath("main.cpp") + breakpoint_lines = [line_number(source, "// breakpoint 2")] step_over_pos = line_number(source, "// position_after_step_over") - breakpoint_ids = self.set_source_breakpoints(source, breakpoint_lines) - self.assertEqual( - len(breakpoint_ids), - len(breakpoint_lines), - "expect correct number of breakpoints.", - ) - self.continue_to_breakpoints(breakpoint_ids) + with session.configure(LaunchArgs(program)) as ctx: + session.resolve_source_breakpoints(source, breakpoint_lines) + process_event = ctx.process_event + stop_event = session.verify_stopped_on_breakpoint(after=process_event) - thread_id = self.dap_server.get_thread_id() - self.stepOver(thread_id) + thread_ctx = session.thread_context_from(stop_event) + thread_ctx.step_over() levels = 1 - frames = self.get_stackFrames(thread_id, 0, levels) + frames = thread_ctx.frames(startFrame=0, levels=levels) self.assertEqual(len(frames), levels, "expect current number of frame levels.") - top_frame = frames[0] + + top_frame = frames[0].frame + top_frame_source = self.expect_not_none(top_frame.source) self.assertEqual( - top_frame["source"]["name"], source, "expect we are in the same file." + top_frame_source.name, source, "expect we are in the same file." ) + top_frame_path = self.expect_not_none(top_frame_source.path) self.assertTrue( - top_frame["source"]["path"].endswith(source), + top_frame_path.endswith(source), f"expect path ending with '{source}'.", ) self.assertEqual( - top_frame["line"], + top_frame.line, step_over_pos, f"expect step_over on line {step_over_pos}", ) - self.continue_to_exit() + session.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/stepInTargets/TestDAP_stepInTargets.py b/lldb/test/API/tools/lldb-dap/stepInTargets/TestDAP_stepInTargets.py index 03b79a805d341..ee6b3ccb0511c 100644 --- a/lldb/test/API/tools/lldb-dap/stepInTargets/TestDAP_stepInTargets.py +++ b/lldb/test/API/tools/lldb-dap/stepInTargets/TestDAP_stepInTargets.py @@ -2,14 +2,13 @@ Test lldb-dap stepInTargets request """ -import dap_server -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -import lldbdap_testcase -from lldbsuite.test import lldbutil +from lldbsuite.test.decorators import expectedFailureAll, no_match, skipIf +from lldbsuite.test.lldbtest import line_number +from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase +from lldbsuite.test.tools.lldb_dap.types import LaunchArgs, StepInTargetsArgs -class TestDAP_stepInTargets(lldbdap_testcase.DAPTestCaseBase): +class TestDAP_stepInTargets(DAPTestCaseBase): @expectedFailureAll(oslist=["windows"]) @skipIf(archs=no_match(["x86_64"])) # InstructionControlFlowKind for ARM is not supported yet. @@ -20,40 +19,23 @@ def test_basic(self): Tests the basic stepping in targets with directly calls. """ program = self.getBuildArtifact("a.out") - self.build_and_launch(program) - source = "main.cpp" + session = self.build_and_create_session() + source = self.getSourcePath("main.cpp") breakpoint_line = line_number(source, "// set breakpoint here") - lines = [breakpoint_line] - # Set breakpoint in the thread function so we can step the threads - 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) - - threads = self.dap_server.get_threads() - self.assertEqual(len(threads), 1, "expect one thread") - tid = threads[0]["id"] + # Set breakpoint in the thread function so we can step the threads. + with session.configure(LaunchArgs(program)) as ctx: + [bp1] = session.resolve_source_breakpoints(source, [breakpoint_line]) + stop_event = session.verify_stopped_on_breakpoint(bp1, after=ctx.process_event) - leaf_frame = self.dap_server.get_stackFrame() - self.assertIsNotNone(leaf_frame, "expect a leaf frame") + thread_ctxs = session.thread_context_from(stop_event) + frame_id = thread_ctxs.top_frame().frame.id # Request all step in targets list and verify the response. - step_in_targets_response = self.dap_server.request_stepInTargets( - leaf_frame["id"] - ) - self.assertEqual(step_in_targets_response["success"], True, "expect success") - self.assertIn( - "body", step_in_targets_response, "expect body field in response body" - ) - self.assertIn( - "targets", - step_in_targets_response["body"], - "expect targets field in response body", - ) + step_args = StepInTargetsArgs(frame_id) + step_in_targets_resp = session.send_request(step_args).result("expect success") + step_in_targets = step_in_targets_resp.body.targets - step_in_targets = step_in_targets_response["body"]["targets"] self.assertEqual(len(step_in_targets), 3, "expect 3 step in targets") # Verify the target names are correct. @@ -61,70 +43,54 @@ def test_basic(self): funcA_target = None funcB_target = None for target in step_in_targets[0:2]: - if "funcB" in target["label"]: + if "funcB" in target.label: funcB_target = target - elif "funcA" in target["label"]: + elif "funcA" in target.label: funcA_target = target else: self.fail(f"Unexpected step in target: {target}") self.assertIsNotNone(funcA_target, "expect funcA") self.assertIsNotNone(funcB_target, "expect funcB") - self.assertIn("foo", step_in_targets[2]["label"], "expect foo") + self.assertIn("foo", step_in_targets[2].label, "expect foo") # Choose to step into second target and verify that we are in the second target, # be it funcA or funcB. - self.stepIn(threadId=tid, targetId=step_in_targets[1]["id"], waitForStop=True) - leaf_frame = self.dap_server.get_stackFrame() - self.assertIsNotNone(leaf_frame, "expect a leaf frame") - self.assertEqual(step_in_targets[1]["label"], leaf_frame["name"]) + thread_ctxs.step_in(targetId=step_in_targets[1].id) + top_frame = thread_ctxs.top_frame().frame + self.assertIsNotNone(top_frame, "expect a top frame") + self.assertEqual(step_in_targets[1].label, top_frame.name) + + session.continue_to_exit() @skipIf(archs=no_match(["x86", "x86_64"])) def test_supported_capability_x86_arch(self): program = self.getBuildArtifact("a.out") - self.build_and_launch(program) - source = "main.cpp" + source = self.getSourcePath("main.cpp") + session = self.build_and_create_session() bp_lines = [line_number(source, "// set breakpoint here")] - breakpoint_ids = self.set_source_breakpoints(source, bp_lines) - self.assertEqual( - len(breakpoint_ids), len(bp_lines), "expect correct number of breakpoints" - ) - self.continue_to_breakpoints(breakpoint_ids) - is_supported = self.dap_server.get_capability("supportsStepInTargetsRequest") + with session.configure(LaunchArgs(program)) as ctx: + session.resolve_source_breakpoints(source, bp_lines) - self.assertEqual( - is_supported, - True, + session.verify_stopped_on_breakpoint(after=ctx.process_event) + self.assertTrue( + session.capabilities().supportsStepInTargetsRequest, f"expect capability `stepInTarget` is supported with architecture {self.getArchitecture()}", ) - # clear breakpoints. - self.set_source_breakpoints(source, []) - self.continue_to_exit() + session.continue_to_exit() @skipIf(archs=["x86", "x86_64"]) def test_supported_capability_other_archs(self): - program = self.getBuildArtifact("a.out") - self.build_and_launch(program) - source = "main.cpp" + program = self.getBuildArtifact("main.cpp") + source = self.getSourcePath("main.cpp") + session = self.build_and_create_session() bp_lines = [line_number(source, "// set breakpoint here")] - breakpoint_ids = self.set_source_breakpoints(source, bp_lines) - self.assertEqual( - len(breakpoint_ids), len(bp_lines), "expect correct number of breakpoints" - ) - self.continue_to_breakpoints(breakpoint_ids) - - try: - is_supported = self.dap_server.get_capability( - "supportsStepInTargetsRequest" - ) - except dap_server.NotSupportedError: - is_supported = False + with session.configure(LaunchArgs(program)) as ctx: + session.resolve_source_breakpoints(source, bp_lines) - self.assertEqual( - is_supported, - False, + session.verify_stopped_on_breakpoint(after=ctx.process_event) + self.assertFalse( + session.capabilities().supportsStepInTargetsRequest, f"expect capability `stepInTarget` is not supported with architecture {self.getArchitecture()}", ) - # clear breakpoints. - self.set_source_breakpoints(source, []) - self.continue_to_exit() + session.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py index d630e1d14c3a0..c8b1386e15927 100644 --- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py +++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py @@ -2,25 +2,27 @@ Test stop hooks """ -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -import lldbdap_testcase +from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase +from lldbsuite.test.tools.lldb_dap.types import LaunchArgs -class TestDAP_stop_hooks(lldbdap_testcase.DAPTestCaseBase): +class TestDAP_stop_hooks(DAPTestCaseBase): def test_stop_hooks_before_run(self): """ Test that there is no race condition between lldb-dap and stop hooks executor """ program = self.getBuildArtifact("a.out") - preRunCommands = ["target stop-hook add -o help"] - self.build_and_launch(program, preRunCommands=preRunCommands) - breakpoint_ids = self.set_function_breakpoints(["main"]) + session = self.build_and_create_session() + launch_args = LaunchArgs( + program, preRunCommands=["target stop-hook add -o help"] + ) + with session.configure(launch_args) as ctx: + breakpoint_ids = session.resolve_function_breakpoints(["main"]) # This request hangs if the race happens, because, in that case, the # command interpreter is in synchronous mode while lldb-dap expects # it to be in asynchronous mode, so, the process doesn't send the stop # event to "lldb.Debugger" listener (which is monitored by lldb-dap). - self.continue_to_breakpoints(breakpoint_ids) + session.verify_stopped_on_breakpoint(breakpoint_ids, after=ctx.process_event) - self.continue_to_exit() + session.continue_to_exit() >From 66f4cd568dc0af10d35096455c2aa103860cf1fa Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Thu, 16 Jul 2026 03:37:21 +0100 Subject: [PATCH 2/2] fix build issue --- lldb/test/API/tools/lldb-dap/step/TestDAP_step.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py index 19bf7e87a235f..e7f067a60768a 100644 --- a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py +++ b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py @@ -81,7 +81,7 @@ def test_step_over_inlined_function(self): """ program = self.getBuildArtifact("a.out") session = self.build_and_create_session() - source = self.getSourcePath("main.cpp") + source = "main.cpp" breakpoint_lines = [line_number(source, "// breakpoint 2")] step_over_pos = line_number(source, "// position_after_step_over") _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
