https://github.com/satyajanga updated 
https://github.com/llvm/llvm-project/pull/201449

>From ac4167a8bac774e1640c6fb0ae4139efacfd3494 Mon Sep 17 00:00:00 2001
From: satya janga <[email protected]>
Date: Sat, 6 Jun 2026 08:25:45 -0700
Subject: [PATCH 1/2] [lldb] Add connection info to the accelerator plugin
 protocol

Add AcceleratorConnectionInfo, describing how the client should create a
new target and reverse-connect to a separate GDB server that serves an
accelerator's state (e.g. a GPU debug stub). It carries the required
connect URL plus an optional exe path, triple, and a synchronous flag.

A connect_info field is added to AcceleratorActions so a plugin can ask
the client to establish such a connection alongside (or instead of)
setting breakpoints. This is the wire-format foundation; the client-side
handling that acts on connect_info comes in a follow-up.

Adds JSON serialization, unit tests, and documents the new fields in the
jAcceleratorPluginInitialize packet.
---
 lldb/docs/resources/lldbgdbremote.md          | 15 ++++-
 .../Utility/AcceleratorGDBRemotePackets.h     | 30 ++++++++++
 .../Utility/AcceleratorGDBRemotePackets.cpp   | 25 +++++++-
 .../AcceleratorGDBRemotePacketsTest.cpp       | 57 +++++++++++++++++++
 4 files changed, 122 insertions(+), 5 deletions(-)

diff --git a/lldb/docs/resources/lldbgdbremote.md 
b/lldb/docs/resources/lldbgdbremote.md
index 577a5ad31674f..840076370c101 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -2814,9 +2814,18 @@ packet when one is hit. Each breakpoint object has the 
following fields:
 Exactly one of `by_name` or `by_address` must be provided for each
 breakpoint.
 
-In future patches, each `accelerator_action` will include additional fields
-such as connection info for secondary debug sessions and synchronization
-options.
+An `accelerator_action` may also include a `connect_info` object asking the
+client to create a new target and connect to a separate GDB server that
+serves the accelerator's state (for example a GPU debug stub). It has the
+following fields:
+
+| Key             | Type   | Description |
+|-----------------|--------|-------------|
+| `connect_url`   | string | Connection URL to connect to, as used by `process 
connect <url>`. |
+| `platform_name` | string | Name of the platform to select when creating the 
accelerator target. The platform must be able to handle `triple` and is used to 
connect to the accelerator's GDB server. |
+| `triple`        | string | Target triple for the accelerator target, used to 
ensure the architecture is compatible with `platform_name`. |
+| `exe_path`      | string | Optional path to the executable to use when 
creating the accelerator target. If omitted, an empty target is created. |
+| `synchronous`   | bool   | If true, connect synchronously: the client blocks 
until the accelerator process is connected and stopped before continuing. If 
false, the connection is made asynchronously. |
 
 **Priority To Implement:** Required for hardware accelerator debugging
 support. Not needed for non-hardware-accelerator debugging.
diff --git a/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h 
b/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
index 9ba36fc540a52..faa7f5575f157 100644
--- a/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
@@ -85,6 +85,33 @@ bool fromJSON(const llvm::json::Value &value,
               AcceleratorBreakpointHitArgs &data, llvm::json::Path path);
 llvm::json::Value toJSON(const AcceleratorBreakpointHitArgs &data);
 
+/// Information the client needs to connect to an accelerator GDB server. When
+/// an AcceleratorActions carries this, the client creates a new target and
+/// connects to \a connect_url.
+struct AcceleratorConnectionInfo {
+  /// Connection URL the client should connect to (as in "process connect
+  /// <url>").
+  std::string connect_url;
+  /// Name of the platform to select when creating the accelerator target. The
+  /// platform must be able to handle \a triple and is used to connect to the
+  /// accelerator's GDB server.
+  std::string platform_name;
+  /// Target triple for the accelerator target. Used to ensure the architecture
+  /// is compatible with \a platform_name.
+  std::string triple;
+  /// Path to the executable to use when creating the accelerator target. If
+  /// not set, an empty target is created.
+  std::optional<std::string> exe_path;
+  /// If true, connect synchronously: the client blocks until the accelerator
+  /// process is connected and stopped before continuing. If false, the
+  /// connection is made asynchronously.
+  bool synchronous = false;
+};
+
+bool fromJSON(const llvm::json::Value &value, AcceleratorConnectionInfo &data,
+              llvm::json::Path path);
+llvm::json::Value toJSON(const AcceleratorConnectionInfo &data);
+
 /// Actions to be performed in the native process on behalf of an accelerator
 /// plugin. AcceleratorActions are returned in the following contexts:
 ///
