[Lldb-commits] [lldb] [lldb-dap] Refactor lldb-dap.cpp to not use global DAP variable. (PR #116272)

via lldb-commits lldb-commits at lists.llvm.org
Thu Nov 14 11:58:25 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: John Harrison (ashgti)

<details>
<summary>Changes</summary>

This removes the global DAP variable and instead allocates a DAP instance in main. This should allow us to refactor lldb-dap to enable a server mode that accepts multiple connections.

---

Patch is 117.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/116272.diff


3 Files Affected:

- (modified) lldb/tools/lldb-dap/DAP.cpp (+4-6) 
- (modified) lldb/tools/lldb-dap/DAP.h (+1-3) 
- (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+543-543) 


``````````diff
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index bdb24fc78cfb64..aee6214857bd0d 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -32,8 +32,6 @@ using namespace lldb_dap;
 
 namespace lldb_dap {
 
-DAP g_dap;
-
 DAP::DAP()
     : broadcaster("lldb-dap"), exception_breakpoints(),
       focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
@@ -693,15 +691,15 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
   if (packet_type == "request") {
     const auto command = GetString(object, "command");
     auto handler_pos = request_handlers.find(command);
-    if (handler_pos != request_handlers.end()) {
-      handler_pos->second(object);
-      return true; // Success
-    } else {
+    if (handler_pos == request_handlers.end()) {
       if (log)
         *log << "error: unhandled command \"" << command.data() << "\""
              << std::endl;
       return false; // Fail
     }
+
+    handler_pos->second(*this, object);
+    return true; // Success
   }
 
   if (packet_type == "response") {
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 5381b3271ba96f..c6e86a59875ea2 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -63,7 +63,7 @@ enum DAPBroadcasterBits {
   eBroadcastBitStopProgressThread = 1u << 1
 };
 
-typedef void (*RequestCallback)(const llvm::json::Object &command);
+typedef void (*RequestCallback)(DAP &dap, const llvm::json::Object &command);
 typedef void (*ResponseCallback)(llvm::Expected<llvm::json::Value> value);
 
 enum class PacketStatus {
@@ -353,8 +353,6 @@ struct DAP {
   void SendJSON(const std::string &json_str);
 };
 
-extern DAP g_dap;
-
 } // namespace lldb_dap
 
 #endif
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index fc22ec03b672e6..055a012ed51c6a 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -24,7 +24,6 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
@@ -119,34 +118,34 @@ constexpr int StackPageSize = 20;
 
 /// Prints a welcome message on the editor if the preprocessor variable
 /// LLDB_DAP_WELCOME_MESSAGE is defined.
-static void PrintWelcomeMessage() {
+static void PrintWelcomeMessage(DAP &dap) {
 #ifdef LLDB_DAP_WELCOME_MESSAGE
-  g_dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE);
+  dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE);
 #endif
 }
 
-lldb::SBValueList *GetTopLevelScope(int64_t variablesReference) {
+lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) {
   switch (variablesReference) {
   case VARREF_LOCALS:
-    return &g_dap.variables.locals;
+    return &dap.variables.locals;
   case VARREF_GLOBALS:
-    return &g_dap.variables.globals;
+    return &dap.variables.globals;
   case VARREF_REGS:
-    return &g_dap.variables.registers;
+    return &dap.variables.registers;
   default:
     return nullptr;
   }
 }
 
-SOCKET AcceptConnection(int portno) {
+SOCKET AcceptConnection(DAP &dap, int portno) {
   // Accept a socket connection from any host on "portno".
   SOCKET newsockfd = -1;
   struct sockaddr_in serv_addr, cli_addr;
   SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0) {
-    if (g_dap.log)
-      *g_dap.log << "error: opening socket (" << strerror(errno) << ")"
-                 << std::endl;
+    if (dap.log)
+      *dap.log << "error: opening socket (" << strerror(errno) << ")"
+               << std::endl;
   } else {
     memset((char *)&serv_addr, 0, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
@@ -154,9 +153,9 @@ SOCKET AcceptConnection(int portno) {
     serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
-      if (g_dap.log)
-        *g_dap.log << "error: binding socket (" << strerror(errno) << ")"
-                   << std::endl;
+      if (dap.log)
+        *dap.log << "error: binding socket (" << strerror(errno) << ")"
+                 << std::endl;
     } else {
       listen(sockfd, 5);
       socklen_t clilen = sizeof(cli_addr);
@@ -164,9 +163,8 @@ SOCKET AcceptConnection(int portno) {
           llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
                                       (struct sockaddr *)&cli_addr, &clilen);
       if (newsockfd < 0)
-        if (g_dap.log)
-          *g_dap.log << "error: accept (" << strerror(errno) << ")"
-                     << std::endl;
+        if (dap.log)
+          *dap.log << "error: accept (" << strerror(errno) << ")" << std::endl;
     }
 #if defined(_WIN32)
     closesocket(sockfd);
@@ -190,66 +188,65 @@ std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
 }
 
 // Send a "exited" event to indicate the process has exited.
-void SendProcessExitedEvent(lldb::SBProcess &process) {
+void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process) {
   llvm::json::Object event(CreateEventObject("exited"));
   llvm::json::Object body;
   body.try_emplace("exitCode", (int64_t)process.GetExitStatus());
   event.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(event)));
+  dap.SendJSON(llvm::json::Value(std::move(event)));
 }
 
-void SendThreadExitedEvent(lldb::tid_t tid) {
+void SendThreadExitedEvent(DAP &dap, lldb::tid_t tid) {
   llvm::json::Object event(CreateEventObject("thread"));
   llvm::json::Object body;
   body.try_emplace("reason", "exited");
   body.try_emplace("threadId", (int64_t)tid);
   event.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(event)));
+  dap.SendJSON(llvm::json::Value(std::move(event)));
 }
 
 // Send a "continued" event to indicate the process is in the running state.
-void SendContinuedEvent() {
-  lldb::SBProcess process = g_dap.target.GetProcess();
+void SendContinuedEvent(DAP &dap) {
+  lldb::SBProcess process = dap.target.GetProcess();
   if (!process.IsValid()) {
     return;
   }
 
   // If the focus thread is not set then we haven't reported any thread status
   // to the client, so nothing to report.
-  if (!g_dap.configuration_done_sent ||
-      g_dap.focus_tid == LLDB_INVALID_THREAD_ID) {
+  if (!dap.configuration_done_sent || dap.focus_tid == LLDB_INVALID_THREAD_ID) {
     return;
   }
 
   llvm::json::Object event(CreateEventObject("continued"));
   llvm::json::Object body;
-  body.try_emplace("threadId", (int64_t)g_dap.focus_tid);
+  body.try_emplace("threadId", (int64_t)dap.focus_tid);
   body.try_emplace("allThreadsContinued", true);
   event.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(event)));
+  dap.SendJSON(llvm::json::Value(std::move(event)));
 }
 
 // Send a "terminated" event to indicate the process is done being
 // debugged.
-void SendTerminatedEvent() {
+void SendTerminatedEvent(DAP &dap) {
   // Prevent races if the process exits while we're being asked to disconnect.
-  llvm::call_once(g_dap.terminated_event_flag, [&] {
-    g_dap.RunTerminateCommands();
+  llvm::call_once(dap.terminated_event_flag, [&] {
+    dap.RunTerminateCommands();
     // Send a "terminated" event
-    llvm::json::Object event(CreateTerminatedEventObject(g_dap.target));
-    g_dap.SendJSON(llvm::json::Value(std::move(event)));
+    llvm::json::Object event(CreateTerminatedEventObject(dap.target));
+    dap.SendJSON(llvm::json::Value(std::move(event)));
   });
 }
 
 // Send a thread stopped event for all threads as long as the process
 // is stopped.
-void SendThreadStoppedEvent() {
-  lldb::SBProcess process = g_dap.target.GetProcess();
+void SendThreadStoppedEvent(DAP &dap) {
+  lldb::SBProcess process = dap.target.GetProcess();
   if (process.IsValid()) {
     auto state = process.GetState();
     if (state == lldb::eStateStopped) {
       llvm::DenseSet<lldb::tid_t> old_thread_ids;
-      old_thread_ids.swap(g_dap.thread_ids);
+      old_thread_ids.swap(dap.thread_ids);
       uint32_t stop_id = process.GetStopID();
       const uint32_t num_threads = process.GetNumThreads();
 
@@ -265,10 +262,10 @@ void SendThreadStoppedEvent() {
         const lldb::tid_t tid = thread.GetThreadID();
         const bool has_reason = ThreadHasStopReason(thread);
         // If the focus thread doesn't have a stop reason, clear the thread ID
-        if (tid == g_dap.focus_tid) {
+        if (tid == dap.focus_tid) {
           focus_thread_exists = true;
           if (!has_reason)
-            g_dap.focus_tid = LLDB_INVALID_THREAD_ID;
+            dap.focus_tid = LLDB_INVALID_THREAD_ID;
         }
         if (has_reason) {
           ++num_threads_with_reason;
@@ -277,47 +274,46 @@ void SendThreadStoppedEvent() {
         }
       }
 
-      // We will have cleared g_dap.focus_tid if the focus thread doesn't have
+      // We will have cleared dap.focus_tid if the focus thread doesn't have
       // a stop reason, so if it was cleared, or wasn't set, or doesn't exist,
       // then set the focus thread to the first thread with a stop reason.
-      if (!focus_thread_exists || g_dap.focus_tid == LLDB_INVALID_THREAD_ID)
-        g_dap.focus_tid = first_tid_with_reason;
+      if (!focus_thread_exists || dap.focus_tid == LLDB_INVALID_THREAD_ID)
+        dap.focus_tid = first_tid_with_reason;
 
       // If no threads stopped with a reason, then report the first one so
       // we at least let the UI know we stopped.
       if (num_threads_with_reason == 0) {
         lldb::SBThread thread = process.GetThreadAtIndex(0);
-        g_dap.focus_tid = thread.GetThreadID();
-        g_dap.SendJSON(CreateThreadStopped(g_dap, thread, stop_id));
+        dap.focus_tid = thread.GetThreadID();
+        dap.SendJSON(CreateThreadStopped(dap, thread, stop_id));
       } else {
         for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
           lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
-          g_dap.thread_ids.insert(thread.GetThreadID());
+          dap.thread_ids.insert(thread.GetThreadID());
           if (ThreadHasStopReason(thread)) {
-            g_dap.SendJSON(CreateThreadStopped(g_dap, thread, stop_id));
+            dap.SendJSON(CreateThreadStopped(dap, thread, stop_id));
           }
         }
       }
 
       for (auto tid : old_thread_ids) {
-        auto end = g_dap.thread_ids.end();
-        auto pos = g_dap.thread_ids.find(tid);
+        auto end = dap.thread_ids.end();
+        auto pos = dap.thread_ids.find(tid);
         if (pos == end)
-          SendThreadExitedEvent(tid);
+          SendThreadExitedEvent(dap, tid);
       }
     } else {
-      if (g_dap.log)
-        *g_dap.log << "error: SendThreadStoppedEvent() when process"
-                      " isn't stopped ("
-                   << lldb::SBDebugger::StateAsCString(state) << ')'
-                   << std::endl;
+      if (dap.log)
+        *dap.log << "error: SendThreadStoppedEvent() when process"
+                    " isn't stopped ("
+                 << lldb::SBDebugger::StateAsCString(state) << ')' << std::endl;
     }
   } else {
-    if (g_dap.log)
-      *g_dap.log << "error: SendThreadStoppedEvent() invalid process"
-                 << std::endl;
+    if (dap.log)
+      *dap.log << "error: SendThreadStoppedEvent() invalid process"
+               << std::endl;
   }
-  g_dap.RunStopCommands();
+  dap.RunStopCommands();
 }
 
 // "ProcessEvent": {
@@ -374,14 +370,14 @@ void SendThreadStoppedEvent() {
 //     }
 //   ]
 // }
-void SendProcessEvent(LaunchMethod launch_method) {
-  lldb::SBFileSpec exe_fspec = g_dap.target.GetExecutable();
+void SendProcessEvent(DAP &dap, LaunchMethod launch_method) {
+  lldb::SBFileSpec exe_fspec = dap.target.GetExecutable();
   char exe_path[PATH_MAX];
   exe_fspec.GetPath(exe_path, sizeof(exe_path));
   llvm::json::Object event(CreateEventObject("process"));
   llvm::json::Object body;
   EmplaceSafeString(body, "name", std::string(exe_path));
-  const auto pid = g_dap.target.GetProcess().GetProcessID();
+  const auto pid = dap.target.GetProcess().GetProcessID();
   body.try_emplace("systemProcessId", (int64_t)pid);
   body.try_emplace("isLocalProcess", true);
   const char *startMethod = nullptr;
@@ -398,31 +394,31 @@ void SendProcessEvent(LaunchMethod launch_method) {
   }
   body.try_emplace("startMethod", startMethod);
   event.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(event)));
+  dap.SendJSON(llvm::json::Value(std::move(event)));
 }
 
 // Grab any STDOUT and STDERR from the process and send it up to VS Code
 // via an "output" event to the "stdout" and "stderr" categories.
-void SendStdOutStdErr(lldb::SBProcess &process) {
+void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process) {
   char buffer[OutputBufferSize];
   size_t count;
   while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0)
-    g_dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
+    dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
   while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0)
-    g_dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
+    dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
 }
 
-void ProgressEventThreadFunction() {
+void ProgressEventThreadFunction(DAP &dap) {
   lldb::SBListener listener("lldb-dap.progress.listener");
-  g_dap.debugger.GetBroadcaster().AddListener(
+  dap.debugger.GetBroadcaster().AddListener(
       listener, lldb::SBDebugger::eBroadcastBitProgress);
-  g_dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread);
+  dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread);
   lldb::SBEvent event;
   bool done = false;
   while (!done) {
     if (listener.WaitForEvent(1, event)) {
       const auto event_mask = event.GetType();
-      if (event.BroadcasterMatchesRef(g_dap.broadcaster)) {
+      if (event.BroadcasterMatchesRef(dap.broadcaster)) {
         if (event_mask & eBroadcastBitStopProgressThread) {
           done = true;
         }
@@ -434,7 +430,7 @@ void ProgressEventThreadFunction() {
         const char *message = lldb::SBDebugger::GetProgressFromEvent(
             event, progress_id, completed, total, is_debugger_specific);
         if (message)
-          g_dap.SendProgressEvent(progress_id, message, completed, total);
+          dap.SendProgressEvent(progress_id, message, completed, total);
       }
     }
   }
@@ -445,9 +441,9 @@ void ProgressEventThreadFunction() {
 // "FILE *" to output packets back to VS Code and they have mutexes in them
 // them prevent multiple threads from writing simultaneously so no locking
 // is required.
-void EventThreadFunction() {
+void EventThreadFunction(DAP &dap) {
   lldb::SBEvent event;
-  lldb::SBListener listener = g_dap.debugger.GetListener();
+  lldb::SBListener listener = dap.debugger.GetListener();
   bool done = false;
   while (!done) {
     if (listener.WaitForEvent(1, event)) {
@@ -483,50 +479,50 @@ void EventThreadFunction() {
             // stop events which we do not want to send an event for. We will
             // manually send a stopped event in request_configurationDone(...)
             // so don't send any before then.
-            if (g_dap.configuration_done_sent) {
+            if (dap.configuration_done_sent) {
               // Only report a stopped event if the process was not
               // automatically restarted.
               if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
-                SendStdOutStdErr(process);
-                SendThreadStoppedEvent();
+                SendStdOutStdErr(dap, process);
+                SendThreadStoppedEvent(dap);
               }
             }
             break;
           case lldb::eStateRunning:
-            g_dap.WillContinue();
-            SendContinuedEvent();
+            dap.WillContinue();
+            SendContinuedEvent(dap);
             break;
           case lldb::eStateExited:
             lldb::SBStream stream;
             process.GetStatus(stream);
-            g_dap.SendOutput(OutputType::Console, stream.GetData());
+            dap.SendOutput(OutputType::Console, stream.GetData());
 
             // When restarting, we can get an "exited" event for the process we
             // just killed with the old PID, or even with no PID. In that case
             // we don't have to terminate the session.
             if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID ||
-                process.GetProcessID() == g_dap.restarting_process_id) {
-              g_dap.restarting_process_id = LLDB_INVALID_PROCESS_ID;
+                process.GetProcessID() == dap.restarting_process_id) {
+              dap.restarting_process_id = LLDB_INVALID_PROCESS_ID;
             } else {
               // Run any exit LLDB commands the user specified in the
               // launch.json
-              g_dap.RunExitCommands();
-              SendProcessExitedEvent(process);
-              SendTerminatedEvent();
+              dap.RunExitCommands();
+              SendProcessExitedEvent(dap, process);
+              SendTerminatedEvent(dap);
               done = true;
             }
             break;
           }
         } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
                    (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
-          SendStdOutStdErr(process);
+          SendStdOutStdErr(dap, process);
         }
       } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
         if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
           auto event_type =
               lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
           auto bp = Breakpoint(
-              g_dap, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
+              dap, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
           // If the breakpoint was originated from the IDE, it will have the
           // BreakpointBase::GetBreakpointLabel() label attached. Regardless
           // of wether the locations were added or removed, the breakpoint
@@ -548,10 +544,10 @@ void EventThreadFunction() {
             body.try_emplace("breakpoint", source_bp);
             body.try_emplace("reason", "changed");
             bp_event.try_emplace("body", std::move(body));
-            g_dap.SendJSON(llvm::json::Value(std::move(bp_event)));
+            dap.SendJSON(llvm::json::Value(std::move(bp_event)));
           }
         }
-      } else if (event.BroadcasterMatchesRef(g_dap.broadcaster)) {
+      } else if (event.BroadcasterMatchesRef(dap.broadcaster)) {
         if (event_mask & eBroadcastBitStopEventThread) {
           done = true;
         }
@@ -560,9 +556,11 @@ void EventThreadFunction() {
   }
 }
 
-lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
+lldb::SBValue FindVariable(DAP &dap, uint64_t variablesReference,
+                           llvm::StringRef name) {
   lldb::SBValue variable;
-  if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) {
+  if (lldb::SBValueList *top_scope =
+          GetTopLevelScope(dap, variablesReference)) {
     bool is_duplicated_variable_name = name.contains(" @");
     // variablesReference is one of our scopes, not an actual variable it is
     // asking for a variable in locals or globals or registers
@@ -584,7 +582,7 @@ lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
 
     // We have a named item within an actual variable so we need to find it
     // withing the container variable by name.
-    lldb::SBValue container = g_dap.variables.GetVariable(variablesReference);
+    lldb::SBValue container = dap.variables.GetVariable(variablesReference);
     variable = container.GetChildMemberWithName(name.data());
     if (!variable.IsValid()) {
       if (name.starts_with("[")) {
@@ -602,7 +600,7 @@ lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
 
 // Both attach and launch take a either a sourcePath or sourceMap
 // argument (or neither), from which we need to set the target.source-map.
-void SetSourceMapFromArguments(const llvm::json::Object &arguments)...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/116272


More information about the lldb-commits mailing list