https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/163976
>From c20a05867dc386698c28d6244b88959686b29c48 Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Fri, 17 Oct 2025 11:39:20 +0100 Subject: [PATCH 1/3] [lldb-dap] Send an Invalidated event on thread stack change. When the user send `thread return <expr>` command this changes the stack length. but the UI does not update. Send stack invalidated event to update the stack --- lldb/tools/lldb-dap/DAP.cpp | 19 +++++++++++++++++++ lldb/tools/lldb-dap/DAP.h | 1 + lldb/tools/lldb-dap/EventHelper.cpp | 8 +++++++- lldb/tools/lldb-dap/EventHelper.h | 5 ++++- .../lldb-dap/Protocol/ProtocolEvents.cpp | 2 +- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index f76656e98ca01..61226cceb6db0 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1368,6 +1368,12 @@ void DAP::EventThread() { broadcaster.AddListener(listener, eBroadcastBitStopEventThread); debugger.GetBroadcaster().AddListener( listener, lldb::eBroadcastBitError | lldb::eBroadcastBitWarning); + + // listen for thread events. + listener.StartListeningForEventClass( + debugger, lldb::SBThread::GetBroadcasterClassName(), + lldb::SBThread::eBroadcastBitStackChanged); + bool done = false; while (!done) { if (listener.WaitForEvent(1, event)) { @@ -1503,6 +1509,9 @@ void DAP::EventThread() { SendJSON(llvm::json::Value(std::move(bp_event))); } } + + } else if (lldb::SBThread::EventIsThreadEvent(event)) { + HandleThreadEvent(event); } else if (event_mask & lldb::eBroadcastBitError || event_mask & lldb::eBroadcastBitWarning) { lldb::SBStructuredData data = @@ -1522,6 +1531,16 @@ void DAP::EventThread() { } } +void DAP::HandleThreadEvent(const lldb::SBEvent &event) { + uint32_t event_type = event.GetType(); + + if (event_type & lldb::SBThread::eBroadcastBitStackChanged) { + const lldb::SBThread evt_thread = lldb::SBThread::GetThreadFromEvent(event); + SendInvalidatedEvent(*this, {InvalidatedEventBody::eAreaStacks}, + evt_thread.GetThreadID()); + } +} + std::vector<protocol::Breakpoint> DAP::SetSourceBreakpoints( const protocol::Source &source, const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index a90ddf59671ee..bf2c3f146a396 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -460,6 +460,7 @@ struct DAP final : public DAPTransport::MessageHandler { /// Event threads. /// @{ void EventThread(); + void HandleThreadEvent(const lldb::SBEvent &event); void ProgressEventThread(); std::thread event_thread; diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index 2b9ed229405a8..04ed8a052bd76 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -15,6 +15,7 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "lldb/API/SBFileSpec.h" +#include "lldb/lldb-defines.h" #include "llvm/Support/Error.h" #include <utility> @@ -276,11 +277,16 @@ void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process) { } void SendInvalidatedEvent( - DAP &dap, llvm::ArrayRef<protocol::InvalidatedEventBody::Area> areas) { + DAP &dap, llvm::ArrayRef<protocol::InvalidatedEventBody::Area> areas, + lldb::tid_t tid) { if (!dap.clientFeatures.contains(protocol::eClientFeatureInvalidatedEvent)) return; protocol::InvalidatedEventBody body; body.areas = areas; + + if (tid != LLDB_INVALID_THREAD_ID) + body.threadId = tid; + dap.Send(protocol::Event{"invalidated", std::move(body)}); } diff --git a/lldb/tools/lldb-dap/EventHelper.h b/lldb/tools/lldb-dap/EventHelper.h index 48eb5af6bd0b9..be783d032a5ae 100644 --- a/lldb/tools/lldb-dap/EventHelper.h +++ b/lldb/tools/lldb-dap/EventHelper.h @@ -11,6 +11,8 @@ #include "DAPForward.h" #include "Protocol/ProtocolEvents.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Error.h" @@ -35,7 +37,8 @@ void SendContinuedEvent(DAP &dap); void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process); void SendInvalidatedEvent( - DAP &dap, llvm::ArrayRef<protocol::InvalidatedEventBody::Area> areas); + DAP &dap, llvm::ArrayRef<protocol::InvalidatedEventBody::Area> areas, + lldb::tid_t tid = LLDB_INVALID_THREAD_ID); void SendMemoryEvent(DAP &dap, lldb::SBValue variable); diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolEvents.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolEvents.cpp index b896eca817be6..df6be06637a13 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolEvents.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolEvents.cpp @@ -51,7 +51,7 @@ llvm::json::Value toJSON(const InvalidatedEventBody::Area &IEBA) { llvm::json::Value toJSON(const InvalidatedEventBody &IEB) { json::Object Result{{"areas", IEB.areas}}; if (IEB.threadId) - Result.insert({"threadID", IEB.threadId}); + Result.insert({"threadId", IEB.threadId}); if (IEB.stackFrameId) Result.insert({"stackFrameId", IEB.stackFrameId}); return Result; >From 6e9df0544dbfcd32302d930c196ce8dca787546f Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Fri, 17 Oct 2025 16:00:36 +0100 Subject: [PATCH 2/3] [lldb-dap] add test case --- .../tools/lldb-dap/invalidated-event/Makefile | 3 + .../TestDAP_invalidatedEvent.py | 55 +++++++++++++++++++ .../tools/lldb-dap/invalidated-event/main.cpp | 9 +++ .../tools/lldb-dap/invalidated-event/other.h | 10 ++++ lldb/unittests/DAP/ProtocolTypesTest.cpp | 19 ++++--- 5 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/invalidated-event/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py create mode 100644 lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp create mode 100644 lldb/test/API/tools/lldb-dap/invalidated-event/other.h diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/Makefile b/lldb/test/API/tools/lldb-dap/invalidated-event/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py b/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py new file mode 100644 index 0000000000000..aef63ffe81060 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py @@ -0,0 +1,55 @@ +""" +Test lldb-dap recieves invalidated-events when the area such as +stack, variables, threads has changes but the client does not +know about it. +""" + +import lldbdap_testcase +from lldbsuite.test.lldbtest import line_number +from dap_server import Event + + +class TestDAP_invalidatedEvent(lldbdap_testcase.DAPTestCaseBase): + def verify_top_frame_name(self, frame_name: str): + all_frames = self.get_stackFrames() + self.assertGreaterEqual(len(all_frames), 1, "Expected at least one frame.") + top_frame_name = all_frames[0]["name"] + self.assertRegex(top_frame_name, f"{frame_name}.*") + + def test_invalidated_stack_area_event(self): + """ + Test an invalidated event for the stack area. + The event is sent when the command `thread return <expr>` is sent by the user. + """ + other_source = "other.h" + return_bp_line = line_number(other_source, "// thread return breakpoint") + + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + self.set_source_breakpoints(other_source, [return_bp_line]) + self.continue_to_next_stop() + + self.verify_top_frame_name("add") + thread_id = self.dap_server.get_thread_id() + self.assertIsNotNone(thread_id, "Exepected a thread id.") + + # run thread return + thread_command = "thread return 20" + eval_resp = self.dap_server.request_evaluate(thread_command, context="repl") + self.assertTrue(eval_resp["success"], f"Failed to evaluate `{thread_command}`.") + + # wait for the invalidated stack event. + stack_event = self.dap_server.wait_for_event(["invalidated"]) + self.assertIsNotNone(stack_event, "Expected an invalidated event.") + event_body: Event = stack_event["body"] + self.assertIn("stacks", event_body["areas"]) + self.assertIn("threadId", event_body.keys()) + self.assertEqual( + thread_id, + event_body["threadId"], + f"Expected the event from thread {thread_id}.", + ) + + # confirm we are back at the main frame. + self.verify_top_frame_name("main") + self.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp b/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp new file mode 100644 index 0000000000000..9fed5cf90f3f1 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp @@ -0,0 +1,9 @@ +#include "other.h" + +int main() { + int first = 5; + int second = 10; + const int result = add(first, second); + + return 0; +} \ No newline at end of file diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/other.h b/lldb/test/API/tools/lldb-dap/invalidated-event/other.h new file mode 100644 index 0000000000000..c3e242676612b --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/other.h @@ -0,0 +1,10 @@ +#ifndef OTHER_H +#define OTHER_H + +int add(int a, int b) { + int first = a; + int second = b; // thread return breakpoint + int result = first + second; + return result; +} +#endif // OTHER_H \ No newline at end of file diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp index a5ae856a185b7..8170abdd25bc6 100644 --- a/lldb/unittests/DAP/ProtocolTypesTest.cpp +++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp @@ -1079,14 +1079,17 @@ TEST(ProtocolTypesTest, InvalidatedEventBody) { body.areas = {InvalidatedEventBody::eAreaStacks, InvalidatedEventBody::eAreaThreads}; body.stackFrameId = 1; - StringRef json = R"({ - "areas": [ - "stacks", - "threads" - ], - "stackFrameId": 1 -})"; - EXPECT_EQ(json, pp(body)); + body.threadId = 20; + Expected<json::Value> expected = json::parse(R"({ + "areas": [ + "stacks", + "threads" + ], + "stackFrameId": 1, + "threadId": 20 + })"); + ASSERT_THAT_EXPECTED(expected, llvm::Succeeded()); + EXPECT_EQ(pp(*expected), pp(body)); } TEST(ProtocolTypesTest, MemoryEventBody) { >From bf6c3286105796ce0396b9667469d13a3bc0b8cf Mon Sep 17 00:00:00 2001 From: Ebuka Ezike <[email protected]> Date: Sun, 19 Oct 2025 18:56:40 +0100 Subject: [PATCH 3/3] [lldb-dap] add review changes --- .../lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py | 2 +- lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp | 2 +- lldb/test/API/tools/lldb-dap/invalidated-event/other.h | 2 +- lldb/tools/lldb-dap/EventHelper.cpp | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py b/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py index aef63ffe81060..8ba56b0bb27ca 100644 --- a/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/TestDAP_invalidatedEvent.py @@ -47,7 +47,7 @@ def test_invalidated_stack_area_event(self): self.assertEqual( thread_id, event_body["threadId"], - f"Expected the event from thread {thread_id}.", + f"Expected the event from thread {thread_id}.", ) # confirm we are back at the main frame. diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp b/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp index 9fed5cf90f3f1..c82f9532b7517 100644 --- a/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/main.cpp @@ -6,4 +6,4 @@ int main() { const int result = add(first, second); return 0; -} \ No newline at end of file +} diff --git a/lldb/test/API/tools/lldb-dap/invalidated-event/other.h b/lldb/test/API/tools/lldb-dap/invalidated-event/other.h index c3e242676612b..856db446d7b5a 100644 --- a/lldb/test/API/tools/lldb-dap/invalidated-event/other.h +++ b/lldb/test/API/tools/lldb-dap/invalidated-event/other.h @@ -7,4 +7,4 @@ int add(int a, int b) { int result = first + second; return result; } -#endif // OTHER_H \ No newline at end of file +#endif // OTHER_H diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index 04ed8a052bd76..3042d3293b482 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -15,7 +15,6 @@ #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "lldb/API/SBFileSpec.h" -#include "lldb/lldb-defines.h" #include "llvm/Support/Error.h" #include <utility> _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
