[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap to support running in a server mode, allowing multiple connections. (PR #114881)

John Harrison via lldb-commits lldb-commits at lists.llvm.org
Tue Nov 5 17:57:09 PST 2024


https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/114881

>From b65c30f2d2cd31298cf4dba7ae91eaadb44bf999 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Wed, 30 Oct 2024 17:35:36 -0700
Subject: [PATCH 1/5] [lldb-dap] Refactoring the lldb-dap to create a new DAP
 object per connection, or a single object when not in server mode.

This is a fairly large refactor of the lldb-dap to allow multiple DAP sessions from a single lldb-dap server.

The majority of the changes are around the removal of the g_dap instance and instead requiring all functions to either accept a DAP instance as a parameter or refactoring some code to not directly rely on the DAP object.

When running without a port, this should behavior the same as it did before.

When running with a port, the server will now accept each new connection and run the debug session to completion. In this mode, the server will continue until interrupted.
---
 lldb/tools/lldb-dap/Breakpoint.cpp            |    8 +-
 lldb/tools/lldb-dap/Breakpoint.h              |    9 +-
 lldb/tools/lldb-dap/BreakpointBase.cpp        |    6 +-
 lldb/tools/lldb-dap/BreakpointBase.h          |   11 +-
 lldb/tools/lldb-dap/DAP.cpp                   |  111 +-
 lldb/tools/lldb-dap/DAP.h                     |   19 +-
 lldb/tools/lldb-dap/DAPForward.h              |    4 +-
 lldb/tools/lldb-dap/ExceptionBreakpoint.cpp   |    6 +-
 lldb/tools/lldb-dap/ExceptionBreakpoint.h     |   12 +-
 lldb/tools/lldb-dap/FunctionBreakpoint.cpp    |    7 +-
 lldb/tools/lldb-dap/FunctionBreakpoint.h      |    4 +-
 lldb/tools/lldb-dap/InstructionBreakpoint.cpp |   11 +-
 lldb/tools/lldb-dap/InstructionBreakpoint.h   |   11 +-
 lldb/tools/lldb-dap/JSONUtils.cpp             |   80 +-
 lldb/tools/lldb-dap/JSONUtils.h               |   60 +-
 lldb/tools/lldb-dap/LLDBUtils.cpp             |   20 +-
 lldb/tools/lldb-dap/LLDBUtils.h               |   12 +-
 lldb/tools/lldb-dap/OutputRedirector.cpp      |    6 +-
 lldb/tools/lldb-dap/OutputRedirector.h        |   12 +-
 lldb/tools/lldb-dap/SourceBreakpoint.cpp      |   17 +-
 lldb/tools/lldb-dap/SourceBreakpoint.h        |    4 +-
 lldb/tools/lldb-dap/Watchpoint.cpp            |    9 +-
 lldb/tools/lldb-dap/Watchpoint.h              |    8 +-
 lldb/tools/lldb-dap/lldb-dap.cpp              | 1302 +++++++++--------
 24 files changed, 947 insertions(+), 802 deletions(-)

diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index 9ea7a42ca85a1e..aee2f87e2cc23e 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -7,11 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "Breakpoint.h"
-#include "DAP.h"
-#include "JSONUtils.h"
+
 #include "lldb/API/SBBreakpointLocation.h"
 #include "llvm/ADT/StringExtras.h"
 
+#include "DAP.h"
+#include "JSONUtils.h"
+
 using namespace lldb_dap;
 
 void Breakpoint::SetCondition() { bp.SetCondition(condition.c_str()); }
@@ -51,7 +53,7 @@ void Breakpoint::CreateJsonObject(llvm::json::Object &object) {
 
   if (bp_addr.IsValid()) {
     std::string formatted_addr =
-        "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(g_dap.target));
+        "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(bp.GetTarget()));
     object.try_emplace("instructionReference", formatted_addr);
     auto line_entry = bp_addr.GetLineEntry();
     const auto line = line_entry.GetLine();
diff --git a/lldb/tools/lldb-dap/Breakpoint.h b/lldb/tools/lldb-dap/Breakpoint.h
index ee9d3736d6190f..cffeb2fab1f0ef 100644
--- a/lldb/tools/lldb-dap/Breakpoint.h
+++ b/lldb/tools/lldb-dap/Breakpoint.h
@@ -9,18 +9,19 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_BREAKPOINT_H
 #define LLDB_TOOLS_LLDB_DAP_BREAKPOINT_H
 
-#include "BreakpointBase.h"
 #include "lldb/API/SBBreakpoint.h"
 
+#include "BreakpointBase.h"
+
 namespace lldb_dap {
 
 struct Breakpoint : public BreakpointBase {
   // The LLDB breakpoint associated wit this source breakpoint
   lldb::SBBreakpoint bp;
 
-  Breakpoint() = default;
-  Breakpoint(const llvm::json::Object &obj) : BreakpointBase(obj){};
-  Breakpoint(lldb::SBBreakpoint bp) : bp(bp) {}
+  Breakpoint(DAP &d) : BreakpointBase(d) {}
+  Breakpoint(DAP &d, const llvm::json::Object &obj) : BreakpointBase(d, obj) {}
+  Breakpoint(DAP &d, lldb::SBBreakpoint bp) : BreakpointBase(d), bp(bp) {}
 
   void SetCondition() override;
   void SetHitCondition() override;
diff --git a/lldb/tools/lldb-dap/BreakpointBase.cpp b/lldb/tools/lldb-dap/BreakpointBase.cpp
index f3cb06a3562d48..f07921783aa985 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.cpp
+++ b/lldb/tools/lldb-dap/BreakpointBase.cpp
@@ -11,8 +11,10 @@
 
 using namespace lldb_dap;
 
-BreakpointBase::BreakpointBase(const llvm::json::Object &obj)
-    : condition(std::string(GetString(obj, "condition"))),
+BreakpointBase::BreakpointBase(DAP &d) : dap(d) {}
+
+BreakpointBase::BreakpointBase(DAP &d, const llvm::json::Object &obj)
+    : dap(d), condition(std::string(GetString(obj, "condition"))),
       hitCondition(std::string(GetString(obj, "hitCondition"))) {}
 
 void BreakpointBase::UpdateBreakpoint(const BreakpointBase &request_bp) {
diff --git a/lldb/tools/lldb-dap/BreakpointBase.h b/lldb/tools/lldb-dap/BreakpointBase.h
index 79301480e0e588..121688d08f1524 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.h
+++ b/lldb/tools/lldb-dap/BreakpointBase.h
@@ -9,12 +9,17 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_BREAKPOINTBASE_H
 #define LLDB_TOOLS_LLDB_DAP_BREAKPOINTBASE_H
 
-#include "llvm/Support/JSON.h"
 #include <string>
 
+#include "llvm/Support/JSON.h"
+
+#include "DAPForward.h"
+
 namespace lldb_dap {
 
 struct BreakpointBase {
+  // Associated DAP session.
+  DAP &dap;
 
   // An optional expression for conditional breakpoints.
   std::string condition;
@@ -22,8 +27,8 @@ struct BreakpointBase {
   // ignored. The backend is expected to interpret the expression as needed
   std::string hitCondition;
 
-  BreakpointBase() = default;
-  BreakpointBase(const llvm::json::Object &obj);
+  BreakpointBase(DAP &d);
+  BreakpointBase(DAP &d, const llvm::json::Object &obj);
   virtual ~BreakpointBase() = default;
 
   virtual void SetCondition() = 0;
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 283392270ba26c..c394d4d1a7990a 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -32,10 +32,11 @@ using namespace lldb_dap;
 
 namespace lldb_dap {
 
-DAP g_dap;
-
-DAP::DAP()
-    : broadcaster("lldb-dap"), exception_breakpoints(),
+DAP::DAP(llvm::StringRef debug_adapter_path, std::shared_ptr<std::ofstream> log,
+         ReplMode repl_mode)
+    : debug_adaptor_path(debug_adapter_path),
+      in(lldb::SBFile(std::fopen("/dev/null", "w"), true)),
+      broadcaster("lldb-dap"), log(std::move(log)), exception_breakpoints(),
       focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
       enable_auto_variable_summaries(false),
       enable_synthetic_child_debugging(false),
@@ -44,21 +45,7 @@ DAP::DAP()
       configuration_done_sent(false), waiting_for_run_in_terminal(false),
       progress_event_reporter(
           [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
-      reverse_request_seq(0), repl_mode(ReplMode::Auto) {
-  const char *log_file_path = getenv("LLDBDAP_LOG");
-#if defined(_WIN32)
-  // Windows opens stdout and stdin in text mode which converts \n to 13,10
-  // while the value is just 10 on Darwin/Linux. Setting the file mode to binary
-  // fixes this.
-  int result = _setmode(fileno(stdout), _O_BINARY);
-  assert(result);
-  result = _setmode(fileno(stdin), _O_BINARY);
-  UNUSED_IF_ASSERT_DISABLED(result);
-  assert(result);
-#endif
-  if (log_file_path)
-    log.reset(new std::ofstream(log_file_path));
-}
+      reverse_request_seq(0), repl_mode(repl_mode) {}
 
 DAP::~DAP() = default;
 
@@ -74,21 +61,21 @@ void DAP::PopulateExceptionBreakpoints() {
     exception_breakpoints = std::vector<ExceptionBreakpoint>{};
 
     if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) {
-      exception_breakpoints->emplace_back("cpp_catch", "C++ Catch",
+      exception_breakpoints->emplace_back(*this, "cpp_catch", "C++ Catch",
                                           lldb::eLanguageTypeC_plus_plus);
-      exception_breakpoints->emplace_back("cpp_throw", "C++ Throw",
+      exception_breakpoints->emplace_back(*this, "cpp_throw", "C++ Throw",
                                           lldb::eLanguageTypeC_plus_plus);
     }
     if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) {
-      exception_breakpoints->emplace_back("objc_catch", "Objective-C Catch",
-                                          lldb::eLanguageTypeObjC);
-      exception_breakpoints->emplace_back("objc_throw", "Objective-C Throw",
-                                          lldb::eLanguageTypeObjC);
+      exception_breakpoints->emplace_back(
+          *this, "objc_catch", "Objective-C Catch", lldb::eLanguageTypeObjC);
+      exception_breakpoints->emplace_back(
+          *this, "objc_throw", "Objective-C Throw", lldb::eLanguageTypeObjC);
     }
     if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) {
-      exception_breakpoints->emplace_back("swift_catch", "Swift Catch",
+      exception_breakpoints->emplace_back(*this, "swift_catch", "Swift Catch",
                                           lldb::eLanguageTypeSwift);
-      exception_breakpoints->emplace_back("swift_throw", "Swift Throw",
+      exception_breakpoints->emplace_back(*this, "swift_throw", "Swift Throw",
                                           lldb::eLanguageTypeSwift);
     }
     // Besides handling the hardcoded list of languages from above, we try to
@@ -119,7 +106,7 @@ void DAP::PopulateExceptionBreakpoints() {
             raw_throw_keyword ? raw_throw_keyword : "throw";
 
         exception_breakpoints->emplace_back(
-            raw_lang_name + "_" + throw_keyword,
+            *this, raw_lang_name + "_" + throw_keyword,
             capitalized_lang_name + " " + capitalize(throw_keyword), lang);
       }
 
@@ -130,7 +117,7 @@ void DAP::PopulateExceptionBreakpoints() {
             raw_catch_keyword ? raw_catch_keyword : "catch";
 
         exception_breakpoints->emplace_back(
-            raw_lang_name + "_" + catch_keyword,
+            *this, raw_lang_name + "_" + catch_keyword,
             capitalized_lang_name + " " + capitalize(catch_keyword), lang);
       }
     }
@@ -477,12 +464,12 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
 
 llvm::json::Value DAP::CreateTopLevelScopes() {
   llvm::json::Array scopes;
-  scopes.emplace_back(CreateScope("Locals", VARREF_LOCALS,
-                                  g_dap.variables.locals.GetSize(), false));
+  scopes.emplace_back(
+      CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false));
   scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS,
-                                  g_dap.variables.globals.GetSize(), false));
+                                  variables.globals.GetSize(), false));
   scopes.emplace_back(CreateScope("Registers", VARREF_REGS,
-                                  g_dap.variables.registers.GetSize(), false));
+                                  variables.registers.GetSize(), false));
   return llvm::json::Value(std::move(scopes));
 }
 
@@ -490,8 +477,8 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
                              bool partial_expression) {
   // Check for the escape hatch prefix.
   if (!expression.empty() &&
-      llvm::StringRef(expression).starts_with(g_dap.command_escape_prefix)) {
-    expression = expression.substr(g_dap.command_escape_prefix.size());
+      llvm::StringRef(expression).starts_with(command_escape_prefix)) {
+    expression = expression.substr(command_escape_prefix.size());
     return ReplMode::Command;
   }
 
@@ -531,7 +518,7 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
           << "Warning: Expression '" << term
           << "' is both an LLDB command and variable. It will be evaluated as "
              "a variable. To evaluate the expression as an LLDB command, use '"
-          << g_dap.command_escape_prefix << "' as a prefix.\n";
+          << command_escape_prefix << "' as a prefix.\n";
     }
 
     // Variables take preference to commands in auto, since commands can always
@@ -548,7 +535,7 @@ bool DAP::RunLLDBCommands(llvm::StringRef prefix,
                           llvm::ArrayRef<std::string> commands) {
   bool required_command_failed = false;
   std::string output =
-      ::RunLLDBCommands(prefix, commands, required_command_failed);
+      ::RunLLDBCommands(*this, prefix, commands, required_command_failed);
   SendOutput(OutputType::Console, output);
   return !required_command_failed;
 }
@@ -694,14 +681,14 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
     const auto command = GetString(object, "command");
     auto handler_pos = request_handlers.find(std::string(command));
     if (handler_pos != request_handlers.end()) {
-      handler_pos->second(object);
+      handler_pos->second(*this, object);
       return true; // Success
-    } else {
-      if (log)
-        *log << "error: unhandled command \"" << command.data() << "\""
-             << std::endl;
-      return false; // Fail
     }
+
+    if (log)
+      *log << "error: unhandled command \"" << command.data() << "\""
+           << std::endl;
+    return false; // Fail
   }
 
   if (packet_type == "response") {
@@ -901,7 +888,7 @@ bool StartDebuggingRequestHandler::DoExecute(
     return false;
   }
 
-  g_dap.SendReverseRequest(
+  dap.SendReverseRequest(
       "startDebugging",
       llvm::json::Object{{"request", request},
                          {"configuration", std::move(*configuration)}},
@@ -925,7 +912,7 @@ bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger,
   // If a new mode is not specified report the current mode.
   if (!command || llvm::StringRef(command[0]).empty()) {
     std::string mode;
-    switch (g_dap.repl_mode) {
+    switch (dap.repl_mode) {
     case ReplMode::Variable:
       mode = "variable";
       break;
@@ -946,11 +933,11 @@ bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger,
   llvm::StringRef new_mode{command[0]};
 
   if (new_mode == "variable") {
-    g_dap.repl_mode = ReplMode::Variable;
+    dap.repl_mode = ReplMode::Variable;
   } else if (new_mode == "command") {
-    g_dap.repl_mode = ReplMode::Command;
+    dap.repl_mode = ReplMode::Command;
   } else if (new_mode == "auto") {
-    g_dap.repl_mode = ReplMode::Auto;
+    dap.repl_mode = ReplMode::Auto;
   } else {
     lldb::SBStream error_message;
     error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', "
@@ -1022,7 +1009,7 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger,
     event.try_emplace("body", std::move(*body));
   }
 
-  g_dap.SendJSON(llvm::json::Value(std::move(event)));
+  dap.SendJSON(llvm::json::Value(std::move(event)));
   result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
   return true;
 }
@@ -1031,14 +1018,13 @@ void DAP::SetFrameFormat(llvm::StringRef format) {
   if (format.empty())
     return;
   lldb::SBError error;
-  g_dap.frame_format = lldb::SBFormat(format.str().c_str(), error);
+  frame_format = lldb::SBFormat(format.str().c_str(), error);
   if (error.Fail()) {
-    g_dap.SendOutput(
-        OutputType::Console,
-        llvm::formatv(
-            "The provided frame format '{0}' couldn't be parsed: {1}\n", format,
-            error.GetCString())
-            .str());
+    SendOutput(OutputType::Console,
+               llvm::formatv(
+                   "The provided frame format '{0}' couldn't be parsed: {1}\n",
+                   format, error.GetCString())
+                   .str());
   }
 }
 
@@ -1046,14 +1032,13 @@ void DAP::SetThreadFormat(llvm::StringRef format) {
   if (format.empty())
     return;
   lldb::SBError error;
-  g_dap.thread_format = lldb::SBFormat(format.str().c_str(), error);
+  thread_format = lldb::SBFormat(format.str().c_str(), error);
   if (error.Fail()) {
-    g_dap.SendOutput(
-        OutputType::Console,
-        llvm::formatv(
-            "The provided thread format '{0}' couldn't be parsed: {1}\n",
-            format, error.GetCString())
-            .str());
+    SendOutput(OutputType::Console,
+               llvm::formatv(
+                   "The provided thread format '{0}' couldn't be parsed: {1}\n",
+                   format, error.GetCString())
+                   .str());
   }
 }
 
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index dab4ce44ab202c..04a747721e86af 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -28,6 +28,7 @@
 #include "lldb/API/SBCommandReturnObject.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFile.h"
 #include "lldb/API/SBFormat.h"
 #include "lldb/API/SBLaunchInfo.h"
 #include "lldb/API/SBTarget.h"
@@ -63,7 +64,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 {
@@ -116,16 +117,22 @@ struct Variables {
 };
 
 struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface {
+  DAP &dap;
+  StartDebuggingRequestHandler(DAP &dap) : dap(dap) {}
   bool DoExecute(lldb::SBDebugger debugger, char **command,
                  lldb::SBCommandReturnObject &result) override;
 };
 
 struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface {
+  DAP &dap;
+  ReplModeRequestHandler(DAP &dap) : dap(dap) {}
   bool DoExecute(lldb::SBDebugger debugger, char **command,
                  lldb::SBCommandReturnObject &result) override;
 };
 
 struct SendEventRequestHandler : public lldb::SBCommandPluginInterface {
+  DAP &dap;
+  SendEventRequestHandler(DAP &dap) : dap(dap) {}
   bool DoExecute(lldb::SBDebugger debugger, char **command,
                  lldb::SBCommandReturnObject &result) override;
 };
@@ -134,13 +141,16 @@ struct DAP {
   std::string debug_adaptor_path;
   InputStream input;
   OutputStream output;
+  lldb::SBFile in;
+  lldb::SBFile out;
+  lldb::SBFile err;
   lldb::SBDebugger debugger;
   lldb::SBTarget target;
   Variables variables;
   lldb::SBBroadcaster broadcaster;
   std::thread event_thread;
   std::thread progress_event_thread;
-  std::unique_ptr<std::ofstream> log;
+  std::shared_ptr<std::ofstream> log;
   llvm::StringMap<SourceBreakpointMap> source_breakpoints;
   FunctionBreakpointMap function_breakpoints;
   InstructionBreakpointMap instruction_breakpoints;
@@ -192,7 +202,8 @@ struct DAP {
   // will contain that expression.
   std::string last_nonempty_var_expression;
 
-  DAP();
+  DAP(llvm::StringRef debug_adapter_path, std::shared_ptr<std::ofstream> log,
+      ReplMode repl_mode);
   ~DAP();
   DAP(const DAP &rhs) = delete;
   void operator=(const DAP &rhs) = delete;
@@ -347,8 +358,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/DAPForward.h b/lldb/tools/lldb-dap/DAPForward.h
index 159d999a63c820..ed7664526847b1 100644
--- a/lldb/tools/lldb-dap/DAPForward.h
+++ b/lldb/tools/lldb-dap/DAPForward.h
@@ -11,11 +11,12 @@
 
 namespace lldb_dap {
 struct BreakpointBase;
+struct DAP;
 struct ExceptionBreakpoint;
 struct FunctionBreakpoint;
+struct InstructionBreakpoint;
 struct SourceBreakpoint;
 struct Watchpoint;
-struct InstructionBreakpoint;
 } // namespace lldb_dap
 
 namespace lldb {
@@ -27,6 +28,7 @@ class SBCommandReturnObject;
 class SBCommunication;
 class SBDebugger;
 class SBEvent;
+class SBFile;
 class SBFrame;
 class SBHostOS;
 class SBInstruction;
diff --git a/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp b/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp
index 130c237e65441d..e9bb11face49df 100644
--- a/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp
@@ -17,8 +17,8 @@ void ExceptionBreakpoint::SetBreakpoint() {
     return;
   bool catch_value = filter.find("_catch") != std::string::npos;
   bool throw_value = filter.find("_throw") != std::string::npos;
-  bp = g_dap.target.BreakpointCreateForException(language, catch_value,
-                                                 throw_value);
+  bp = dap.target.BreakpointCreateForException(language, catch_value,
+                                               throw_value);
   // See comments in BreakpointBase::GetBreakpointLabel() for details of why
   // we add a label to our breakpoints.
   bp.AddName(BreakpointBase::GetBreakpointLabel());
@@ -27,7 +27,7 @@ void ExceptionBreakpoint::SetBreakpoint() {
 void ExceptionBreakpoint::ClearBreakpoint() {
   if (!bp.IsValid())
     return;
-  g_dap.target.BreakpointDelete(bp.GetID());
+  dap.target.BreakpointDelete(bp.GetID());
   bp = lldb::SBBreakpoint();
 }
 
diff --git a/lldb/tools/lldb-dap/ExceptionBreakpoint.h b/lldb/tools/lldb-dap/ExceptionBreakpoint.h
index 7b81d845cb26be..7819bea726a1d0 100644
--- a/lldb/tools/lldb-dap/ExceptionBreakpoint.h
+++ b/lldb/tools/lldb-dap/ExceptionBreakpoint.h
@@ -13,17 +13,21 @@
 
 #include "lldb/API/SBBreakpoint.h"
 
+#include "DAPForward.h"
+
 namespace lldb_dap {
 
 struct ExceptionBreakpoint {
+  DAP &dap;
   std::string filter;
   std::string label;
   lldb::LanguageType language;
-  bool default_value;
+  bool default_value = false;
   lldb::SBBreakpoint bp;
-  ExceptionBreakpoint(std::string f, std::string l, lldb::LanguageType lang)
-      : filter(std::move(f)), label(std::move(l)), language(lang),
-        default_value(false), bp() {}
+  ExceptionBreakpoint(DAP &d, std::string f, std::string l,
+                      lldb::LanguageType lang)
+      : dap(d), filter(std::move(f)), label(std::move(l)), language(lang),
+        bp() {}
 
   void SetBreakpoint();
   void ClearBreakpoint();
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
index 216c685f633da8..ef6df6c0dc91cc 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
@@ -7,18 +7,19 @@
 //===----------------------------------------------------------------------===//
 
 #include "FunctionBreakpoint.h"
+
 #include "DAP.h"
 #include "JSONUtils.h"
 
 namespace lldb_dap {
 
-FunctionBreakpoint::FunctionBreakpoint(const llvm::json::Object &obj)
-    : Breakpoint(obj), functionName(std::string(GetString(obj, "name"))) {}
+FunctionBreakpoint::FunctionBreakpoint(DAP &d, const llvm::json::Object &obj)
+    : Breakpoint(d, obj), functionName(std::string(GetString(obj, "name"))) {}
 
 void FunctionBreakpoint::SetBreakpoint() {
   if (functionName.empty())
     return;
-  bp = g_dap.target.BreakpointCreateByName(functionName.c_str());
+  bp = dap.target.BreakpointCreateByName(functionName.c_str());
   Breakpoint::SetBreakpoint();
 }
 
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.h b/lldb/tools/lldb-dap/FunctionBreakpoint.h
index b15ff1931a6b22..93f0b93b35291d 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.h
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.h
@@ -10,14 +10,14 @@
 #define LLDB_TOOLS_LLDB_DAP_FUNCTIONBREAKPOINT_H
 
 #include "Breakpoint.h"
+#include "DAPForward.h"
 
 namespace lldb_dap {
 
 struct FunctionBreakpoint : public Breakpoint {
   std::string functionName;
 
-  FunctionBreakpoint() = default;
-  FunctionBreakpoint(const llvm::json::Object &obj);
+  FunctionBreakpoint(DAP &dap, const llvm::json::Object &obj);
 
   // Set this breakpoint in LLDB as a new breakpoint
   void SetBreakpoint();
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
index e3a8460bb7b301..d6ccb2dfc29111 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
@@ -8,22 +8,25 @@
 //===----------------------------------------------------------------------===//
 
 #include "InstructionBreakpoint.h"
+
 #include "DAP.h"
 #include "JSONUtils.h"
 
 namespace lldb_dap {
 
 // Instruction Breakpoint
-InstructionBreakpoint::InstructionBreakpoint(const llvm::json::Object &obj)
-    : Breakpoint(obj), instructionAddressReference(LLDB_INVALID_ADDRESS), id(0),
-      offset(GetSigned(obj, "offset", 0)) {
+InstructionBreakpoint::InstructionBreakpoint(DAP &d,
+                                             const llvm::json::Object &obj)
+    : Breakpoint(d, obj), instructionAddressReference(LLDB_INVALID_ADDRESS),
+      id(0), offset(GetSigned(obj, "offset", 0)) {
   GetString(obj, "instructionReference")
       .getAsInteger(0, instructionAddressReference);
   instructionAddressReference += offset;
 }
 
 void InstructionBreakpoint::SetInstructionBreakpoint() {
-  bp = g_dap.target.BreakpointCreateByAddress(instructionAddressReference);
+  bp = dap.target.BreakpointCreateByAddress(instructionAddressReference);
   id = bp.GetID();
 }
+
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.h b/lldb/tools/lldb-dap/InstructionBreakpoint.h
index 53912af46ca148..d7f3fb8ad3a4eb 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.h
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.h
@@ -10,7 +10,12 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_INSTRUCTIONBREAKPOINT_H
 #define LLDB_TOOLS_LLDB_DAP_INSTRUCTIONBREAKPOINT_H
 
+#include <cstdint>
+
+#include "lldb/lldb-types.h"
+
 #include "Breakpoint.h"
+#include "DAPForward.h"
 
 namespace lldb_dap {
 
@@ -21,10 +26,10 @@ struct InstructionBreakpoint : public Breakpoint {
   int32_t id;
   int32_t offset;
 
-  InstructionBreakpoint()
-      : Breakpoint(), instructionAddressReference(LLDB_INVALID_ADDRESS), id(0),
+  InstructionBreakpoint(DAP &d)
+      : Breakpoint(d), instructionAddressReference(LLDB_INVALID_ADDRESS), id(0),
         offset(0) {}
-  InstructionBreakpoint(const llvm::json::Object &obj);
+  InstructionBreakpoint(DAP &d, const llvm::json::Object &obj);
 
   // Set instruction breakpoint in LLDB as a new breakpoint
   void SetInstructionBreakpoint();
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 97fe6b4f9f05db..c6d9e86f0d8bf1 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -184,12 +184,6 @@ static bool IsClassStructOrUnionType(lldb::SBType t) {
 /// glance.
 static std::optional<std::string>
 TryCreateAutoSummaryForContainer(lldb::SBValue &v) {
-  // We gate this feature because it performs GetNumChildren(), which can
-  // cause performance issues because LLDB needs to complete possibly huge
-  // types.
-  if (!g_dap.enable_auto_variable_summaries)
-    return std::nullopt;
-
   if (!v.MightHaveChildren())
     return std::nullopt;
   /// As this operation can be potentially slow, we limit the total time spent
@@ -245,10 +239,7 @@ TryCreateAutoSummaryForContainer(lldb::SBValue &v) {
 
 /// Try to create a summary string for the given value that doesn't have a
 /// summary of its own.
-static std::optional<std::string> TryCreateAutoSummary(lldb::SBValue value) {
-  if (!g_dap.enable_auto_variable_summaries)
-    return std::nullopt;
-
+static std::optional<std::string> TryCreateAutoSummary(lldb::SBValue &value) {
   // We use the dereferenced value for generating the summary.
   if (value.GetType().IsPointerType() || value.GetType().IsReferenceType())
     value = value.Dereference();
@@ -459,9 +450,10 @@ static std::string ConvertDebugInfoSizeToString(uint64_t debug_info) {
   }
   return oss.str();
 }
-llvm::json::Value CreateModule(lldb::SBModule &module) {
+
+llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module) {
   llvm::json::Object object;
-  if (!module.IsValid())
+  if (!target.IsValid() && !module.IsValid())
     return llvm::json::Value(std::move(object));
   const char *uuid = module.GetUUIDString();
   object.try_emplace("id", uuid ? std::string(uuid) : std::string(""));
@@ -488,7 +480,7 @@ llvm::json::Value CreateModule(lldb::SBModule &module) {
     object.try_emplace("symbolStatus", "Symbols not found.");
   }
   std::string loaded_addr = std::to_string(
-      module.GetObjectFileHeaderAddress().GetLoadAddress(g_dap.target));
+      module.GetObjectFileHeaderAddress().GetLoadAddress(target));
   object.try_emplace("addressRange", loaded_addr);
   std::string version_str;
   uint32_t version_nums[3];
@@ -750,15 +742,15 @@ std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) {
 //   },
 //   "required": [ "id", "name", "line", "column" ]
 // }
-llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
+                                   lldb::SBFormat &format) {
   llvm::json::Object object;
   int64_t frame_id = MakeDAPFrameID(frame);
   object.try_emplace("id", frame_id);
 
   std::string frame_name;
   lldb::SBStream stream;
-  if (g_dap.frame_format &&
-      frame.GetDescriptionWithFormat(g_dap.frame_format, stream).Success()) {
+  if (format && frame.GetDescriptionWithFormat(format, stream).Success()) {
     frame_name = stream.GetData();
 
     // `function_name` can be a nullptr, which throws an error when assigned to
@@ -775,7 +767,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
   }
 
   // We only include `[opt]` if a custom frame format is not specified.
-  if (!g_dap.frame_format && frame.GetFunction().GetIsOptimized())
+  if (!format && frame.GetFunction().GetIsOptimized())
     frame_name += " [opt]";
 
   EmplaceSafeString(object, "name", frame_name);
@@ -809,11 +801,11 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
   return llvm::json::Value(std::move(object));
 }
 
-llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread) {
+llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread,
+                                                lldb::SBFormat &format) {
   std::string name;
   lldb::SBStream stream;
-  if (g_dap.thread_format &&
-      thread.GetDescriptionWithFormat(g_dap.thread_format, stream).Success()) {
+  if (format && thread.GetDescriptionWithFormat(format, stream).Success()) {
     name = stream.GetData();
   } else {
     const uint32_t thread_idx = thread.GetExtendedBacktraceOriginatingIndexID();
@@ -910,13 +902,12 @@ llvm::json::Value CreateInstructionBreakpoint(BreakpointBase *ibp) {
 //   },
 //   "required": [ "id", "name" ]
 // }
-llvm::json::Value CreateThread(lldb::SBThread &thread) {
+llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format) {
   llvm::json::Object object;
   object.try_emplace("id", (int64_t)thread.GetThreadID());
   std::string thread_str;
   lldb::SBStream stream;
-  if (g_dap.thread_format &&
-      thread.GetDescriptionWithFormat(g_dap.thread_format, stream).Success()) {
+  if (format && thread.GetDescriptionWithFormat(format, stream).Success()) {
     thread_str = stream.GetData();
   } else {
     const char *thread_name = thread.GetName();
@@ -1004,7 +995,7 @@ llvm::json::Value CreateThread(lldb::SBThread &thread) {
 //     "required": [ "event", "body" ]
 //   }]
 // }
-llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
+llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread,
                                       uint32_t stop_id) {
   llvm::json::Object event(CreateEventObject("stopped"));
   llvm::json::Object body;
@@ -1014,13 +1005,13 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
     body.try_emplace("reason", "step");
     break;
   case lldb::eStopReasonBreakpoint: {
-    ExceptionBreakpoint *exc_bp = g_dap.GetExceptionBPFromStopReason(thread);
+    ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
     if (exc_bp) {
       body.try_emplace("reason", "exception");
       EmplaceSafeString(body, "description", exc_bp->label);
     } else {
       InstructionBreakpoint *inst_bp =
-          g_dap.GetInstructionBPFromStopReason(thread);
+          dap.GetInstructionBPFromStopReason(thread);
       if (inst_bp) {
         body.try_emplace("reason", "instruction breakpoint");
       } else {
@@ -1080,10 +1071,10 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
     }
   }
   // "threadCausedFocus" is used in tests to validate breaking behavior.
-  if (tid == g_dap.focus_tid) {
+  if (tid == dap.focus_tid) {
     body.try_emplace("threadCausedFocus", true);
   }
-  body.try_emplace("preserveFocusHint", tid != g_dap.focus_tid);
+  body.try_emplace("preserveFocusHint", tid != dap.focus_tid);
   body.try_emplace("allThreadsStopped", true);
   event.try_emplace("body", std::move(body));
   return llvm::json::Value(std::move(event));
@@ -1111,7 +1102,9 @@ std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v,
   return name_builder.GetData();
 }
 
-VariableDescription::VariableDescription(lldb::SBValue v, bool format_hex,
+VariableDescription::VariableDescription(lldb::SBValue &v,
+                                         bool auto_variable_summaries,
+                                         bool format_hex,
                                          bool is_name_duplicated,
                                          std::optional<std::string> custom_name)
     : v(v) {
@@ -1142,7 +1135,7 @@ VariableDescription::VariableDescription(lldb::SBValue v, bool format_hex,
   } else {
     value = llvm::StringRef(v.GetValue()).str();
     summary = llvm::StringRef(v.GetSummary()).str();
-    if (summary.empty())
+    if (summary.empty() && auto_variable_summaries)
       auto_summary = TryCreateAutoSummary(v);
 
     std::optional<std::string> effective_summary =
@@ -1220,13 +1213,13 @@ std::string VariableDescription::GetResult(llvm::StringRef context) {
   return description.trim().str();
 }
 
-bool ValuePointsToCode(lldb::SBValue v) {
+bool ValuePointsToCode(lldb::SBValue &v) {
   if (!v.GetType().GetPointeeType().IsFunctionType())
     return false;
 
   lldb::addr_t addr = v.GetValueAsAddress();
   lldb::SBLineEntry line_entry =
-      g_dap.target.ResolveLoadAddress(addr).GetLineEntry();
+      v.GetTarget().ResolveLoadAddress(addr).GetLineEntry();
 
   return line_entry.IsValid();
 }
@@ -1386,10 +1379,13 @@ std::pair<int64_t, bool> UnpackLocation(int64_t location_id) {
 //   },
 //   "required": [ "name", "value", "variablesReference" ]
 // }
-llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref,
-                                 bool format_hex, bool is_name_duplicated,
+llvm::json::Value CreateVariable(lldb::SBValue &v, int64_t var_ref,
+                                 bool format_hex, bool auto_variable_summaries,
+                                 bool synthetic_child_debugging,
+                                 bool is_name_duplicated,
                                  std::optional<std::string> custom_name) {
-  VariableDescription desc(v, format_hex, is_name_duplicated, custom_name);
+  VariableDescription desc(v, auto_variable_summaries, format_hex,
+                           is_name_duplicated, custom_name);
   llvm::json::Object object;
   EmplaceSafeString(object, "name", desc.name);
   EmplaceSafeString(object, "value", desc.display_value);
@@ -1425,7 +1421,7 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref,
         size_t num_children = v.GetNumChildren();
         // If we are creating a "[raw]" fake child for each synthetic type, we
         // have to account for it when returning indexed variables.
-        if (g_dap.enable_synthetic_child_debugging)
+        if (synthetic_child_debugging)
           ++num_children;
         object.try_emplace("indexedVariables", num_children);
       }
@@ -1504,9 +1500,7 @@ CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request,
     llvm::StringRef value = envs.GetValueAtIndex(index);
 
     if (key.empty())
-      g_dap.SendOutput(OutputType::Stderr,
-                       "empty environment variable for value: \"" +
-                           value.str() + '\"');
+      continue;
     else
       env_json.try_emplace(key, value);
   }
@@ -1562,8 +1556,8 @@ void FilterAndGetValueForKey(const lldb::SBStructuredData data, const char *key,
   }
 }
 
-void addStatistic(llvm::json::Object &event) {
-  lldb::SBStructuredData statistics = g_dap.target.GetStatistics();
+void addStatistic(lldb::SBTarget &target, llvm::json::Object &event) {
+  lldb::SBStructuredData statistics = target.GetStatistics();
   bool is_dictionary =
       statistics.GetType() == lldb::eStructuredDataTypeDictionary;
   if (!is_dictionary)
@@ -1580,9 +1574,9 @@ void addStatistic(llvm::json::Object &event) {
   event.try_emplace("statistics", std::move(stats_body));
 }
 
-llvm::json::Object CreateTerminatedEventObject() {
+llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target) {
   llvm::json::Object event(CreateEventObject("terminated"));
-  addStatistic(event);
+  addStatistic(target, event);
   return event;
 }
 
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 54fc4323475723..d06c0ddb9e638e 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -9,14 +9,15 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_JSONUTILS_H
 #define LLDB_TOOLS_LLDB_DAP_JSONUTILS_H
 
+#include <cstdint>
+#include <optional>
+#include <unordered_map>
+
 #include "BreakpointBase.h"
 #include "DAPForward.h"
 #include "lldb/API/SBModule.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/JSON.h"
-#include <cstdint>
-#include <optional>
-#include <unordered_map>
 
 namespace lldb_dap {
 
@@ -260,13 +261,16 @@ CreateBreakpoint(BreakpointBase *bp,
 
 /// Converts a LLDB module to a VS Code DAP module for use in "modules" events.
 ///
+/// \param[in] target
+///     A LLDB target object to convert into a JSON value.
+///
 /// \param[in] module
-///     A LLDB module object to convert into a JSON value
+///     A LLDB module object to convert into a JSON value.
 ///
 /// \return
 ///     A "Module" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateModule(lldb::SBModule &module);
+llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module);
 
 /// Create a "Event" JSON object using \a event_name as the event name
 ///
@@ -356,10 +360,15 @@ llvm::json::Value CreateSource(llvm::StringRef source_path);
 ///     The LLDB stack frame to use when populating out the "StackFrame"
 ///     object.
 ///
+/// \param[in] format
+///     The LLDB format to use when populating out the "StackFrame"
+///     object.
+///
 /// \return
 ///     A "StackFrame" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateStackFrame(lldb::SBFrame &frame);
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
+                                   lldb::SBFormat &format);
 
 /// Create a "StackFrame" label object for a LLDB thread.
 ///
@@ -375,10 +384,14 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame);
 ///     The LLDB thread to use when populating out the "Thread"
 ///     object.
 ///
+/// \param[in] format
+///     The configured formatter for the DAP session.
+///
 /// \return
 ///     A "StackFrame" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread);
+llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread,
+                                                lldb::SBFormat &format);
 
 /// Create a "instruction" object for a LLDB disassemble object as described in
 /// the Visual Studio Code debug adaptor definition.
@@ -403,11 +416,14 @@ llvm::json::Value CreateInstructionBreakpoint(BreakpointBase *ibp);
 /// \param[in] thread
 ///     The LLDB thread to use when populating out the "Thread"
 ///     object.
+/// \param[in] format
+///     The LLDB format to use when populating out the "Thread"
+///     object.
 ///
 /// \return
 ///     A "Thread" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateThread(lldb::SBThread &thread);
+llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format);
 
 /// Create a "StoppedEvent" object for a LLDB thread object.
 ///
@@ -423,6 +439,9 @@ llvm::json::Value CreateThread(lldb::SBThread &thread);
 ///   "allThreadsStopped" - set to True to indicate that all threads
 ///                         stop when any thread stops.
 ///
+/// \param[in] dap
+///     The DAP session associated with the stopped thread.
+///
 /// \param[in] thread
 ///     The LLDB thread to use when populating out the "StoppedEvent"
 ///     object.
@@ -430,7 +449,8 @@ llvm::json::Value CreateThread(lldb::SBThread &thread);
 /// \return
 ///     A "StoppedEvent" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, uint32_t stop_id);
+llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread,
+                                      uint32_t stop_id);
 
 /// \return
 ///     The variable name of \a value or a default placeholder.
@@ -468,8 +488,8 @@ struct VariableDescription {
   /// The SBValue for this variable.
   lldb::SBValue v;
 
-  VariableDescription(lldb::SBValue v, bool format_hex = false,
-                      bool is_name_duplicated = false,
+  VariableDescription(lldb::SBValue &v, bool auto_variable_summaries,
+                      bool format_hex = false, bool is_name_duplicated = false,
                       std::optional<std::string> custom_name = {});
 
   /// Create a JSON object that represents these extensions to the DAP variable
@@ -481,7 +501,7 @@ struct VariableDescription {
 };
 
 /// Does the given variable have an associated value location?
-bool ValuePointsToCode(lldb::SBValue v);
+bool ValuePointsToCode(lldb::SBValue &v);
 
 /// Pack a location into a single integer which we can send via
 /// the debug adapter protocol.
@@ -521,6 +541,13 @@ std::pair<int64_t, bool> UnpackLocation(int64_t location_id);
 ///     It set to true the variable will be formatted as hex in
 ///     the "value" key value pair for the value of the variable.
 ///
+/// \param[in] auto_variable_summaries
+///     Whether the variable should include an auto summary if the default
+///     summary is empty.
+///
+/// \param[in] synthetic_child_debugging
+///    Whether the variable should include synthetic children references.
+///
 /// \param[in] is_name_duplicated
 ///     Whether the same variable name appears multiple times within the same
 ///     context (e.g. locals). This can happen due to shadowed variables in
@@ -536,14 +563,15 @@ std::pair<int64_t, bool> UnpackLocation(int64_t location_id);
 /// \return
 ///     A "Variable" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref,
-                                 bool format_hex,
+llvm::json::Value CreateVariable(lldb::SBValue &v, int64_t var_ref,
+                                 bool format_hex, bool auto_variable_summaries,
+                                 bool synthetic_child_debugging,
                                  bool is_name_duplicated = false,
                                  std::optional<std::string> custom_name = {});
 
 llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit);
 
-/// Create a runInTerminal reverse request object
+/// Create a runInTerminal reverse request object.
 ///
 /// \param[in] launch_request
 ///     The original launch_request object whose fields are used to construct
@@ -574,7 +602,7 @@ CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request,
 ///
 /// \return
 ///     A body JSON object with debug info and breakpoint info
-llvm::json::Object CreateTerminatedEventObject();
+llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target);
 
 /// Convert a given JSON object to a string.
 std::string JSONToString(const llvm::json::Value &json);
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index 2ffcba7dff4f24..4c4bac8db3dca9 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -7,15 +7,17 @@
 //===----------------------------------------------------------------------===//
 
 #include "LLDBUtils.h"
-#include "DAP.h"
-#include "JSONUtils.h"
-#include "lldb/API/SBStringList.h"
 
 #include <mutex>
 
+#include "lldb/API/SBStringList.h"
+
+#include "DAP.h"
+#include "JSONUtils.h"
+
 namespace lldb_dap {
 
-bool RunLLDBCommands(llvm::StringRef prefix,
+bool RunLLDBCommands(DAP &dap, llvm::StringRef prefix,
                      const llvm::ArrayRef<std::string> &commands,
                      llvm::raw_ostream &strm, bool parse_command_directives) {
   if (commands.empty())
@@ -23,7 +25,7 @@ bool RunLLDBCommands(llvm::StringRef prefix,
 
   bool did_print_prefix = false;
 
-  lldb::SBCommandInterpreter interp = g_dap.debugger.GetCommandInterpreter();
+  lldb::SBCommandInterpreter interp = dap.debugger.GetCommandInterpreter();
   for (llvm::StringRef command : commands) {
     lldb::SBCommandReturnObject result;
     bool quiet_on_success = false;
@@ -78,7 +80,7 @@ bool RunLLDBCommands(llvm::StringRef prefix,
   return true;
 }
 
-std::string RunLLDBCommands(llvm::StringRef prefix,
+std::string RunLLDBCommands(DAP &dap, llvm::StringRef prefix,
                             const llvm::ArrayRef<std::string> &commands,
                             bool &required_command_failed,
                             bool parse_command_directives) {
@@ -86,15 +88,15 @@ std::string RunLLDBCommands(llvm::StringRef prefix,
   std::string s;
   llvm::raw_string_ostream strm(s);
   required_command_failed =
-      !RunLLDBCommands(prefix, commands, strm, parse_command_directives);
+      !RunLLDBCommands(dap, prefix, commands, strm, parse_command_directives);
   return s;
 }
 
 std::string
-RunLLDBCommandsVerbatim(llvm::StringRef prefix,
+RunLLDBCommandsVerbatim(DAP &dap, llvm::StringRef prefix,
                         const llvm::ArrayRef<std::string> &commands) {
   bool required_command_failed = false;
-  return RunLLDBCommands(prefix, commands, required_command_failed,
+  return RunLLDBCommands(dap, prefix, commands, required_command_failed,
                          /*parse_command_directives=*/false);
 }
 
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index d5072d19029a1e..3a3d02f8867dfd 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -30,6 +30,9 @@ namespace lldb_dap {
 /// emitted regardless, and \b false is returned without executing the
 /// remaining commands.
 ///
+/// \param[in] dap
+///     The DAP session to execute the commands from.
+///
 /// \param[in] prefix
 ///     A string that will be printed into \a strm prior to emitting
 ///     the prompt + command and command output. Can be NULL.
@@ -48,7 +51,7 @@ namespace lldb_dap {
 /// \return
 ///     \b true, unless a command prefixed with \b ! fails and parsing of
 ///     command directives is enabled.
-bool RunLLDBCommands(llvm::StringRef prefix,
+bool RunLLDBCommands(DAP &dap, llvm::StringRef prefix,
                      const llvm::ArrayRef<std::string> &commands,
                      llvm::raw_ostream &strm, bool parse_command_directives);
 
@@ -57,6 +60,9 @@ bool RunLLDBCommands(llvm::StringRef prefix,
 /// All output from every command, including the prompt + the command
 /// is returned in the std::string return value.
 ///
+/// \param[in] dap
+///     The DAP session to execute the commands from.
+///
 /// \param[in] prefix
 ///     A string that will be printed into \a strm prior to emitting
 ///     the prompt + command and command output. Can be NULL.
@@ -75,14 +81,14 @@ bool RunLLDBCommands(llvm::StringRef prefix,
 /// \return
 ///     A std::string that contains the prefix and all commands and
 ///     command output.
-std::string RunLLDBCommands(llvm::StringRef prefix,
+std::string RunLLDBCommands(DAP &dap, llvm::StringRef prefix,
                             const llvm::ArrayRef<std::string> &commands,
                             bool &required_command_failed,
                             bool parse_command_directives = true);
 
 /// Similar to the method above, but without parsing command directives.
 std::string
-RunLLDBCommandsVerbatim(llvm::StringRef prefix,
+RunLLDBCommandsVerbatim(DAP &dap, llvm::StringRef prefix,
                         const llvm::ArrayRef<std::string> &commands);
 
 /// Check if a thread has a stop reason.
diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp
index 2c2f49569869b4..7fc9aaef20b911 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.cpp
+++ b/lldb/tools/lldb-dap/OutputRedirector.cpp
@@ -21,7 +21,7 @@ using namespace llvm;
 
 namespace lldb_dap {
 
-Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
+Expected<int> RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
   int new_fd[2];
 #if defined(_WIN32)
   if (_pipe(new_fd, 4096, O_TEXT) == -1) {
@@ -34,7 +34,7 @@ Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
                              strerror(error));
   }
 
-  if (dup2(new_fd[1], fd) == -1) {
+  if (fd != -1 && dup2(new_fd[1], fd) == -1) {
     int error = errno;
     return createStringError(inconvertibleErrorCode(),
                              "Couldn't override the fd %d. %s", fd,
@@ -57,7 +57,7 @@ Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
     }
   });
   t.detach();
-  return Error::success();
+  return new_fd[1];
 }
 
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/OutputRedirector.h b/lldb/tools/lldb-dap/OutputRedirector.h
index e26d1648b104f9..418b8bac102c7f 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.h
+++ b/lldb/tools/lldb-dap/OutputRedirector.h
@@ -16,10 +16,16 @@ namespace lldb_dap {
 
 /// Redirects the output of a given file descriptor to a callback.
 ///
+/// \param[in] fd
+///     Either -1 or the fd duplicate into the new handle.
+///
+/// \param[in] callback
+///     A callback invoked each time the file is written.
+///
 /// \return
-///     \a Error::success if the redirection was set up correctly, or an error
-///     otherwise.
-llvm::Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback);
+///     A new file handle for the output.
+llvm::Expected<int> RedirectFd(int fd,
+                               std::function<void(llvm::StringRef)> callback);
 
 } // namespace lldb_dap
 
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
index d1a3a5bedb0ae2..7415a0914dad43 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
@@ -12,15 +12,16 @@
 
 namespace lldb_dap {
 
-SourceBreakpoint::SourceBreakpoint(const llvm::json::Object &obj)
-    : Breakpoint(obj), logMessage(std::string(GetString(obj, "logMessage"))),
+SourceBreakpoint::SourceBreakpoint(DAP &dap, const llvm::json::Object &obj)
+    : Breakpoint(dap, obj),
+      logMessage(std::string(GetString(obj, "logMessage"))),
       line(GetUnsigned(obj, "line", 0)), column(GetUnsigned(obj, "column", 0)) {
 }
 
 void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
   lldb::SBFileSpecList module_list;
-  bp = g_dap.target.BreakpointCreateByLocation(source_path.str().c_str(), line,
-                                               column, 0, module_list);
+  bp = dap.target.BreakpointCreateByLocation(source_path.str().c_str(), line,
+                                             column, 0, module_list);
   if (!logMessage.empty())
     SetLogMessage();
   Breakpoint::SetBreakpoint();
@@ -279,7 +280,7 @@ void SourceBreakpoint::SetLogMessage() {
 void SourceBreakpoint::NotifyLogMessageError(llvm::StringRef error) {
   std::string message = "Log message has error: ";
   message += error;
-  g_dap.SendOutput(OutputType::Console, message);
+  dap.SendOutput(OutputType::Console, message);
 }
 
 /*static*/
@@ -304,14 +305,16 @@ bool SourceBreakpoint::BreakpointHitCallback(
           frame.GetValueForVariablePath(expr, lldb::eDynamicDontRunTarget);
       if (value.GetError().Fail())
         value = frame.EvaluateExpression(expr);
-      output += VariableDescription(value).display_value;
+      output +=
+          VariableDescription(value, bp->dap.enable_auto_variable_summaries)
+              .display_value;
     } else {
       output += messagePart.text;
     }
   }
   if (!output.empty() && output.back() != '\n')
     output.push_back('\n'); // Ensure log message has line break.
-  g_dap.SendOutput(OutputType::Console, output.c_str());
+  bp->dap.SendOutput(OutputType::Console, output.c_str());
 
   // Do not stop.
   return false;
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h
index aa3fbe6d0f96d2..ae5f0548707d85 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.h
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.h
@@ -31,8 +31,8 @@ struct SourceBreakpoint : public Breakpoint {
   uint32_t line;   ///< The source line of the breakpoint or logpoint
   uint32_t column; ///< An optional source column of the breakpoint
 
-  SourceBreakpoint() : Breakpoint(), line(0), column(0) {}
-  SourceBreakpoint(const llvm::json::Object &obj);
+  SourceBreakpoint(DAP &dap) : Breakpoint(dap), line(0), column(0) {}
+  SourceBreakpoint(DAP &dap, const llvm::json::Object &obj);
 
   // Set this breakpoint in LLDB as a new breakpoint
   void SetBreakpoint(const llvm::StringRef source_path);
diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp
index 21765509449140..8cd297aa696168 100644
--- a/lldb/tools/lldb-dap/Watchpoint.cpp
+++ b/lldb/tools/lldb-dap/Watchpoint.cpp
@@ -7,12 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "Watchpoint.h"
+
+#include "llvm/ADT/StringExtras.h"
+
 #include "DAP.h"
 #include "JSONUtils.h"
-#include "llvm/ADT/StringExtras.h"
 
 namespace lldb_dap {
-Watchpoint::Watchpoint(const llvm::json::Object &obj) : BreakpointBase(obj) {
+Watchpoint::Watchpoint(DAP &dap, const llvm::json::Object &obj)
+    : BreakpointBase(dap, obj) {
   llvm::StringRef dataId = GetString(obj, "dataId");
   std::string accessType = GetString(obj, "accessType").str();
   auto [addr_str, size_str] = dataId.split('/');
@@ -42,7 +45,7 @@ void Watchpoint::CreateJsonObject(llvm::json::Object &object) {
 }
 
 void Watchpoint::SetWatchpoint() {
-  wp = g_dap.target.WatchpointCreateByAddress(addr, size, options, error);
+  wp = dap.target.WatchpointCreateByAddress(addr, size, options, error);
   if (!condition.empty())
     SetCondition();
   if (!hitCondition.empty())
diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h
index 4d2e58ed753360..a789208f1c7ae6 100644
--- a/lldb/tools/lldb-dap/Watchpoint.h
+++ b/lldb/tools/lldb-dap/Watchpoint.h
@@ -9,11 +9,12 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H
 #define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H
 
-#include "BreakpointBase.h"
 #include "lldb/API/SBError.h"
 #include "lldb/API/SBWatchpoint.h"
 #include "lldb/API/SBWatchpointOptions.h"
 
+#include "BreakpointBase.h"
+
 namespace lldb_dap {
 
 struct Watchpoint : public BreakpointBase {
@@ -24,9 +25,8 @@ struct Watchpoint : public BreakpointBase {
   lldb::SBWatchpoint wp;
   lldb::SBError error;
 
-  Watchpoint() = default;
-  Watchpoint(const llvm::json::Object &obj);
-  Watchpoint(lldb::SBWatchpoint wp) : wp(wp) {}
+  Watchpoint(DAP &dap, const llvm::json::Object &obj);
+  Watchpoint(DAP &dap, lldb::SBWatchpoint wp) : BreakpointBase(dap), wp(wp) {}
 
   void SetCondition() override;
   void SetHitCondition() override;
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index a2f7be2b214e4a..65dfbbabdcdd12 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -120,62 +120,166 @@ 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) {
+void RegisterRequestCallbacks(DAP &dap);
+
+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) {
-  // Accept a socket connection from any host on "portno".
-  SOCKET newsockfd = -1;
-  struct sockaddr_in serv_addr, cli_addr;
+/// used only by TestVSCode_redirection_to_console.py
+void redirection_test() {
+  printf("stdout message\n");
+  fprintf(stderr, "stderr message\n");
+  fflush(stdout);
+  fflush(stderr);
+}
+
+/// Redirect stdout and stderr fo the IDE's console output.
+///
+/// Errors in this operation will be printed to the log file and the IDE's
+/// console output as well.
+///
+/// \return
+///     A fd pointing to the original stdout.
+void SetupRedirection(DAP &dap, int stdoutfd = -1, int stderrfd = -1) {
+  auto output_callback_stderr = [&dap](llvm::StringRef data) {
+    dap.SendOutput(OutputType::Stderr, data);
+  };
+  auto output_callback_stdout = [&dap](llvm::StringRef data) {
+    dap.SendOutput(OutputType::Stdout, data);
+  };
+
+  llvm::Expected<int> new_stdout_fd =
+      RedirectFd(stdoutfd, output_callback_stdout);
+  if (auto err = new_stdout_fd.takeError()) {
+    std::string error_message = llvm::toString(std::move(err));
+    if (dap.log)
+      *dap.log << error_message << std::endl;
+    output_callback_stderr(error_message);
+  }
+  dap.out = lldb::SBFile(new_stdout_fd.get(), "w", false);
+
+  llvm::Expected<int> new_stderr_fd =
+      RedirectFd(stderrfd, output_callback_stderr);
+  if (auto err = new_stderr_fd.takeError()) {
+    std::string error_message = llvm::toString(std::move(err));
+    if (dap.log)
+      *dap.log << error_message << std::endl;
+    output_callback_stderr(error_message);
+  }
+  dap.err = lldb::SBFile(new_stderr_fd.get(), "w", false);
+
+  /// used only by TestVSCode_redirection_to_console.py
+  if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr)
+    redirection_test();
+}
+
+int AcceptConnection(llvm::StringRef program_path,
+                     const std::vector<std::string> &pre_init_commands,
+                     std::shared_ptr<std::ofstream> log,
+                     ReplMode default_repl_mode, int portno) {
   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;
-  } else {
-    memset((char *)&serv_addr, 0, sizeof(serv_addr));
-    serv_addr.sin_family = AF_INET;
-    // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    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;
-    } else {
-      listen(sockfd, 5);
-      socklen_t clilen = sizeof(cli_addr);
-      newsockfd =
-          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 (log)
+      *log << "error: opening socket (" << strerror(errno) << ")" << std::endl;
+    perror("error: socket(int, int, int)");
+    return 1;
+  }
+
+  struct sockaddr_in serv_addr, cli_addr;
+  bzero(&serv_addr, sizeof(serv_addr));
+  bzero(&cli_addr, sizeof(cli_addr));
+  socklen_t clilen = sizeof(cli_addr);
+  serv_addr.sin_family = AF_INET;
+  // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  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 (log)
+      *log << "error: binding socket (" << strerror(errno) << ")" << std::endl;
+    perror("error: bind(int, struct sockaddr *, socklen_t)");
+#if defined(_WIN32)
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+    return 1;
+  }
+
+  if (listen(sockfd, 5) < 0) {
+    if (log)
+      *log << "error: listen() (" << strerror(errno) << ")" << std::endl;
+    perror("error: listen(int, int)");
 #if defined(_WIN32)
     closesocket(sockfd);
 #else
     close(sockfd);
 #endif
+    return 1;
   }
-  return newsockfd;
+
+  while (true) {
+    SOCKET clientfd =
+        llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
+                                    (struct sockaddr *)&cli_addr, &clilen);
+    if (clientfd < 0) {
+      if (log)
+        *log << "error: accept (" << strerror(errno) << ")" << std::endl;
+      perror("error: accept(int, struct sockaddr *, socklen_t *)");
+      break;
+    }
+
+    std::thread t([program_path, pre_init_commands, log, default_repl_mode,
+                   clientfd]() {
+      printf("accepted client fd %d\n", clientfd);
+      DAP dap = DAP(program_path, log, default_repl_mode);
+      dap.debug_adaptor_path = program_path;
+
+      SetupRedirection(dap);
+      RegisterRequestCallbacks(dap);
+
+      dap.input.descriptor = StreamDescriptor::from_socket(clientfd, false);
+      dap.output.descriptor = StreamDescriptor::from_socket(clientfd, false);
+
+      for (const std::string &arg : pre_init_commands) {
+        dap.pre_init_commands.push_back(arg);
+      }
+
+      bool CleanExit = true;
+      if (auto Err = dap.Loop()) {
+        llvm::errs() << "Transport Error: " << llvm::toString(std::move(Err))
+                     << "\n";
+        CleanExit = false;
+      }
+
+      printf("closing client fd %d ? %s\n", clientfd,
+             CleanExit ? "true" : "false");
+      close(clientfd);
+    });
+    t.detach();
+  }
+
+#if defined(_WIN32)
+  closesocket(sockfd);
+#else
+  close(sockfd);
+#endif
+  return 0;
 }
 
 std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
@@ -191,66 +295,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.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();
 
@@ -266,10 +369,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;
@@ -278,47 +381,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(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(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": {
@@ -375,14 +477,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;
@@ -399,31 +501,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;
         }
@@ -435,7 +537,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);
       }
     }
   }
@@ -446,9 +548,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)) {
@@ -484,50 +586,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(lldb::SBBreakpoint::GetBreakpointFromEvent(event));
+          auto bp = Breakpoint(
+              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
@@ -549,10 +651,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;
         }
@@ -561,9 +663,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
@@ -585,7 +689,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("[")) {
@@ -603,7 +707,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) {
+void SetSourceMapFromArguments(DAP &dap, const llvm::json::Object &arguments) {
   const char *sourceMapHelp =
       "source must be be an array of two-element arrays, "
       "each containing a source and replacement path string.\n";
@@ -622,7 +726,7 @@ void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
       if (mapping == nullptr || mapping->size() != 2 ||
           (*mapping)[0].kind() != llvm::json::Value::String ||
           (*mapping)[1].kind() != llvm::json::Value::String) {
-        g_dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
+        dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
         return;
       }
       const auto mapFrom = GetAsString((*mapping)[0]);
@@ -637,7 +741,7 @@ void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
     }
   } else {
     if (ObjectContainsKey(arguments, sourceMapKey)) {
-      g_dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
+      dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
       return;
     }
     if (sourcePath.empty())
@@ -646,7 +750,7 @@ void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
     strm << "\".\" \"" << sourcePath << "\"";
   }
   if (!sourceMapCommand.empty()) {
-    g_dap.RunLLDBCommands("Setting source map:", {sourceMapCommand});
+    dap.RunLLDBCommands("Setting source map:", {sourceMapCommand});
   }
 }
 
@@ -682,14 +786,15 @@ void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
 // 13. th3->s2
 //
 // s=3,l=3 = [th0->s3, label1, th1->s0]
-bool FillStackFrames(lldb::SBThread &thread, llvm::json::Array &stack_frames,
-                     int64_t &offset, const int64_t start_frame,
-                     const int64_t levels) {
+bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
+                     llvm::json::Array &stack_frames, int64_t &offset,
+                     const int64_t start_frame, const int64_t levels) {
   bool reached_end_of_stack = false;
   for (int64_t i = start_frame;
        static_cast<int64_t>(stack_frames.size()) < levels; i++) {
     if (i == -1) {
-      stack_frames.emplace_back(CreateExtendedStackFrameLabel(thread));
+      stack_frames.emplace_back(
+          CreateExtendedStackFrameLabel(thread, dap.thread_format));
       continue;
     }
 
@@ -700,10 +805,10 @@ bool FillStackFrames(lldb::SBThread &thread, llvm::json::Array &stack_frames,
       break;
     }
 
-    stack_frames.emplace_back(CreateStackFrame(frame));
+    stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format));
   }
 
-  if (g_dap.display_extended_backtrace && reached_end_of_stack) {
+  if (dap.display_extended_backtrace && reached_end_of_stack) {
     // Check for any extended backtraces.
     for (uint32_t bt = 0;
          bt < thread.GetProcess().GetNumExtendedBacktraceTypes(); bt++) {
@@ -713,7 +818,7 @@ bool FillStackFrames(lldb::SBThread &thread, llvm::json::Array &stack_frames,
         continue;
 
       reached_end_of_stack = FillStackFrames(
-          backtrace, stack_frames, offset,
+          dap, backtrace, stack_frames, offset,
           (start_frame - offset) > 0 ? start_frame - offset : -1, levels);
       if (static_cast<int64_t>(stack_frames.size()) >= levels)
         break;
@@ -751,15 +856,15 @@ bool FillStackFrames(lldb::SBThread &thread, llvm::json::Array &stack_frames,
 //     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_attach(const llvm::json::Object &request) {
-  g_dap.is_attach = true;
-  g_dap.last_launch_or_attach_request = request;
+void request_attach(DAP &dap, const llvm::json::Object &request) {
+  dap.is_attach = true;
+  dap.last_launch_or_attach_request = request;
   llvm::json::Object response;
   lldb::SBError error;
   FillResponse(request, response);
   lldb::SBAttachInfo attach_info;
   const int invalid_port = 0;
-  auto arguments = request.getObject("arguments");
+  const auto *arguments = request.getObject("arguments");
   const lldb::pid_t pid =
       GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID);
   const auto gdb_remote_port =
@@ -770,30 +875,29 @@ void request_attach(const llvm::json::Object &request) {
     attach_info.SetProcessID(pid);
   const auto wait_for = GetBoolean(arguments, "waitFor", false);
   attach_info.SetWaitForLaunch(wait_for, false /*async*/);
-  g_dap.init_commands = GetStrings(arguments, "initCommands");
-  g_dap.pre_run_commands = GetStrings(arguments, "preRunCommands");
-  g_dap.stop_commands = GetStrings(arguments, "stopCommands");
-  g_dap.exit_commands = GetStrings(arguments, "exitCommands");
-  g_dap.terminate_commands = GetStrings(arguments, "terminateCommands");
+  dap.init_commands = GetStrings(arguments, "initCommands");
+  dap.pre_run_commands = GetStrings(arguments, "preRunCommands");
+  dap.stop_commands = GetStrings(arguments, "stopCommands");
+  dap.exit_commands = GetStrings(arguments, "exitCommands");
+  dap.terminate_commands = GetStrings(arguments, "terminateCommands");
   auto attachCommands = GetStrings(arguments, "attachCommands");
   llvm::StringRef core_file = GetString(arguments, "coreFile");
   const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30);
-  g_dap.stop_at_entry =
+  dap.stop_at_entry =
       core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true;
-  g_dap.post_run_commands = GetStrings(arguments, "postRunCommands");
+  dap.post_run_commands = GetStrings(arguments, "postRunCommands");
   const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
-  g_dap.enable_auto_variable_summaries =
+  dap.enable_auto_variable_summaries =
       GetBoolean(arguments, "enableAutoVariableSummaries", false);
-  g_dap.enable_synthetic_child_debugging =
+  dap.enable_synthetic_child_debugging =
       GetBoolean(arguments, "enableSyntheticChildDebugging", false);
-  g_dap.display_extended_backtrace =
+  dap.display_extended_backtrace =
       GetBoolean(arguments, "displayExtendedBacktrace", false);
-  g_dap.command_escape_prefix =
-      GetString(arguments, "commandEscapePrefix", "`");
-  g_dap.SetFrameFormat(GetString(arguments, "customFrameFormat"));
-  g_dap.SetThreadFormat(GetString(arguments, "customThreadFormat"));
+  dap.command_escape_prefix = GetString(arguments, "commandEscapePrefix", "`");
+  dap.SetFrameFormat(GetString(arguments, "customFrameFormat"));
+  dap.SetThreadFormat(GetString(arguments, "customThreadFormat"));
 
-  PrintWelcomeMessage();
+  PrintWelcomeMessage(dap);
 
   // This is a hack for loading DWARF in .o files on Mac where the .o files
   // in the debug map of the main executable have relative paths which require
@@ -803,29 +907,29 @@ void request_attach(const llvm::json::Object &request) {
     llvm::sys::fs::set_current_path(debuggerRoot);
 
   // Run any initialize LLDB commands the user specified in the launch.json
-  if (llvm::Error err = g_dap.RunInitCommands()) {
+  if (llvm::Error err = dap.RunInitCommands()) {
     response["success"] = false;
     EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
-  SetSourceMapFromArguments(*arguments);
+  SetSourceMapFromArguments(dap, *arguments);
 
   lldb::SBError status;
-  g_dap.SetTarget(g_dap.CreateTargetFromArguments(*arguments, status));
+  dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status));
   if (status.Fail()) {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message", status.GetCString());
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
   // Run any pre run LLDB commands the user specified in the launch.json
-  if (llvm::Error err = g_dap.RunPreRunCommands()) {
+  if (llvm::Error err = dap.RunPreRunCommands()) {
     response["success"] = false;
     EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
@@ -834,15 +938,15 @@ void request_attach(const llvm::json::Object &request) {
     char attach_msg[256];
     auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg),
                                    "Waiting to attach to \"%s\"...",
-                                   g_dap.target.GetExecutable().GetFilename());
-    g_dap.SendOutput(OutputType::Console,
-                     llvm::StringRef(attach_msg, attach_msg_len));
+                                   dap.target.GetExecutable().GetFilename());
+    dap.SendOutput(OutputType::Console,
+                   llvm::StringRef(attach_msg, attach_msg_len));
   }
   if (attachCommands.empty()) {
     // No "attachCommands", just attach normally.
     // Disable async events so the attach will be successful when we return from
     // the launch call and the launch will happen synchronously
-    g_dap.debugger.SetAsync(false);
+    dap.debugger.SetAsync(false);
     if (core_file.empty()) {
       if ((pid != LLDB_INVALID_PROCESS_ID) &&
           (gdb_remote_port != invalid_port)) {
@@ -850,44 +954,44 @@ void request_attach(const llvm::json::Object &request) {
         error.SetErrorString("The user can't specify both pid and port");
       } else if (gdb_remote_port != invalid_port) {
         // If port is specified and pid is not.
-        lldb::SBListener listener = g_dap.debugger.GetListener();
+        lldb::SBListener listener = dap.debugger.GetListener();
 
         // If the user hasn't provided the hostname property, default localhost
         // being used.
         std::string connect_url =
             llvm::formatv("connect://{0}:", gdb_remote_hostname);
         connect_url += std::to_string(gdb_remote_port);
-        g_dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
-                                   error);
+        dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
+                                 error);
       } else {
         // Attach by process name or id.
-        g_dap.target.Attach(attach_info, error);
+        dap.target.Attach(attach_info, error);
       }
     } else
-      g_dap.target.LoadCore(core_file.data(), error);
+      dap.target.LoadCore(core_file.data(), error);
     // Reenable async events
-    g_dap.debugger.SetAsync(true);
+    dap.debugger.SetAsync(true);
   } else {
     // We have "attachCommands" that are a set of commands that are expected
     // to execute the commands after which a process should be created. If there
     // is no valid process after running these commands, we have failed.
-    if (llvm::Error err = g_dap.RunAttachCommands(attachCommands)) {
+    if (llvm::Error err = dap.RunAttachCommands(attachCommands)) {
       response["success"] = false;
       EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-      g_dap.SendJSON(llvm::json::Value(std::move(response)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
       return;
     }
     // The custom commands might have created a new target so we should use the
     // selected target after these commands are run.
-    g_dap.target = g_dap.debugger.GetSelectedTarget();
+    dap.target = dap.debugger.GetSelectedTarget();
 
     // Make sure the process is attached and stopped before proceeding as the
     // the launch commands are not run using the synchronous mode.
-    error = g_dap.WaitForProcessToStop(timeout_seconds);
+    error = dap.WaitForProcessToStop(timeout_seconds);
   }
 
   if (error.Success() && core_file.empty()) {
-    auto attached_pid = g_dap.target.GetProcess().GetProcessID();
+    auto attached_pid = dap.target.GetProcess().GetProcessID();
     if (attached_pid == LLDB_INVALID_PROCESS_ID) {
       if (attachCommands.empty())
         error.SetErrorString("failed to attach to a process");
@@ -900,13 +1004,13 @@ void request_attach(const llvm::json::Object &request) {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message", std::string(error.GetCString()));
   } else {
-    g_dap.RunPostRunCommands();
+    dap.RunPostRunCommands();
   }
 
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
   if (error.Success()) {
-    SendProcessEvent(Attach);
-    g_dap.SendJSON(CreateEventObject("initialized"));
+    SendProcessEvent(dap, Attach);
+    dap.SendJSON(CreateEventObject("initialized"));
   }
 }
 
@@ -964,15 +1068,15 @@ void request_attach(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_continue(const llvm::json::Object &request) {
+void request_continue(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  lldb::SBProcess process = g_dap.target.GetProcess();
+  lldb::SBProcess process = dap.target.GetProcess();
   lldb::SBError error = process.Continue();
   llvm::json::Object body;
   body.try_emplace("allThreadsContinued", true);
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "ConfigurationDoneRequest": {
@@ -1006,15 +1110,15 @@ void request_continue(const llvm::json::Object &request) {
 //             just an acknowledgement, so no body field is required."
 //             }]
 // },
-void request_configurationDone(const llvm::json::Object &request) {
+void request_configurationDone(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
-  g_dap.configuration_done_sent = true;
-  if (g_dap.stop_at_entry)
-    SendThreadStoppedEvent();
+  dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.configuration_done_sent = true;
+  if (dap.stop_at_entry)
+    SendThreadStoppedEvent(dap);
   else
-    g_dap.target.GetProcess().Continue();
+    dap.target.GetProcess().Continue();
 }
 
 // "DisconnectRequest": {
@@ -1061,15 +1165,15 @@ void request_configurationDone(const llvm::json::Object &request) {
 //                     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_disconnect(const llvm::json::Object &request) {
+void request_disconnect(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
+  const auto *arguments = request.getObject("arguments");
 
-  bool defaultTerminateDebuggee = g_dap.is_attach ? false : true;
+  bool defaultTerminateDebuggee = dap.is_attach ? false : true;
   bool terminateDebuggee =
       GetBoolean(arguments, "terminateDebuggee", defaultTerminateDebuggee);
-  lldb::SBProcess process = g_dap.target.GetProcess();
+  lldb::SBProcess process = dap.target.GetProcess();
   auto state = process.GetState();
   switch (state) {
   case lldb::eStateInvalid:
@@ -1085,24 +1189,24 @@ void request_disconnect(const llvm::json::Object &request) {
   case lldb::eStateSuspended:
   case lldb::eStateStopped:
   case lldb::eStateRunning:
-    g_dap.debugger.SetAsync(false);
+    dap.debugger.SetAsync(false);
     lldb::SBError error = terminateDebuggee ? process.Kill() : process.Detach();
     if (!error.Success())
       EmplaceSafeString(response, "error", error.GetCString());
-    g_dap.debugger.SetAsync(true);
+    dap.debugger.SetAsync(true);
     break;
   }
-  SendTerminatedEvent();
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
-  if (g_dap.event_thread.joinable()) {
-    g_dap.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);
-    g_dap.event_thread.join();
+  SendTerminatedEvent(dap);
+  dap.SendJSON(llvm::json::Value(std::move(response)));
+  if (dap.event_thread.joinable()) {
+    dap.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);
+    dap.event_thread.join();
   }
-  if (g_dap.progress_event_thread.joinable()) {
-    g_dap.broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread);
-    g_dap.progress_event_thread.join();
+  if (dap.progress_event_thread.joinable()) {
+    dap.broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread);
+    dap.progress_event_thread.join();
   }
-  g_dap.disconnecting = true;
+  dap.disconnecting = true;
 }
 
 // "ExceptionInfoRequest": {
@@ -1202,18 +1306,18 @@ void request_disconnect(const llvm::json::Object &request) {
 //     }
 //   }
 // },
-void request_exceptionInfo(const llvm::json::Object &request) {
+void request_exceptionInfo(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
   llvm::json::Object body;
-  lldb::SBThread thread = g_dap.GetLLDBThread(*arguments);
+  lldb::SBThread thread = dap.GetLLDBThread(*arguments);
   if (thread.IsValid()) {
     auto stopReason = thread.GetStopReason();
     if (stopReason == lldb::eStopReasonSignal)
       body.try_emplace("exceptionId", "signal");
     else if (stopReason == lldb::eStopReasonBreakpoint) {
-      ExceptionBreakpoint *exc_bp = g_dap.GetExceptionBPFromStopReason(thread);
+      ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
       if (exc_bp) {
         EmplaceSafeString(body, "exceptionId", exc_bp->filter);
         EmplaceSafeString(body, "description", exc_bp->label);
@@ -1259,7 +1363,7 @@ void request_exceptionInfo(const llvm::json::Object &request) {
     response["success"] = llvm::json::Value(false);
   }
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "CompletionsRequest": {
@@ -1377,14 +1481,14 @@ void request_exceptionInfo(const llvm::json::Object &request) {
 //   "interface", "module", "property", "unit", "value", "enum", "keyword",
 //   "snippet", "text", "color", "file", "reference", "customcolor" ]
 // }
-void request_completions(const llvm::json::Object &request) {
+void request_completions(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body;
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
 
   // If we have a frame, try to set the context for variable completions.
-  lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments);
+  lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
   if (frame.IsValid()) {
     frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
     frame.GetThread().SetSelectedFrame(frame.GetFrameID());
@@ -1404,19 +1508,19 @@ void request_completions(const llvm::json::Object &request) {
   llvm::json::Array targets;
 
   bool had_escape_prefix =
-      llvm::StringRef(text).starts_with(g_dap.command_escape_prefix);
-  ReplMode completion_mode = g_dap.DetectReplMode(frame, text, true);
+      llvm::StringRef(text).starts_with(dap.command_escape_prefix);
+  ReplMode completion_mode = dap.DetectReplMode(frame, text, true);
 
   // Handle the offset change introduced by stripping out the
   // `command_escape_prefix`.
   if (had_escape_prefix) {
-    if (offset < static_cast<int64_t>(g_dap.command_escape_prefix.size())) {
+    if (offset < static_cast<int64_t>(dap.command_escape_prefix.size())) {
       body.try_emplace("targets", std::move(targets));
       response.try_emplace("body", std::move(body));
-      g_dap.SendJSON(llvm::json::Value(std::move(response)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
       return;
     }
-    offset -= g_dap.command_escape_prefix.size();
+    offset -= dap.command_escape_prefix.size();
   }
 
   // While the user is typing then we likely have an incomplete input and cannot
@@ -1433,9 +1537,8 @@ void request_completions(const llvm::json::Object &request) {
 
     lldb::SBStringList matches;
     lldb::SBStringList descriptions;
-    if (!g_dap.debugger.GetCommandInterpreter()
-             .HandleCompletionWithDescriptions(line.c_str(), cursor, 0, 100,
-                                               matches, descriptions))
+    if (!dap.debugger.GetCommandInterpreter().HandleCompletionWithDescriptions(
+            line.c_str(), cursor, 0, 100, matches, descriptions))
       continue;
 
     // The first element is the common substring after the cursor position for
@@ -1465,7 +1568,7 @@ void request_completions(const llvm::json::Object &request) {
 
   body.try_emplace("targets", std::move(targets));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 //  "EvaluateRequest": {
@@ -1592,31 +1695,31 @@ void request_completions(const llvm::json::Object &request) {
 //      "required": [ "body" ]
 //    }]
 //  }
-void request_evaluate(const llvm::json::Object &request) {
+void request_evaluate(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body;
-  auto arguments = request.getObject("arguments");
-  lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments);
+  const auto *const arguments = request.getObject("arguments");
+  lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
   std::string expression = GetString(arguments, "expression").str();
   llvm::StringRef context = GetString(arguments, "context");
   bool repeat_last_command =
-      expression.empty() && g_dap.last_nonempty_var_expression.empty();
+      expression.empty() && dap.last_nonempty_var_expression.empty();
 
   if (context == "repl" &&
       (repeat_last_command ||
        (!expression.empty() &&
-        g_dap.DetectReplMode(frame, expression, false) == ReplMode::Command))) {
+        dap.DetectReplMode(frame, expression, false) == ReplMode::Command))) {
     // Since the current expression is not for a variable, clear the
     // last_nonempty_var_expression field.
-    g_dap.last_nonempty_var_expression.clear();
+    dap.last_nonempty_var_expression.clear();
     // If we're evaluating a command relative to the current frame, set the
     // focus_tid to the current frame for any thread related events.
     if (frame.IsValid()) {
-      g_dap.focus_tid = frame.GetThread().GetThreadID();
+      dap.focus_tid = frame.GetThread().GetThreadID();
     }
-    auto result =
-        RunLLDBCommandsVerbatim(llvm::StringRef(), {std::string(expression)});
+    auto result = RunLLDBCommandsVerbatim(dap, llvm::StringRef(),
+                                          {std::string(expression)});
     EmplaceSafeString(body, "result", result);
     body.try_emplace("variablesReference", (int64_t)0);
   } else {
@@ -1626,9 +1729,9 @@ void request_evaluate(const llvm::json::Object &request) {
       // evaluation); otherwise save the current non-empty expression for the
       // next (possibly empty) variable expression.
       if (expression.empty())
-        expression = g_dap.last_nonempty_var_expression;
+        expression = dap.last_nonempty_var_expression;
       else
-        g_dap.last_nonempty_var_expression = expression;
+        dap.last_nonempty_var_expression = expression;
     }
     // Always try to get the answer from the local variables if possible. If
     // this fails, then if the context is not "hover", actually evaluate an
@@ -1657,12 +1760,12 @@ void request_evaluate(const llvm::json::Object &request) {
       else
         EmplaceSafeString(response, "message", "evaluate failed");
     } else {
-      VariableDescription desc(value);
+      VariableDescription desc(value, dap.enable_auto_variable_summaries);
       EmplaceSafeString(body, "result", desc.GetResult(context));
       EmplaceSafeString(body, "type", desc.display_type_name);
       int64_t var_ref = 0;
       if (value.MightHaveChildren() || ValuePointsToCode(value))
-        var_ref = g_dap.variables.InsertVariable(
+        var_ref = dap.variables.InsertVariable(
             value, /*is_permanent=*/context == "repl");
       if (value.MightHaveChildren())
         body.try_emplace("variablesReference", var_ref);
@@ -1676,7 +1779,7 @@ void request_evaluate(const llvm::json::Object &request) {
     }
   }
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "compileUnitsRequest": {
@@ -1719,16 +1822,16 @@ void request_evaluate(const llvm::json::Object &request) {
 //     }
 //   }]
 // }
-void request_compileUnits(const llvm::json::Object &request) {
+void request_compileUnits(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body;
   llvm::json::Array units;
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
   std::string module_id = std::string(GetString(arguments, "moduleId"));
-  int num_modules = g_dap.target.GetNumModules();
+  int num_modules = dap.target.GetNumModules();
   for (int i = 0; i < num_modules; i++) {
-    auto curr_module = g_dap.target.GetModuleAtIndex(i);
+    auto curr_module = dap.target.GetModuleAtIndex(i);
     if (module_id == curr_module.GetUUIDString()) {
       int num_units = curr_module.GetNumCompileUnits();
       for (int j = 0; j < num_units; j++) {
@@ -1740,7 +1843,7 @@ void request_compileUnits(const llvm::json::Object &request) {
     }
   }
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "modulesRequest": {
@@ -1769,20 +1872,20 @@ void request_compileUnits(const llvm::json::Object &request) {
 //     }
 //   }]
 // }
-void request_modules(const llvm::json::Object &request) {
+void request_modules(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
 
   llvm::json::Array modules;
-  for (size_t i = 0; i < g_dap.target.GetNumModules(); i++) {
-    lldb::SBModule module = g_dap.target.GetModuleAtIndex(i);
-    modules.emplace_back(CreateModule(module));
+  for (size_t i = 0; i < dap.target.GetNumModules(); i++) {
+    lldb::SBModule module = dap.target.GetModuleAtIndex(i);
+    modules.emplace_back(CreateModule(dap.target, module));
   }
 
   llvm::json::Object body;
   body.try_emplace("modules", std::move(modules));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "InitializeRequest": {
@@ -1861,49 +1964,61 @@ void request_modules(const llvm::json::Object &request) {
 //     }
 //   }]
 // }
-void request_initialize(const llvm::json::Object &request) {
+void request_initialize(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body;
 
-  auto log_cb = [](const char *buf, void *baton) -> void {
-    g_dap.SendOutput(OutputType::Console, llvm::StringRef{buf});
-  };
+  const auto *const arguments = request.getObject("arguments");
 
-  auto arguments = request.getObject("arguments");
   // sourceInitFile option is not from formal DAP specification. It is only
   // used by unit tests to prevent sourcing .lldbinit files from environment
   // which may affect the outcome of tests.
   bool source_init_file = GetBoolean(arguments, "sourceInitFile", true);
 
-  g_dap.debugger = lldb::SBDebugger::Create(source_init_file, log_cb, nullptr);
-  if (llvm::Error err = g_dap.RunPreInitCommands()) {
+  lldb::SBDebugger debugger = lldb::SBDebugger::Create(false);
+
+  debugger.SetInputFile(dap.in);
+  debugger.SetOutputFile(dap.out);
+  debugger.SetErrorFile(dap.err);
+
+  lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter();
+
+  if (source_init_file) {
+    lldb::SBCommandReturnObject result;
+    interp.SourceInitFileInCurrentWorkingDirectory(result);
+    interp.SourceInitFileInHomeDirectory(result, false);
+  }
+
+  dap.debugger = debugger;
+  if (llvm::Error err = dap.RunPreInitCommands()) {
     response["success"] = false;
     EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
-  g_dap.PopulateExceptionBreakpoints();
-  auto cmd = g_dap.debugger.GetCommandInterpreter().AddMultiwordCommand(
+  dap.PopulateExceptionBreakpoints();
+  auto cmd = dap.debugger.GetCommandInterpreter().AddMultiwordCommand(
       "lldb-dap", "Commands for managing lldb-dap.");
   if (GetBoolean(arguments, "supportsStartDebuggingRequest", false)) {
     cmd.AddCommand(
-        "start-debugging", new StartDebuggingRequestHandler(),
+        "start-debugging", new StartDebuggingRequestHandler(dap),
         "Sends a startDebugging request from the debug adapter to the client "
         "to start a child debug session of the same type as the caller.");
   }
   cmd.AddCommand(
-      "repl-mode", new ReplModeRequestHandler(),
+      "repl-mode", new ReplModeRequestHandler(dap),
       "Get or set the repl behavior of lldb-dap evaluation requests.");
-  cmd.AddCommand("send-event", new SendEventRequestHandler(),
+  cmd.AddCommand("send-event", new SendEventRequestHandler(dap),
                  "Sends an DAP event to the client.");
 
-  g_dap.progress_event_thread = std::thread(ProgressEventThreadFunction);
+  dap.progress_event_thread =
+      std::thread(ProgressEventThreadFunction, std::ref(dap));
 
   // Start our event thread so we can receive events from the debugger, target,
   // process and more.
-  g_dap.event_thread = std::thread(EventThreadFunction);
+  dap.event_thread = std::thread(EventThreadFunction, std::ref(dap));
 
   // The debug adapter supports the configurationDoneRequest.
   body.try_emplace("supportsConfigurationDoneRequest", true);
@@ -1919,7 +2034,7 @@ void request_initialize(const llvm::json::Object &request) {
   body.try_emplace("supportsEvaluateForHovers", true);
   // Available filters or options for the setExceptionBreakpoints request.
   llvm::json::Array filters;
-  for (const auto &exc_bp : *g_dap.exception_breakpoints) {
+  for (const auto &exc_bp : *dap.exception_breakpoints) {
     filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
   }
   body.try_emplace("exceptionBreakpointFilters", std::move(filters));
@@ -1992,16 +2107,17 @@ void request_initialize(const llvm::json::Object &request) {
 
   // Put in non-DAP specification lldb specific information.
   llvm::json::Object lldb_json;
-  lldb_json.try_emplace("version", g_dap.debugger.GetVersionString());
+  lldb_json.try_emplace("version", dap.debugger.GetVersionString());
   body.try_emplace("__lldb", std::move(lldb_json));
 
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
-llvm::Error request_runInTerminal(const llvm::json::Object &launch_request,
+llvm::Error request_runInTerminal(DAP &dap,
+                                  const llvm::json::Object &launch_request,
                                   const uint64_t timeout_seconds) {
-  g_dap.is_attach = true;
+  dap.is_attach = true;
   lldb::SBAttachInfo attach_info;
 
   llvm::Expected<std::shared_ptr<FifoFile>> comm_file_or_err =
@@ -2017,25 +2133,25 @@ llvm::Error request_runInTerminal(const llvm::json::Object &launch_request,
   debugger_pid = getpid();
 #endif
   llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
-      launch_request, g_dap.debug_adaptor_path, comm_file.m_path, debugger_pid);
-  g_dap.SendReverseRequest("runInTerminal", std::move(reverse_request),
-                           [](llvm::Expected<llvm::json::Value> value) {
-                             if (!value) {
-                               llvm::Error err = value.takeError();
-                               llvm::errs()
-                                   << "runInTerminal request failed: "
-                                   << llvm::toString(std::move(err)) << "\n";
-                             }
-                           });
+      launch_request, dap.debug_adaptor_path, comm_file.m_path, debugger_pid);
+  dap.SendReverseRequest("runInTerminal", std::move(reverse_request),
+                         [](llvm::Expected<llvm::json::Value> value) {
+                           if (!value) {
+                             llvm::Error err = value.takeError();
+                             llvm::errs()
+                                 << "runInTerminal request failed: "
+                                 << llvm::toString(std::move(err)) << "\n";
+                           }
+                         });
 
   if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid())
     attach_info.SetProcessID(*pid);
   else
     return pid.takeError();
 
-  g_dap.debugger.SetAsync(false);
+  dap.debugger.SetAsync(false);
   lldb::SBError error;
-  g_dap.target.Attach(attach_info, error);
+  dap.target.Attach(attach_info, error);
 
   if (error.Fail())
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -2053,11 +2169,11 @@ llvm::Error request_runInTerminal(const llvm::json::Object &launch_request,
   // process right in the middle of the exec. To the user, what we are doing is
   // transparent, as they will only be able to see the process since the exec,
   // completely unaware of the preparatory work.
-  g_dap.target.GetProcess().Continue();
+  dap.target.GetProcess().Continue();
 
   // Now that the actual target is just starting (i.e. exec was just invoked),
   // we return the debugger to its async state.
-  g_dap.debugger.SetAsync(true);
+  dap.debugger.SetAsync(true);
 
   // If sending the notification failed, the launcher should be dead by now and
   // the async didAttach notification should have an error message, so we
@@ -2074,13 +2190,13 @@ llvm::Error request_runInTerminal(const llvm::json::Object &launch_request,
 // runInTerminal if applicable. It doesn't do any of the additional
 // initialization and bookkeeping stuff that is needed for `request_launch`.
 // This way we can reuse the process launching logic for RestartRequest too.
-lldb::SBError LaunchProcess(const llvm::json::Object &request) {
+lldb::SBError LaunchProcess(DAP &dap, const llvm::json::Object &request) {
   lldb::SBError error;
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
   auto launchCommands = GetStrings(arguments, "launchCommands");
 
   // Instantiate a launch info instance for the target.
-  auto launch_info = g_dap.target.GetLaunchInfo();
+  auto launch_info = dap.target.GetLaunchInfo();
 
   // Grab the current working directory if there is one and set it in the
   // launch info.
@@ -2113,29 +2229,29 @@ lldb::SBError LaunchProcess(const llvm::json::Object &request) {
   const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30);
 
   if (GetBoolean(arguments, "runInTerminal", false)) {
-    if (llvm::Error err = request_runInTerminal(request, timeout_seconds))
+    if (llvm::Error err = request_runInTerminal(dap, request, timeout_seconds))
       error.SetErrorString(llvm::toString(std::move(err)).c_str());
   } else if (launchCommands.empty()) {
     // Disable async events so the launch will be successful when we return from
     // the launch call and the launch will happen synchronously
-    g_dap.debugger.SetAsync(false);
-    g_dap.target.Launch(launch_info, error);
-    g_dap.debugger.SetAsync(true);
+    dap.debugger.SetAsync(false);
+    dap.target.Launch(launch_info, error);
+    dap.debugger.SetAsync(true);
   } else {
     // Set the launch info so that run commands can access the configured
     // launch details.
-    g_dap.target.SetLaunchInfo(launch_info);
-    if (llvm::Error err = g_dap.RunLaunchCommands(launchCommands)) {
+    dap.target.SetLaunchInfo(launch_info);
+    if (llvm::Error err = dap.RunLaunchCommands(launchCommands)) {
       error.SetErrorString(llvm::toString(std::move(err)).c_str());
       return error;
     }
     // The custom commands might have created a new target so we should use the
     // selected target after these commands are run.
-    g_dap.target = g_dap.debugger.GetSelectedTarget();
+    dap.target = dap.debugger.GetSelectedTarget();
     // Make sure the process is launched and stopped at the entry point before
     // proceeding as the launch commands are not run using the synchronous
     // mode.
-    error = g_dap.WaitForProcessToStop(timeout_seconds);
+    error = dap.WaitForProcessToStop(timeout_seconds);
   }
   return error;
 }
@@ -2174,32 +2290,31 @@ lldb::SBError LaunchProcess(const llvm::json::Object &request) {
 //                     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_launch(const llvm::json::Object &request) {
-  g_dap.is_attach = false;
-  g_dap.last_launch_or_attach_request = request;
+void request_launch(DAP &dap, const llvm::json::Object &request) {
+  dap.is_attach = false;
+  dap.last_launch_or_attach_request = request;
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
-  g_dap.init_commands = GetStrings(arguments, "initCommands");
-  g_dap.pre_run_commands = GetStrings(arguments, "preRunCommands");
-  g_dap.stop_commands = GetStrings(arguments, "stopCommands");
-  g_dap.exit_commands = GetStrings(arguments, "exitCommands");
-  g_dap.terminate_commands = GetStrings(arguments, "terminateCommands");
-  g_dap.post_run_commands = GetStrings(arguments, "postRunCommands");
-  g_dap.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
+  const auto *const arguments = request.getObject("arguments");
+  dap.init_commands = GetStrings(arguments, "initCommands");
+  dap.pre_run_commands = GetStrings(arguments, "preRunCommands");
+  dap.stop_commands = GetStrings(arguments, "stopCommands");
+  dap.exit_commands = GetStrings(arguments, "exitCommands");
+  dap.terminate_commands = GetStrings(arguments, "terminateCommands");
+  dap.post_run_commands = GetStrings(arguments, "postRunCommands");
+  dap.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
   const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot");
-  g_dap.enable_auto_variable_summaries =
+  dap.enable_auto_variable_summaries =
       GetBoolean(arguments, "enableAutoVariableSummaries", false);
-  g_dap.enable_synthetic_child_debugging =
+  dap.enable_synthetic_child_debugging =
       GetBoolean(arguments, "enableSyntheticChildDebugging", false);
-  g_dap.display_extended_backtrace =
+  dap.display_extended_backtrace =
       GetBoolean(arguments, "displayExtendedBacktrace", false);
-  g_dap.command_escape_prefix =
-      GetString(arguments, "commandEscapePrefix", "`");
-  g_dap.SetFrameFormat(GetString(arguments, "customFrameFormat"));
-  g_dap.SetThreadFormat(GetString(arguments, "customThreadFormat"));
+  dap.command_escape_prefix = GetString(arguments, "commandEscapePrefix", "`");
+  dap.SetFrameFormat(GetString(arguments, "customFrameFormat"));
+  dap.SetThreadFormat(GetString(arguments, "customThreadFormat"));
 
-  PrintWelcomeMessage();
+  PrintWelcomeMessage(dap);
 
   // This is a hack for loading DWARF in .o files on Mac where the .o files
   // in the debug map of the main executable have relative paths which
@@ -2211,50 +2326,50 @@ void request_launch(const llvm::json::Object &request) {
   // Run any initialize LLDB commands the user specified in the launch.json.
   // This is run before target is created, so commands can't do anything with
   // the targets - preRunCommands are run with the target.
-  if (llvm::Error err = g_dap.RunInitCommands()) {
+  if (llvm::Error err = dap.RunInitCommands()) {
     response["success"] = false;
     EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
-  SetSourceMapFromArguments(*arguments);
+  SetSourceMapFromArguments(dap, *arguments);
 
   lldb::SBError status;
-  g_dap.SetTarget(g_dap.CreateTargetFromArguments(*arguments, status));
+  dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status));
   if (status.Fail()) {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message", status.GetCString());
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
   // Run any pre run LLDB commands the user specified in the launch.json
-  if (llvm::Error err = g_dap.RunPreRunCommands()) {
+  if (llvm::Error err = dap.RunPreRunCommands()) {
     response["success"] = false;
     EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
-  status = LaunchProcess(request);
+  status = LaunchProcess(dap, request);
 
   if (status.Fail()) {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message", std::string(status.GetCString()));
   } else {
-    g_dap.RunPostRunCommands();
+    dap.RunPostRunCommands();
   }
 
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 
   if (!status.Fail()) {
-    if (g_dap.is_attach)
-      SendProcessEvent(Attach); // this happens when doing runInTerminal
+    if (dap.is_attach)
+      SendProcessEvent(dap, Attach); // this happens when doing runInTerminal
     else
-      SendProcessEvent(Launch);
+      SendProcessEvent(dap, Launch);
   }
-  g_dap.SendJSON(CreateEventObject("initialized"));
+  dap.SendJSON(CreateEventObject("initialized"));
 }
 
 // Check if the step-granularity is `instruction`
@@ -2308,15 +2423,15 @@ static bool hasInstructionGranularity(const llvm::json::Object &requestArgs) {
 //                     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_next(const llvm::json::Object &request) {
+void request_next(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
-  lldb::SBThread thread = g_dap.GetLLDBThread(*arguments);
+  const auto *const arguments = request.getObject("arguments");
+  lldb::SBThread thread = dap.GetLLDBThread(*arguments);
   if (thread.IsValid()) {
     // Remember the thread ID that caused the resume so we can set the
     // "threadCausedFocus" boolean value in the "stopped" events.
-    g_dap.focus_tid = thread.GetThreadID();
+    dap.focus_tid = thread.GetThreadID();
     if (hasInstructionGranularity(*arguments)) {
       thread.StepInstruction(/*step_over=*/true);
     } else {
@@ -2325,7 +2440,7 @@ void request_next(const llvm::json::Object &request) {
   } else {
     response["success"] = llvm::json::Value(false);
   }
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "PauseRequest": {
@@ -2364,12 +2479,12 @@ void request_next(const llvm::json::Object &request) {
 //     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_pause(const llvm::json::Object &request) {
+void request_pause(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  lldb::SBProcess process = g_dap.target.GetProcess();
+  lldb::SBProcess process = dap.target.GetProcess();
   lldb::SBError error = process.Stop();
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "RestartRequest": {
@@ -2413,14 +2528,14 @@ void request_pause(const llvm::json::Object &request) {
 //     acknowledgement, so no body field is required."
 //   }]
 // },
-void request_restart(const llvm::json::Object &request) {
+void request_restart(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  if (!g_dap.last_launch_or_attach_request) {
+  if (!dap.last_launch_or_attach_request) {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message",
                       "Restart request received but no process was launched.");
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
   // Check if we were in a "launch" session or an "attach" session.
@@ -2432,35 +2547,36 @@ void request_restart(const llvm::json::Object &request) {
   // Note that when using runInTerminal we're technically attached, but it's an
   // implementation detail. The adapter *did* launch the process in response to
   // a "launch" command, so we can still stop it and re-run it. This is why we
-  // don't just check `g_dap.is_attach`.
-  if (GetString(*g_dap.last_launch_or_attach_request, "command") == "attach") {
+  // don't just check `dap.is_attach`.
+  if (GetString(*dap.last_launch_or_attach_request, "command") == "attach") {
     response["success"] = llvm::json::Value(false);
     EmplaceSafeString(response, "message",
                       "Restarting an \"attach\" session is not supported.");
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
   // The optional `arguments` field in RestartRequest can contain an updated
   // version of the launch arguments. If there's one, use it.
-  auto restart_arguments = request.getObject("arguments");
+  const auto *restart_arguments = request.getObject("arguments");
   if (restart_arguments) {
-    auto launch_request_arguments = restart_arguments->getObject("arguments");
+    const auto *launch_request_arguments =
+        restart_arguments->getObject("arguments");
     if (launch_request_arguments) {
-      (*g_dap.last_launch_or_attach_request)["arguments"] =
+      (*dap.last_launch_or_attach_request)["arguments"] =
           llvm::json::Value(llvm::json::Object(*launch_request_arguments));
     }
   }
 
   // Keep track of the old PID so when we get a "process exited" event from the
   // killed process we can detect it and not shut down the whole session.
-  lldb::SBProcess process = g_dap.target.GetProcess();
-  g_dap.restarting_process_id = process.GetProcessID();
+  lldb::SBProcess process = dap.target.GetProcess();
+  dap.restarting_process_id = process.GetProcessID();
 
   // Stop the current process if necessary. The logic here is similar to
   // CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that
   // we don't ask the user for confirmation.
-  g_dap.debugger.SetAsync(false);
+  dap.debugger.SetAsync(false);
   if (process.IsValid()) {
     lldb::StateType state = process.GetState();
     if (state != lldb::eStateConnected) {
@@ -2468,21 +2584,21 @@ void request_restart(const llvm::json::Object &request) {
     }
     // Clear the list of thread ids to avoid sending "thread exited" events
     // for threads of the process we are terminating.
-    g_dap.thread_ids.clear();
+    dap.thread_ids.clear();
   }
-  g_dap.debugger.SetAsync(true);
-  LaunchProcess(*g_dap.last_launch_or_attach_request);
+  dap.debugger.SetAsync(true);
+  LaunchProcess(dap, *dap.last_launch_or_attach_request);
 
   // This is normally done after receiving a "configuration done" request.
   // Because we're restarting, configuration has already happened so we can
   // continue the process right away.
-  if (g_dap.stop_at_entry) {
-    SendThreadStoppedEvent();
+  if (dap.stop_at_entry) {
+    SendThreadStoppedEvent(dap);
   } else {
-    g_dap.target.GetProcess().Continue();
+    dap.target.GetProcess().Continue();
   }
 
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "ScopesRequest": {
@@ -2536,12 +2652,12 @@ void request_restart(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_scopes(const llvm::json::Object &request) {
+void request_scopes(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body;
-  auto arguments = request.getObject("arguments");
-  lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments);
+  const auto *const arguments = request.getObject("arguments");
+  lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
   // As the user selects different stack frames in the GUI, a "scopes" request
   // will be sent to the DAP. This is the only way we know that the user has
   // selected a frame in a thread. There are no other notifications that are
@@ -2561,18 +2677,18 @@ void request_scopes(const llvm::json::Object &request) {
     frame.GetThread().SetSelectedFrame(frame.GetFrameID());
   }
 
-  g_dap.variables.locals = frame.GetVariables(/*arguments=*/true,
-                                              /*locals=*/true,
-                                              /*statics=*/false,
-                                              /*in_scope_only=*/true);
-  g_dap.variables.globals = frame.GetVariables(/*arguments=*/false,
-                                               /*locals=*/false,
-                                               /*statics=*/true,
-                                               /*in_scope_only=*/true);
-  g_dap.variables.registers = frame.GetRegisters();
-  body.try_emplace("scopes", g_dap.CreateTopLevelScopes());
+  dap.variables.locals = frame.GetVariables(/*arguments=*/true,
+                                            /*locals=*/true,
+                                            /*statics=*/false,
+                                            /*in_scope_only=*/true);
+  dap.variables.globals = frame.GetVariables(/*arguments=*/false,
+                                             /*locals=*/false,
+                                             /*statics=*/true,
+                                             /*in_scope_only=*/true);
+  dap.variables.registers = frame.GetRegisters();
+  body.try_emplace("scopes", dap.CreateTopLevelScopes());
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SetBreakpointsRequest": {
@@ -2685,14 +2801,14 @@ void request_scopes(const llvm::json::Object &request) {
 //   },
 //   "required": [ "line" ]
 // }
-void request_setBreakpoints(const llvm::json::Object &request) {
+void request_setBreakpoints(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   lldb::SBError error;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
-  auto source = arguments->getObject("source");
+  const auto *const arguments = request.getObject("arguments");
+  const auto *source = arguments->getObject("source");
   const auto path = GetString(source, "path");
-  auto breakpoints = arguments->getArray("breakpoints");
+  const auto *breakpoints = arguments->getArray("breakpoints");
   llvm::json::Array response_breakpoints;
 
   // Decode the source breakpoint infos for this "setBreakpoints" request
@@ -2701,14 +2817,14 @@ void request_setBreakpoints(const llvm::json::Object &request) {
   // to an empty array.
   if (breakpoints) {
     for (const auto &bp : *breakpoints) {
-      auto bp_obj = bp.getAsObject();
+      const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
-        SourceBreakpoint src_bp(*bp_obj);
-        request_bps[src_bp.line] = src_bp;
+        SourceBreakpoint src_bp(dap, *bp_obj);
+        request_bps.try_emplace(src_bp.line, src_bp);
 
         // We check if this breakpoint already exists to update it
-        auto existing_source_bps = g_dap.source_breakpoints.find(path);
-        if (existing_source_bps != g_dap.source_breakpoints.end()) {
+        auto existing_source_bps = dap.source_breakpoints.find(path);
+        if (existing_source_bps != dap.source_breakpoints.end()) {
           const auto &existing_bp =
               existing_source_bps->second.find(src_bp.line);
           if (existing_bp != existing_source_bps->second.end()) {
@@ -2719,10 +2835,9 @@ void request_setBreakpoints(const llvm::json::Object &request) {
           }
         }
         // At this point the breakpoint is new
-        g_dap.source_breakpoints[path][src_bp.line] = src_bp;
-        SourceBreakpoint &new_bp = g_dap.source_breakpoints[path][src_bp.line];
-        new_bp.SetBreakpoint(path.data());
-        AppendBreakpoint(&new_bp, response_breakpoints, path, new_bp.line);
+        dap.source_breakpoints[path].try_emplace(src_bp.line, src_bp);
+        src_bp.SetBreakpoint(path.data());
+        AppendBreakpoint(&src_bp, response_breakpoints, path, src_bp.line);
       }
     }
   }
@@ -2730,13 +2845,13 @@ void request_setBreakpoints(const llvm::json::Object &request) {
   // Delete any breakpoints in this source file that aren't in the
   // request_bps set. There is no call to remove breakpoints other than
   // calling this function with a smaller or empty "breakpoints" list.
-  auto old_src_bp_pos = g_dap.source_breakpoints.find(path);
-  if (old_src_bp_pos != g_dap.source_breakpoints.end()) {
+  auto old_src_bp_pos = dap.source_breakpoints.find(path);
+  if (old_src_bp_pos != dap.source_breakpoints.end()) {
     for (auto &old_bp : old_src_bp_pos->second) {
       auto request_pos = request_bps.find(old_bp.first);
       if (request_pos == request_bps.end()) {
         // This breakpoint no longer exists in this source file, delete it
-        g_dap.target.BreakpointDelete(old_bp.second.bp.GetID());
+        dap.target.BreakpointDelete(old_bp.second.bp.GetID());
         old_src_bp_pos->second.erase(old_bp.first);
       }
     }
@@ -2745,7 +2860,7 @@ void request_setBreakpoints(const llvm::json::Object &request) {
   llvm::json::Object body;
   body.try_emplace("breakpoints", std::move(response_breakpoints));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SetExceptionBreakpointsRequest": {
@@ -2795,32 +2910,33 @@ void request_setBreakpoints(const llvm::json::Object &request) {
 //     just an acknowledgement, so no body field is required."
 //   }]
 // }
-void request_setExceptionBreakpoints(const llvm::json::Object &request) {
+void request_setExceptionBreakpoints(DAP &dap,
+                                     const llvm::json::Object &request) {
   llvm::json::Object response;
   lldb::SBError error;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
-  auto filters = arguments->getArray("filters");
+  const auto *const arguments = request.getObject("arguments");
+  const auto *filters = arguments->getArray("filters");
   // Keep a list of any exception breakpoint filter names that weren't set
   // so we can clear any exception breakpoints if needed.
   std::set<std::string> unset_filters;
-  for (const auto &bp : *g_dap.exception_breakpoints)
+  for (const auto &bp : *dap.exception_breakpoints)
     unset_filters.insert(bp.filter);
 
   for (const auto &value : *filters) {
     const auto filter = GetAsString(value);
-    auto exc_bp = g_dap.GetExceptionBreakpoint(std::string(filter));
+    auto *exc_bp = dap.GetExceptionBreakpoint(std::string(filter));
     if (exc_bp) {
       exc_bp->SetBreakpoint();
       unset_filters.erase(std::string(filter));
     }
   }
   for (const auto &filter : unset_filters) {
-    auto exc_bp = g_dap.GetExceptionBreakpoint(filter);
+    auto *exc_bp = dap.GetExceptionBreakpoint(filter);
     if (exc_bp)
       exc_bp->ClearBreakpoint();
   }
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SetFunctionBreakpointsRequest": {
@@ -2901,31 +3017,32 @@ void request_setExceptionBreakpoints(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_setFunctionBreakpoints(const llvm::json::Object &request) {
+void request_setFunctionBreakpoints(DAP &dap,
+                                    const llvm::json::Object &request) {
   llvm::json::Object response;
   lldb::SBError error;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
-  auto breakpoints = arguments->getArray("breakpoints");
+  const auto *const arguments = request.getObject("arguments");
+  const auto *breakpoints = arguments->getArray("breakpoints");
   FunctionBreakpointMap request_bps;
   llvm::json::Array response_breakpoints;
   for (const auto &value : *breakpoints) {
-    auto bp_obj = value.getAsObject();
+    const auto *bp_obj = value.getAsObject();
     if (bp_obj == nullptr)
       continue;
-    FunctionBreakpoint func_bp(*bp_obj);
-    request_bps[func_bp.functionName] = std::move(func_bp);
+    FunctionBreakpoint func_bp(dap, *bp_obj);
+    request_bps.try_emplace(func_bp.functionName, std::move(func_bp));
   }
 
   std::vector<llvm::StringRef> remove_names;
   // Disable any function breakpoints that aren't in the request_bps.
   // There is no call to remove function breakpoints other than calling this
   // function with a smaller or empty "breakpoints" list.
-  for (auto &pair : g_dap.function_breakpoints) {
+  for (auto &pair : dap.function_breakpoints) {
     auto request_pos = request_bps.find(pair.first());
     if (request_pos == request_bps.end()) {
       // This function breakpoint no longer exists delete it from LLDB
-      g_dap.target.BreakpointDelete(pair.second.bp.GetID());
+      dap.target.BreakpointDelete(pair.second.bp.GetID());
       remove_names.push_back(pair.first());
     } else {
       // Update the existing breakpoint as any setting withing the function
@@ -2940,22 +3057,21 @@ void request_setFunctionBreakpoints(const llvm::json::Object &request) {
   }
   // Remove any breakpoints that are no longer in our list
   for (const auto &name : remove_names)
-    g_dap.function_breakpoints.erase(name);
+    dap.function_breakpoints.erase(name);
 
   // Any breakpoints that are left in "request_bps" are breakpoints that
   // need to be set.
   for (auto &pair : request_bps) {
+    pair.second.SetBreakpoint();
     // Add this breakpoint info to the response
-    g_dap.function_breakpoints[pair.first()] = std::move(pair.second);
-    FunctionBreakpoint &new_bp = g_dap.function_breakpoints[pair.first()];
-    new_bp.SetBreakpoint();
-    AppendBreakpoint(&new_bp, response_breakpoints);
+    AppendBreakpoint(&pair.second, response_breakpoints);
+    dap.function_breakpoints.try_emplace(pair.first(), std::move(pair.second));
   }
 
   llvm::json::Object body;
   body.try_emplace("breakpoints", std::move(response_breakpoints));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "DataBreakpointInfoRequest": {
@@ -3050,7 +3166,7 @@ void request_setFunctionBreakpoints(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_dataBreakpointInfo(const llvm::json::Object &request) {
+void request_dataBreakpointInfo(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body;
@@ -3060,8 +3176,8 @@ void request_dataBreakpointInfo(const llvm::json::Object &request) {
   const auto variablesReference =
       GetUnsigned(arguments, "variablesReference", 0);
   llvm::StringRef name = GetString(arguments, "name");
-  lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments);
-  lldb::SBValue variable = FindVariable(variablesReference, name);
+  lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
+  lldb::SBValue variable = FindVariable(dap, variablesReference, name);
   std::string addr, size;
 
   if (variable.IsValid()) {
@@ -3096,7 +3212,7 @@ void request_dataBreakpointInfo(const llvm::json::Object &request) {
         addr = llvm::utohexstr(load_addr);
         lldb::SBMemoryRegionInfo region;
         lldb::SBError err =
-            g_dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region);
+            dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region);
         // Only lldb-server supports "qMemoryRegionInfo". So, don't fail this
         // request if SBProcess::GetMemoryRegionInfo returns error.
         if (err.Success()) {
@@ -3126,7 +3242,7 @@ void request_dataBreakpointInfo(const llvm::json::Object &request) {
                      size + " bytes at " + addr + " " + name.str());
   }
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SetDataBreakpointsRequest": {
@@ -3189,20 +3305,20 @@ void request_dataBreakpointInfo(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_setDataBreakpoints(const llvm::json::Object &request) {
+void request_setDataBreakpoints(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   lldb::SBError error;
   FillResponse(request, response);
   const auto *arguments = request.getObject("arguments");
   const auto *breakpoints = arguments->getArray("breakpoints");
   llvm::json::Array response_breakpoints;
-  g_dap.target.DeleteAllWatchpoints();
+  dap.target.DeleteAllWatchpoints();
   std::vector<Watchpoint> watchpoints;
   if (breakpoints) {
     for (const auto &bp : *breakpoints) {
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
-        Watchpoint wp(*bp_obj);
+        Watchpoint wp(dap, *bp_obj);
         watchpoints.push_back(wp);
       }
     }
@@ -3223,7 +3339,7 @@ void request_setDataBreakpoints(const llvm::json::Object &request) {
   llvm::json::Object body;
   body.try_emplace("breakpoints", std::move(response_breakpoints));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SourceRequest": {
@@ -3284,12 +3400,12 @@ void request_setDataBreakpoints(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_source(const llvm::json::Object &request) {
+void request_source(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Object body{{"content", ""}};
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "StackTraceRequest": {
@@ -3370,12 +3486,12 @@ void request_source(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_stackTrace(const llvm::json::Object &request) {
+void request_stackTrace(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   lldb::SBError error;
-  auto arguments = request.getObject("arguments");
-  lldb::SBThread thread = g_dap.GetLLDBThread(*arguments);
+  const auto *const arguments = request.getObject("arguments");
+  lldb::SBThread thread = dap.GetLLDBThread(*arguments);
   llvm::json::Array stack_frames;
   llvm::json::Object body;
 
@@ -3384,7 +3500,7 @@ void request_stackTrace(const llvm::json::Object &request) {
     const auto levels = GetUnsigned(arguments, "levels", 0);
     int64_t offset = 0;
     bool reached_end_of_stack =
-        FillStackFrames(thread, stack_frames, offset, start_frame,
+        FillStackFrames(dap, thread, stack_frames, offset, start_frame,
                         levels == 0 ? INT64_MAX : levels);
     body.try_emplace("totalFrames",
                      start_frame + stack_frames.size() +
@@ -3393,7 +3509,7 @@ void request_stackTrace(const llvm::json::Object &request) {
 
   body.try_emplace("stackFrames", std::move(stack_frames));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "StepInRequest": {
@@ -3446,25 +3562,25 @@ void request_stackTrace(const llvm::json::Object &request) {
 //     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_stepIn(const llvm::json::Object &request) {
+void request_stepIn(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
 
   std::string step_in_target;
   uint64_t target_id = GetUnsigned(arguments, "targetId", 0);
-  auto it = g_dap.step_in_targets.find(target_id);
-  if (it != g_dap.step_in_targets.end())
+  auto it = dap.step_in_targets.find(target_id);
+  if (it != dap.step_in_targets.end())
     step_in_target = it->second;
 
   const bool single_thread = GetBoolean(arguments, "singleThread", false);
   lldb::RunMode run_mode =
       single_thread ? lldb::eOnlyThisThread : lldb::eOnlyDuringStepping;
-  lldb::SBThread thread = g_dap.GetLLDBThread(*arguments);
+  lldb::SBThread thread = dap.GetLLDBThread(*arguments);
   if (thread.IsValid()) {
     // Remember the thread ID that caused the resume so we can set the
     // "threadCausedFocus" boolean value in the "stopped" events.
-    g_dap.focus_tid = thread.GetThreadID();
+    dap.focus_tid = thread.GetThreadID();
     if (hasInstructionGranularity(*arguments)) {
       thread.StepInstruction(/*step_over=*/false);
     } else {
@@ -3473,7 +3589,7 @@ void request_stepIn(const llvm::json::Object &request) {
   } else {
     response["success"] = llvm::json::Value(false);
   }
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "StepInTargetsRequest": {
@@ -3529,24 +3645,24 @@ void request_stepIn(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_stepInTargets(const llvm::json::Object &request) {
+void request_stepInTargets(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
 
-  g_dap.step_in_targets.clear();
-  lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments);
+  dap.step_in_targets.clear();
+  lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
   if (frame.IsValid()) {
     lldb::SBAddress pc_addr = frame.GetPCAddress();
     lldb::SBAddress line_end_addr =
         pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(true);
-    lldb::SBInstructionList insts = g_dap.target.ReadInstructions(
+    lldb::SBInstructionList insts = dap.target.ReadInstructions(
         pc_addr, line_end_addr, /*flavor_string=*/nullptr);
 
     if (!insts.IsValid()) {
       response["success"] = false;
       response["message"] = "Failed to get instructions for frame.";
-      g_dap.SendJSON(llvm::json::Value(std::move(response)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
       return;
     }
 
@@ -3557,29 +3673,29 @@ void request_stepInTargets(const llvm::json::Object &request) {
       if (!inst.IsValid())
         break;
 
-      lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(g_dap.target);
+      lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(dap.target);
 
       // Note: currently only x86/x64 supports flow kind.
       lldb::InstructionControlFlowKind flow_kind =
-          inst.GetControlFlowKind(g_dap.target);
+          inst.GetControlFlowKind(dap.target);
       if (flow_kind == lldb::eInstructionControlFlowKindCall) {
         // Use call site instruction address as id which is easy to debug.
         llvm::json::Object step_in_target;
         step_in_target["id"] = inst_addr;
 
-        llvm::StringRef call_operand_name = inst.GetOperands(g_dap.target);
+        llvm::StringRef call_operand_name = inst.GetOperands(dap.target);
         lldb::addr_t call_target_addr;
         if (call_operand_name.getAsInteger(0, call_target_addr))
           continue;
 
         lldb::SBAddress call_target_load_addr =
-            g_dap.target.ResolveLoadAddress(call_target_addr);
+            dap.target.ResolveLoadAddress(call_target_addr);
         if (!call_target_load_addr.IsValid())
           continue;
 
         // The existing ThreadPlanStepInRange only accept step in target
         // function with debug info.
-        lldb::SBSymbolContext sc = g_dap.target.ResolveSymbolContextForAddress(
+        lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress(
             call_target_load_addr, lldb::eSymbolContextFunction);
 
         // The existing ThreadPlanStepInRange only accept step in target
@@ -3592,7 +3708,7 @@ void request_stepInTargets(const llvm::json::Object &request) {
         if (step_in_target_name.empty())
           continue;
 
-        g_dap.step_in_targets.try_emplace(inst_addr, step_in_target_name);
+        dap.step_in_targets.try_emplace(inst_addr, step_in_target_name);
         step_in_target.try_emplace("label", step_in_target_name);
         step_in_targets.emplace_back(std::move(step_in_target));
       }
@@ -3604,7 +3720,7 @@ void request_stepInTargets(const llvm::json::Object &request) {
     response["success"] = llvm::json::Value(false);
     response["message"] = "Failed to get frame for input frameId.";
   }
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "StepOutRequest": {
@@ -3643,20 +3759,20 @@ void request_stepInTargets(const llvm::json::Object &request) {
 //     acknowledgement, so no body field is required."
 //   }]
 // }
-void request_stepOut(const llvm::json::Object &request) {
+void request_stepOut(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
-  auto arguments = request.getObject("arguments");
-  lldb::SBThread thread = g_dap.GetLLDBThread(*arguments);
+  const auto *const arguments = request.getObject("arguments");
+  lldb::SBThread thread = dap.GetLLDBThread(*arguments);
   if (thread.IsValid()) {
     // Remember the thread ID that caused the resume so we can set the
     // "threadCausedFocus" boolean value in the "stopped" events.
-    g_dap.focus_tid = thread.GetThreadID();
+    dap.focus_tid = thread.GetThreadID();
     thread.StepOut();
   } else {
     response["success"] = llvm::json::Value(false);
   }
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "ThreadsRequest": {
@@ -3694,8 +3810,8 @@ void request_stepOut(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_threads(const llvm::json::Object &request) {
-  lldb::SBProcess process = g_dap.target.GetProcess();
+void request_threads(DAP &dap, const llvm::json::Object &request) {
+  lldb::SBProcess process = dap.target.GetProcess();
   llvm::json::Object response;
   FillResponse(request, response);
 
@@ -3703,7 +3819,7 @@ void request_threads(const llvm::json::Object &request) {
   llvm::json::Array threads;
   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
     lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
-    threads.emplace_back(CreateThread(thread));
+    threads.emplace_back(CreateThread(thread, dap.thread_format));
   }
   if (threads.size() == 0) {
     response["success"] = llvm::json::Value(false);
@@ -3711,7 +3827,7 @@ void request_threads(const llvm::json::Object &request) {
   llvm::json::Object body;
   body.try_emplace("threads", std::move(threads));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SetVariableRequest": {
@@ -3807,12 +3923,12 @@ void request_threads(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_setVariable(const llvm::json::Object &request) {
+void request_setVariable(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Array variables;
   llvm::json::Object body;
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
   // This is a reference to the containing variable/scope
   const auto variablesReference =
       GetUnsigned(arguments, "variablesReference", 0);
@@ -3832,28 +3948,28 @@ void request_setVariable(const llvm::json::Object &request) {
   // only specifies the variable reference of the enclosing scope/variable, and
   // the name of the variable. We could have two shadowed variables with the
   // same name in "Locals" or "Globals". In our case the "id" absolute index
-  // of the variable within the g_dap.variables list.
+  // of the variable within the dap.variables list.
   const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX);
   if (id_value != UINT64_MAX) {
-    variable = g_dap.variables.GetVariable(id_value);
+    variable = dap.variables.GetVariable(id_value);
   } else {
-    variable = FindVariable(variablesReference, name);
+    variable = FindVariable(dap, variablesReference, name);
   }
 
   if (variable.IsValid()) {
     lldb::SBError error;
     bool success = variable.SetValueFromCString(value.data(), error);
     if (success) {
-      VariableDescription desc(variable);
+      VariableDescription desc(variable, dap.enable_auto_variable_summaries);
       EmplaceSafeString(body, "result", desc.display_value);
       EmplaceSafeString(body, "type", desc.display_type_name);
 
-      // We don't know the index of the variable in our g_dap.variables
+      // We don't know the index of the variable in our dap.variables
       // so always insert a new one to get its variablesReference.
       // is_permanent is false because debug console does not support
       // setVariable request.
       int64_t new_var_ref =
-          g_dap.variables.InsertVariable(variable, /*is_permanent=*/false);
+          dap.variables.InsertVariable(variable, /*is_permanent=*/false);
       if (variable.MightHaveChildren())
         body.try_emplace("variablesReference", new_var_ref);
       else
@@ -3872,7 +3988,7 @@ void request_setVariable(const llvm::json::Object &request) {
   }
 
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "VariablesRequest": {
@@ -3948,21 +4064,22 @@ void request_setVariable(const llvm::json::Object &request) {
 //     "required": [ "body" ]
 //   }]
 // }
-void request_variables(const llvm::json::Object &request) {
+void request_variables(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Array variables;
-  auto arguments = request.getObject("arguments");
+  const auto *const arguments = request.getObject("arguments");
   const auto variablesReference =
       GetUnsigned(arguments, "variablesReference", 0);
   const int64_t start = GetSigned(arguments, "start", 0);
   const int64_t count = GetSigned(arguments, "count", 0);
   bool hex = false;
-  auto format = arguments->getObject("format");
+  const auto *format = arguments->getObject("format");
   if (format)
     hex = GetBoolean(format, "hex", false);
 
-  if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) {
+  if (lldb::SBValueList *top_scope =
+          GetTopLevelScope(dap, variablesReference)) {
     // variablesReference is one of our scopes, not an actual variable it is
     // asking for the list of args, locals or globals.
     int64_t start_idx = 0;
@@ -3974,8 +4091,8 @@ void request_variables(const llvm::json::Object &request) {
       // and resolve what the pointer resolves to. Only change the format if the
       // format was set to the default format or if it was hex as some registers
       // have formats set for them.
-      const uint32_t addr_size = g_dap.target.GetProcess().GetAddressByteSize();
-      lldb::SBValue reg_set = g_dap.variables.registers.GetValueAtIndex(0);
+      const uint32_t addr_size = dap.target.GetProcess().GetAddressByteSize();
+      lldb::SBValue reg_set = dap.variables.registers.GetValueAtIndex(0);
       const uint32_t num_regs = reg_set.GetNumChildren();
       for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
         lldb::SBValue reg = reg_set.GetChildAtIndex(reg_idx);
@@ -4032,25 +4149,27 @@ void request_variables(const llvm::json::Object &request) {
         break;
 
       int64_t var_ref =
-          g_dap.variables.InsertVariable(variable, /*is_permanent=*/false);
+          dap.variables.InsertVariable(variable, /*is_permanent=*/false);
       variables.emplace_back(CreateVariable(
-          variable, var_ref, hex,
+          variable, var_ref, hex, dap.enable_auto_variable_summaries,
           variable_name_counts[GetNonNullVariableName(variable)] > 1));
     }
   } else {
     // We are expanding a variable that has children, so we will return its
     // children.
-    lldb::SBValue variable = g_dap.variables.GetVariable(variablesReference);
+    lldb::SBValue variable = dap.variables.GetVariable(variablesReference);
     if (variable.IsValid()) {
       auto addChild = [&](lldb::SBValue child,
                           std::optional<std::string> custom_name = {}) {
         if (!child.IsValid())
           return;
         bool is_permanent =
-            g_dap.variables.IsPermanentVariableReference(variablesReference);
-        int64_t var_ref = g_dap.variables.InsertVariable(child, is_permanent);
+            dap.variables.IsPermanentVariableReference(variablesReference);
+        int64_t var_ref = dap.variables.InsertVariable(child, is_permanent);
         variables.emplace_back(CreateVariable(
-            child, var_ref, hex, /*is_name_duplicated=*/false, custom_name));
+            child, var_ref, hex, dap.enable_auto_variable_summaries,
+            dap.enable_synthetic_child_debugging,
+            /*is_name_duplicated=*/false, custom_name));
       };
       const int64_t num_children = variable.GetNumChildren();
       int64_t end_idx = start + ((count == 0) ? num_children : count);
@@ -4062,7 +4181,7 @@ void request_variables(const llvm::json::Object &request) {
       // "[raw]" child that can be used to inspect the raw version of a
       // synthetic member. That eliminates the need for the user to go to the
       // debug console and type `frame var <variable> to get these values.
-      if (g_dap.enable_synthetic_child_debugging && variable.IsSynthetic() &&
+      if (dap.enable_synthetic_child_debugging && variable.IsSynthetic() &&
           i == num_children)
         addChild(variable.GetNonSyntheticValue(), "[raw]");
     }
@@ -4070,7 +4189,7 @@ void request_variables(const llvm::json::Object &request) {
   llvm::json::Object body;
   body.try_emplace("variables", std::move(variables));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "LocationsRequest": {
@@ -4150,7 +4269,7 @@ void request_variables(const llvm::json::Object &request) {
 //     }
 //   }]
 // },
-void request_locations(const llvm::json::Object &request) {
+void request_locations(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   auto *arguments = request.getObject("arguments");
@@ -4159,11 +4278,11 @@ void request_locations(const llvm::json::Object &request) {
   // We use the lowest bit to distinguish between value location and declaration
   // location
   auto [var_ref, is_value_location] = UnpackLocation(location_id);
-  lldb::SBValue variable = g_dap.variables.GetVariable(var_ref);
+  lldb::SBValue variable = dap.variables.GetVariable(var_ref);
   if (!variable.IsValid()) {
     response["success"] = false;
     response["message"] = "Invalid variable reference";
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
@@ -4175,18 +4294,18 @@ void request_locations(const llvm::json::Object &request) {
       response["success"] = false;
       response["message"] =
           "Value locations are only available for pointers and references";
-      g_dap.SendJSON(llvm::json::Value(std::move(response)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
       return;
     }
 
     lldb::addr_t addr = variable.GetValueAsAddress();
     lldb::SBLineEntry line_entry =
-        g_dap.target.ResolveLoadAddress(addr).GetLineEntry();
+        dap.target.ResolveLoadAddress(addr).GetLineEntry();
 
     if (!line_entry.IsValid()) {
       response["success"] = false;
       response["message"] = "Failed to resolve line entry for location";
-      g_dap.SendJSON(llvm::json::Value(std::move(response)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
       return;
     }
 
@@ -4201,7 +4320,7 @@ void request_locations(const llvm::json::Object &request) {
     if (!decl.IsValid()) {
       response["success"] = false;
       response["message"] = "No declaration location available";
-      g_dap.SendJSON(llvm::json::Value(std::move(response)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
       return;
     }
 
@@ -4213,7 +4332,7 @@ void request_locations(const llvm::json::Object &request) {
   }
 
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "DisassembleRequest": {
@@ -4288,7 +4407,7 @@ void request_locations(const llvm::json::Object &request) {
 //     }
 //   }]
 // }
-void request_disassemble(const llvm::json::Object &request) {
+void request_disassemble(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   auto *arguments = request.getObject("arguments");
@@ -4299,28 +4418,27 @@ void request_disassemble(const llvm::json::Object &request) {
     response["success"] = false;
     response["message"] =
         "Malformed memory reference: " + memoryReference.str();
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
   lldb::addr_t addr_ptr = *addr_opt;
 
   addr_ptr += GetSigned(arguments, "instructionOffset", 0);
-  lldb::SBAddress addr(addr_ptr, g_dap.target);
+  lldb::SBAddress addr(addr_ptr, dap.target);
   if (!addr.IsValid()) {
     response["success"] = false;
     response["message"] = "Memory reference not found in the current binary.";
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
   const auto inst_count = GetUnsigned(arguments, "instructionCount", 0);
-  lldb::SBInstructionList insts =
-      g_dap.target.ReadInstructions(addr, inst_count);
+  lldb::SBInstructionList insts = dap.target.ReadInstructions(addr, inst_count);
 
   if (!insts.IsValid()) {
     response["success"] = false;
     response["message"] = "Failed to find instructions for memory address.";
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
 
@@ -4330,11 +4448,11 @@ void request_disassemble(const llvm::json::Object &request) {
   for (size_t i = 0; i < num_insts; ++i) {
     lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
     auto addr = inst.GetAddress();
-    const auto inst_addr = addr.GetLoadAddress(g_dap.target);
-    const char *m = inst.GetMnemonic(g_dap.target);
-    const char *o = inst.GetOperands(g_dap.target);
-    const char *c = inst.GetComment(g_dap.target);
-    auto d = inst.GetData(g_dap.target);
+    const auto inst_addr = addr.GetLoadAddress(dap.target);
+    const char *m = inst.GetMnemonic(dap.target);
+    const char *o = inst.GetOperands(dap.target);
+    const char *c = inst.GetComment(dap.target);
+    auto d = inst.GetData(dap.target);
 
     std::string bytes;
     llvm::raw_string_ostream sb(bytes);
@@ -4418,7 +4536,7 @@ void request_disassemble(const llvm::json::Object &request) {
   llvm::json::Object body;
   body.try_emplace("instructions", std::move(instructions));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "ReadMemoryRequest": {
@@ -4498,7 +4616,7 @@ void request_disassemble(const llvm::json::Object &request) {
 //     }
 //   }]
 // },
-void request_readMemory(const llvm::json::Object &request) {
+void request_readMemory(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   auto *arguments = request.getObject("arguments");
@@ -4509,7 +4627,7 @@ void request_readMemory(const llvm::json::Object &request) {
     response["success"] = false;
     response["message"] =
         "Malformed memory reference: " + memoryReference.str();
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
   lldb::addr_t addr_int = *addr_opt;
@@ -4523,13 +4641,13 @@ void request_readMemory(const llvm::json::Object &request) {
   std::vector<uint8_t> buf;
   buf.resize(count_read);
   lldb::SBError error;
-  lldb::SBAddress addr{addr_int, g_dap.target};
+  lldb::SBAddress addr{addr_int, dap.target};
   size_t count_result =
-      g_dap.target.ReadMemory(addr, buf.data(), count_read, error);
+      dap.target.ReadMemory(addr, buf.data(), count_read, error);
   if (count_result == 0) {
     response["success"] = false;
     EmplaceSafeString(response, "message", error.GetCString());
-    g_dap.SendJSON(llvm::json::Value(std::move(response)));
+    dap.SendJSON(llvm::json::Value(std::move(response)));
     return;
   }
   buf.resize(std::min<size_t>(count_result, count_requested));
@@ -4539,25 +4657,26 @@ void request_readMemory(const llvm::json::Object &request) {
   body.try_emplace("address", formatted_addr);
   body.try_emplace("data", llvm::encodeBase64(buf));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // A request used in testing to get the details on all breakpoints that are
 // currently set in the target. This helps us to test "setBreakpoints" and
 // "setFunctionBreakpoints" requests to verify we have the correct set of
 // breakpoints currently set in LLDB.
-void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
+void request__testGetTargetBreakpoints(DAP &dap,
+                                       const llvm::json::Object &request) {
   llvm::json::Object response;
   FillResponse(request, response);
   llvm::json::Array response_breakpoints;
-  for (uint32_t i = 0; g_dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
-    auto bp = Breakpoint(g_dap.target.GetBreakpointAtIndex(i));
+  for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
+    auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i));
     AppendBreakpoint(&bp, response_breakpoints);
   }
   llvm::json::Object body;
   body.try_emplace("breakpoints", std::move(response_breakpoints));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
 // "SetInstructionBreakpointsRequest" : {
@@ -4748,31 +4867,32 @@ void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
 //       },
 //       "required" : ["verified"]
 //     },
-
-void request_setInstructionBreakpoints(const llvm::json::Object &request) {
+void request_setInstructionBreakpoints(DAP &dap,
+                                       const llvm::json::Object &request) {
   llvm::json::Object response;
   llvm::json::Array response_breakpoints;
   llvm::json::Object body;
   FillResponse(request, response);
 
-  auto arguments = request.getObject("arguments");
-  auto breakpoints = arguments->getArray("breakpoints");
+  const auto *const arguments = request.getObject("arguments");
+  const auto *breakpoints = arguments->getArray("breakpoints");
 
   // It holds active instruction breakpoint list received from DAP.
   InstructionBreakpointMap request_ibp;
   if (breakpoints) {
     for (const auto &bp : *breakpoints) {
-      auto bp_obj = bp.getAsObject();
+      const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
         // Read instruction breakpoint request.
-        InstructionBreakpoint inst_bp(*bp_obj);
+        InstructionBreakpoint inst_bp(dap, *bp_obj);
         // Store them into map for reference.
-        request_ibp[inst_bp.instructionAddressReference] = std::move(inst_bp);
+        request_ibp.try_emplace(inst_bp.instructionAddressReference,
+                                std::move(inst_bp));
       }
     }
 
     // Iterate previous active instruction breakpoint list.
-    for (auto &prev_ibp : g_dap.instruction_breakpoints) {
+    for (auto &prev_ibp : dap.instruction_breakpoints) {
       // Find previous instruction breakpoint reference address in newly
       // received instruction breakpoint list.
       auto inst_reference = request_ibp.find(prev_ibp.first);
@@ -4780,9 +4900,9 @@ void request_setInstructionBreakpoints(const llvm::json::Object &request) {
       // breakpoint ID is not available in active instrcation breakpoint list.
       // Means delete removed breakpoint instance.
       if (inst_reference == request_ibp.end()) {
-        g_dap.target.BreakpointDelete(prev_ibp.second.id);
+        dap.target.BreakpointDelete(prev_ibp.second.id);
         // Update Prev instruction breakpoint list.
-        g_dap.instruction_breakpoints.erase(prev_ibp.first);
+        dap.instruction_breakpoints.erase(prev_ibp.first);
       } else {
         // Instead of recreating breakpoint instance, update the breakpoint if
         // there are any conditional changes.
@@ -4794,62 +4914,60 @@ void request_setInstructionBreakpoints(const llvm::json::Object &request) {
     }
 
     for (auto &req_bpi : request_ibp) {
+      req_bpi.second.SetInstructionBreakpoint();
       // Add this breakpoint info to the response
-      g_dap.instruction_breakpoints[req_bpi.first] = std::move(req_bpi.second);
-      InstructionBreakpoint &new_bp =
-          g_dap.instruction_breakpoints[req_bpi.first];
-      new_bp.SetInstructionBreakpoint();
-      response_breakpoints.emplace_back(CreateInstructionBreakpoint(&new_bp));
+      response_breakpoints.emplace_back(
+          CreateInstructionBreakpoint(&req_bpi.second));
+      dap.instruction_breakpoints.try_emplace(req_bpi.first,
+                                              std::move(req_bpi.second));
     }
   }
 
   body.try_emplace("breakpoints", std::move(response_breakpoints));
   response.try_emplace("body", std::move(body));
-  g_dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.SendJSON(llvm::json::Value(std::move(response)));
 }
 
-void RegisterRequestCallbacks() {
-  g_dap.RegisterRequestCallback("attach", request_attach);
-  g_dap.RegisterRequestCallback("completions", request_completions);
-  g_dap.RegisterRequestCallback("continue", request_continue);
-  g_dap.RegisterRequestCallback("configurationDone", request_configurationDone);
-  g_dap.RegisterRequestCallback("disconnect", request_disconnect);
-  g_dap.RegisterRequestCallback("evaluate", request_evaluate);
-  g_dap.RegisterRequestCallback("exceptionInfo", request_exceptionInfo);
-  g_dap.RegisterRequestCallback("initialize", request_initialize);
-  g_dap.RegisterRequestCallback("launch", request_launch);
-  g_dap.RegisterRequestCallback("next", request_next);
-  g_dap.RegisterRequestCallback("pause", request_pause);
-  g_dap.RegisterRequestCallback("restart", request_restart);
-  g_dap.RegisterRequestCallback("scopes", request_scopes);
-  g_dap.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
-  g_dap.RegisterRequestCallback("setExceptionBreakpoints",
-                                request_setExceptionBreakpoints);
-  g_dap.RegisterRequestCallback("setFunctionBreakpoints",
-                                request_setFunctionBreakpoints);
-  g_dap.RegisterRequestCallback("dataBreakpointInfo",
-                                request_dataBreakpointInfo);
-  g_dap.RegisterRequestCallback("setDataBreakpoints",
-                                request_setDataBreakpoints);
-  g_dap.RegisterRequestCallback("setVariable", request_setVariable);
-  g_dap.RegisterRequestCallback("source", request_source);
-  g_dap.RegisterRequestCallback("stackTrace", request_stackTrace);
-  g_dap.RegisterRequestCallback("stepIn", request_stepIn);
-  g_dap.RegisterRequestCallback("stepInTargets", request_stepInTargets);
-  g_dap.RegisterRequestCallback("stepOut", request_stepOut);
-  g_dap.RegisterRequestCallback("threads", request_threads);
-  g_dap.RegisterRequestCallback("variables", request_variables);
-  g_dap.RegisterRequestCallback("locations", request_locations);
-  g_dap.RegisterRequestCallback("disassemble", request_disassemble);
-  g_dap.RegisterRequestCallback("readMemory", request_readMemory);
-  g_dap.RegisterRequestCallback("setInstructionBreakpoints",
-                                request_setInstructionBreakpoints);
+void RegisterRequestCallbacks(DAP &dap) {
+  dap.RegisterRequestCallback("attach", request_attach);
+  dap.RegisterRequestCallback("completions", request_completions);
+  dap.RegisterRequestCallback("continue", request_continue);
+  dap.RegisterRequestCallback("configurationDone", request_configurationDone);
+  dap.RegisterRequestCallback("disconnect", request_disconnect);
+  dap.RegisterRequestCallback("evaluate", request_evaluate);
+  dap.RegisterRequestCallback("exceptionInfo", request_exceptionInfo);
+  dap.RegisterRequestCallback("initialize", request_initialize);
+  dap.RegisterRequestCallback("launch", request_launch);
+  dap.RegisterRequestCallback("next", request_next);
+  dap.RegisterRequestCallback("pause", request_pause);
+  dap.RegisterRequestCallback("restart", request_restart);
+  dap.RegisterRequestCallback("scopes", request_scopes);
+  dap.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
+  dap.RegisterRequestCallback("setExceptionBreakpoints",
+                              request_setExceptionBreakpoints);
+  dap.RegisterRequestCallback("setFunctionBreakpoints",
+                              request_setFunctionBreakpoints);
+  dap.RegisterRequestCallback("dataBreakpointInfo", request_dataBreakpointInfo);
+  dap.RegisterRequestCallback("setDataBreakpoints", request_setDataBreakpoints);
+  dap.RegisterRequestCallback("setVariable", request_setVariable);
+  dap.RegisterRequestCallback("source", request_source);
+  dap.RegisterRequestCallback("stackTrace", request_stackTrace);
+  dap.RegisterRequestCallback("stepIn", request_stepIn);
+  dap.RegisterRequestCallback("stepInTargets", request_stepInTargets);
+  dap.RegisterRequestCallback("stepOut", request_stepOut);
+  dap.RegisterRequestCallback("threads", request_threads);
+  dap.RegisterRequestCallback("variables", request_variables);
+  dap.RegisterRequestCallback("locations", request_locations);
+  dap.RegisterRequestCallback("disassemble", request_disassemble);
+  dap.RegisterRequestCallback("readMemory", request_readMemory);
+  dap.RegisterRequestCallback("setInstructionBreakpoints",
+                              request_setInstructionBreakpoints);
   // Custom requests
-  g_dap.RegisterRequestCallback("compileUnits", request_compileUnits);
-  g_dap.RegisterRequestCallback("modules", request_modules);
+  dap.RegisterRequestCallback("compileUnits", request_compileUnits);
+  dap.RegisterRequestCallback("modules", request_modules);
   // Testing requests
-  g_dap.RegisterRequestCallback("_testGetTargetBreakpoints",
-                                request__testGetTargetBreakpoints);
+  dap.RegisterRequestCallback("_testGetTargetBreakpoints",
+                              request__testGetTargetBreakpoints);
 }
 
 } // anonymous namespace
@@ -4940,49 +5058,6 @@ void LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
 #endif
 }
 
-/// used only by TestVSCode_redirection_to_console.py
-void redirection_test() {
-  printf("stdout message\n");
-  fprintf(stderr, "stderr message\n");
-  fflush(stdout);
-  fflush(stderr);
-}
-
-/// Redirect stdout and stderr fo the IDE's console output.
-///
-/// Errors in this operation will be printed to the log file and the IDE's
-/// console output as well.
-///
-/// \return
-///     A fd pointing to the original stdout.
-int SetupStdoutStderrRedirection() {
-  int stdoutfd = fileno(stdout);
-  int new_stdout_fd = dup(stdoutfd);
-  auto output_callback_stderr = [](llvm::StringRef data) {
-    g_dap.SendOutput(OutputType::Stderr, data);
-  };
-  auto output_callback_stdout = [](llvm::StringRef data) {
-    g_dap.SendOutput(OutputType::Stdout, data);
-  };
-  if (llvm::Error err = RedirectFd(stdoutfd, output_callback_stdout)) {
-    std::string error_message = llvm::toString(std::move(err));
-    if (g_dap.log)
-      *g_dap.log << error_message << std::endl;
-    output_callback_stderr(error_message);
-  }
-  if (llvm::Error err = RedirectFd(fileno(stderr), output_callback_stderr)) {
-    std::string error_message = llvm::toString(std::move(err));
-    if (g_dap.log)
-      *g_dap.log << error_message << std::endl;
-    output_callback_stderr(error_message);
-  }
-
-  /// used only by TestVSCode_redirection_to_console.py
-  if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr)
-    redirection_test();
-  return new_stdout_fd;
-}
-
 int main(int argc, char *argv[]) {
   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
 #if !defined(__APPLE__)
@@ -4996,7 +5071,6 @@ int main(int argc, char *argv[]) {
 
   llvm::SmallString<256> program_path(argv[0]);
   llvm::sys::fs::make_absolute(program_path);
-  g_dap.debug_adaptor_path = program_path.str().str();
 
   LLDBDAPOptTable T;
   unsigned MAI, MAC;
@@ -5008,15 +5082,16 @@ int main(int argc, char *argv[]) {
     return EXIT_SUCCESS;
   }
 
+  auto default_repl_mode = ReplMode::Auto;
   if (input_args.hasArg(OPT_repl_mode)) {
     llvm::opt::Arg *repl_mode = input_args.getLastArg(OPT_repl_mode);
     llvm::StringRef repl_mode_value = repl_mode->getValue();
     if (repl_mode_value == "auto") {
-      g_dap.repl_mode = ReplMode::Auto;
+      default_repl_mode = ReplMode::Auto;
     } else if (repl_mode_value == "variable") {
-      g_dap.repl_mode = ReplMode::Variable;
+      default_repl_mode = ReplMode::Variable;
     } else if (repl_mode_value == "command") {
-      g_dap.repl_mode = ReplMode::Command;
+      default_repl_mode = ReplMode::Command;
     } else {
       llvm::errs()
           << "'" << repl_mode_value
@@ -5053,22 +5128,21 @@ int main(int argc, char *argv[]) {
     }
   }
 
-  // stdout/stderr redirection to the IDE's console
-  int new_stdout_fd = SetupStdoutStderrRedirection();
-
   // Initialize LLDB first before we do anything.
-  lldb::SBDebugger::Initialize();
+  lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling();
+  if (error.Fail()) {
+    llvm::errs() << "Failed to initialize LLDB: " << error.GetCString() << "\n";
+    return EXIT_FAILURE;
+  }
 
   // Terminate the debugger before the C++ destructor chain kicks in.
   auto terminate_debugger =
       llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
 
-  RegisterRequestCallbacks();
-
   int portno = -1;
 
   if (auto *arg = input_args.getLastArg(OPT_port)) {
-    auto optarg = arg->getValue();
+    const auto *optarg = arg->getValue();
     char *remainder;
     portno = strtol(optarg, &remainder, 0);
     if (remainder == optarg || *remainder != '\0') {
@@ -5077,36 +5151,46 @@ int main(int argc, char *argv[]) {
     }
   }
 
+  const char *log_file_path = getenv("LLDBDAP_LOG");
+  std::shared_ptr<std::ofstream> log;
+  if (log_file_path)
+    log = std::make_shared<std::ofstream>(log_file_path);
+
 #if !defined(_WIN32)
   if (input_args.hasArg(OPT_wait_for_debugger)) {
     printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid());
     pause();
   }
 #endif
+
   if (portno != -1) {
     printf("Listening on port %i...\n", portno);
-    SOCKET socket_fd = AcceptConnection(portno);
-    if (socket_fd >= 0) {
-      g_dap.input.descriptor = StreamDescriptor::from_socket(socket_fd, true);
-      g_dap.output.descriptor = StreamDescriptor::from_socket(socket_fd, false);
-    } else {
-      return EXIT_FAILURE;
-    }
-  } else {
-    g_dap.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false);
-    g_dap.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false);
+    auto pre_init_commands = input_args.getAllArgValues(OPT_pre_init_command);
+    return AcceptConnection(program_path.str(), pre_init_commands,
+                            std::move(log), default_repl_mode, portno);
   }
 
+  DAP dap = DAP(program_path.str(), std::move(log), default_repl_mode);
+
+  // stdout/stderr redirection to the IDE's console
+  int new_stdout_fd = dup(fileno(stdout));
+  SetupRedirection(dap, new_stdout_fd, fileno(stderr));
+
+  // Register request callbacks.
+  RegisterRequestCallbacks(dap);
+
+  dap.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false);
+  dap.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false);
+
   for (const std::string &arg :
        input_args.getAllArgValues(OPT_pre_init_command)) {
-    g_dap.pre_init_commands.push_back(arg);
+    dap.pre_init_commands.push_back(arg);
   }
 
   bool CleanExit = true;
-  if (auto Err = g_dap.Loop()) {
-    if (g_dap.log)
-      *g_dap.log << "Transport Error: " << llvm::toString(std::move(Err))
-                 << "\n";
+  if (auto Err = dap.Loop()) {
+    if (dap.log)
+      *dap.log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
     CleanExit = false;
   }
 

>From 4c8a1b73e591686123f92aa2d02920afebbb1b0d Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 1 Nov 2024 14:44:12 -0700
Subject: [PATCH 2/5] Fix dap_server.py to work with python3, we need to
 explicitly open file handles for sockets with "b" to write `bytes` instead of
 `str`.

Fix lldb-dap.cpp handling of stdout.
---
 .../Python/lldbsuite/test/lldbtest.py         |   8 +
 .../test/tools/lldb-dap/dap_server.py         |  93 +++--
 .../test/tools/lldb-dap/lldbdap_testcase.py   |  18 +-
 lldb/test/API/tools/lldb-dap/server/Makefile  |   3 +
 .../tools/lldb-dap/server/TestDAP_server.py   |  67 ++++
 lldb/test/API/tools/lldb-dap/server/main.c    |   6 +
 lldb/tools/lldb-dap/Breakpoint.h              |   6 +-
 lldb/tools/lldb-dap/BreakpointBase.cpp        |   4 +-
 lldb/tools/lldb-dap/BreakpointBase.h          |   8 +-
 lldb/tools/lldb-dap/FunctionBreakpoint.cpp    |   6 +-
 lldb/tools/lldb-dap/FunctionBreakpoint.h      |   2 +-
 lldb/tools/lldb-dap/InstructionBreakpoint.cpp |   6 +-
 lldb/tools/lldb-dap/InstructionBreakpoint.h   |   4 +-
 lldb/tools/lldb-dap/JSONUtils.cpp             |   5 +-
 lldb/tools/lldb-dap/JSONUtils.h               |   2 +-
 lldb/tools/lldb-dap/Options.td                |   9 +
 lldb/tools/lldb-dap/SourceBreakpoint.cpp      |  20 +-
 lldb/tools/lldb-dap/SourceBreakpoint.h        |   3 +-
 lldb/tools/lldb-dap/Watchpoint.cpp            |   7 +-
 lldb/tools/lldb-dap/Watchpoint.h              |   4 +-
 lldb/tools/lldb-dap/lldb-dap.cpp              | 354 ++++++++++++------
 21 files changed, 453 insertions(+), 182 deletions(-)
 create mode 100644 lldb/test/API/tools/lldb-dap/server/Makefile
 create mode 100644 lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
 create mode 100644 lldb/test/API/tools/lldb-dap/server/main.c

diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 8884ef5933ada8..c143b7ba37af22 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -37,6 +37,7 @@
 import re
 import shutil
 import signal
+import socket
 from subprocess import *
 import sys
 import time
@@ -250,6 +251,13 @@ def which(program):
     return None
 
 
+def pickrandomport():
+    """Returns a random open port."""
+    with socket.socket() as sock:
+        sock.bind(("", 0))
+        return sock.getsockname()[1]
+
+
 class ValueCheck:
     def __init__(
         self,
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 c29992ce9c7848..31819328040aca 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
@@ -903,7 +903,7 @@ def request_setBreakpoints(self, file_path, line_array, data=None):
             "sourceModified": False,
         }
         if line_array is not None:
-            args_dict["lines"] = "%s" % line_array
+            args_dict["lines"] = line_array
             breakpoints = []
             for i, line in enumerate(line_array):
                 breakpoint_data = None
@@ -1154,34 +1154,32 @@ class DebugAdaptorServer(DebugCommunication):
     def __init__(
         self,
         executable=None,
-        port=None,
+        launch=True,
+        connect=None,
         init_commands=[],
         log_file=None,
         env=None,
     ):
         self.process = None
-        if executable is not None:
-            adaptor_env = os.environ.copy()
-            if env is not None:
-                adaptor_env.update(env)
-
-            if log_file:
-                adaptor_env["LLDBDAP_LOG"] = log_file
-            self.process = subprocess.Popen(
-                [executable],
-                stdin=subprocess.PIPE,
-                stdout=subprocess.PIPE,
-                stderr=subprocess.PIPE,
-                env=adaptor_env,
+        if launch:
+            self.process = DebugAdaptorServer.launch(
+                executable, connect=connect, log_file=log_file, env=env
             )
+
+        if connect:
+            if isinstance(connect, str) and connect.startswith("/"):
+                s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+                s.connect(connect)
+            else:
+                port = int(connect)
+                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                s.connect(("127.0.0.1", port))
             DebugCommunication.__init__(
-                self, self.process.stdout, self.process.stdin, init_commands, log_file
+                self, s.makefile("rb"), s.makefile("wb"), init_commands, log_file
             )
-        elif port is not None:
-            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            s.connect(("127.0.0.1", port))
+        else:
             DebugCommunication.__init__(
-                self, s.makefile("r"), s.makefile("w"), init_commands
+                self, self.process.stdout, self.process.stdin, init_commands, log_file
             )
 
     def get_pid(self):
@@ -1191,11 +1189,45 @@ def get_pid(self):
 
     def terminate(self):
         super(DebugAdaptorServer, self).terminate()
-        if self.process is not None:
+        if self.process:
             self.process.terminate()
             self.process.wait()
             self.process = None
 
+    @classmethod
+    def launch(
+        cls, executable: str, /, connect=None, log_file=None, env=None
+    ) -> subprocess.Popen:
+        adaptor_env = os.environ.copy()
+        if env:
+            adaptor_env.update(env)
+
+        if log_file:
+            adaptor_env["LLDBDAP_LOG"] = log_file
+
+        args = [executable]
+        if connect:
+            if isinstance(connect, str) and connect.startswith("/"):
+                args.append("--unix-socket")
+                args.append(connect)
+            else:
+                args.append("--port")
+                args.append(str(connect))
+
+        proc = subprocess.Popen(
+            args,
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            stderr=sys.stdout,
+            env=adaptor_env,
+        )
+
+        if connect:
+            # Wait for the server to startup.
+            time.sleep(0.1)
+
+        return proc
+
 
 def attach_options_specified(options):
     if options.pid is not None:
@@ -1271,9 +1303,9 @@ def main():
     )
 
     parser.add_option(
-        "--vscode",
+        "--dap",
         type="string",
-        dest="vscode_path",
+        dest="dap",
         help=(
             "The path to the command line program that implements the "
             "Visual Studio Code Debug Adaptor protocol."
@@ -1349,10 +1381,9 @@ def main():
     )
 
     parser.add_option(
-        "--port",
-        type="int",
-        dest="port",
-        help="Attach a socket to a port instead of using STDIN for VSCode",
+        "--connect",
+        dest="connect",
+        help="Attach a socket to the connection ('<port>' or '<path>') instead of using STDIN for VSCode",
         default=None,
     )
 
@@ -1498,15 +1529,15 @@ def main():
 
     (options, args) = parser.parse_args(sys.argv[1:])
 
-    if options.vscode_path is None and options.port is None:
+    if options.dap is None and options.connect is None:
         print(
             "error: must either specify a path to a Visual Studio Code "
-            "Debug Adaptor vscode executable path using the --vscode "
+            "Debug Adaptor vscode executable path using the --dap "
             "option, or a port to attach to for an existing lldb-dap "
-            "using the --port option"
+            "using the --connect option"
         )
         return
-    dbg = DebugAdaptorServer(executable=options.vscode_path, port=options.port)
+    dbg = DebugAdaptorServer(executable=options.dap, port=options.connect)
     if options.debug:
         raw_input('Waiting for debugger to attach pid "%i"' % (dbg.get_pid()))
     if options.replay:
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index a25466f07fa557..39d200a2ac566e 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -13,7 +13,7 @@ class DAPTestCaseBase(TestBase):
     timeoutval = 10 * (10 if ('ASAN_OPTIONS' in os.environ) else 1)
     NO_DEBUG_INFO_TESTCASE = True
 
-    def create_debug_adaptor(self, lldbDAPEnv=None):
+    def create_debug_adaptor(self, env=None, launch=True, connect=None):
         """Create the Visual Studio Code debug adaptor"""
         self.assertTrue(
             is_exe(self.lldbDAPExec), "lldb-dap must exist and be executable"
@@ -21,14 +21,20 @@ def create_debug_adaptor(self, lldbDAPEnv=None):
         log_file_path = self.getBuildArtifact("dap.txt")
         self.dap_server = dap_server.DebugAdaptorServer(
             executable=self.lldbDAPExec,
+            launch=launch,
+            connect=connect,
             init_commands=self.setUpCommands(),
             log_file=log_file_path,
-            env=lldbDAPEnv,
+            env=env,
         )
 
-    def build_and_create_debug_adaptor(self, lldbDAPEnv=None):
+    def build_and_create_debug_adaptor(
+        self, lldbDAPEnv=None, lldbDAPLaunch=True, lldbDAPConnect=None
+    ):
         self.build()
-        self.create_debug_adaptor(lldbDAPEnv)
+        self.create_debug_adaptor(
+            lldbDAPEnv, launch=lldbDAPLaunch, connect=lldbDAPConnect
+        )
 
     def set_source_breakpoints(self, source_path, lines, data=None):
         """Sets source breakpoints and returns an array of strings containing
@@ -475,11 +481,13 @@ def build_and_launch(
         customThreadFormat=None,
         launchCommands=None,
         expectFailure=False,
+        lldbDAPConnect=None,
+        lldbDAPLaunch=True,
     ):
         """Build the default Makefile target, create the DAP debug adaptor,
         and launch the process.
         """
-        self.build_and_create_debug_adaptor(lldbDAPEnv)
+        self.build_and_create_debug_adaptor(lldbDAPEnv, lldbDAPLaunch, lldbDAPConnect)
         self.assertTrue(os.path.exists(program), "executable must exist")
 
         return self.launch(
diff --git a/lldb/test/API/tools/lldb-dap/server/Makefile b/lldb/test/API/tools/lldb-dap/server/Makefile
new file mode 100644
index 00000000000000..10495940055b63
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/server/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
new file mode 100644
index 00000000000000..ae7094b096c4d7
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
@@ -0,0 +1,67 @@
+"""
+Test lldb-dap server integration.
+"""
+
+import os
+import tempfile
+
+import dap_server
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbdap_testcase
+
+
+class TestDAP_server(lldbdap_testcase.DAPTestCaseBase):
+    def do_test_server(self, connect):
+        log_file_path = self.getBuildArtifact("dap.txt")
+        print("connect", connect)
+        server = dap_server.DebugAdaptorServer.launch(
+            self.lldbDAPExec, connect=connect, log_file=log_file_path
+        )
+
+        def cleanup():
+            server.terminate()
+            server.wait()
+
+        self.addTearDownHook(cleanup)
+
+        self.build()
+        program = self.getBuildArtifact("a.out")
+        source = "main.c"
+        breakpoint_line = line_number(source, "// breakpoint")
+
+        # Initial connection over the port.
+        self.create_debug_adaptor(launch=False, connect=connect)
+        self.launch(
+            program,
+            disconnectAutomatically=False,
+        )
+        self.set_source_breakpoints(source, [breakpoint_line])
+        self.continue_to_next_stop()
+        self.continue_to_exit()
+        output = self.get_stdout()
+        self.assertEquals(output, "hello world!\r\n")
+        self.dap_server.request_disconnect()
+
+        # Second connection over the port.
+        self.create_debug_adaptor(launch=False, connect=connect)
+        self.launch(program)
+        self.set_source_breakpoints(source, [breakpoint_line])
+        self.continue_to_next_stop()
+        self.continue_to_exit()
+        output = self.get_stdout()
+        self.assertEquals(output, "hello world!\r\n")
+
+    def test_server_port(self):
+        """
+        Test launching a binary with a lldb-dap in server mode on a specific port.
+        """
+        port = pickrandomport()
+        self.do_test_server(port)
+
+    def test_server_unix_socket(self):
+        """
+        Test launching a binary with a lldb-dap in server mode on a unix socket.
+        """
+        dir = tempfile.gettempdir()
+        self.do_test_server(dir + "/dap-connection-" + str(os.getpid()))
diff --git a/lldb/test/API/tools/lldb-dap/server/main.c b/lldb/test/API/tools/lldb-dap/server/main.c
new file mode 100644
index 00000000000000..c3599057621276
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/server/main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char const *argv[]) {
+  printf("hello world!\n"); // breakpoint 1
+  return 0;
+}
diff --git a/lldb/tools/lldb-dap/Breakpoint.h b/lldb/tools/lldb-dap/Breakpoint.h
index cffeb2fab1f0ef..add4ff4da2a9bb 100644
--- a/lldb/tools/lldb-dap/Breakpoint.h
+++ b/lldb/tools/lldb-dap/Breakpoint.h
@@ -19,9 +19,9 @@ struct Breakpoint : public BreakpointBase {
   // The LLDB breakpoint associated wit this source breakpoint
   lldb::SBBreakpoint bp;
 
-  Breakpoint(DAP &d) : BreakpointBase(d) {}
-  Breakpoint(DAP &d, const llvm::json::Object &obj) : BreakpointBase(d, obj) {}
-  Breakpoint(DAP &d, lldb::SBBreakpoint bp) : BreakpointBase(d), bp(bp) {}
+  Breakpoint(DAP *d) : BreakpointBase(d) {}
+  Breakpoint(DAP *d, const llvm::json::Object &obj) : BreakpointBase(d, obj) {}
+  Breakpoint(DAP *d, lldb::SBBreakpoint bp) : BreakpointBase(d), bp(bp) {}
 
   void SetCondition() override;
   void SetHitCondition() override;
diff --git a/lldb/tools/lldb-dap/BreakpointBase.cpp b/lldb/tools/lldb-dap/BreakpointBase.cpp
index f07921783aa985..27ae000e88c37a 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.cpp
+++ b/lldb/tools/lldb-dap/BreakpointBase.cpp
@@ -11,9 +11,7 @@
 
 using namespace lldb_dap;
 
-BreakpointBase::BreakpointBase(DAP &d) : dap(d) {}
-
-BreakpointBase::BreakpointBase(DAP &d, const llvm::json::Object &obj)
+BreakpointBase::BreakpointBase(DAP *d, const llvm::json::Object &obj)
     : dap(d), condition(std::string(GetString(obj, "condition"))),
       hitCondition(std::string(GetString(obj, "hitCondition"))) {}
 
diff --git a/lldb/tools/lldb-dap/BreakpointBase.h b/lldb/tools/lldb-dap/BreakpointBase.h
index 121688d08f1524..cc808f396e99e2 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.h
+++ b/lldb/tools/lldb-dap/BreakpointBase.h
@@ -19,7 +19,7 @@ namespace lldb_dap {
 
 struct BreakpointBase {
   // Associated DAP session.
-  DAP &dap;
+  DAP *dap;
 
   // An optional expression for conditional breakpoints.
   std::string condition;
@@ -27,8 +27,10 @@ struct BreakpointBase {
   // ignored. The backend is expected to interpret the expression as needed
   std::string hitCondition;
 
-  BreakpointBase(DAP &d);
-  BreakpointBase(DAP &d, const llvm::json::Object &obj);
+  BreakpointBase(DAP *d) : dap(d) {}
+  BreakpointBase(DAP *d, const llvm::json::Object &obj);
+  BreakpointBase() = default;
+  BreakpointBase(const BreakpointBase &) = default;
   virtual ~BreakpointBase() = default;
 
   virtual void SetCondition() = 0;
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
index ef6df6c0dc91cc..e35dc2dc2ca4b8 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
@@ -13,13 +13,13 @@
 
 namespace lldb_dap {
 
-FunctionBreakpoint::FunctionBreakpoint(DAP &d, const llvm::json::Object &obj)
+FunctionBreakpoint::FunctionBreakpoint(DAP *d, const llvm::json::Object &obj)
     : Breakpoint(d, obj), functionName(std::string(GetString(obj, "name"))) {}
 
 void FunctionBreakpoint::SetBreakpoint() {
-  if (functionName.empty())
+  if (functionName.empty() || !dap)
     return;
-  bp = dap.target.BreakpointCreateByName(functionName.c_str());
+  bp = dap->target.BreakpointCreateByName(functionName.c_str());
   Breakpoint::SetBreakpoint();
 }
 
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.h b/lldb/tools/lldb-dap/FunctionBreakpoint.h
index 93f0b93b35291d..a66acf8b1945e9 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.h
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.h
@@ -17,7 +17,7 @@ namespace lldb_dap {
 struct FunctionBreakpoint : public Breakpoint {
   std::string functionName;
 
-  FunctionBreakpoint(DAP &dap, const llvm::json::Object &obj);
+  FunctionBreakpoint(DAP *dap, const llvm::json::Object &obj);
 
   // Set this breakpoint in LLDB as a new breakpoint
   void SetBreakpoint();
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
index d6ccb2dfc29111..cd4f719ff13517 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
@@ -15,7 +15,7 @@
 namespace lldb_dap {
 
 // Instruction Breakpoint
-InstructionBreakpoint::InstructionBreakpoint(DAP &d,
+InstructionBreakpoint::InstructionBreakpoint(DAP *d,
                                              const llvm::json::Object &obj)
     : Breakpoint(d, obj), instructionAddressReference(LLDB_INVALID_ADDRESS),
       id(0), offset(GetSigned(obj, "offset", 0)) {
@@ -25,7 +25,9 @@ InstructionBreakpoint::InstructionBreakpoint(DAP &d,
 }
 
 void InstructionBreakpoint::SetInstructionBreakpoint() {
-  bp = dap.target.BreakpointCreateByAddress(instructionAddressReference);
+  if (!dap)
+    return;
+  bp = dap->target.BreakpointCreateByAddress(instructionAddressReference);
   id = bp.GetID();
 }
 
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.h b/lldb/tools/lldb-dap/InstructionBreakpoint.h
index d7f3fb8ad3a4eb..8c5249f9e0825f 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.h
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.h
@@ -26,10 +26,10 @@ struct InstructionBreakpoint : public Breakpoint {
   int32_t id;
   int32_t offset;
 
-  InstructionBreakpoint(DAP &d)
+  InstructionBreakpoint(DAP *d)
       : Breakpoint(d), instructionAddressReference(LLDB_INVALID_ADDRESS), id(0),
         offset(0) {}
-  InstructionBreakpoint(DAP &d, const llvm::json::Object &obj);
+  InstructionBreakpoint(DAP *d, const llvm::json::Object &obj);
 
   // Set instruction breakpoint in LLDB as a new breakpoint
   void SetInstructionBreakpoint();
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index c6d9e86f0d8bf1..0d56b235c52c1c 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -27,6 +27,7 @@
 #include "ExceptionBreakpoint.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
+#include "lldb/lldb-defines.h"
 
 namespace lldb_dap {
 
@@ -496,10 +497,10 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module) {
   return llvm::json::Value(std::move(object));
 }
 
-void AppendBreakpoint(BreakpointBase *bp, llvm::json::Array &breakpoints,
+void AppendBreakpoint(BreakpointBase &bp, llvm::json::Array &breakpoints,
                       std::optional<llvm::StringRef> request_path,
                       std::optional<uint32_t> request_line) {
-  breakpoints.emplace_back(CreateBreakpoint(bp, request_path, request_line));
+  breakpoints.emplace_back(CreateBreakpoint(&bp, request_path, request_line));
 }
 
 // "Event": {
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index d06c0ddb9e638e..6212d2e0d0a554 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -222,7 +222,7 @@ void FillResponse(const llvm::json::Object &request,
 ///     provided by the setBreakpoints request are returned to the IDE as a
 ///     fallback.
 void AppendBreakpoint(
-    BreakpointBase *bp, llvm::json::Array &breakpoints,
+    BreakpointBase &bp, llvm::json::Array &breakpoints,
     std::optional<llvm::StringRef> request_path = std::nullopt,
     std::optional<uint32_t> request_line = std::nullopt);
 
diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td
index d7b4a065abec01..dfca79b2884ac8 100644
--- a/lldb/tools/lldb-dap/Options.td
+++ b/lldb/tools/lldb-dap/Options.td
@@ -22,8 +22,17 @@ def port: S<"port">,
   HelpText<"Communicate with the lldb-dap tool over the defined port.">;
 def: Separate<["-"], "p">,
   Alias<port>,
+  MetaVarName<"<port>">,
   HelpText<"Alias for --port">;
 
+def unix_socket: S<"unix-socket">,
+  MetaVarName<"<path>">,
+  HelpText<"Communicate with the lldb-dap tool over the unix socket or named pipe.">;
+def: Separate<["-"], "u">,
+  Alias<unix_socket>,
+  MetaVarName<"<path>">,
+  HelpText<"Alias for --unix_socket">;
+
 def launch_target: S<"launch-target">,
   MetaVarName<"<target>">,
   HelpText<"Launch a target for the launchInTerminal request. Any argument "
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
index 7415a0914dad43..f4803c82cb34b1 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
@@ -12,16 +12,19 @@
 
 namespace lldb_dap {
 
-SourceBreakpoint::SourceBreakpoint(DAP &dap, const llvm::json::Object &obj)
+SourceBreakpoint::SourceBreakpoint(DAP *dap, const llvm::json::Object &obj)
     : Breakpoint(dap, obj),
       logMessage(std::string(GetString(obj, "logMessage"))),
       line(GetUnsigned(obj, "line", 0)), column(GetUnsigned(obj, "column", 0)) {
 }
 
 void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
+  if (!dap)
+    return;
+
   lldb::SBFileSpecList module_list;
-  bp = dap.target.BreakpointCreateByLocation(source_path.str().c_str(), line,
-                                             column, 0, module_list);
+  bp = dap->target.BreakpointCreateByLocation(source_path.str().c_str(), line,
+                                              column, 0, module_list);
   if (!logMessage.empty())
     SetLogMessage();
   Breakpoint::SetBreakpoint();
@@ -278,16 +281,19 @@ void SourceBreakpoint::SetLogMessage() {
 }
 
 void SourceBreakpoint::NotifyLogMessageError(llvm::StringRef error) {
+  if (!dap)
+    return;
+
   std::string message = "Log message has error: ";
   message += error;
-  dap.SendOutput(OutputType::Console, message);
+  dap->SendOutput(OutputType::Console, message);
 }
 
 /*static*/
 bool SourceBreakpoint::BreakpointHitCallback(
     void *baton, lldb::SBProcess &process, lldb::SBThread &thread,
     lldb::SBBreakpointLocation &location) {
-  if (!baton)
+  if (!baton || !(static_cast<SourceBreakpoint *>(baton)->dap))
     return true;
 
   SourceBreakpoint *bp = (SourceBreakpoint *)baton;
@@ -306,7 +312,7 @@ bool SourceBreakpoint::BreakpointHitCallback(
       if (value.GetError().Fail())
         value = frame.EvaluateExpression(expr);
       output +=
-          VariableDescription(value, bp->dap.enable_auto_variable_summaries)
+          VariableDescription(value, bp->dap->enable_auto_variable_summaries)
               .display_value;
     } else {
       output += messagePart.text;
@@ -314,7 +320,7 @@ bool SourceBreakpoint::BreakpointHitCallback(
   }
   if (!output.empty() && output.back() != '\n')
     output.push_back('\n'); // Ensure log message has line break.
-  bp->dap.SendOutput(OutputType::Console, output.c_str());
+  bp->dap->SendOutput(OutputType::Console, output.c_str());
 
   // Do not stop.
   return false;
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h
index ae5f0548707d85..e7e661803156dd 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.h
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.h
@@ -31,8 +31,7 @@ struct SourceBreakpoint : public Breakpoint {
   uint32_t line;   ///< The source line of the breakpoint or logpoint
   uint32_t column; ///< An optional source column of the breakpoint
 
-  SourceBreakpoint(DAP &dap) : Breakpoint(dap), line(0), column(0) {}
-  SourceBreakpoint(DAP &dap, const llvm::json::Object &obj);
+  SourceBreakpoint(DAP *d, const llvm::json::Object &obj);
 
   // Set this breakpoint in LLDB as a new breakpoint
   void SetBreakpoint(const llvm::StringRef source_path);
diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp
index 8cd297aa696168..29f7f91569155a 100644
--- a/lldb/tools/lldb-dap/Watchpoint.cpp
+++ b/lldb/tools/lldb-dap/Watchpoint.cpp
@@ -14,8 +14,8 @@
 #include "JSONUtils.h"
 
 namespace lldb_dap {
-Watchpoint::Watchpoint(DAP &dap, const llvm::json::Object &obj)
-    : BreakpointBase(dap, obj) {
+Watchpoint::Watchpoint(DAP *d, const llvm::json::Object &obj)
+    : BreakpointBase(d, obj) {
   llvm::StringRef dataId = GetString(obj, "dataId");
   std::string accessType = GetString(obj, "accessType").str();
   auto [addr_str, size_str] = dataId.split('/');
@@ -45,7 +45,8 @@ void Watchpoint::CreateJsonObject(llvm::json::Object &object) {
 }
 
 void Watchpoint::SetWatchpoint() {
-  wp = dap.target.WatchpointCreateByAddress(addr, size, options, error);
+  if (!dap) return;
+  wp = dap->target.WatchpointCreateByAddress(addr, size, options, error);
   if (!condition.empty())
     SetCondition();
   if (!hitCondition.empty())
diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h
index a789208f1c7ae6..f32034bba24997 100644
--- a/lldb/tools/lldb-dap/Watchpoint.h
+++ b/lldb/tools/lldb-dap/Watchpoint.h
@@ -25,8 +25,8 @@ struct Watchpoint : public BreakpointBase {
   lldb::SBWatchpoint wp;
   lldb::SBError error;
 
-  Watchpoint(DAP &dap, const llvm::json::Object &obj);
-  Watchpoint(DAP &dap, lldb::SBWatchpoint wp) : BreakpointBase(dap), wp(wp) {}
+  Watchpoint(DAP *dap, const llvm::json::Object &obj);
+  Watchpoint(DAP *d, lldb::SBWatchpoint wp) : BreakpointBase(d), wp(wp) {}
 
   void SetCondition() override;
   void SetHitCondition() override;
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 65dfbbabdcdd12..d7fa657cd7e1fe 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -15,7 +15,9 @@
 #include "lldb/API/SBListener.h"
 #include "lldb/API/SBMemoryRegionInfo.h"
 #include "lldb/API/SBStringList.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Base64.h"
+#include "llvm/Support/raw_socket_stream.h"
 
 #include <cassert>
 #include <climits>
@@ -26,6 +28,7 @@
 #include <optional>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <system_error>
 #if defined(_WIN32)
 // We need to #define NOMINMAX in order to skip `min()` and `max()` macro
 // definitions that conflict with other system headers.
@@ -33,12 +36,15 @@
 // the JSON code we use also has methods named `GetObject()` and we conflict
 // against these.
 #define NOMINMAX
+#include <afunix.h>
 #include <windows.h>
+#include <winsock2.h>
 #undef GetObject
 #include <io.h>
 #else
 #include <netinet/in.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 #endif
 
@@ -189,95 +195,194 @@ void SetupRedirection(DAP &dap, int stdoutfd = -1, int stderrfd = -1) {
     redirection_test();
 }
 
-int AcceptConnection(llvm::StringRef program_path,
-                     const std::vector<std::string> &pre_init_commands,
-                     std::shared_ptr<std::ofstream> log,
-                     ReplMode default_repl_mode, int portno) {
+void HandleClient(int clientfd, llvm::StringRef program_path,
+                  const std::vector<std::string> &pre_init_commands,
+                  std::shared_ptr<std::ofstream> log,
+                  ReplMode default_repl_mode) {
+  if (log)
+    *log << "client[" << clientfd << "] connected\n";
+  DAP dap = DAP(program_path, log, default_repl_mode);
+  dap.debug_adaptor_path = program_path;
+
+  SetupRedirection(dap);
+  RegisterRequestCallbacks(dap);
+
+  dap.input.descriptor = StreamDescriptor::from_socket(clientfd, false);
+  dap.output.descriptor = StreamDescriptor::from_socket(clientfd, false);
+
+  for (const std::string &arg : pre_init_commands) {
+    dap.pre_init_commands.push_back(arg);
+  }
+
+  if (auto Err = dap.Loop()) {
+    if (log)
+      *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
+  }
+
+  if (log)
+    *log << "client[" << clientfd << "] connection closed\n";
+#if defined(_WIN32)
+  closesocket(clientfd);
+#else
+  close(clientfd);
+#endif
+}
+
+std::error_code getLastSocketErrorCode() {
+#ifdef _WIN32
+  return std::error_code(::WSAGetLastError(), std::system_category());
+#else
+  return llvm::errnoAsErrorCode();
+#endif
+}
+
+llvm::Expected<int> getSocketFD(llvm::StringRef path) {
+  if (llvm::sys::fs::exists(path) && (::remove(path.str().c_str()) == -1)) {
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Remove existing socket failed");
+  }
+
+  SOCKET sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sockfd == -1) {
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Create socket failed");
+  }
+
+  struct sockaddr_un addr;
+  bzero(&addr, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, path.str().c_str(), sizeof(addr.sun_path) - 1);
+
+  if (::bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+#if defined(_WIN32)
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket bind() failed");
+  }
+
+  if (listen(sockfd, llvm::hardware_concurrency().compute_thread_count()) < 0) {
+#if defined(_WIN32)
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket listen() failed");
+  }
+
+  return sockfd;
+}
+
+llvm::Expected<int> getSocketFD(int portno) {
   SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0) {
-    if (log)
-      *log << "error: opening socket (" << strerror(errno) << ")" << std::endl;
-    perror("error: socket(int, int, int)");
-    return 1;
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Create socket failed");
   }
 
-  struct sockaddr_in serv_addr, cli_addr;
+  struct sockaddr_in serv_addr;
   bzero(&serv_addr, sizeof(serv_addr));
-  bzero(&cli_addr, sizeof(cli_addr));
-  socklen_t clilen = sizeof(cli_addr);
   serv_addr.sin_family = AF_INET;
   // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   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 (log)
-      *log << "error: binding socket (" << strerror(errno) << ")" << std::endl;
-    perror("error: bind(int, struct sockaddr *, socklen_t)");
 #if defined(_WIN32)
     closesocket(sockfd);
 #else
     close(sockfd);
 #endif
-    return 1;
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket bind() failed");
   }
 
-  if (listen(sockfd, 5) < 0) {
-    if (log)
-      *log << "error: listen() (" << strerror(errno) << ")" << std::endl;
-    perror("error: listen(int, int)");
+  if (listen(sockfd, llvm::hardware_concurrency().compute_thread_count()) < 0) {
 #if defined(_WIN32)
     closesocket(sockfd);
 #else
     close(sockfd);
 #endif
-    return 1;
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket listen() failed");
+  }
+
+  return sockfd;
+}
+
+int AcceptConnection(llvm::StringRef program_path,
+                     const std::vector<std::string> &pre_init_commands,
+                     std::shared_ptr<std::ofstream> log,
+                     ReplMode default_repl_mode,
+                     llvm::StringRef unix_socket_path) {
+  auto listening = getSocketFD(unix_socket_path);
+  if (auto E = listening.takeError()) {
+    llvm::errs() << "Listening on " << unix_socket_path
+                 << " failed: " << llvm::toString(std::move(E)) << "\n";
+    return EXIT_FAILURE;
   }
 
   while (true) {
+    struct sockaddr_un cli_addr;
+    bzero(&cli_addr, sizeof(struct sockaddr_un));
+    socklen_t clilen = sizeof(cli_addr);
     SOCKET clientfd =
-        llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
+        llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, *listening,
                                     (struct sockaddr *)&cli_addr, &clilen);
     if (clientfd < 0) {
-      if (log)
-        *log << "error: accept (" << strerror(errno) << ")" << std::endl;
-      perror("error: accept(int, struct sockaddr *, socklen_t *)");
-      break;
+      llvm::errs() << "Client accept failed: "
+                   << getLastSocketErrorCode().message() << "\n";
+      return EXIT_FAILURE;
     }
 
-    std::thread t([program_path, pre_init_commands, log, default_repl_mode,
-                   clientfd]() {
-      printf("accepted client fd %d\n", clientfd);
-      DAP dap = DAP(program_path, log, default_repl_mode);
-      dap.debug_adaptor_path = program_path;
-
-      SetupRedirection(dap);
-      RegisterRequestCallbacks(dap);
+    std::thread t(HandleClient, clientfd, program_path, pre_init_commands, log,
+                  default_repl_mode);
+    t.detach();
+  }
 
-      dap.input.descriptor = StreamDescriptor::from_socket(clientfd, false);
-      dap.output.descriptor = StreamDescriptor::from_socket(clientfd, false);
+#if defined(_WIN32)
+  closesocket(*listening);
+#else
+  close(*listening);
+#endif
+  return 0;
+}
 
-      for (const std::string &arg : pre_init_commands) {
-        dap.pre_init_commands.push_back(arg);
-      }
+int AcceptConnection(llvm::StringRef program_path,
+                     const std::vector<std::string> &pre_init_commands,
+                     std::shared_ptr<std::ofstream> log,
+                     ReplMode default_repl_mode, int portno) {
+  auto listening = getSocketFD(portno);
+  if (auto E = listening.takeError()) {
+    llvm::errs() << "Listening on " << portno
+                 << " failed: " << llvm::toString(std::move(E)) << "\n";
+    return EXIT_FAILURE;
+  }
 
-      bool CleanExit = true;
-      if (auto Err = dap.Loop()) {
-        llvm::errs() << "Transport Error: " << llvm::toString(std::move(Err))
-                     << "\n";
-        CleanExit = false;
-      }
+  while (true) {
+    struct sockaddr_in cli_addr;
+    bzero(&cli_addr, sizeof(struct sockaddr_in));
+    socklen_t clilen = sizeof(cli_addr);
+    SOCKET clientfd =
+        llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, *listening,
+                                    (struct sockaddr *)&cli_addr, &clilen);
+    if (clientfd < 0) {
+      llvm::errs() << "Client accept failed: "
+                   << getLastSocketErrorCode().message() << "\n";
+      return EXIT_FAILURE;
+    }
 
-      printf("closing client fd %d ? %s\n", clientfd,
-             CleanExit ? "true" : "false");
-      close(clientfd);
-    });
+    std::thread t(HandleClient, clientfd, program_path, pre_init_commands, log,
+                  default_repl_mode);
     t.detach();
   }
 
 #if defined(_WIN32)
-  closesocket(sockfd);
+  closesocket(*listening);
 #else
-  close(sockfd);
+  close(*listening);
 #endif
   return 0;
 }
@@ -629,7 +734,7 @@ void EventThreadFunction(DAP &dap) {
           auto event_type =
               lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
           auto bp = Breakpoint(
-              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
@@ -2712,12 +2817,12 @@ void request_scopes(DAP &dap, const llvm::json::Object &request) {
 // },
 // "SetBreakpointsArguments": {
 //   "type": "object",
-//   "description": "Arguments for 'setBreakpoints' request.",
+//   "description": "Arguments for `setBreakpoints` request.",
 //   "properties": {
 //     "source": {
 //       "$ref": "#/definitions/Source",
 //       "description": "The source location of the breakpoints; either
-//       source.path or source.reference must be specified."
+// `source.path` or `source.sourceReference` must be specified."
 //     },
 //     "breakpoints": {
 //       "type": "array",
@@ -2731,15 +2836,16 @@ void request_scopes(DAP &dap, const llvm::json::Object &request) {
 //       "items": {
 //         "type": "integer"
 //       },
-//       "description": "Deprecated: The code locations of the breakpoints."
+//       "description": "Deprecated: The code locations of the
+// breakpoints."
 //     },
 //     "sourceModified": {
 //       "type": "boolean",
-//       "description": "A value of true indicates that the underlying source
-//       has been modified which results in new breakpoint locations."
+//       "description": "A value of true indicates that the underlying
+// source has been modified which results in new breakpoint locations."
 //     }
-//   },
-//   "required": [ "source" ]
+// 	},
+// 	"required": [ "source" ]
 // },
 // "SetBreakpointsResponse": {
 //   "allOf": [ { "$ref": "#/definitions/Response" }, {
@@ -2771,36 +2877,55 @@ void request_scopes(DAP &dap, const llvm::json::Object &request) {
 //   }]
 // },
 // "SourceBreakpoint": {
-//   "type": "object",
-//   "description": "Properties of a breakpoint or logpoint passed to the
-//   setBreakpoints request.", "properties": {
+// 	 "type": "object",
+// 	 "description": "Properties of a breakpoint or logpoint passed to the
+// `setBreakpoints` request.",
+//   "properties": {
 //     "line": {
-//       "type": "integer",
-//       "description": "The source line of the breakpoint or logpoint."
+//   	   "type": "integer",
+//   	   "description": "The source line of the breakpoint or logpoint."
 //     },
 //     "column": {
-//       "type": "integer",
-//       "description": "An optional source column of the breakpoint."
+//     	 "type": "integer",
+//     	 "description": "Start position within source line of the breakpoint or
+//       logpoint. It is measured in UTF-16 code units and the client capability
+//       `columnsStartAt1` determines whether it is 0- or 1-based."
 //     },
 //     "condition": {
-//       "type": "string",
-//       "description": "An optional expression for conditional breakpoints."
+//    	 "type": "string",
+//   	   "description": "The expression for conditional breakpoints.\nIt is
+//       only honored by a debug adapter if the corresponding capability
+//       `supportsConditionalBreakpoints` is true."
 //     },
 //     "hitCondition": {
-//       "type": "string",
-//       "description": "An optional expression that controls how many hits of
-//       the breakpoint are ignored. The backend is expected to interpret the
-//       expression as needed."
+//   	   "type": "string",
+//   	   "description": "The expression that controls how many hits of the
+//       breakpoint are ignored.\nThe debug adapter is expected to interpret the
+//       expression as needed.\nThe attribute is only honored by a debug adapter
+//       if the corresponding capability `supportsHitConditionalBreakpoints` is
+//       true.\nIf both this property and `condition` are specified,
+//       `hitCondition` should be evaluated only if the `condition` is met, and
+//       the debug adapter should stop only if both conditions are met."
 //     },
 //     "logMessage": {
-//       "type": "string",
-//       "description": "If this attribute exists and is non-empty, the backend
-//       must not 'break' (stop) but log the message instead. Expressions within
-//       {} are interpolated."
+//   	   "type": "string",
+//   	   "description": "If this attribute exists and is non-empty, the debug
+//       adapter must not 'break' (stop)\nbut log the message instead.
+//       Expressions within `{}` are interpolated.\nThe attribute is only
+//       honored by a debug adapter if the corresponding capability
+//       `supportsLogPoints` is true.\nIf either `hitCondition` or `condition`
+//       is specified, then the message should only be logged if those
+//       conditions are met."
+//     },
+//     "mode": {
+//   	   "type": "string",
+//   	   "description": "The mode of this breakpoint. If defined, this must be
+//       one of the `breakpointModes` the debug adapter advertised in its
+//       `Capabilities`."
 //     }
-//   },
-//   "required": [ "line" ]
-// }
+// 	 },
+// 	 "required": [ "line" ]
+// },
 void request_setBreakpoints(DAP &dap, const llvm::json::Object &request) {
   llvm::json::Object response;
   lldb::SBError error;
@@ -2819,25 +2944,19 @@ void request_setBreakpoints(DAP &dap, const llvm::json::Object &request) {
     for (const auto &bp : *breakpoints) {
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
-        SourceBreakpoint src_bp(dap, *bp_obj);
+        SourceBreakpoint src_bp(&dap, *bp_obj);
         request_bps.try_emplace(src_bp.line, src_bp);
-
+        const auto [kv, inserted] =
+            dap.source_breakpoints[path].try_emplace(src_bp.line, src_bp);
         // We check if this breakpoint already exists to update it
-        auto existing_source_bps = dap.source_breakpoints.find(path);
-        if (existing_source_bps != dap.source_breakpoints.end()) {
-          const auto &existing_bp =
-              existing_source_bps->second.find(src_bp.line);
-          if (existing_bp != existing_source_bps->second.end()) {
-            existing_bp->second.UpdateBreakpoint(src_bp);
-            AppendBreakpoint(&existing_bp->second, response_breakpoints, path,
-                             src_bp.line);
-            continue;
-          }
+        if (inserted) {
+          kv->getSecond().SetBreakpoint(path.data());
+        } else {
+          kv->getSecond().UpdateBreakpoint(src_bp);
         }
-        // At this point the breakpoint is new
-        dap.source_breakpoints[path].try_emplace(src_bp.line, src_bp);
-        src_bp.SetBreakpoint(path.data());
-        AppendBreakpoint(&src_bp, response_breakpoints, path, src_bp.line);
+
+        AppendBreakpoint(kv->getSecond(), response_breakpoints, path,
+                         src_bp.line);
       }
     }
   }
@@ -3030,7 +3149,7 @@ void request_setFunctionBreakpoints(DAP &dap,
     const auto *bp_obj = value.getAsObject();
     if (bp_obj == nullptr)
       continue;
-    FunctionBreakpoint func_bp(dap, *bp_obj);
+    FunctionBreakpoint func_bp(&dap, *bp_obj);
     request_bps.try_emplace(func_bp.functionName, std::move(func_bp));
   }
 
@@ -3052,7 +3171,7 @@ void request_setFunctionBreakpoints(DAP &dap,
       // handled it here and we don't need to set a new breakpoint below.
       request_bps.erase(request_pos);
       // Add this breakpoint info to the response
-      AppendBreakpoint(&pair.second, response_breakpoints);
+      AppendBreakpoint(pair.second, response_breakpoints);
     }
   }
   // Remove any breakpoints that are no longer in our list
@@ -3064,7 +3183,7 @@ void request_setFunctionBreakpoints(DAP &dap,
   for (auto &pair : request_bps) {
     pair.second.SetBreakpoint();
     // Add this breakpoint info to the response
-    AppendBreakpoint(&pair.second, response_breakpoints);
+    AppendBreakpoint(pair.second, response_breakpoints);
     dap.function_breakpoints.try_emplace(pair.first(), std::move(pair.second));
   }
 
@@ -3318,7 +3437,7 @@ void request_setDataBreakpoints(DAP &dap, const llvm::json::Object &request) {
     for (const auto &bp : *breakpoints) {
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
-        Watchpoint wp(dap, *bp_obj);
+        Watchpoint wp(&dap, *bp_obj);
         watchpoints.push_back(wp);
       }
     }
@@ -3334,7 +3453,7 @@ void request_setDataBreakpoints(DAP &dap, const llvm::json::Object &request) {
     }
   }
   for (auto wp : watchpoints)
-    AppendBreakpoint(&wp, response_breakpoints);
+    AppendBreakpoint(wp, response_breakpoints);
 
   llvm::json::Object body;
   body.try_emplace("breakpoints", std::move(response_breakpoints));
@@ -4152,6 +4271,7 @@ void request_variables(DAP &dap, const llvm::json::Object &request) {
           dap.variables.InsertVariable(variable, /*is_permanent=*/false);
       variables.emplace_back(CreateVariable(
           variable, var_ref, hex, dap.enable_auto_variable_summaries,
+          dap.enable_synthetic_child_debugging,
           variable_name_counts[GetNonNullVariableName(variable)] > 1));
     }
   } else {
@@ -4670,8 +4790,8 @@ void request__testGetTargetBreakpoints(DAP &dap,
   FillResponse(request, response);
   llvm::json::Array response_breakpoints;
   for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
-    auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i));
-    AppendBreakpoint(&bp, response_breakpoints);
+    auto bp = Breakpoint(&dap, dap.target.GetBreakpointAtIndex(i));
+    AppendBreakpoint(bp, response_breakpoints);
   }
   llvm::json::Object body;
   body.try_emplace("breakpoints", std::move(response_breakpoints));
@@ -4884,7 +5004,7 @@ void request_setInstructionBreakpoints(DAP &dap,
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
         // Read instruction breakpoint request.
-        InstructionBreakpoint inst_bp(dap, *bp_obj);
+        InstructionBreakpoint inst_bp(&dap, *bp_obj);
         // Store them into map for reference.
         request_ibp.try_emplace(inst_bp.instructionAddressReference,
                                 std::move(inst_bp));
@@ -5139,6 +5259,9 @@ int main(int argc, char *argv[]) {
   auto terminate_debugger =
       llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); });
 
+  const auto pre_init_commands =
+      input_args.getAllArgValues(OPT_pre_init_command);
+
   int portno = -1;
 
   if (auto *arg = input_args.getLastArg(OPT_port)) {
@@ -5151,6 +5274,12 @@ int main(int argc, char *argv[]) {
     }
   }
 
+  std::string unix_socket_path;
+  if (auto *arg = input_args.getLastArg(OPT_unix_socket)) {
+    const auto *path = arg->getValue();
+    unix_socket_path.assign(path);
+  }
+
   const char *log_file_path = getenv("LLDBDAP_LOG");
   std::shared_ptr<std::ofstream> log;
   if (log_file_path)
@@ -5164,33 +5293,34 @@ int main(int argc, char *argv[]) {
 #endif
 
   if (portno != -1) {
-    printf("Listening on port %i...\n", portno);
-    auto pre_init_commands = input_args.getAllArgValues(OPT_pre_init_command);
+    llvm::errs() << llvm::format("Listening on port %i...\n", portno);
     return AcceptConnection(program_path.str(), pre_init_commands,
                             std::move(log), default_repl_mode, portno);
   }
 
+  if (!unix_socket_path.empty()) {
+    return AcceptConnection(program_path.str(), pre_init_commands,
+                            std::move(log), default_repl_mode,
+                            unix_socket_path);
+  }
+
   DAP dap = DAP(program_path.str(), std::move(log), default_repl_mode);
 
   // stdout/stderr redirection to the IDE's console
   int new_stdout_fd = dup(fileno(stdout));
-  SetupRedirection(dap, new_stdout_fd, fileno(stderr));
+  SetupRedirection(dap, fileno(stdout), fileno(stderr));
 
   // Register request callbacks.
   RegisterRequestCallbacks(dap);
 
   dap.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false);
   dap.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false);
-
-  for (const std::string &arg :
-       input_args.getAllArgValues(OPT_pre_init_command)) {
-    dap.pre_init_commands.push_back(arg);
-  }
+  dap.pre_init_commands = pre_init_commands;
 
   bool CleanExit = true;
   if (auto Err = dap.Loop()) {
-    if (dap.log)
-      *dap.log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
+    if (log)
+      *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
     CleanExit = false;
   }
 

>From 0132c0dc3a1092fe6a4eb2a9f21265d39e0252fe Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Mon, 4 Nov 2024 14:28:20 -0800
Subject: [PATCH 3/5] Apply clang-format

---
 lldb/tools/lldb-dap/OutputRedirector.cpp | 3 ++-
 lldb/tools/lldb-dap/Watchpoint.cpp       | 4 +++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp
index 7fc9aaef20b911..0b725e1901b9fd 100644
--- a/lldb/tools/lldb-dap/OutputRedirector.cpp
+++ b/lldb/tools/lldb-dap/OutputRedirector.cpp
@@ -21,7 +21,8 @@ using namespace llvm;
 
 namespace lldb_dap {
 
-Expected<int> RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
+Expected<int> RedirectFd(int fd,
+                         std::function<void(llvm::StringRef)> callback) {
   int new_fd[2];
 #if defined(_WIN32)
   if (_pipe(new_fd, 4096, O_TEXT) == -1) {
diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp
index 29f7f91569155a..c11cfa0375cc8c 100644
--- a/lldb/tools/lldb-dap/Watchpoint.cpp
+++ b/lldb/tools/lldb-dap/Watchpoint.cpp
@@ -45,7 +45,9 @@ void Watchpoint::CreateJsonObject(llvm::json::Object &object) {
 }
 
 void Watchpoint::SetWatchpoint() {
-  if (!dap) return;
+  if (!dap)
+    return;
+
   wp = dap->target.WatchpointCreateByAddress(addr, size, options, error);
   if (!condition.empty())
     SetCondition();

>From d710b9bd77859ecc5179aa745133c64874001a7f Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Tue, 5 Nov 2024 16:27:31 -0800
Subject: [PATCH 4/5] Use a DAP& instead of a DAP* in breakpoint helpers.

---
 lldb/tools/lldb-dap/Breakpoint.h              |  6 +++---
 lldb/tools/lldb-dap/BreakpointBase.cpp        |  2 +-
 lldb/tools/lldb-dap/BreakpointBase.h          |  7 +++----
 lldb/tools/lldb-dap/FunctionBreakpoint.cpp    |  6 +++---
 lldb/tools/lldb-dap/FunctionBreakpoint.h      |  2 +-
 lldb/tools/lldb-dap/InstructionBreakpoint.cpp |  6 ++----
 lldb/tools/lldb-dap/InstructionBreakpoint.h   |  4 ++--
 lldb/tools/lldb-dap/SourceBreakpoint.cpp      | 18 ++++++------------
 lldb/tools/lldb-dap/SourceBreakpoint.h        |  2 +-
 lldb/tools/lldb-dap/Watchpoint.cpp            |  7 ++-----
 lldb/tools/lldb-dap/Watchpoint.h              |  4 ++--
 lldb/tools/lldb-dap/lldb-dap.cpp              | 13 ++++++-------
 12 files changed, 32 insertions(+), 45 deletions(-)

diff --git a/lldb/tools/lldb-dap/Breakpoint.h b/lldb/tools/lldb-dap/Breakpoint.h
index add4ff4da2a9bb..cffeb2fab1f0ef 100644
--- a/lldb/tools/lldb-dap/Breakpoint.h
+++ b/lldb/tools/lldb-dap/Breakpoint.h
@@ -19,9 +19,9 @@ struct Breakpoint : public BreakpointBase {
   // The LLDB breakpoint associated wit this source breakpoint
   lldb::SBBreakpoint bp;
 
-  Breakpoint(DAP *d) : BreakpointBase(d) {}
-  Breakpoint(DAP *d, const llvm::json::Object &obj) : BreakpointBase(d, obj) {}
-  Breakpoint(DAP *d, lldb::SBBreakpoint bp) : BreakpointBase(d), bp(bp) {}
+  Breakpoint(DAP &d) : BreakpointBase(d) {}
+  Breakpoint(DAP &d, const llvm::json::Object &obj) : BreakpointBase(d, obj) {}
+  Breakpoint(DAP &d, lldb::SBBreakpoint bp) : BreakpointBase(d), bp(bp) {}
 
   void SetCondition() override;
   void SetHitCondition() override;
diff --git a/lldb/tools/lldb-dap/BreakpointBase.cpp b/lldb/tools/lldb-dap/BreakpointBase.cpp
index 27ae000e88c37a..c5d7a9778df018 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.cpp
+++ b/lldb/tools/lldb-dap/BreakpointBase.cpp
@@ -11,7 +11,7 @@
 
 using namespace lldb_dap;
 
-BreakpointBase::BreakpointBase(DAP *d, const llvm::json::Object &obj)
+BreakpointBase::BreakpointBase(DAP &d, const llvm::json::Object &obj)
     : dap(d), condition(std::string(GetString(obj, "condition"))),
       hitCondition(std::string(GetString(obj, "hitCondition"))) {}
 
diff --git a/lldb/tools/lldb-dap/BreakpointBase.h b/lldb/tools/lldb-dap/BreakpointBase.h
index cc808f396e99e2..bb660ddc451bd5 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.h
+++ b/lldb/tools/lldb-dap/BreakpointBase.h
@@ -19,7 +19,7 @@ namespace lldb_dap {
 
 struct BreakpointBase {
   // Associated DAP session.
-  DAP *dap;
+  DAP &dap;
 
   // An optional expression for conditional breakpoints.
   std::string condition;
@@ -27,9 +27,8 @@ struct BreakpointBase {
   // ignored. The backend is expected to interpret the expression as needed
   std::string hitCondition;
 
-  BreakpointBase(DAP *d) : dap(d) {}
-  BreakpointBase(DAP *d, const llvm::json::Object &obj);
-  BreakpointBase() = default;
+  BreakpointBase(DAP &d) : dap(d) {}
+  BreakpointBase(DAP &d, const llvm::json::Object &obj);
   BreakpointBase(const BreakpointBase &) = default;
   virtual ~BreakpointBase() = default;
 
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
index e35dc2dc2ca4b8..ef6df6c0dc91cc 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
@@ -13,13 +13,13 @@
 
 namespace lldb_dap {
 
-FunctionBreakpoint::FunctionBreakpoint(DAP *d, const llvm::json::Object &obj)
+FunctionBreakpoint::FunctionBreakpoint(DAP &d, const llvm::json::Object &obj)
     : Breakpoint(d, obj), functionName(std::string(GetString(obj, "name"))) {}
 
 void FunctionBreakpoint::SetBreakpoint() {
-  if (functionName.empty() || !dap)
+  if (functionName.empty())
     return;
-  bp = dap->target.BreakpointCreateByName(functionName.c_str());
+  bp = dap.target.BreakpointCreateByName(functionName.c_str());
   Breakpoint::SetBreakpoint();
 }
 
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.h b/lldb/tools/lldb-dap/FunctionBreakpoint.h
index a66acf8b1945e9..93f0b93b35291d 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.h
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.h
@@ -17,7 +17,7 @@ namespace lldb_dap {
 struct FunctionBreakpoint : public Breakpoint {
   std::string functionName;
 
-  FunctionBreakpoint(DAP *dap, const llvm::json::Object &obj);
+  FunctionBreakpoint(DAP &dap, const llvm::json::Object &obj);
 
   // Set this breakpoint in LLDB as a new breakpoint
   void SetBreakpoint();
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
index cd4f719ff13517..d6ccb2dfc29111 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
@@ -15,7 +15,7 @@
 namespace lldb_dap {
 
 // Instruction Breakpoint
-InstructionBreakpoint::InstructionBreakpoint(DAP *d,
+InstructionBreakpoint::InstructionBreakpoint(DAP &d,
                                              const llvm::json::Object &obj)
     : Breakpoint(d, obj), instructionAddressReference(LLDB_INVALID_ADDRESS),
       id(0), offset(GetSigned(obj, "offset", 0)) {
@@ -25,9 +25,7 @@ InstructionBreakpoint::InstructionBreakpoint(DAP *d,
 }
 
 void InstructionBreakpoint::SetInstructionBreakpoint() {
-  if (!dap)
-    return;
-  bp = dap->target.BreakpointCreateByAddress(instructionAddressReference);
+  bp = dap.target.BreakpointCreateByAddress(instructionAddressReference);
   id = bp.GetID();
 }
 
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.h b/lldb/tools/lldb-dap/InstructionBreakpoint.h
index 8c5249f9e0825f..d7f3fb8ad3a4eb 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.h
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.h
@@ -26,10 +26,10 @@ struct InstructionBreakpoint : public Breakpoint {
   int32_t id;
   int32_t offset;
 
-  InstructionBreakpoint(DAP *d)
+  InstructionBreakpoint(DAP &d)
       : Breakpoint(d), instructionAddressReference(LLDB_INVALID_ADDRESS), id(0),
         offset(0) {}
-  InstructionBreakpoint(DAP *d, const llvm::json::Object &obj);
+  InstructionBreakpoint(DAP &d, const llvm::json::Object &obj);
 
   // Set instruction breakpoint in LLDB as a new breakpoint
   void SetInstructionBreakpoint();
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
index f4803c82cb34b1..364fe3cefb2a6a 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
@@ -12,18 +12,15 @@
 
 namespace lldb_dap {
 
-SourceBreakpoint::SourceBreakpoint(DAP *dap, const llvm::json::Object &obj)
+SourceBreakpoint::SourceBreakpoint(DAP &dap, const llvm::json::Object &obj)
     : Breakpoint(dap, obj),
       logMessage(std::string(GetString(obj, "logMessage"))),
       line(GetUnsigned(obj, "line", 0)), column(GetUnsigned(obj, "column", 0)) {
 }
 
 void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
-  if (!dap)
-    return;
-
   lldb::SBFileSpecList module_list;
-  bp = dap->target.BreakpointCreateByLocation(source_path.str().c_str(), line,
+  bp = dap.target.BreakpointCreateByLocation(source_path.str().c_str(), line,
                                               column, 0, module_list);
   if (!logMessage.empty())
     SetLogMessage();
@@ -281,19 +278,16 @@ void SourceBreakpoint::SetLogMessage() {
 }
 
 void SourceBreakpoint::NotifyLogMessageError(llvm::StringRef error) {
-  if (!dap)
-    return;
-
   std::string message = "Log message has error: ";
   message += error;
-  dap->SendOutput(OutputType::Console, message);
+  dap.SendOutput(OutputType::Console, message);
 }
 
 /*static*/
 bool SourceBreakpoint::BreakpointHitCallback(
     void *baton, lldb::SBProcess &process, lldb::SBThread &thread,
     lldb::SBBreakpointLocation &location) {
-  if (!baton || !(static_cast<SourceBreakpoint *>(baton)->dap))
+  if (!baton)
     return true;
 
   SourceBreakpoint *bp = (SourceBreakpoint *)baton;
@@ -312,7 +306,7 @@ bool SourceBreakpoint::BreakpointHitCallback(
       if (value.GetError().Fail())
         value = frame.EvaluateExpression(expr);
       output +=
-          VariableDescription(value, bp->dap->enable_auto_variable_summaries)
+          VariableDescription(value, bp->dap.enable_auto_variable_summaries)
               .display_value;
     } else {
       output += messagePart.text;
@@ -320,7 +314,7 @@ bool SourceBreakpoint::BreakpointHitCallback(
   }
   if (!output.empty() && output.back() != '\n')
     output.push_back('\n'); // Ensure log message has line break.
-  bp->dap->SendOutput(OutputType::Console, output.c_str());
+  bp->dap.SendOutput(OutputType::Console, output.c_str());
 
   // Do not stop.
   return false;
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h
index e7e661803156dd..113c0efbddcc5c 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.h
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.h
@@ -31,7 +31,7 @@ struct SourceBreakpoint : public Breakpoint {
   uint32_t line;   ///< The source line of the breakpoint or logpoint
   uint32_t column; ///< An optional source column of the breakpoint
 
-  SourceBreakpoint(DAP *d, const llvm::json::Object &obj);
+  SourceBreakpoint(DAP &d, const llvm::json::Object &obj);
 
   // Set this breakpoint in LLDB as a new breakpoint
   void SetBreakpoint(const llvm::StringRef source_path);
diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp
index c11cfa0375cc8c..56dd5434269151 100644
--- a/lldb/tools/lldb-dap/Watchpoint.cpp
+++ b/lldb/tools/lldb-dap/Watchpoint.cpp
@@ -14,7 +14,7 @@
 #include "JSONUtils.h"
 
 namespace lldb_dap {
-Watchpoint::Watchpoint(DAP *d, const llvm::json::Object &obj)
+Watchpoint::Watchpoint(DAP &d, const llvm::json::Object &obj)
     : BreakpointBase(d, obj) {
   llvm::StringRef dataId = GetString(obj, "dataId");
   std::string accessType = GetString(obj, "accessType").str();
@@ -45,10 +45,7 @@ void Watchpoint::CreateJsonObject(llvm::json::Object &object) {
 }
 
 void Watchpoint::SetWatchpoint() {
-  if (!dap)
-    return;
-
-  wp = dap->target.WatchpointCreateByAddress(addr, size, options, error);
+  wp = dap.target.WatchpointCreateByAddress(addr, size, options, error);
   if (!condition.empty())
     SetCondition();
   if (!hitCondition.empty())
diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h
index f32034bba24997..b84b4b1c9ff3d3 100644
--- a/lldb/tools/lldb-dap/Watchpoint.h
+++ b/lldb/tools/lldb-dap/Watchpoint.h
@@ -25,8 +25,8 @@ struct Watchpoint : public BreakpointBase {
   lldb::SBWatchpoint wp;
   lldb::SBError error;
 
-  Watchpoint(DAP *dap, const llvm::json::Object &obj);
-  Watchpoint(DAP *d, lldb::SBWatchpoint wp) : BreakpointBase(d), wp(wp) {}
+  Watchpoint(DAP &d, const llvm::json::Object &obj);
+  Watchpoint(DAP &d, lldb::SBWatchpoint wp) : BreakpointBase(d), wp(wp) {}
 
   void SetCondition() override;
   void SetHitCondition() override;
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index d7fa657cd7e1fe..4c577546f52ff3 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -734,7 +734,7 @@ void EventThreadFunction(DAP &dap) {
           auto event_type =
               lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
           auto bp = Breakpoint(
-              &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
@@ -2944,7 +2944,7 @@ void request_setBreakpoints(DAP &dap, const llvm::json::Object &request) {
     for (const auto &bp : *breakpoints) {
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
-        SourceBreakpoint src_bp(&dap, *bp_obj);
+        SourceBreakpoint src_bp(dap, *bp_obj);
         request_bps.try_emplace(src_bp.line, src_bp);
         const auto [kv, inserted] =
             dap.source_breakpoints[path].try_emplace(src_bp.line, src_bp);
@@ -3149,7 +3149,7 @@ void request_setFunctionBreakpoints(DAP &dap,
     const auto *bp_obj = value.getAsObject();
     if (bp_obj == nullptr)
       continue;
-    FunctionBreakpoint func_bp(&dap, *bp_obj);
+    FunctionBreakpoint func_bp(dap, *bp_obj);
     request_bps.try_emplace(func_bp.functionName, std::move(func_bp));
   }
 
@@ -3437,8 +3437,7 @@ void request_setDataBreakpoints(DAP &dap, const llvm::json::Object &request) {
     for (const auto &bp : *breakpoints) {
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
-        Watchpoint wp(&dap, *bp_obj);
-        watchpoints.push_back(wp);
+        watchpoints.emplace_back(dap, *bp_obj);
       }
     }
   }
@@ -4790,7 +4789,7 @@ void request__testGetTargetBreakpoints(DAP &dap,
   FillResponse(request, response);
   llvm::json::Array response_breakpoints;
   for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
-    auto bp = Breakpoint(&dap, dap.target.GetBreakpointAtIndex(i));
+    auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i));
     AppendBreakpoint(bp, response_breakpoints);
   }
   llvm::json::Object body;
@@ -5004,7 +5003,7 @@ void request_setInstructionBreakpoints(DAP &dap,
       const auto *bp_obj = bp.getAsObject();
       if (bp_obj) {
         // Read instruction breakpoint request.
-        InstructionBreakpoint inst_bp(&dap, *bp_obj);
+        InstructionBreakpoint inst_bp(dap, *bp_obj);
         // Store them into map for reference.
         request_ibp.try_emplace(inst_bp.instructionAddressReference,
                                 std::move(inst_bp));

>From ec85f0f7397c4790442cf99cd51ce61510da498f Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Tue, 5 Nov 2024 17:56:19 -0800
Subject: [PATCH 5/5] Adjust the naming of the test
 dap_server.DebugAdaptorServer to be more consistent.

---
 .../test/tools/lldb-dap/dap_server.py         | 39 ++++++++++---------
 .../test/tools/lldb-dap/lldbdap_testcase.py   | 14 ++++---
 .../tools/lldb-dap/server/TestDAP_server.py   | 13 +++----
 3 files changed, 34 insertions(+), 32 deletions(-)

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 31819328040aca..72287ab46a7797 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
@@ -1155,7 +1155,8 @@ def __init__(
         self,
         executable=None,
         launch=True,
-        connect=None,
+        port=None,
+        unix_socket=None,
         init_commands=[],
         log_file=None,
         env=None,
@@ -1163,17 +1164,18 @@ def __init__(
         self.process = None
         if launch:
             self.process = DebugAdaptorServer.launch(
-                executable, connect=connect, log_file=log_file, env=env
+                executable, port=port, unix_socket=unix_socket, log_file=log_file, env=env
             )
 
-        if connect:
-            if isinstance(connect, str) and connect.startswith("/"):
-                s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-                s.connect(connect)
-            else:
-                port = int(connect)
-                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                s.connect(("127.0.0.1", port))
+        if port:
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.connect(("127.0.0.1", port))
+            DebugCommunication.__init__(
+                self, s.makefile("rb"), s.makefile("wb"), init_commands, log_file
+            )
+        elif unix_socket:
+            s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            s.connect(unix_socket)
             DebugCommunication.__init__(
                 self, s.makefile("rb"), s.makefile("wb"), init_commands, log_file
             )
@@ -1196,7 +1198,7 @@ def terminate(self):
 
     @classmethod
     def launch(
-        cls, executable: str, /, connect=None, log_file=None, env=None
+        cls, executable: str, /, port=None, unix_socket=None, log_file=None, env=None
     ) -> subprocess.Popen:
         adaptor_env = os.environ.copy()
         if env:
@@ -1206,13 +1208,12 @@ def launch(
             adaptor_env["LLDBDAP_LOG"] = log_file
 
         args = [executable]
-        if connect:
-            if isinstance(connect, str) and connect.startswith("/"):
-                args.append("--unix-socket")
-                args.append(connect)
-            else:
-                args.append("--port")
-                args.append(str(connect))
+        if port:
+            args.append("--port")
+            args.append(str(port))
+        elif unix_socket:
+            args.append("--unix-socket")
+            args.append(unix_socket)
 
         proc = subprocess.Popen(
             args,
@@ -1222,7 +1223,7 @@ def launch(
             env=adaptor_env,
         )
 
-        if connect:
+        if port or unix_socket:
             # Wait for the server to startup.
             time.sleep(0.1)
 
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index 39d200a2ac566e..1f7d6e4e21e310 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -13,7 +13,7 @@ class DAPTestCaseBase(TestBase):
     timeoutval = 10 * (10 if ('ASAN_OPTIONS' in os.environ) else 1)
     NO_DEBUG_INFO_TESTCASE = True
 
-    def create_debug_adaptor(self, env=None, launch=True, connect=None):
+    def create_debug_adaptor(self, env=None, launch=True, port=None, unix_socket=None):
         """Create the Visual Studio Code debug adaptor"""
         self.assertTrue(
             is_exe(self.lldbDAPExec), "lldb-dap must exist and be executable"
@@ -22,18 +22,19 @@ def create_debug_adaptor(self, env=None, launch=True, connect=None):
         self.dap_server = dap_server.DebugAdaptorServer(
             executable=self.lldbDAPExec,
             launch=launch,
-            connect=connect,
+            port=port,
+            unix_socket=unix_socket,
             init_commands=self.setUpCommands(),
             log_file=log_file_path,
             env=env,
         )
 
     def build_and_create_debug_adaptor(
-        self, lldbDAPEnv=None, lldbDAPLaunch=True, lldbDAPConnect=None
+        self, lldbDAPEnv=None, lldbDAPLaunch=True, lldbDAPPort=None, lldbDAPUnixSocket=None
     ):
         self.build()
         self.create_debug_adaptor(
-            lldbDAPEnv, launch=lldbDAPLaunch, connect=lldbDAPConnect
+            lldbDAPEnv, launch=lldbDAPLaunch, port=lldbDAPPort, unix_socket=lldbDAPUnixSocket
         )
 
     def set_source_breakpoints(self, source_path, lines, data=None):
@@ -481,13 +482,14 @@ def build_and_launch(
         customThreadFormat=None,
         launchCommands=None,
         expectFailure=False,
-        lldbDAPConnect=None,
+        lldbDAPPort=None,
+        lldbDAPUnixSocket=None,
         lldbDAPLaunch=True,
     ):
         """Build the default Makefile target, create the DAP debug adaptor,
         and launch the process.
         """
-        self.build_and_create_debug_adaptor(lldbDAPEnv, lldbDAPLaunch, lldbDAPConnect)
+        self.build_and_create_debug_adaptor(lldbDAPEnv=lldbDAPEnv, lldbDAPLaunch=lldbDAPLaunch, lldbDAPPort=lldbDAPPort, lldbDAPUnixSocket=lldbDAPUnixSocket)
         self.assertTrue(os.path.exists(program), "executable must exist")
 
         return self.launch(
diff --git a/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
index ae7094b096c4d7..46b992a77a4815 100644
--- a/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
+++ b/lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
@@ -12,11 +12,10 @@
 
 
 class TestDAP_server(lldbdap_testcase.DAPTestCaseBase):
-    def do_test_server(self, connect):
+    def do_test_server(self, port=None, unix_socket=None):
         log_file_path = self.getBuildArtifact("dap.txt")
-        print("connect", connect)
         server = dap_server.DebugAdaptorServer.launch(
-            self.lldbDAPExec, connect=connect, log_file=log_file_path
+            self.lldbDAPExec, port=port, unix_socket=unix_socket, log_file=log_file_path
         )
 
         def cleanup():
@@ -31,7 +30,7 @@ def cleanup():
         breakpoint_line = line_number(source, "// breakpoint")
 
         # Initial connection over the port.
-        self.create_debug_adaptor(launch=False, connect=connect)
+        self.create_debug_adaptor(launch=False, port=port, unix_socket=unix_socket)
         self.launch(
             program,
             disconnectAutomatically=False,
@@ -44,7 +43,7 @@ def cleanup():
         self.dap_server.request_disconnect()
 
         # Second connection over the port.
-        self.create_debug_adaptor(launch=False, connect=connect)
+        self.create_debug_adaptor(launch=False, port=port, unix_socket=unix_socket)
         self.launch(program)
         self.set_source_breakpoints(source, [breakpoint_line])
         self.continue_to_next_stop()
@@ -57,11 +56,11 @@ def test_server_port(self):
         Test launching a binary with a lldb-dap in server mode on a specific port.
         """
         port = pickrandomport()
-        self.do_test_server(port)
+        self.do_test_server(port=port)
 
     def test_server_unix_socket(self):
         """
         Test launching a binary with a lldb-dap in server mode on a unix socket.
         """
         dir = tempfile.gettempdir()
-        self.do_test_server(dir + "/dap-connection-" + str(os.getpid()))
+        self.do_test_server(unix_socket=dir + "/dap-connection-" + str(os.getpid()))



More information about the lldb-commits mailing list