@@ -114,6 +141,9 @@ struct AcceleratorActions {
   int64_t identifier = 0;
   /// New breakpoints to set. Nothing to set if this is empty.
   std::vector<AcceleratorBreakpointInfo> breakpoints;
+  /// If set, the client should create a new target and connect to the
+  /// accelerator GDB server described here.
+  std::optional<AcceleratorConnectionInfo> connect_info;
 };
 
 bool fromJSON(const llvm::json::Value &value, AcceleratorActions &data,
diff --git a/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp 
b/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
index 34067b1fa64c7..3b9edada64c65 100644
--- a/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
+++ b/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
@@ -86,21 +86,42 @@ AcceleratorBreakpointHitArgs::GetSymbolValue(StringRef 
symbol_name) const {
   return std::nullopt;
 }
 
+bool fromJSON(const Value &value, AcceleratorConnectionInfo &data, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("connect_url", data.connect_url) &&
+         o.map("platform_name", data.platform_name) &&
+         o.map("triple", data.triple) &&
+         o.mapOptional("exe_path", data.exe_path) &&
+         o.map("synchronous", data.synchronous);
+}
+
+json::Value toJSON(const AcceleratorConnectionInfo &data) {
+  return Object{
+      {"connect_url", data.connect_url}, {"platform_name", data.platform_name},
+      {"triple", data.triple},           {"exe_path", data.exe_path},
+      {"synchronous", data.synchronous},
+  };
+}
+
 bool fromJSON(const Value &value, AcceleratorActions &data, Path path) {
   ObjectMapper o(value, path);
   return o && o.map("plugin_name", data.plugin_name) &&
          o.map("session_name", data.session_name) &&
          o.map("identifier", data.identifier) &&
-         o.map("breakpoints", data.breakpoints);
+         o.map("breakpoints", data.breakpoints) &&
+         o.mapOptional("connect_info", data.connect_info);
 }
 
 json::Value toJSON(const AcceleratorActions &data) {
-  return Object{
+  Object obj{
       {"plugin_name", data.plugin_name},
       {"session_name", data.session_name},
       {"identifier", data.identifier},
       {"breakpoints", data.breakpoints},
   };
+  if (data.connect_info)
+    obj["connect_info"] = *data.connect_info;
+  return obj;
 }
 
 bool fromJSON(const Value &value, AcceleratorBreakpointHitResponse &data,
diff --git a/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp 
b/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp
index fdcb0585fa3c7..571dd2cab124a 100644
--- a/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp
+++ b/lldb/unittests/Utility/AcceleratorGDBRemotePacketsTest.cpp
@@ -187,3 +187,60 @@ TEST(AcceleratorGDBRemotePacketsTest,
   EXPECT_EQ("exit",
             deserialized->actions->breakpoints[0].by_name->function_name);
 }
+
+TEST(AcceleratorGDBRemotePacketsTest, AcceleratorConnectionInfo) {
+  AcceleratorConnectionInfo conn;
+  conn.connect_url = "connect://localhost:1234";
+  conn.platform_name = "remote-gdb-server";
+  conn.triple = "amdgcn-amd-amdhsa";
+  conn.exe_path = "/path/to/accel.elf";
+  conn.synchronous = true;
+
+  Expected<AcceleratorConnectionInfo> deserialized = roundtripJSON(conn);
+  ASSERT_THAT_EXPECTED(deserialized, Succeeded());
+  EXPECT_EQ(conn.connect_url, deserialized->connect_url);
+  EXPECT_EQ(conn.platform_name, deserialized->platform_name);
+  EXPECT_EQ(conn.triple, deserialized->triple);
+  EXPECT_EQ(conn.exe_path, deserialized->exe_path);
+  EXPECT_EQ(conn.synchronous, deserialized->synchronous);
+}
+
+TEST(AcceleratorGDBRemotePacketsTest, AcceleratorConnectionInfoMinimal) {
+  // Only the required fields; exe_path defaults to nullopt and synchronous to
+  // false.
+  AcceleratorConnectionInfo conn;
+  conn.connect_url = "connect://localhost:5678";
+  conn.platform_name = "host";
+  conn.triple = "x86_64-unknown-linux-gnu";
+
+  Expected<AcceleratorConnectionInfo> deserialized = roundtripJSON(conn);
+  ASSERT_THAT_EXPECTED(deserialized, Succeeded());
+  EXPECT_EQ(conn.connect_url, deserialized->connect_url);
+  EXPECT_EQ(conn.platform_name, deserialized->platform_name);
+  EXPECT_EQ(conn.triple, deserialized->triple);
+  EXPECT_EQ(std::nullopt, deserialized->exe_path);
+  EXPECT_FALSE(deserialized->synchronous);
+}
+
+TEST(AcceleratorGDBRemotePacketsTest, AcceleratorActionsWithConnectInfo) {
+  AcceleratorActions actions("mock", 3);
+  AcceleratorConnectionInfo conn;
+  conn.connect_url = "connect://localhost:9999";
+  conn.synchronous = true;
+  actions.connect_info = std::move(conn);
+
+  Expected<AcceleratorActions> deserialized = roundtripJSON(actions);
+  ASSERT_THAT_EXPECTED(deserialized, Succeeded());
+  ASSERT_TRUE(deserialized->connect_info.has_value());
+  EXPECT_EQ("connect://localhost:9999",
+            deserialized->connect_info->connect_url);
+  EXPECT_TRUE(deserialized->connect_info->synchronous);
+}
+
+TEST(AcceleratorGDBRemotePacketsTest, AcceleratorActionsWithoutConnectInfo) {
+  AcceleratorActions actions("mock", 4);
+
+  Expected<AcceleratorActions> deserialized = roundtripJSON(actions);
+  ASSERT_THAT_EXPECTED(deserialized, Succeeded());
+  EXPECT_FALSE(deserialized->connect_info.has_value());
+}

>From e40c50789a2d30458ce5f45b89a115b8e5455b29 Mon Sep 17 00:00:00 2001
From: satya janga <[email protected]>
Date: Mon, 8 Jun 2026 08:01:22 -0700
Subject: [PATCH 2/2] [lldb] Create and connect an accelerator target from
 connect_info

Act on the AcceleratorConnectionInfo returned by an accelerator plugin:
when an AcceleratorActions carries connect_info, ProcessGDBRemote creates
a new target and reverse-connects it to the GDB server the plugin points
at, broadcasting the new target so listeners (e.g. IDEs) can pick it up.

To exercise this end to end, the mock accelerator plugin runs a second
gdb-remote server inside the lldb-server process, backed by a minimal
synthetic accelerator process (ProcessMockAccelerator + one stopped
ThreadMockAccelerator + a tiny RegisterContextMockAccelerator with fixed
register values); no real process is launched. When the initialize
breakpoint is hit, the plugin requests a breakpoint on a dedicated
"mock_gpu_accelerator_connect" hook; hitting that hook returns connect_info
so the client connects. The hook is added to the existing mock inferior
used by the breakpoint test.

The existing end-to-end breakpoint test is extended to continue to the
connection hook and verify that a second (accelerator) target is created
alongside the original one, that its process is connected and stopped, and
that each of its registers reads back the expected value.
---
 .../LLDBServerAcceleratorPlugin.cpp           |   9 +-
 .../gdb-remote/LLDBServerAcceleratorPlugin.h  |  27 ++-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  75 +++++-
 .../Process/gdb-remote/ProcessGDBRemote.h     |   4 +
 .../mock/TestMockAcceleratorActions.py        | 226 ++++++++++++++++++
 .../mock/TestMockAcceleratorBreakpoints.py    | 104 --------
 ...lugin.py => TestMockAcceleratorPackets.py} |  52 +++-
 lldb/test/API/accelerator/mock/main.c         |  12 +-
 .../Plugins/Accelerator/Mock/CMakeLists.txt   |   3 +
 .../Mock/LLDBServerMockAcceleratorPlugin.cpp  | 165 ++++++++++++-
 .../Mock/LLDBServerMockAcceleratorPlugin.h    |  36 ++-
 .../Mock/ProcessMockAccelerator.cpp           | 112 +++++++++
 .../Accelerator/Mock/ProcessMockAccelerator.h |  71 ++++++
 .../Mock/RegisterContextMockAccelerator.cpp   | 133 +++++++++++
 .../Mock/RegisterContextMockAccelerator.h     |  49 ++++
 .../Mock/ThreadMockAccelerator.cpp            |  54 +++++
 .../Accelerator/Mock/ThreadMockAccelerator.h  |  48 ++++
 17 files changed, 1053 insertions(+), 127 deletions(-)
 create mode 100644 lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py
 delete mode 100644 
lldb/test/API/accelerator/mock/TestMockAcceleratorBreakpoints.py
 rename lldb/test/API/accelerator/mock/{TestMockAcceleratorPlugin.py => 
TestMockAcceleratorPackets.py} (70%)
 create mode 100644 
lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.cpp
 create mode 100644 
lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
 create mode 100644 
lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.cpp
 create mode 100644 
lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.h
 create mode 100644 
lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.cpp
 create mode 100644 
lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.h

diff --git 
a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.cpp 
b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.cpp
index ce3b767832095..302a70976bfa7 100644
--- a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.cpp
@@ -8,10 +8,13 @@
 
 #include "LLDBServerAcceleratorPlugin.h"
 
+#include "GDBRemoteCommunicationServerLLGS.h"
+
 using namespace lldb_private::lldb_server;
 
-LLDBServerAcceleratorPlugin::LLDBServerAcceleratorPlugin(GDBServer &gdb_server,
-                                                         MainLoop &main_loop)
-    : m_gdb_server(gdb_server), m_main_loop(main_loop) {}
+LLDBServerAcceleratorPlugin::LLDBServerAcceleratorPlugin(
+    GDBServer &native_gdb_server, MainLoop &native_main_loop)
+    : m_native_gdb_server(native_gdb_server),
+      m_native_main_loop(native_main_loop) {}
 
 LLDBServerAcceleratorPlugin::~LLDBServerAcceleratorPlugin() = default;
diff --git 
a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h 
b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
index 0230b38e5b0fa..43b6abffd4414 100644
--- a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
+++ b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
@@ -10,8 +10,10 @@
 #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_LLDBSERVERACCELERATORPLUGIN_H
 
 #include "lldb/Host/MainLoop.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
 #include "lldb/Utility/AcceleratorGDBRemotePackets.h"
 #include "llvm/ADT/StringRef.h"
+#include <memory>
 #include <optional>
 
 namespace lldb_private {
@@ -25,8 +27,10 @@ namespace lldb_server {
 class LLDBServerAcceleratorPlugin {
 public:
   using GDBServer = process_gdb_remote::GDBRemoteCommunicationServerLLGS;
+  using Manager = NativeProcessProtocol::Manager;
 
-  LLDBServerAcceleratorPlugin(GDBServer &gdb_server, MainLoop &main_loop);
+  LLDBServerAcceleratorPlugin(GDBServer &native_gdb_server,
+                              MainLoop &native_main_loop);
   virtual ~LLDBServerAcceleratorPlugin();
 
   virtual llvm::StringRef GetPluginName() = 0;
@@ -36,9 +40,26 @@ class LLDBServerAcceleratorPlugin {
   virtual llvm::Expected<AcceleratorBreakpointHitResponse>
   BreakpointWasHit(AcceleratorBreakpointHitArgs &args) = 0;
 
+  /// Create an AcceleratorActions whose identifier is unique within this
+  /// plugin. All actions a plugin creates should be made through this so their
+  /// identifiers do not collide.
+  AcceleratorActions GetNewAcceleratorAction() {
+    return AcceleratorActions(GetPluginName(),
+                              ++m_accelerator_action_identifier);
+  }
+
 protected:
-  GDBServer &m_gdb_server;
-  MainLoop &m_main_loop;
+  // The native process's GDB server that this plugin is attached to.
+  GDBServer &m_native_gdb_server;
+  // The native process's main loop. Plugins should prefer to run their
+  // accelerator server on their own main loop so native and accelerator packet
+  // handling don't slow each other down.
+  MainLoop &m_native_main_loop;
+  // The accelerator process and the in-process GDB server we own to serve it,
+  // exposing the accelerator as a separate target the client connects to.
+  std::unique_ptr<Manager> m_process_manager_up;
+  std::unique_ptr<GDBServer> m_accelerator_gdb_server;
+  int64_t m_accelerator_action_identifier = 0;
 };
 
 } // namespace lldb_server
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp 
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a986d0350bf57..f668106704b05 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -53,6 +53,7 @@
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionArgParser.h"
 #include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
 #include "lldb/Interpreter/OptionGroupUInt64.h"
 #include "lldb/Interpreter/OptionValueProperties.h"
 #include "lldb/Interpreter/Options.h"
@@ -4238,6 +4239,67 @@ ProcessGDBRemote::HandleAcceleratorActions(const 
AcceleratorActions &actions) {
       return error;
   }
 
+  if (actions.connect_info) {
+    if (llvm::Error error = HandleAcceleratorConnection(actions))
+      return error;
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error ProcessGDBRemote::HandleAcceleratorConnection(
+    const AcceleratorActions &actions) {
+  const AcceleratorConnectionInfo &connect_info = *actions.connect_info;
+  Debugger &debugger = GetTarget().GetDebugger();
+
+  // Create the accelerator target. Select the platform by the requested name 
so
+  // we connect through the right platform: each vendor's platform decides how
+  // to reach its accelerator GDB server. The triple ensures the selected
+  // platform is compatible with the architecture; the executable path is
+  // optional.
+  OptionGroupPlatform platform_options(/*include_platform_option=*/false);
+  platform_options.SetPlatformName(connect_info.platform_name.c_str());
+  std::string exe_path = connect_info.exe_path.value_or("");
+  TargetSP accelerator_target_sp;
+  Status error = debugger.GetTargetList().CreateTarget(
+      debugger, exe_path, connect_info.triple, eLoadDependentsNo,
+      &platform_options, accelerator_target_sp);
+  if (error.Fail())
+    return error.takeError();
+  if (!accelerator_target_sp)
+    return llvm::createStringError("failed to create accelerator target");
+
+  // Make sure we got a platform compatible with the requested triple before
+  // connecting through it.
+  PlatformSP platform_sp = accelerator_target_sp->GetPlatform();
+  if (!platform_sp)
+    return llvm::createStringErrorV(
+        "no platform '{0}' compatible with triple '{1}' for the accelerator "
+        "target",
+        connect_info.platform_name, connect_info.triple);
+  ProcessSP process_sp =
+      connect_info.synchronous
+          ? platform_sp->ConnectProcessSynchronous(
+                connect_info.connect_url, GetPluginNameStatic(), debugger,
+                *debugger.GetAsyncOutputStream(), accelerator_target_sp.get(),
+                error)
+          : platform_sp->ConnectProcess(connect_info.connect_url,
+                                        GetPluginNameStatic(), debugger,
+                                        accelerator_target_sp.get(), error);
+  if (error.Fail())
+    return error.takeError();
+  if (!process_sp)
+    return llvm::createStringError("failed to connect to the accelerator");
+
+  accelerator_target_sp->SetTargetSessionName(actions.session_name);
+
+  // Broadcast the new target creation event so clients of the API can detect
+  // when new targets are created.
+  auto event_sp = std::make_shared<Event>(
+      Target::eBroadcastBitNewTargetCreated,
+      new Target::TargetEventData(GetTarget().shared_from_this(),
+                                  accelerator_target_sp));
+  GetTarget().BroadcastEvent(event_sp);
   return llvm::Error::success();
 }
 
@@ -4372,9 +4434,16 @@ bool ProcessGDBRemote::AcceleratorBreakpointHit(
   // The plugin may request new actions (e.g. additional breakpoints) in
   // response to this breakpoint being hit.
   if (response->actions) {
-    if (llvm::Error error = HandleAcceleratorActions(*response->actions))
-      LLDB_LOG_ERROR(log, std::move(error),
-                     "failed to handle accelerator actions: {0}");
+    if (llvm::Error error = HandleAcceleratorActions(*response->actions)) {
+      // Surface the failure (e.g. a connection that could not be made) to the
+      // user in addition to logging it; this runs during a stop where the user
+      // would otherwise see nothing.
+      std::string message = llvm::toString(std::move(error));
+      LLDB_LOG(log, "failed to handle accelerator actions: {0}", message);
+      target.GetDebugger().GetAsyncErrorStream()->Printf(
+          "error: accelerator plugin '%s': %s\n",
+          response->actions->plugin_name.c_str(), message.c_str());
+    }
   }
 
   // Returning true stops the native process; false auto-resumes it.
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h 
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 0a3386082c388..525a45f7cce21 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -488,6 +488,10 @@ class ProcessGDBRemote : public Process,
   /// breakpoints are still set.
   llvm::Error HandleAcceleratorBreakpoints(const AcceleratorActions &actions);
 
+  /// Create a new target for an accelerator and connect it to the GDB server
+  /// described by the action's connection info.
+  llvm::Error HandleAcceleratorConnection(const AcceleratorActions &actions);
+
   /// Breakpoint callback invoked when an accelerator-plugin-requested
   /// breakpoint is hit. Resolves any requested symbol values, notifies the
   /// plugin via the "jAcceleratorPluginBreakpointHit" packet, and handles the
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py 
b/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py
new file mode 100644
index 0000000000000..3506c18688a9a
--- /dev/null
+++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py
@@ -0,0 +1,226 @@
+"""
+End-to-end test for accelerator plugin actions (breakpoints and connections).
+
+Launches a real process against an lldb-server that has the mock accelerator
+plugin enabled and verifies that the breakpoints requested by the plugin are
+set in the native process, hit, and that hitting one breakpoint can request
+further breakpoints. This exercises all three breakpoint types: by name, by
+name scoped to a shared library, and by address.
+
+It also verifies that hitting the plugin's connection-trigger breakpoint causes
+the client to create a second (accelerator) target and connect it to the mock
+accelerator GDB server.
+"""
+
+import os
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import configuration
+
+
+def uint64_to_int64(value):
+    """Reinterpret an unsigned 64-bit value as a signed 64-bit integer."""
+    if value >= (1 << 63):
+        return value - (1 << 64)
+    return value
+
+
+class MockAcceleratorActionsTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setUp(self):
+        super().setUp()
+        if "mock-accelerator" not in configuration.enabled_plugins:
+            self.skipTest("mock-accelerator plugin is not enabled")
+
+    def check_accelerator_breakpoint_stop(self, process, function_name, 
hit_count=None):
+        """Verify the process stopped at an internal accelerator breakpoint in
+        the given function. If hit_count is not None, also verify the
+        breakpoint's hit count. Returns the breakpoint."""
+        self.assertState(process.GetState(), lldb.eStateStopped)
+        thread = process.GetSelectedThread()
+
+        # The stop must be due to a breakpoint, and the frame must be in the
+        # expected function.
+        self.assertStopReason(thread.GetStopReason(), 
lldb.eStopReasonBreakpoint)
+        frame = thread.GetFrameAtIndex(0)
+        self.assertEqual(frame.GetFunctionName(), function_name)
+
+        # The breakpoint id is carried in the stop reason data. Accelerator
+        # breakpoints are internal, so they are not in the public breakpoint
+        # list, but can still be looked up by id. The datum is an unsigned
+        # 64-bit value holding the (signed) breakpoint id; internal ids are
+        # negative.
+        self.assertGreater(thread.GetStopReasonDataCount(), 0)
+        bp_id = uint64_to_int64(thread.GetStopReasonDataAtIndex(0))
+        bp = process.GetTarget().FindBreakpointByID(bp_id)
+        self.assertTrue(bp.IsValid())
+        self.assertTrue(bp.IsInternal(), "accelerator breakpoints are 
internal")
+
+        if hit_count is not None:
+            self.assertEqual(bp.GetHitCount(), hit_count)
+        return bp
+
+    def set_mock_env(self, name, value):
+        """Set an environment variable the mock plugin reads (it is inherited 
by
+        the lldb-server that hosts the plugin), restoring it after the test."""
+        previous = os.environ.get(name)
+        os.environ[name] = value
+
+        def restore():
+            if previous is None:
+                os.environ.pop(name, None)
+            else:
+                os.environ[name] = previous
+
+        self.addTearDownHook(restore)
+
+    @skipIfRemote
+    @add_test_categories(["llgs"])
+    def test_accelerator_actions(self):
+        """The mock accelerator plugin drives breakpoints in the inferior and,
+        once initialized, a connection that creates a second target."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Launching the process should stop at the
+        # "mock_gpu_accelerator_initialize" breakpoint that the mock plugin
+        # requested via jAcceleratorPluginInitialize (it requests the native
+        # process not auto-resume). This is a breakpoint by name with no shared
+        # library.
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_initialize", hit_count=1
+        )
+
+        # The accelerator breakpoint was set and hit, yet it is internal, so it
+        # never appears in the public breakpoint list.
+        self.assertEqual(target.GetNumBreakpoints(), 0)
+
+        # Hitting the mock_gpu_accelerator_initialize breakpoint caused the
+        # plugin to request three more breakpoints: the connection hook (hit
+        # next, since main() connects right after initializing), one by address
+        # (on "mock_gpu_accelerator_compute", from the symbol value delivered
+        # with the hit), and one by name scoped to the "a.out" shared library 
(on
+        # "mock_gpu_accelerator_finish"). Only the native target exists until 
the
+        # connection hook is hit.
+        self.assertEqual(self.dbg.GetNumTargets(), 1)
+        process.Continue()
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_connect", hit_count=1
+        )
+
+        # The accelerator target now exists alongside the native target.
+        self.assertEqual(self.dbg.GetNumTargets(), 2)
+        accelerator_target = None
+        for i in range(self.dbg.GetNumTargets()):
+            candidate = self.dbg.GetTargetAtIndex(i)
+            if candidate != target:
+                accelerator_target = candidate
+                break
+        self.assertTrue(accelerator_target.IsValid())
+
+        # The accelerator process must be successfully connected and stopped.
+        accelerator_process = accelerator_target.GetProcess()
+        self.assertTrue(accelerator_process.IsValid())
+        self.assertState(accelerator_process.GetState(), lldb.eStateStopped)
+
+        # Validate the registers (each value == 0x1000 + register index).
+        accelerator_frame = 
accelerator_process.GetThreadAtIndex(0).GetFrameAtIndex(0)
+        expected_registers = {
+            "r0": 0x1000,
+            "r1": 0x1001,
+            "sp": 0x1002,
+            "fp": 0x1003,
+            "pc": 0x1004,
+            "flags": 0x1005,
+        }
+        for name, value in expected_registers.items():
+            reg = accelerator_frame.FindRegister(name)
+            self.assertTrue(reg.IsValid(), "register %s should exist" % name)
+            self.assertEqual(
+                reg.GetValueAsUnsigned(),
+                value,
+                "register %s should read back its expected value" % name,
+            )
+
+        # With the accelerator connected, continue through the remaining
+        # breakpoint types: by address (on mock_gpu_accelerator_compute), then 
by
+        # name scoped to a shared library (on mock_gpu_accelerator_finish).
+        process.Continue()
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_compute", hit_count=1
+        )
+
+        process.Continue()
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_finish", hit_count=1
+        )
+
+        # No more accelerator breakpoints; the process runs to exit.
+        process.Continue()
+        self.assertState(process.GetState(), lldb.eStateExited)
+        self.assertEqual(process.GetExitStatus(), 0)
+
+    def run_expecting_failed_connection(self):
+        """Run the inferior through its breakpoints, asserting the connection 
is
+        attempted at the connection hook but no accelerator target is created
+        (and lldb does not crash), then runs to exit."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
+        self.assertTrue(process, PROCESS_IS_VALID)
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_initialize", hit_count=1
+        )
+
+        # At the connection hook the plugin returns connect_info the client
+        # cannot use, so no second target is created and lldb does not crash.
+        process.Continue()
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_connect", hit_count=1
+        )
+        self.assertEqual(
+            self.dbg.GetNumTargets(), 1, "connection should fail; no 
accelerator target"
+        )
+
+        # The native process is unaffected: the remaining breakpoints still 
fire
+        # and it runs to exit.
+        process.Continue()
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_compute", hit_count=1
+        )
+        process.Continue()
+        self.check_accelerator_breakpoint_stop(
+            process, "mock_gpu_accelerator_finish", hit_count=1
+        )
+        process.Continue()
+        self.assertState(process.GetState(), lldb.eStateExited)
+        self.assertEqual(process.GetExitStatus(), 0)
+
+    @skipIfRemote
+    @add_test_categories(["llgs"])
+    def test_accelerator_connection_invalid_platform(self):
+        """An invalid platform name in connect_info fails the connection
+        gracefully."""
+        self.set_mock_env("LLDB_MOCK_ACCELERATOR_PLATFORM", "no-such-platform")
+        self.run_expecting_failed_connection()
+
+    @skipIfRemote
+    @add_test_categories(["llgs"])
+    def test_accelerator_connection_incompatible_triple(self):
+        """A valid platform with a triple it does not support fails the
+        connection gracefully."""
+        # remote-linux is a real platform but cannot handle a GPU triple.
+        self.set_mock_env("LLDB_MOCK_ACCELERATOR_PLATFORM", "remote-linux")
+        self.set_mock_env("LLDB_MOCK_ACCELERATOR_TRIPLE", "amdgcn-amd-amdhsa")
+        self.run_expecting_failed_connection()
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorBreakpoints.py 
b/lldb/test/API/accelerator/mock/TestMockAcceleratorBreakpoints.py
deleted file mode 100644
index 885e73e3cec15..0000000000000
--- a/lldb/test/API/accelerator/mock/TestMockAcceleratorBreakpoints.py
+++ /dev/null
@@ -1,104 +0,0 @@
-"""
-End-to-end test for accelerator plugin breakpoints.
-
-Launches a real process against an lldb-server that has the mock accelerator
-plugin enabled and verifies that the breakpoints requested by the plugin are
-set in the native process, hit, and that hitting one breakpoint can request
-further breakpoints. This exercises all three breakpoint types: by name, by
-name scoped to a shared library, and by address.
-"""
-
-import lldb
-import lldbsuite.test.lldbutil as lldbutil
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import configuration
-
-
-def uint64_to_int64(value):
-    """Reinterpret an unsigned 64-bit value as a signed 64-bit integer."""
-    if value >= (1 << 63):
-        return value - (1 << 64)
-    return value
-
-
-class MockAcceleratorBreakpointsTestCase(TestBase):
-    NO_DEBUG_INFO_TESTCASE = True
-
-    def setUp(self):
-        super().setUp()
-        if "mock-accelerator" not in configuration.enabled_plugins:
-            self.skipTest("mock-accelerator plugin is not enabled")
-
-    def check_accelerator_breakpoint_stop(self, process, function_name, 
hit_count=None):
-        """Verify the process stopped at an internal accelerator breakpoint in
-        the given function. If hit_count is not None, also verify the
-        breakpoint's hit count. Returns the breakpoint."""
-        self.assertState(process.GetState(), lldb.eStateStopped)
-        thread = process.GetSelectedThread()
-
-        # The stop must be due to a breakpoint, and the frame must be in the
-        # expected function.
-        self.assertStopReason(thread.GetStopReason(), 
lldb.eStopReasonBreakpoint)
-        frame = thread.GetFrameAtIndex(0)
-        self.assertEqual(frame.GetFunctionName(), function_name)
-
-        # The breakpoint id is carried in the stop reason data. Accelerator
-        # breakpoints are internal, so they are not in the public breakpoint
-        # list, but can still be looked up by id. The datum is an unsigned
-        # 64-bit value holding the (signed) breakpoint id; internal ids are
-        # negative.
-        self.assertGreater(thread.GetStopReasonDataCount(), 0)
-        bp_id = uint64_to_int64(thread.GetStopReasonDataAtIndex(0))
-        bp = process.GetTarget().FindBreakpointByID(bp_id)
-        self.assertTrue(bp.IsValid())
-        self.assertTrue(bp.IsInternal(), "accelerator breakpoints are 
internal")
-
-        if hit_count is not None:
-            self.assertEqual(bp.GetHitCount(), hit_count)
-        return bp
-
-    @skipIfRemote
-    @add_test_categories(["llgs"])
-    def test_accelerator_breakpoints(self):
-        """The mock accelerator plugin drives breakpoints in the inferior."""
-        self.build()
-        exe = self.getBuildArtifact("a.out")
-        target = self.dbg.CreateTarget(exe)
-        self.assertTrue(target, VALID_TARGET)
-
-        # Launching the process should stop at the
-        # "mock_gpu_accelerator_initialize" breakpoint that the mock plugin
-        # requested via jAcceleratorPluginInitialize (it requests the native
-        # process not auto-resume). This is a breakpoint by name with no shared
-        # library.
-        process = target.LaunchSimple(None, None, 
self.get_process_working_directory())
-        self.assertTrue(process, PROCESS_IS_VALID)
-        self.check_accelerator_breakpoint_stop(
-            process, "mock_gpu_accelerator_initialize", hit_count=1
-        )
-
-        # The accelerator breakpoint was set and hit, yet it is internal, so it
-        # never appears in the public breakpoint list.
-        self.assertEqual(target.GetNumBreakpoints(), 0)
-
-        # Hitting the mock_gpu_accelerator_initialize breakpoint caused the
-        # plugin to request two more breakpoints: one by address (on
-        # "mock_gpu_accelerator_compute", from the symbol value delivered with
-        # the hit) and one by name scoped to the "a.out" shared library (on
-        # "mock_gpu_accelerator_finish"). main() calls
-        # mock_gpu_accelerator_compute() first.
-        process.Continue()
-        self.check_accelerator_breakpoint_stop(
-            process, "mock_gpu_accelerator_compute", hit_count=1
-        )
-
-        process.Continue()
-        self.check_accelerator_breakpoint_stop(
-            process, "mock_gpu_accelerator_finish", hit_count=1
-        )
-
-        # No more accelerator breakpoints; the process runs to exit.
-        process.Continue()
-        self.assertState(process.GetState(), lldb.eStateExited)
-        self.assertEqual(process.GetExitStatus(), 0)
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py 
b/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py
similarity index 70%
rename from lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py
rename to lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py
index 1eeeb7f731eb7..941e0c97a8f2e 100644
--- a/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py
+++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py
@@ -1,9 +1,9 @@
 """
-Tests for the lldb-server mock accelerator plugin.
+Packet-level tests for the lldb-server mock accelerator plugin.
 
 Verifies the accelerator-plugins+ feature in qSupported,
 the jAcceleratorPluginInitialize packet response, and
-the jAcceleratorPluginBreakpointHit round-trip.
+the jAcceleratorPluginBreakpointHit round-trip (including connect_info).
 """
 
 import json
@@ -22,7 +22,7 @@ def get_accelerator_action(actions, plugin_name):
     return None
 
 
-class MockAcceleratorPluginTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
+class MockAcceleratorPacketsTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
     def setUp(self):
         super().setUp()
         if "mock-accelerator" not in configuration.enabled_plugins:
@@ -140,3 +140,49 @@ def test_jAcceleratorPluginBreakpointHit_response(self):
         # "mock_gpu_accelerator_compute" symbol value.
         self.assertIn(2, new_bps)
         self.assertEqual(new_bps[2]["by_address"]["load_address"], 0x4000)
+
+        # The initialize hit also arms the connection-trigger breakpoint by 
name.
+        self.assertIn(4, new_bps)
+        self.assertEqual(
+            new_bps[4]["by_name"]["function_name"], 
"mock_gpu_accelerator_connect"
+        )
+
+    @add_test_categories(["llgs"])
+    def test_jAcceleratorPluginBreakpointHit_returns_connect_info(self):
+        self.build()
+        self.set_inferior_startup_launch()
+        self.prep_debug_monitor_and_inferior()
+
+        self.add_qSupported_packets()
+        self.expect_gdbremote_sequence()
+
+        # Simulate the connection-trigger breakpoint (identifier 4) being hit.
+        # The plugin responds with connect_info describing the connection the
+        # client should make to the mock accelerator GDB server.
+        hit_args = {
+            "plugin_name": "mock",
+            "breakpoint": {"identifier": 4, "symbol_names": []},
+            "symbol_values": [],
+        }
+        hit_json = json.dumps(hit_args, separators=(",", ":"))
+        escaped_json = escape_binary(hit_json)
+        response = self.send_and_decode_json(
+            "jAcceleratorPluginBreakpointHit:" + escaped_json
+        )
+
+        self.assertTrue(response["disable_bp"])
+        self.assertFalse(response["auto_resume_native"])
+
+        actions = response["actions"]
+        self.assertEqual(actions["plugin_name"], "mock")
+        self.assertEqual(actions["session_name"], "Mock Accelerator Session")
+
+        # The connect_info must carry a connect URL to a local port and request
+        # a synchronous connection.
+        self.assertIn("connect_info", actions)
+        connect_info = actions["connect_info"]
+        self.assertTrue(
+            connect_info["connect_url"].startswith("connect://localhost:"),
+            connect_info["connect_url"],
+        )
+        self.assertTrue(connect_info["synchronous"])
diff --git a/lldb/test/API/accelerator/mock/main.c 
b/lldb/test/API/accelerator/mock/main.c
index 5f4c7b1fd3147..18aed944b8d8f 100644
--- a/lldb/test/API/accelerator/mock/main.c
+++ b/lldb/test/API/accelerator/mock/main.c
@@ -1,15 +1,19 @@
-// The mock accelerator plugin sets its initialize breakpoint on this function.
-// Using a dedicated, uniquely named function (rather than "main") ensures the
-// mock plugin only affects this test program and not other inferiors launched
-// by lldb-server.
+// The mock accelerator plugin sets its breakpoints on these dedicated, 
uniquely
+// named functions.
 void mock_gpu_accelerator_initialize(void) {}
 
 int mock_gpu_accelerator_compute(int x) { return x * 2; }
 
 int mock_gpu_accelerator_finish(void) { return 0; }
 
+// When the plugin's connection-trigger breakpoint on this function is hit, it
+// asks the client to create a second target and connect to the mock 
accelerator
+// GDB server.
+void mock_gpu_accelerator_connect(void) {}
+
 int main(void) {
   mock_gpu_accelerator_initialize();
+  mock_gpu_accelerator_connect();
   int result = mock_gpu_accelerator_compute(21);
   mock_gpu_accelerator_finish();
   return result == 42 ? 0 : 1;
diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt
index 9b5a82a087e3d..d6cdc603213e3 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/CMakeLists.txt
@@ -1,5 +1,8 @@
 add_lldb_library(lldbServerPluginMockAccelerator
   LLDBServerMockAcceleratorPlugin.cpp
+  ProcessMockAccelerator.cpp
+  ThreadMockAccelerator.cpp
+  RegisterContextMockAccelerator.cpp
 
   LINK_LIBS
     lldbHost
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
index f89fb90e26aa6..7f98e9bd65c62 100644
--- 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
+++ 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
@@ -7,13 +7,121 @@
 
//===----------------------------------------------------------------------===//
 
 #include "LLDBServerMockAcceleratorPlugin.h"
+#include "ProcessMockAccelerator.h"
 
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Connection.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <cstdlib>
+
+using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::lldb_server;
+using namespace lldb_private::process_gdb_remote;
+
+// Read a mock-accelerator setting from an environment variable so tests can
+// configure the connection the mock advertises; falls back to default_value.
+static std::string GetMockEnvSetting(const char *env_var,
+                                     std::string default_value) {
+  if (const char *value = ::getenv(env_var))
+    return value;
+  return default_value;
+}
 
 LLDBServerMockAcceleratorPlugin::LLDBServerMockAcceleratorPlugin(
-    GDBServer &gdb_server, MainLoop &main_loop)
-    : LLDBServerAcceleratorPlugin(gdb_server, main_loop) {}
+    GDBServer &native_gdb_server, MainLoop &native_main_loop)
+    : LLDBServerAcceleratorPlugin(native_gdb_server, native_main_loop) {
+  Log *log = GetLog(GDBRLog::Plugin);
+
+  // Run a second gdb-remote server inside this lldb-server process, on its own
+  // main loop and thread (separate from the native process so neither slows 
the
+  // other's packets), backed by ProcessMockAccelerator. No real process is
+  // launched or exec'd: ProcessMockAccelerator::Manager just returns a
+  // synthetic, already-stopped process with a single thread and a fixed set of
+  // registers.
+  m_process_manager_up =
+      std::make_unique<ProcessMockAccelerator::Manager>(m_mock_main_loop);
+  m_accelerator_gdb_server = 
std::make_unique<GDBRemoteCommunicationServerLLGS>(
+      m_mock_main_loop, *m_process_manager_up);
+
+  // LaunchProcess() is how LLGS obtains its current process; it routes to
+  // ProcessMockAccelerator::Manager::Launch() (which ignores this info) and
+  // only requires a non-empty argument list, so a single placeholder is 
enough.
+  ProcessLaunchInfo info;
+  Args args;
+  args.AppendArgument("/pretend/path/to/mockgpu");
+  info.SetArguments(args, /*first_arg_is_executable=*/true);
+  m_accelerator_gdb_server->SetLaunchInfo(info);
+  if (Status error = m_accelerator_gdb_server->LaunchProcess(); error.Fail())
+    LLDB_LOG(log, "failed to create mock accelerator process: {0}",
+             error.AsCString());
+
+  // Listen on an ephemeral local port for the client's connection, registering
+  // the accept handler now -- before the main loop thread starts -- so the
+  // loop's handles are only ever touched from its own thread.
+  llvm::Expected<std::unique_ptr<TCPSocket>> sock =
+      Socket::TcpListen("localhost:0");
+  if (!sock) {
+    LLDB_LOG_ERROR(log, sock.takeError(),
+                   "mock accelerator failed to listen: {0}");
+    return;
+  }
+  m_listen_socket = std::move(*sock);
+  llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> handles =
+      m_listen_socket->Accept(
+          m_mock_main_loop, [this](std::unique_ptr<Socket> socket) {
+            std::unique_ptr<Connection> connection_up =
+                std::make_unique<ConnectionFileDescriptor>(std::move(socket));
+            m_accelerator_gdb_server->InitializeConnection(
+                std::move(connection_up));
+          });
+  if (!handles) {
+    LLDB_LOG_ERROR(log, handles.takeError(),
+                   "mock accelerator failed to accept: {0}");
+    return;
+  }
+  m_read_handles = std::move(*handles);
+  m_connect_url = llvm::formatv("connect://localhost:{0}",
+                                m_listen_socket->GetLocalPortNumber());
+
+  // Service the mock accelerator server on its own thread.
+  llvm::Expected<HostThread> loop_thread = ThreadLauncher::LaunchThread(
+      "mock-accel.loop", [this]() -> lldb::thread_result_t {
+        m_mock_main_loop.Run();
+        return {};
+      });
+  if (!loop_thread) {
+    LLDB_LOG_ERROR(log, loop_thread.takeError(),
+                   "mock accelerator failed to start its main loop: {0}");
+    m_connect_url.clear();
+    return;
+  }
+  m_mock_main_loop_thread = *loop_thread;
+}
+
+LLDBServerMockAcceleratorPlugin::~LLDBServerMockAcceleratorPlugin() {
+  // Stop the mock main loop and wait for its thread, then tear down the 
objects
+  // that reference the loop before it (a member) is destroyed.
+  m_mock_main_loop.AddPendingCallback(
+      [](MainLoopBase &loop) { loop.RequestTermination(); });
+  if (m_mock_main_loop_thread.IsJoinable())
+    m_mock_main_loop_thread.Join(/*result=*/nullptr);
+  m_read_handles.clear();
+  m_listen_socket.reset();
+  m_accelerator_gdb_server.reset();
+  m_process_manager_up.reset();
+}
 
 llvm::StringRef LLDBServerMockAcceleratorPlugin::GetPluginName() {
   return "mock";
@@ -21,7 +129,7 @@ llvm::StringRef 
LLDBServerMockAcceleratorPlugin::GetPluginName() {
 
 std::optional<AcceleratorActions>
 LLDBServerMockAcceleratorPlugin::GetInitializeActions() {
-  AcceleratorActions actions(GetPluginName(), 1);
+  AcceleratorActions actions = GetNewAcceleratorAction();
 
   // Set a breakpoint by function name (no shared library scope) on the
   // dedicated "mock_gpu_accelerator_initialize" hook and ask for the load
@@ -47,12 +155,12 @@ LLDBServerMockAcceleratorPlugin::BreakpointWasHit(
   switch (args.breakpoint.identifier) {
   case kBreakpointIDInitialize: {
     // The initialize breakpoint was hit. Disable it, stop the native process,
-    // and request two more breakpoints to exercise the remaining breakpoint
-    // types.
+    // and request more breakpoints: two to exercise the remaining breakpoint
+    // types, plus the connection hook now that the accelerator has 
initialized.
     response.disable_bp = true;
     response.auto_resume_native = false;
 
-    AcceleratorActions actions(GetPluginName(), 2);
+    AcceleratorActions actions = GetNewAcceleratorAction();
 
     // Breakpoint by function name scoped to a shared library. Tests build to
     // "a.out", so use that as the shared library name.
@@ -72,6 +180,17 @@ LLDBServerMockAcceleratorPlugin::BreakpointWasHit(
       actions.breakpoints.push_back(std::move(by_address));
     }
 
+    // Now that the accelerator has initialized, set the breakpoint on the
+    // dedicated connection hook. Arming it only after the initialize hit
+    // (rather than up front) mirrors how a real GPU plugin connects once the
+    // runtime is ready. It only resolves in programs that define
+    // "mock_gpu_accelerator_connect".
+    AcceleratorBreakpointInfo connect_bp;
+    connect_bp.identifier = kBreakpointIDConnect;
+    connect_bp.by_name = AcceleratorBreakpointByName{
+        std::nullopt, "mock_gpu_accelerator_connect"};
+    actions.breakpoints.push_back(std::move(connect_bp));
+
     response.actions = std::move(actions);
     break;
   }
@@ -81,7 +200,41 @@ LLDBServerMockAcceleratorPlugin::BreakpointWasHit(
     response.disable_bp = true;
     response.auto_resume_native = false;
     break;
+  case kBreakpointIDConnect: {
+    // The program reached its connection hook. Ask the client to create a
+    // second target and connect to our in-process mock accelerator GDB
+    // server.
+    response.disable_bp = true;
+    response.auto_resume_native = false;
+    AcceleratorActions actions = GetNewAcceleratorAction();
+    actions.session_name = "Mock Accelerator Session";
+    actions.connect_info = CreateConnection();
+    response.actions = std::move(actions);
+    break;
+  }
   }
 
   return response;
 }
+
+std::optional<AcceleratorConnectionInfo>
+LLDBServerMockAcceleratorPlugin::CreateConnection() {
+  // The listen socket and its main loop thread are set up in the constructor;
+  // m_connect_url is empty if that failed.
+  if (m_connect_url.empty())
+    return std::nullopt;
+
+  AcceleratorConnectionInfo info;
+  info.connect_url = m_connect_url;
+  // The platform and triple let the client select a compatible platform to
+  // connect through. They default to the host (the mock process uses the host
+  // architecture), but can be overridden via environment variables so tests 
can
+  // exercise invalid-platform and incompatible-triple failures.
+  info.platform_name =
+      GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_PLATFORM", "host");
+  info.triple =
+      GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_TRIPLE",
+                        HostInfo::GetArchitecture().GetTriple().str());
+  info.synchronous = true;
+  return info;
+}
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
index 7a1b57e0bb0b7..c2dbdd4413d2f 100644
--- 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
+++ 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
@@ -10,13 +10,25 @@
 #define 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_LLDBSERVERMOCKACCELERATORPLUGIN_H
 
 #include "Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/MainLoop.h"
+#include "lldb/Host/MainLoopBase.h"
+
+#include <memory>
+#include <string>
+#include <vector>
 
 namespace lldb_private {
+
+class TCPSocket;
+
 namespace lldb_server {
 
 class LLDBServerMockAcceleratorPlugin : public LLDBServerAcceleratorPlugin {
 public:
-  LLDBServerMockAcceleratorPlugin(GDBServer &gdb_server, MainLoop &main_loop);
+  LLDBServerMockAcceleratorPlugin(GDBServer &native_gdb_server,
+                                  MainLoop &native_main_loop);
+  ~LLDBServerMockAcceleratorPlugin() override;
 
   llvm::StringRef GetPluginName() override;
   std::optional<AcceleratorActions> GetInitializeActions() override;
@@ -24,6 +36,10 @@ class LLDBServerMockAcceleratorPlugin : public 
LLDBServerAcceleratorPlugin {
   BreakpointWasHit(AcceleratorBreakpointHitArgs &args) override;
 
 private:
+  // Start listening for the client's connection to the mock accelerator GDB
+  // server and return the connection info the client should connect to.
+  std::optional<AcceleratorConnectionInfo> CreateConnection();
+
   // Breakpoint set during initialization, by function name with no shared
   // library. Requests the "compute" symbol value when hit.
   static constexpr int64_t kBreakpointIDInitialize = 1;
@@ -32,6 +48,24 @@ class LLDBServerMockAcceleratorPlugin : public 
LLDBServerAcceleratorPlugin {
   static constexpr int64_t kBreakpointIDByAddress = 2;
   // Breakpoint set by function name scoped to a shared library.
   static constexpr int64_t kBreakpointIDByNameShlib = 3;
+  // Breakpoint on the dedicated "mock_gpu_accelerator_connect" hook. When hit,
+  // the plugin asks the client to create a second target and connect to the
+  // mock accelerator GDB server. Only programs that define that function (the
+  // connection test) trigger it.
+  static constexpr int64_t kBreakpointIDConnect = 4;
+
+  // The mock accelerator server runs on its own main loop and thread, separate
+  // from the native process's main loop, so native and accelerator packet
+  // handling don't slow each other down.
+  MainLoop m_mock_main_loop;
+  HostThread m_mock_main_loop_thread;
+  // Listen socket and accept handles for the client's connection to the
+  // accelerator GDB server (m_accelerator_gdb_server, owned by the base 
class).
+  std::unique_ptr<TCPSocket> m_listen_socket;
+  std::vector<MainLoopBase::ReadHandleUP> m_read_handles;
+  // The "connect://localhost:<port>" URL the client should connect to, set 
once
+  // the listen socket is up; empty if listening failed.
+  std::string m_connect_url;
 };
 
 } // namespace lldb_server
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.cpp 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.cpp
new file mode 100644
index 0000000000000..174ab1a0143d4
--- /dev/null
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.cpp
@@ -0,0 +1,112 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMockAccelerator.h"
+#include "ThreadMockAccelerator.h"
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "llvm/Support/Error.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+
+// A fixed, fake pid and tid for the single mock accelerator process/thread.
+static constexpr lldb::pid_t kMockPid = 1234;
+static constexpr lldb::tid_t kMockTid = 3456;
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ProcessMockAccelerator::Manager::Launch(ProcessLaunchInfo &launch_info,
+                                        NativeDelegate &native_delegate) {
+  return std::make_unique<ProcessMockAccelerator>(kMockPid, native_delegate);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ProcessMockAccelerator::Manager::Attach(lldb::pid_t pid,
+                                        NativeDelegate &native_delegate) {
+  return llvm::createStringError("attach is not supported by the mock "
+                                 "accelerator process");
+}
+
+ProcessMockAccelerator::ProcessMockAccelerator(lldb::pid_t pid,
+                                               NativeDelegate &delegate)
+    : NativeProcessProtocol(pid, /*terminal_fd=*/-1, delegate) {
+  m_state = eStateStopped;
+  UpdateThreads();
+}
+
+Status ProcessMockAccelerator::Resume(const ResumeActionList &resume_actions) {
+  // Nothing actually runs; stay stopped.
+  return Status();
+}
+
+Status ProcessMockAccelerator::Halt() { return Status(); }
+
+Status ProcessMockAccelerator::Detach() {
+  SetState(eStateDetached, true);
+  return Status();
+}
+
+Status ProcessMockAccelerator::Signal(int signo) {
+  return Status::FromErrorString("unimplemented");
+}
+
+Status ProcessMockAccelerator::Kill() { return Status(); }
+
+Status ProcessMockAccelerator::ReadMemory(lldb::addr_t addr, void *buf,
+                                          size_t size, size_t &bytes_read) {
+  bytes_read = 0;
+  return Status::FromErrorString("unimplemented");
+}
+
+Status ProcessMockAccelerator::WriteMemory(lldb::addr_t addr, const void *buf,
+                                           size_t size, size_t &bytes_written) 
{
+  bytes_written = 0;
+  return Status::FromErrorString("unimplemented");
+}
+
+lldb::addr_t ProcessMockAccelerator::GetSharedLibraryInfoAddress() {
+  return LLDB_INVALID_ADDRESS;
+}
+
+size_t ProcessMockAccelerator::UpdateThreads() {
+  if (m_threads.empty()) {
+    m_threads.push_back(
+        std::make_unique<ThreadMockAccelerator>(*this, kMockTid));
+    SetCurrentThreadID(kMockTid);
+  }
+  return m_threads.size();
+}
+
+const ArchSpec &ProcessMockAccelerator::GetArchitecture() const {
+  if (!m_arch.IsValid())
+    m_arch = HostInfo::GetArchitecture();
+  return m_arch;
+}
+
+Status ProcessMockAccelerator::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+                                             bool hardware) {
+  return Status::FromErrorString("unimplemented");
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ProcessMockAccelerator::GetAuxvData() const {
+  return std::error_code(ENOENT, std::generic_category());
+}
+
+Status ProcessMockAccelerator::GetLoadedModuleFileSpec(const char *module_path,
+                                                       FileSpec &file_spec) {
+  return Status::FromErrorString("unimplemented");
+}
+
+Status
+ProcessMockAccelerator::GetFileLoadAddress(const llvm::StringRef &file_name,
+                                           lldb::addr_t &load_addr) {
+  return Status::FromErrorString("unimplemented");
+}
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
new file mode 100644
index 0000000000000..07c0c4c6d5ef5
--- /dev/null
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_PROCESSMOCKACCELERATOR_H
+#define 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_PROCESSMOCKACCELERATOR_H
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Utility/ArchSpec.h"
+
+namespace lldb_private {
+namespace lldb_server {
+
+/// A minimal, always-stopped fake process used to serve a GDB remote
+/// connection for the mock accelerator plugin. It models a single stopped
+/// thread and nothing else; it lets the client create and connect to a second
+/// (accelerator) target without requiring any real hardware.
+class ProcessMockAccelerator : public NativeProcessProtocol {
+public:
+  class Manager : public NativeProcessProtocol::Manager {
+  public:
+    using NativeProcessProtocol::Manager::Manager;
+
+    llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+    Launch(ProcessLaunchInfo &launch_info,
+           NativeDelegate &native_delegate) override;
+
+    llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+    Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
+  };
+
+  ProcessMockAccelerator(lldb::pid_t pid, NativeDelegate &delegate);
+
+  Status Resume(const ResumeActionList &resume_actions) override;
+  Status Halt() override;
+  Status Detach() override;
+  Status Signal(int signo) override;
+  Status Kill() override;
+
+  Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+                    size_t &bytes_read) override;
+  Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+                     size_t &bytes_written) override;
+
+  lldb::addr_t GetSharedLibraryInfoAddress() override;
+  size_t UpdateThreads() override;
+  const ArchSpec &GetArchitecture() const override;
+
+  Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+                       bool hardware) override;
+
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+  GetAuxvData() const override;
+
+  Status GetLoadedModuleFileSpec(const char *module_path,
+                                 FileSpec &file_spec) override;
+  Status GetFileLoadAddress(const llvm::StringRef &file_name,
+                            lldb::addr_t &load_addr) override;
+
+private:
+  mutable ArchSpec m_arch;
+};
+
+} // namespace lldb_server
+} // namespace lldb_private
+
+#endif // 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_PROCESSMOCKACCELERATOR_H
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.cpp
 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.cpp
new file mode 100644
index 0000000000000..b7eac116f8f7b
--- /dev/null
+++ 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMockAccelerator.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+
+// LLDB register numbers must start at 0 and be contiguous. This minimal set is
+// just enough for the mock accelerator process to be debugged over GDB remote.
+enum LLDBRegNum : uint32_t {
+  LLDB_R0 = 0,
+  LLDB_R1,
+  LLDB_SP,
+  LLDB_FP,
+  LLDB_PC,
+  LLDB_Flags,
+  kNumRegs
+};
+
+#define DEFINE_REG(name, idx, generic)                                         
\
+  {name,                                                                       
\
+   nullptr,                                                                    
\
+   sizeof(uint64_t),                                                           
\
+   idx * sizeof(uint64_t),                                                     
\
+   eEncodingUint,                                                              
\
+   eFormatHex,                                                                 
\
+   {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, generic, LLDB_INVALID_REGNUM,    
\
+    idx},                                                                      
\
+   nullptr,                                                                    
\
+   nullptr,                                                                    
\
+   nullptr}
+
+static const RegisterInfo g_register_infos[] = {
+    DEFINE_REG("r0", LLDB_R0, LLDB_INVALID_REGNUM),
+    DEFINE_REG("r1", LLDB_R1, LLDB_INVALID_REGNUM),
+    DEFINE_REG("sp", LLDB_SP, LLDB_REGNUM_GENERIC_SP),
+    DEFINE_REG("fp", LLDB_FP, LLDB_REGNUM_GENERIC_FP),
+    DEFINE_REG("pc", LLDB_PC, LLDB_REGNUM_GENERIC_PC),
+    DEFINE_REG("flags", LLDB_Flags, LLDB_INVALID_REGNUM),
+};
+
+// The set's member register numbers. This must be a valid array (not null):
+// the stop-reply path reads it to expedite the set's registers.
+static const uint32_t g_register_nums[] = {LLDB_R0, LLDB_R1, LLDB_SP,
+                                           LLDB_FP, LLDB_PC, LLDB_Flags};
+
+static const RegisterSet g_register_set = {"General Purpose Registers", "gpr",
+                                           kNumRegs, g_register_nums};
+
+RegisterContextMockAccelerator::RegisterContextMockAccelerator(
+    NativeThreadProtocol &native_thread)
+    : NativeRegisterContext(native_thread) {
+  // Give each register a distinct, constant value so reads are deterministic.
+  for (uint32_t i = 0; i < kNumRegs; ++i)
+    m_regs[i] = 0x1000 + i;
+}
+
+uint32_t RegisterContextMockAccelerator::GetRegisterCount() const {
+  return kNumRegs;
+}
+
+uint32_t RegisterContextMockAccelerator::GetUserRegisterCount() const {
+  return kNumRegs;
+}
+
+const RegisterInfo *
+RegisterContextMockAccelerator::GetRegisterInfoAtIndex(uint32_t reg) const {
+  if (reg < kNumRegs)
+    return &g_register_infos[reg];
+  return nullptr;
+}
+
+uint32_t RegisterContextMockAccelerator::GetRegisterSetCount() const {
+  return 1;
+}
+
+const RegisterSet *
+RegisterContextMockAccelerator::GetRegisterSet(uint32_t set_index) const {
+  if (set_index == 0)
+    return &g_register_set;
+  return nullptr;
+}
+
+Status
+RegisterContextMockAccelerator::ReadRegister(const RegisterInfo *reg_info,
+                                             RegisterValue &reg_value) {
+  if (!reg_info)
+    return Status::FromErrorString("invalid register info");
+  const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+  if (reg >= kNumRegs)
+    return Status::FromErrorString("invalid register number");
+  reg_value.SetUInt64(m_regs[reg]);
+  return Status();
+}
+
+Status
+RegisterContextMockAccelerator::WriteRegister(const RegisterInfo *reg_info,
+                                              const RegisterValue &reg_value) {
+  if (!reg_info)
+    return Status::FromErrorString("invalid register info");
+  const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+  if (reg >= kNumRegs)
+    return Status::FromErrorString("invalid register number");
+  m_regs[reg] = reg_value.GetAsUInt64();
+  return Status();
+}
+
+Status RegisterContextMockAccelerator::ReadAllRegisterValues(
+    lldb::WritableDataBufferSP &data_sp) {
+  data_sp = std::make_shared<DataBufferHeap>(
+      reinterpret_cast<const uint8_t *>(m_regs.data()),
+      m_regs.size() * sizeof(uint64_t));
+  return Status();
+}
+
+Status RegisterContextMockAccelerator::WriteAllRegisterValues(
+    const lldb::DataBufferSP &data_sp) {
+  if (!data_sp || data_sp->GetByteSize() != m_regs.size() * sizeof(uint64_t))
+    return Status::FromErrorString("invalid register data");
+  ::memcpy(m_regs.data(), data_sp->GetBytes(),
+           m_regs.size() * sizeof(uint64_t));
+  return Status();
+}
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.h
 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.h
new file mode 100644
index 0000000000000..b26a5d454826c
--- /dev/null
+++ 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/RegisterContextMockAccelerator.h
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_REGISTERCONTEXTMOCKACCELERATOR_H
+#define 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_REGISTERCONTEXTMOCKACCELERATOR_H
+
+#include "lldb/Host/common/NativeRegisterContext.h"
+
+#include <array>
+
+namespace lldb_private {
+namespace lldb_server {
+
+/// A minimal register context for the mock accelerator process. It exposes a
+/// small, fixed register set with constant values; it exists only so the mock
+/// accelerator process can be debugged over the GDB remote protocol, not to
+/// model any real hardware.
+class RegisterContextMockAccelerator : public NativeRegisterContext {
+public:
+  RegisterContextMockAccelerator(NativeThreadProtocol &native_thread);
+
+  uint32_t GetRegisterCount() const override;
+  uint32_t GetUserRegisterCount() const override;
+  const RegisterInfo *GetRegisterInfoAtIndex(uint32_t reg) const override;
+  uint32_t GetRegisterSetCount() const override;
+  const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+  Status ReadRegister(const RegisterInfo *reg_info,
+                      RegisterValue &reg_value) override;
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value) override;
+
+  Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+  Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+private:
+  /// The registers, indexed by LLDB register number. Each one is 64 bits.
+  std::array<uint64_t, 6> m_regs;
+};
+
+} // namespace lldb_server
+} // namespace lldb_private
+
+#endif // 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_REGISTERCONTEXTMOCKACCELERATOR_H
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.cpp 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.cpp
new file mode 100644
index 0000000000000..69b7408ef3b56
--- /dev/null
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadMockAccelerator.h"
+#include "ProcessMockAccelerator.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::lldb_server;
+
+ThreadMockAccelerator::ThreadMockAccelerator(ProcessMockAccelerator &process,
+                                             lldb::tid_t tid)
+    : NativeThreadProtocol(process, tid), m_reg_context(*this) {
+  m_stop_info.reason = lldb::eStopReasonTrace;
+}
+
+std::string ThreadMockAccelerator::GetName() {
+  return "Mock Accelerator Thread";
+}
+
+lldb::StateType ThreadMockAccelerator::GetState() {
+  return lldb::eStateStopped;
+}
+
+bool ThreadMockAccelerator::GetStopReason(ThreadStopInfo &stop_info,
+                                          std::string &description) {
+  stop_info = m_stop_info;
+  description = "mock accelerator thread stopped";
+  return true;
+}
+
+Status ThreadMockAccelerator::SetWatchpoint(lldb::addr_t addr, size_t size,
+                                            uint32_t watch_flags,
+                                            bool hardware) {
+  return Status::FromErrorString("unimplemented");
+}
+
+Status ThreadMockAccelerator::RemoveWatchpoint(lldb::addr_t addr) {
+  return Status::FromErrorString("unimplemented");
+}
+
+Status ThreadMockAccelerator::SetHardwareBreakpoint(lldb::addr_t addr,
+                                                    size_t size) {
+  return Status::FromErrorString("unimplemented");
+}
+
+Status ThreadMockAccelerator::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+  return Status::FromErrorString("unimplemented");
+}
diff --git 
a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.h 
b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.h
new file mode 100644
index 0000000000000..5f9dec9483511
--- /dev/null
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ThreadMockAccelerator.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_THREADMOCKACCELERATOR_H
+#define LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_THREADMOCKACCELERATOR_H
+
+#include "RegisterContextMockAccelerator.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include <string>
+
+namespace lldb_private {
+namespace lldb_server {
+
+class ProcessMockAccelerator;
+
+/// A single, always-stopped thread for the mock accelerator process.
+class ThreadMockAccelerator : public NativeThreadProtocol {
+public:
+  ThreadMockAccelerator(ProcessMockAccelerator &process, lldb::tid_t tid);
+
+  std::string GetName() override;
+  lldb::StateType GetState() override;
+  bool GetStopReason(ThreadStopInfo &stop_info,
+                     std::string &description) override;
+  RegisterContextMockAccelerator &GetRegisterContext() override {
+    return m_reg_context;
+  }
+
+  Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+                       bool hardware) override;
+  Status RemoveWatchpoint(lldb::addr_t addr) override;
+  Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+  Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+private:
+  RegisterContextMockAccelerator m_reg_context;
+  ThreadStopInfo m_stop_info;
+};
+
+} // namespace lldb_server
+} // namespace lldb_private
+
+#endif // 
LLDB_TOOLS_LLDB_SERVER_PLUGINS_ACCELERATOR_MOCK_THREADMOCKACCELERATOR_H

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to