Skip to content

[lldb-dap] Support the Module Event #137380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

JDevlieghere
Copy link
Member

The module event indicates that some information about a module has changed. The event is supported by the Emacs and Visual Studio DAP clients. This PR adds support for emitting the event from lldb-dap.

Fixes #137058

The module event indicates that some information about a module has
changed. The event is supported by the Emacs and Visual Studio DAP
clients. This PR adds support for emitting the event from lldb-dap.

Fixes llvm#137058
@llvmbot
Copy link
Member

llvmbot commented Apr 25, 2025

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

The module event indicates that some information about a module has changed. The event is supported by the Emacs and Visual Studio DAP clients. This PR adds support for emitting the event from lldb-dap.

Fixes #137058


Full diff: https://github.com/llvm/llvm-project/pull/137380.diff

4 Files Affected:

  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+6)
  • (modified) lldb/test/API/tools/lldb-dap/module/TestDAP_module.py (+11)
  • (modified) lldb/tools/lldb-dap/DAP.cpp (+3-1)
  • (modified) lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp (+24)
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index 0f8a84461c9e7..5c43c91734b43 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -135,6 +135,7 @@ def __init__(self, recv, send, init_commands, log_file=None):
         self.breakpoint_events = []
         self.progress_events = []
         self.reverse_requests = []
+        self.module_events = []
         self.sequence = 1
         self.threads = None
         self.recv_thread.start()
@@ -255,6 +256,11 @@ def handle_recv_packet(self, packet):
                 # and 'progressEnd' events. Keep these around in case test
                 # cases want to verify them.
                 self.progress_events.append(packet)
+            elif event == "module":
+                # Module events indicate that some information about a module has changed.
+                self.module_events.append(packet)
+                # no need to add 'module' event packets to our packets list
+                return keepGoing
 
         elif packet_type == "response":
             if packet["command"] == "disconnect":
diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py
index a4e0f04d450d9..e839d46e1d114 100644
--- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py
+++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py
@@ -57,6 +57,17 @@ def checkSymbolsLoadedWithSize():
         self.assertEqual(program, program_module["path"])
         self.assertIn("addressRange", program_module)
 
+        # Collect all the module names we saw as events.
+        module_event_names = set()
+        for module_event in self.dap_server.module_events:
+            module_event_names.add(module_event["body"]["module"]["name"])
+        self.assertNotEqual(len(module_event_names), 0)
+
+        # Make sure we got an event for every active module.
+        for module in active_modules:
+            # assertIn doesn't work with set.
+            self.assertTrue(module in module_event_names)
+
     @skipIfWindows
     def test_modules(self):
         """
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index f8dbc4c1398e6..f866886c33014 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -692,7 +692,9 @@ void DAP::SetTarget(const lldb::SBTarget target) {
     lldb::SBListener listener = this->debugger.GetListener();
     listener.StartListeningForEvents(
         this->target.GetBroadcaster(),
-        lldb::SBTarget::eBroadcastBitBreakpointChanged);
+        lldb::SBTarget::eBroadcastBitBreakpointChanged |
+            lldb::SBTarget::eBroadcastBitModulesLoaded |
+            lldb::SBTarget::eBroadcastBitModulesUnloaded);
     listener.StartListeningForEvents(this->broadcaster,
                                      eBroadcastBitStopEventThread);
   }
diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
index 7d8ac676ba935..f98c4d743b2d8 100644
--- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
@@ -15,6 +15,8 @@
 #include "lldb/API/SBEvent.h"
 #include "lldb/API/SBListener.h"
 #include "lldb/API/SBStream.h"
+#include "lldb/API/SBTarget.h"
+#include <cstdint>
 
 using namespace lldb;
 using namespace lldb_dap::protocol;
@@ -193,6 +195,28 @@ static void EventThreadFunction(DAP &dap) {
                    (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
           SendStdOutStdErr(dap, process);
         }
+      } else if (lldb::SBTarget::EventIsTargetEvent(event)) {
+        if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded ||
+            event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded) {
+          const llvm::StringRef reason =
+              event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded
+                  ? "new"
+                  : "removed";
+          const uint32_t num_modules = SBTarget::GetNumModulesFromEvent(event);
+          for (uint32_t i = 0; i < num_modules; ++i) {
+            lldb::SBModule module =
+                SBTarget::GetModuleAtIndexFromEvent(i, event);
+            if (!module.IsValid())
+              continue;
+
+            llvm::json::Object body;
+            body.try_emplace("reason", reason);
+            body.try_emplace("module", CreateModule(dap.target, module));
+            llvm::json::Object module_event = CreateEventObject("module");
+            module_event.try_emplace("body", std::move(body));
+            dap.SendJSON(llvm::json::Value(std::move(module_event)));
+          }
+        }
       } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
         if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
           auto event_type =

@@ -692,7 +692,9 @@ void DAP::SetTarget(const lldb::SBTarget target) {
lldb::SBListener listener = this->debugger.GetListener();
listener.StartListeningForEvents(
this->target.GetBroadcaster(),
lldb::SBTarget::eBroadcastBitBreakpointChanged);
lldb::SBTarget::eBroadcastBitBreakpointChanged |
lldb::SBTarget::eBroadcastBitModulesLoaded |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should handle when the symbols in the module changes eBroadcastBitSymbolsLoaded and eBroadcastBitSymbolsChanged since symbol changes are reported when CreateModule is called

This corresponds to the module event reason changed

@JDevlieghere JDevlieghere requested a review from da-viper April 25, 2025 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support the Module Event in lldb-dap
4 participants