[Lldb-commits] [lldb] [lldb] Add accelerator dynamic loader over gdb-remote (PR #217393)

satyanarayana reddy janga via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 30 12:46:01 PDT 2026


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

>From c6cf62eeb2fdb4cb32ef6a08dc50358ac0c4e6ce Mon Sep 17 00:00:00 2001
From: satya janga <satyajanga at fb.com>
Date: Fri, 30 Oct 2026 12:32:06 -0700
Subject: [PATCH 1/2] [lldb] Add server support for jLLDBSettings

---
 .../lldb/Host/common/NativeProcessProtocol.h  |  3 ++-
 .../tools/lldb-server/gdbremote_testcase.py   |  1 +
 .../GDBRemoteCommunicationServerLLGS.cpp      | 23 +++++++++++++++++++
 .../GDBRemoteCommunicationServerLLGS.h        | 13 +++++++++++
 .../gdb-remote/LLDBServerAcceleratorPlugin.h  | 13 +++++++++++
 .../mock/TestMockAcceleratorActions.py        | 15 ++++++++++++
 .../mock/TestMockAcceleratorPackets.py        |  1 +
 .../Mock/LLDBServerMockAcceleratorPlugin.cpp  |  1 +
 .../Accelerator/Mock/ProcessMockAccelerator.h |  2 +-
 9 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index da1fa26abefa9e..25c075077bb9c1 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -306,8 +306,9 @@ class NativeProcessProtocol {
     libraries = (1u << 9),
     accelerator_plugins = (1u << 10),
     address_spaces = (1u << 11),
+    lldb_settings = (1u << 12),
 
-    LLVM_MARK_AS_BITMASK_ENUM(address_spaces)
+    LLVM_MARK_AS_BITMASK_ENUM(lldb_settings)
   };
 
   class Manager {
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index 41ba3d45d5e0bd..74ec0c9a4a436b 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -954,6 +954,7 @@ def add_qSupported_packets(self, client_features=[]):
         "MultiMemRead",
         "jMultiBreakpoint",
         "accelerator-plugins",
+        "lldb-settings",
         "ExpediteStack",
         "ExpediteRecentReads",
     ]
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index db62be06d60ff9..5466817d844c59 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -210,6 +210,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
       StringExtractorGDBRemote::eServerPacketType_QPassSignals,
       &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
 
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jLLDBSettings,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBSettings);
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupported,
       &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported);
@@ -4568,6 +4571,8 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures(
   }
   if (!m_accelerator_plugins.empty())
     ret.push_back("accelerator-plugins+");
+  if (bool(plugin_features & Extension::lldb_settings))
+    ret.push_back("lldb-settings+");
 
   // check for client features
   m_extensions_supported = {};
@@ -4667,6 +4672,24 @@ void GDBRemoteCommunicationServerLLGS::InstallPlugin(
   m_accelerator_plugins.emplace_back(std::move(plugin_up));
 }
 
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBSettings(
+    StringExtractorGDBRemote &) {
+  if (!m_connection_accelerator_plugin)
+    return SendErrorResponse(
+        Status::FromErrorString("invalid accelerator plugin"));
+
+  std::optional<LLDBSettings> settings =
+      m_connection_accelerator_plugin->GetLLDBSettings();
+  if (!settings)
+    return SendErrorResponse(
+        Status::FromErrorString("no LLDB settings available"));
+
+  StreamGDBRemote response;
+  response.PutAsJSON(*settings, /*hex_ascii=*/false);
+  return SendPacketNoLock(response.GetString());
+}
+
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_jAcceleratorPluginInitialize(
     StringExtractorGDBRemote &) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index ac24c69dee0fae..efb7c30b9464f7 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -77,6 +77,13 @@ class GDBRemoteCommunicationServerLLGS
   void InstallPlugin(
       std::unique_ptr<lldb_server::LLDBServerAcceleratorPlugin> plugin_up);
 
+  /// Associate this server with the accelerator plugin for this connection.
+  /// The plugin must outlive this server.
+  void SetConnectionAcceleratorPlugin(
+      lldb_server::LLDBServerAcceleratorPlugin &plugin) {
+    m_connection_accelerator_plugin = &plugin;
+  }
+
   // NativeProcessProtocol::NativeDelegate overrides
   void InitializeDelegate(NativeProcessProtocol *process) override;
 
@@ -120,6 +127,10 @@ class GDBRemoteCommunicationServerLLGS
   NativeProcessProtocol::Manager &m_process_manager;
   std::vector<std::unique_ptr<lldb_server::LLDBServerAcceleratorPlugin>>
       m_accelerator_plugins;
+  /// The plugin that owns this accelerator connection. This is null for the
+  /// native connection and does not own the plugin.
+  lldb_server::LLDBServerAcceleratorPlugin *m_connection_accelerator_plugin =
+      nullptr;
   lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID;
   lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID;
   NativeProcessProtocol *m_current_process;
@@ -304,6 +315,8 @@ class GDBRemoteCommunicationServerLLGS
 
   PacketResult Handle_jMultiBreakpoint(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_jLLDBSettings(StringExtractorGDBRemote &packet);
+
   PacketResult
   Handle_jAcceleratorPluginInitialize(StringExtractorGDBRemote &packet);
 
diff --git a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
index 2e585d9a64c6aa..af9cf944482ea0 100644
--- a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
+++ b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
@@ -35,6 +35,19 @@ class LLDBServerAcceleratorPlugin {
 
   virtual llvm::StringRef GetPluginName() = 0;
 
+  /// Return the LLDB settings needed to debug this accelerator.
+  ///
+  /// The settings select the accelerator dynamic loader and identify this
+  /// server-side plugin. They also determine whether dynamic-loader packets
+  /// are sent over the accelerator or native connection.
+  virtual std::optional<LLDBSettings> GetLLDBSettings() {
+    LLDBSettings settings;
+    settings.dyld_plugin_name = "accelerator-gdb-remote";
+    settings.accelerator_plugin_name = GetPluginName();
+    settings.send_dyld_packet_to_accelerator = true;
+    return settings;
+  }
+
   virtual std::optional<AcceleratorActions> GetInitializeActions() = 0;
 
   virtual llvm::Expected<AcceleratorBreakpointHitResponse>
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py b/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py
index 58c9f2e193ed9b..655e525da1201b 100644
--- a/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py
+++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorActions.py
@@ -142,6 +142,21 @@ def test_accelerator_actions(self):
         self.assertTrue(accelerator_process.IsValid())
         self.assertState(accelerator_process.GetState(), lldb.eStateStopped)
 
+        # LLDB settings are advertised and served only on the accelerator
+        # connection.
+        self.dbg.SetSelectedTarget(accelerator_target)
+        self.expect("process plugin packet send qSupported", substrs=["lldb-settings+"])
+        self.expect(
+            "process plugin packet send jLLDBSettings",
+            substrs=[
+                '"dyld_plugin_name":"accelerator-gdb-remote"',
+                '"accelerator_plugin_name":"mock"',
+                '"send_dyld_packet_to_accelerator":true',
+            ],
+            ordered=False,
+        )
+        self.dbg.SetSelectedTarget(target)
+
         # Validate the registers (each value == 0x1000 + register index).
         accelerator_frame = accelerator_process.GetThreadAtIndex(0).GetFrameAtIndex(0)
         expected_registers = {
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py b/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py
index e40e6491e59a05..a9081e64e5567c 100644
--- a/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py
+++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorPackets.py
@@ -58,6 +58,7 @@ def test_qSupported_reports_accelerator_plugins(self):
 
         self.assertIn("accelerator-plugins", features)
         self.assertEqual(features["accelerator-plugins"], "+")
+        self.assertNotIn("lldb-settings", features)
 
     @add_test_categories(["llgs"])
     def test_jAcceleratorPluginInitialize_returns_breakpoints(self):
diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
index b525f8e3592a7b..069bee0e4ef52b 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
@@ -156,6 +156,7 @@ LLDBServerMockAcceleratorPlugin::CreateConnection() {
       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);
+  m_accelerator_gdb_server->SetConnectionAcceleratorPlugin(*this);
 
   // LLGS creates its current process from a launch; the manager ignores the
   // path but requires a non-empty argument list.
diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
index af1631ebc46084..7b88bd36f2ea53 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
@@ -32,7 +32,7 @@ class ProcessMockAccelerator : public NativeProcessProtocol {
     Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
 
     Extension GetSupportedExtensions() const override {
-      return Extension::address_spaces;
+      return Extension::address_spaces | Extension::lldb_settings;
     }
   };
 

>From b384605f6df49b4f1b31c257705953c2fa6a9738 Mon Sep 17 00:00:00 2001
From: satya janga <satyajanga at fb.com>
Date: Mon, 5 Oct 2026 11:22:20 -0700
Subject: [PATCH 2/2] [lldb] Add accelerator dynamic loader over gdb-remote

Add a DynamicLoader that gets accelerator library load and unload information over GDB-remote. Let the accelerator server select the LLDB loader through jLLDBSettings, and include its server-side plugin name in those settings.

Handle module loads and unloads with end-to-end coverage through the mock accelerator server.
---
 lldb/docs/resources/lldbgdbremote.md          |   8 +-
 .../lldb/Host/common/NativeProcessProtocol.h  |  11 +
 .../Host/common/NativeProcessProtocol.cpp     |   4 +
 .../AcceleratorGDBRemote/CMakeLists.txt       |  13 ++
 .../DynamicLoaderAcceleratorGDBRemote.cpp     | 217 ++++++++++++++++++
 .../DynamicLoaderAcceleratorGDBRemote.h       |  46 ++++
 .../Plugins/DynamicLoader/CMakeLists.txt      |   1 +
 .../GDBRemoteCommunicationClient.cpp          |  24 ++
 .../gdb-remote/GDBRemoteCommunicationClient.h |   5 +
 .../GDBRemoteCommunicationServerLLGS.cpp      |  17 +-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |   8 +-
 .../TestAcceleratorDynamicLoader.py           | 157 +++++++++++++
 .../dynamic_loader/accelerator.yaml           |  23 ++
 .../dynamic_loader/accelerator_lib.yaml       |  23 ++
 .../mock/TestMockAcceleratorDynamicLoader.py  | 148 ++++++++++++
 .../API/accelerator/mock/accelerator_lib.yaml |  23 ++
 lldb/test/API/accelerator/mock/main.c         |   2 +
 .../Mock/LLDBServerMockAcceleratorPlugin.cpp  |  43 +++-
 .../Mock/LLDBServerMockAcceleratorPlugin.h    |   6 +-
 .../Mock/ProcessMockAccelerator.cpp           |  41 +++-
 .../Accelerator/Mock/ProcessMockAccelerator.h |  36 ++-
 21 files changed, 832 insertions(+), 24 deletions(-)
 create mode 100644 lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/CMakeLists.txt
 create mode 100644 lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.cpp
 create mode 100644 lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.h
 create mode 100644 lldb/test/API/accelerator/dynamic_loader/TestAcceleratorDynamicLoader.py
 create mode 100644 lldb/test/API/accelerator/dynamic_loader/accelerator.yaml
 create mode 100644 lldb/test/API/accelerator/dynamic_loader/accelerator_lib.yaml
 create mode 100644 lldb/test/API/accelerator/mock/TestMockAcceleratorDynamicLoader.py
 create mode 100644 lldb/test/API/accelerator/mock/accelerator_lib.yaml

diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md
index 53a36646444bfe..d00bca80246278 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -312,6 +312,9 @@ The fields are:
   through either the native or accelerator connection. If absent, this
   defaults to true.
 
+An accelerator GDB server can use `dyld_plugin_name` to select either LLDB's
+generic `accelerator-gdb-remote` loader or a vendor-specific loader.
+
 The settings object can be extended with more fields as needed.
 
 Example:
@@ -3040,8 +3043,7 @@ support. Not needed for non-hardware-accelerator debugging.
 
 Requests shared library information from an accelerator plugin. The client
 sends this packet when it needs to load or update the accelerator's shared
-library list. This packet requires the `accelerator-plugins+` feature from
-`qSupported`.
+library list.
 
 ```
 LLDB SENDS:    jAcceleratorPluginGetDynamicLoaderLibraryInfo:<json>
@@ -3052,7 +3054,7 @@ The request JSON has the following fields:
 
 | Key           | Type   | Description |
 |---------------|--------|-------------|
-| `plugin_name` | string | Name of the accelerator plugin to query. |
+| `plugin_name` | string | Name of the accelerator plugin to query when using the native connection. It is empty on an accelerator connection, where the connection identifies the plugin. |
 | `full`        | bool   | If true, return every library the plugin knows about. If false, return only what changed since the last query. |
 
 A plugin may track thousands of code objects, so `full` lets a client that is
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 25c075077bb9c1..8eb5873c8de555 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -14,6 +14,7 @@
 #include "NativeWatchpointList.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/MainLoop.h"
+#include "lldb/Utility/AcceleratorGDBRemotePackets.h"
 #include "lldb/Utility/AddressSpace.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/Iterable.h"
@@ -170,6 +171,14 @@ class NativeProcessProtocol {
                                    "Not implemented");
   }
 
+  /// Answers "jAcceleratorPluginGetDynamicLoaderLibraryInfo" on an accelerator
+  /// connection. std::nullopt if this process does not provide libraries.
+  virtual std::optional<AcceleratorDynamicLoaderResponse>
+  GetAcceleratorDynamicLoaderLibraryInfos(
+      const AcceleratorDynamicLoaderArgs &args) {
+    return std::nullopt;
+  }
+
   virtual bool HasPendingLibraryEvents() { return false; }
 
   virtual bool IsAlive() const;
@@ -209,6 +218,8 @@ class NativeProcessProtocol {
   // Accessors
   lldb::pid_t GetID() const { return m_pid; }
 
+  virtual bool GetProcessInfo(ProcessInstanceInfo &proc_info);
+
   lldb::StateType GetState() const;
 
   bool IsRunning() const {
diff --git a/lldb/source/Host/common/NativeProcessProtocol.cpp b/lldb/source/Host/common/NativeProcessProtocol.cpp
index c94825828435ad..b4dd61495e03ba 100644
--- a/lldb/source/Host/common/NativeProcessProtocol.cpp
+++ b/lldb/source/Host/common/NativeProcessProtocol.cpp
@@ -851,4 +851,8 @@ void NativeProcessProtocol::DoStopIDBumped(uint32_t /* newBumpId */) {
   // Default implementation does nothing.
 }
 
+bool NativeProcessProtocol::GetProcessInfo(ProcessInstanceInfo &proc_info) {
+  return Host::GetProcessInfo(m_pid, proc_info);
+}
+
 NativeProcessProtocol::Manager::~Manager() = default;
diff --git a/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/CMakeLists.txt
new file mode 100644
index 00000000000000..b5cf71d1f8b31a
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginDynamicLoaderAcceleratorGDBRemote PLUGIN
+  DynamicLoaderAcceleratorGDBRemote.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbSymbol
+    lldbTarget
+    lldbUtility
+    lldbPluginProcessGDBRemote
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.cpp b/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.cpp
new file mode 100644
index 00000000000000..a32f94cd0d2292
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.cpp
@@ -0,0 +1,217 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "DynamicLoaderAcceleratorGDBRemote.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetGroup.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderAcceleratorGDBRemote)
+
+DynamicLoader *
+DynamicLoaderAcceleratorGDBRemote::CreateInstance(Process *process,
+                                                  bool force) {
+  // The library list comes from the accelerator's GDB server.
+  if (!force ||
+      process->GetPluginName() != ProcessGDBRemote::GetPluginNameStatic())
+    return nullptr;
+  return new DynamicLoaderAcceleratorGDBRemote(process);
+}
+
+DynamicLoaderAcceleratorGDBRemote::DynamicLoaderAcceleratorGDBRemote(
+    Process *process)
+    : DynamicLoader(process) {}
+
+void DynamicLoaderAcceleratorGDBRemote::DidAttach() {
+  LoadModulesFromGDBServer(/*full=*/true);
+}
+
+void DynamicLoaderAcceleratorGDBRemote::DidLaunch() {
+  LoadModulesFromGDBServer(/*full=*/true);
+}
+
+bool DynamicLoaderAcceleratorGDBRemote::LoadModulesFromGDBServer(bool full) {
+  Log *log = GetLog(LLDBLog::DynamicLoader);
+
+  // CreateInstance ensures that m_process is a ProcessGDBRemote. Send the
+  // request on its accelerator connection unless the server asks us to route
+  // it through the native connection instead.
+  ProcessGDBRemote *accelerator_process =
+      static_cast<ProcessGDBRemote *>(m_process);
+  ProcessGDBRemote *send_process = accelerator_process;
+  AcceleratorDynamicLoaderArgs args;
+  args.full = full;
+
+  Target &target = m_process->GetTarget();
+  std::shared_ptr<TargetGroupCPUAndAccelerators> group_sp =
+      target.GetFirstTargetGroupOfType<TargetGroupCPUAndAccelerators>();
+  TargetSP native_target_sp = group_sp ? group_sp->GetCPUTarget() : nullptr;
+  ProcessSP native_process_sp =
+      native_target_sp ? native_target_sp->GetProcessSP() : nullptr;
+
+  std::optional<LLDBSettings> settings =
+      accelerator_process->GetGDBRemote().GetLLDBSettings();
+  if (settings && !settings->send_dyld_packet_to_accelerator) {
+    if (settings->accelerator_plugin_name.empty()) {
+      LLDB_LOG(log, "cannot route dynamic-loader request through the native "
+                    "connection without an accelerator plugin name");
+      return false;
+    }
+
+    if (!native_process_sp || native_process_sp->GetPluginName() !=
+                                  ProcessGDBRemote::GetPluginNameStatic()) {
+      LLDB_LOG(log, "cannot route dynamic-loader request through the native "
+                    "connection: no native gdb-remote process");
+      return false;
+    }
+
+    send_process = static_cast<ProcessGDBRemote *>(native_process_sp.get());
+    args.plugin_name = settings->accelerator_plugin_name;
+  }
+
+  ModuleList loaded_module_list;
+  std::optional<AcceleratorDynamicLoaderResponse> response =
+      send_process->GetGDBRemote().GetAcceleratorDynamicLoaderLibraryInfos(
+          args);
+  if (!response) {
+    LLDB_LOG(log, "failed to get dynamic loader info from the GDB server");
+    return false;
+  }
+
+  for (const AcceleratorDynamicLoaderLibraryInfo &info :
+       response->library_infos) {
+    std::shared_ptr<DataBufferHeap> data_sp;
+    if (info.load && info.native_memory_address && info.native_memory_size) {
+      LLDB_LOG(log, "reading \"{0}\" from native memory at {1:x}",
+               info.pathname, *info.native_memory_address);
+      if (native_process_sp) {
+        data_sp = std::make_shared<DataBufferHeap>(*info.native_memory_size, 0);
+        Status error;
+        const size_t bytes_read = native_process_sp->ReadMemory(
+            *info.native_memory_address, data_sp->GetBytes(),
+            data_sp->GetByteSize(), error);
+        if (bytes_read != *info.native_memory_size) {
+          LLDB_LOG(log,
+                   "failed to read \"{0}\" from native memory at {1:x}: {2}",
+                   info.pathname, *info.native_memory_address, error);
+          data_sp.reset();
+        }
+      } else {
+        LLDB_LOG(log, "no native process available to read \"{0}\" at {1:x}",
+                 info.pathname, *info.native_memory_address);
+      }
+    }
+
+    UUID uuid;
+    if (info.uuid_str)
+      uuid.SetFromStringRef(*info.uuid_str);
+
+    // Either a whole file, or a slice of a containing file.
+    DataExtractorSP extractor_sp;
+    if (data_sp)
+      extractor_sp = std::make_shared<DataExtractor>(data_sp);
+    ModuleSpec module_spec(FileSpec(info.pathname), uuid, extractor_sp);
+    // Select the target device image when a loaded file contains an offload
+    // bundle. An unload identifies an existing module and does not need this
+    // architecture filter.
+    if (info.load)
+      module_spec.GetArchitecture() = target.GetArchitecture();
+    if (info.file_offset)
+      module_spec.SetObjectOffset(*info.file_offset);
+    if (info.file_size)
+      module_spec.SetObjectSize(*info.file_size);
+
+    if (!info.load) {
+      ModuleList matching_module_list;
+      target.GetImages().FindModules(module_spec, matching_module_list);
+      matching_module_list.ForEach(
+          [this](const ModuleSP &module_sp) -> IterationAction {
+            UnloadSections(module_sp);
+            return IterationAction::Continue;
+          });
+      target.ModulesDidUnload(matching_module_list,
+                              /*delete_locations=*/false);
+      continue;
+    }
+
+    ModuleSP module_sp =
+        target.GetOrCreateModule(module_spec, /*notify=*/false);
+    if (!module_sp)
+      continue;
+
+    bool changed = false;
+    if (info.load_address) {
+      module_sp->SetLoadAddress(target, *info.load_address,
+                                /*value_is_offset=*/true, changed);
+    } else if (!info.loaded_sections.empty()) {
+      for (const AcceleratorSectionInfo &sect : info.loaded_sections) {
+        if (sect.names.empty())
+          continue;
+        SectionSP section_sp;
+        for (const std::string &name : sect.names) {
+          ConstString section_name(name);
+          if (section_sp)
+            section_sp =
+                section_sp->GetChildren().FindSectionByName(section_name);
+          else
+            section_sp =
+                module_sp->GetSectionList()->FindSectionByName(section_name);
+          if (!section_sp)
+            break;
+        }
+        if (section_sp)
+          changed |= target.SetSectionLoadAddress(section_sp, sect.load_address,
+                                                  /*warn_multiple=*/true);
+      }
+    } else {
+      // No slide: load at the file addresses.
+      module_sp->SetLoadAddress(target, 0, /*value_is_offset=*/true, changed);
+    }
+
+    if (changed)
+      loaded_module_list.AppendIfNeeded(module_sp);
+  }
+
+  target.ModulesDidLoad(loaded_module_list);
+  return true;
+}
+
+ThreadPlanSP DynamicLoaderAcceleratorGDBRemote::GetStepThroughTrampolinePlan(
+    Thread &thread, bool stop_others) {
+  return ThreadPlanSP();
+}
+
+Status DynamicLoaderAcceleratorGDBRemote::CanLoadImage() {
+  return Status::FromErrorString("can't load images on accelerator targets");
+}
+
+void DynamicLoaderAcceleratorGDBRemote::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderAcceleratorGDBRemote::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef
+DynamicLoaderAcceleratorGDBRemote::GetPluginDescriptionStatic() {
+  return "Dynamic loader plug-in that gets shared library loads/unloads from "
+         "an lldb-server accelerator plugin.";
+}
diff --git a/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.h b/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.h
new file mode 100644
index 00000000000000..b5080322ed714d
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AcceleratorGDBRemote/DynamicLoaderAcceleratorGDBRemote.h
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SOURCE_PLUGINS_DYNAMICLOADER_ACCELERATORGDBREMOTE_DYNAMICLOADERACCELERATORGDBREMOTE_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_ACCELERATORGDBREMOTE_DYNAMICLOADERACCELERATORGDBREMOTE_H
+
+#include "lldb/Target/DynamicLoader.h"
+
+/// Dynamic loader for accelerator (e.g. GPU) targets.
+///
+/// Accelerators don't set a rendezvous breakpoint the way SVR4 loaders do;
+/// their runtime tells the lldb-server plugin when libraries load or unload.
+/// This loader asks the server for that list via
+/// "jAcceleratorPluginGetDynamicLoaderLibraryInfo".
+class DynamicLoaderAcceleratorGDBRemote : public lldb_private::DynamicLoader {
+public:
+  DynamicLoaderAcceleratorGDBRemote(lldb_private::Process *process);
+
+  static void Initialize();
+  static void Terminate();
+  static llvm::StringRef GetPluginNameStatic() {
+    return "accelerator-gdb-remote";
+  }
+  static llvm::StringRef GetPluginDescriptionStatic();
+  static lldb_private::DynamicLoader *
+  CreateInstance(lldb_private::Process *process, bool force);
+
+  void DidAttach() override;
+  void DidLaunch() override;
+  lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+                                                  bool stop_others) override;
+  lldb_private::Status CanLoadImage() override;
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+  /// Returns true if the server answered the packet.
+  bool LoadModulesFromGDBServer(bool full);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_ACCELERATORGDBREMOTE_DYNAMICLOADERACCELERATORGDBREMOTE_H
diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
index 01aba34b941697..97604bb4824db4 100644
--- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
+++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -5,6 +5,7 @@ set_property(DIRECTORY PROPERTY LLDB_TOLERATED_PLUGIN_DEPENDENCIES
   TypeSystem
 )
 
+add_subdirectory(AcceleratorGDBRemote)
 add_subdirectory(Darwin-Kernel)
 add_subdirectory(FreeBSD-Kernel)
 add_subdirectory(MacOSX-DYLD)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 1a5b5a2c534d84..283418ca0590ca 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -341,6 +341,30 @@ GDBRemoteCommunicationClient::AcceleratorBreakpointHit(
       response.GetStringRef(), llvm::toString(hit_response.takeError()));
 }
 
+std::optional<AcceleratorDynamicLoaderResponse>
+GDBRemoteCommunicationClient::GetAcceleratorDynamicLoaderLibraryInfos(
+    const AcceleratorDynamicLoaderArgs &args) {
+  StreamGDBRemote packet;
+  packet.PutCString("jAcceleratorPluginGetDynamicLoaderLibraryInfo:");
+  packet.PutAsJSON(args, /*hex_ascii=*/false);
+
+  StringExtractorGDBRemote response;
+  response.SetResponseValidatorToJSON();
+  if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+          PacketResult::Success ||
+      response.IsErrorResponse())
+    return std::nullopt;
+
+  llvm::Expected<AcceleratorDynamicLoaderResponse> parsed =
+      llvm::json::parse<AcceleratorDynamicLoaderResponse>(
+          response.Peek(), "AcceleratorDynamicLoaderResponse");
+  if (!parsed) {
+    llvm::consumeError(parsed.takeError());
+    return std::nullopt;
+  }
+  return *parsed;
+}
+
 bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() {
   if (m_supports_not_sending_acks == eLazyBoolCalculate) {
     m_send_acks = true;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index e38eb03f7593e0..984d4534836d29 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -395,6 +395,11 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
   llvm::Expected<AcceleratorBreakpointHitResponse>
   AcceleratorBreakpointHit(const AcceleratorBreakpointHitArgs &args);
 
+  /// Returns std::nullopt if the packet failed or the response did not parse.
+  std::optional<AcceleratorDynamicLoaderResponse>
+  GetAcceleratorDynamicLoaderLibraryInfos(
+      const AcceleratorDynamicLoaderArgs &args);
+
   LazyBool SupportsAllocDeallocMemory() // const
   {
     // Uncomment this to have lldb pretend the debug server doesn't respond to
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 5466817d844c59..717fb8a22b32a4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -1543,7 +1543,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
     return SendErrorResponse(1);
 
   ProcessInstanceInfo proc_info;
-  if (!Host::GetProcessInfo(pid, proc_info))
+  if (!m_current_process->GetProcessInfo(proc_info))
     return SendErrorResponse(1);
 
   StreamString response;
@@ -4741,6 +4741,21 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::
   if (!args)
     return SendErrorResponse(args.takeError());
 
+  // On the accelerator connection, ask the process directly.
+  if (m_connection_accelerator_plugin) {
+    if (!m_current_process)
+      return SendErrorResponse(Status::FromErrorString("no current process"));
+    std::optional<AcceleratorDynamicLoaderResponse> response =
+        m_current_process->GetAcceleratorDynamicLoaderLibraryInfos(*args);
+    if (!response)
+      return SendErrorResponse(
+          Status::FromErrorString("dynamic loader library info not supported"));
+    StreamGDBRemote stream;
+    stream.PutAsJSON(*response, /*hex_ascii=*/false);
+    return SendPacketNoLock(stream.GetString());
+  }
+
+  // On the native connection, forward to the named accelerator plugin.
   for (std::unique_ptr<lldb_server::LLDBServerAcceleratorPlugin> &plugin_up :
        m_accelerator_plugins) {
     if (plugin_up->GetPluginName() == args->plugin_name) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 540f620be4c957..4c59c698f782ad 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4670,8 +4670,12 @@ bool ProcessGDBRemote::StopNoticingNewThreads() {
 }
 
 DynamicLoader *ProcessGDBRemote::GetDynamicLoader() {
-  if (m_dyld_up.get() == nullptr)
-    m_dyld_up.reset(DynamicLoader::FindPlugin(this, ""));
+  if (m_dyld_up.get() == nullptr) {
+    std::string plugin_name;
+    if (std::optional<LLDBSettings> settings = m_gdb_comm.GetLLDBSettings())
+      plugin_name = settings->dyld_plugin_name;
+    m_dyld_up.reset(DynamicLoader::FindPlugin(this, plugin_name));
+  }
   return m_dyld_up.get();
 }
 
diff --git a/lldb/test/API/accelerator/dynamic_loader/TestAcceleratorDynamicLoader.py b/lldb/test/API/accelerator/dynamic_loader/TestAcceleratorDynamicLoader.py
new file mode 100644
index 00000000000000..152c76ee9d968f
--- /dev/null
+++ b/lldb/test/API/accelerator/dynamic_loader/TestAcceleratorDynamicLoader.py
@@ -0,0 +1,157 @@
+"""
+Test the accelerator dynamic loader against a mock GDB server.
+
+The server selects the loader by name through jLLDBSettings. The loader
+then asks the server for the loaded libraries via
+jAcceleratorPluginGetDynamicLoaderLibraryInfo and loads them into the target.
+"""
+
+import json
+import os
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.gdbclientutils import *
+from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
+
+DYLD_PACKET = "jAcceleratorPluginGetDynamicLoaderLibraryInfo:"
+
+
+class AcceleratorResponder(MockGDBServerResponder):
+    """Serves a fixed set of library infos, and counts how often it is asked."""
+
+    def __init__(
+        self,
+        library_infos,
+        dyld_plugin_name="accelerator-gdb-remote",
+    ):
+        MockGDBServerResponder.__init__(self)
+        self.library_infos = library_infos
+        self.dyld_plugin_name = dyld_plugin_name
+        self.dyld_queries = 0
+        self.last_dyld_packet = None
+
+    def qSupported(self, client_supported):
+        features = super().qSupported(client_supported) + ";qXfer:features:read+"
+        if self.dyld_plugin_name is not None:
+            features += ";lldb-settings+"
+        return features
+
+    def qXferRead(self, obj, annex, offset, length):
+        # An accelerator architecture has no built-in register set in lldb.
+        if obj == "features" and annex == "target.xml":
+            return (
+                """<?xml version="1.0"?>
+                <target version="1.0">
+                  <feature name="org.llvm.accelerator">
+                    <reg name="pc" bitsize="64" regnum="0" type="code_ptr" group="general"/>
+                  </feature>
+                </target>""",
+                False,
+            )
+        return None, False
+
+    def readRegisters(self):
+        return "00" * 8
+
+    def other(self, packet):
+        if packet == "jLLDBSettings":
+            response = {
+                "dyld_plugin_name": self.dyld_plugin_name,
+                "accelerator_plugin_name": "mock",
+                "send_dyld_packet_to_accelerator": True,
+            }
+            return escape_binary(json.dumps(response, separators=(",", ":")))
+        if packet.startswith(DYLD_PACKET):
+            self.dyld_queries += 1
+            self.last_dyld_packet = packet
+            # "}" is the gdb-remote escape character.
+            return escape_binary(
+                json.dumps({"library_infos": self.library_infos}, separators=(",", ":"))
+            )
+        return ""
+
+
+class TestAcceleratorDynamicLoader(GDBRemoteTestBase):
+    def find_module(self, target, path):
+        basename = os.path.basename(path)
+        for i in range(target.GetNumModules()):
+            module = target.GetModuleAtIndex(i)
+            if module.GetFileSpec().GetFilename() == basename:
+                return module
+        return None
+
+    def connect_accelerator(self, library_infos):
+        self.server.responder = AcceleratorResponder(library_infos)
+        target = self.createTarget("accelerator.yaml")
+        process = self.connect(target)
+        self.assertTrue(process.IsValid(), "Process is valid")
+        self.assertIsNotNone(self.server.responder.last_dyld_packet)
+        self.assertIn('"full":true', self.server.responder.last_dyld_packet)
+        return target
+
+    def assert_text_loaded_at(self, target, module, expected):
+        section = module.FindSection(".text")
+        self.assertTrue(section.IsValid(), "library should have a .text section")
+        self.assertEqual(section.GetLoadAddress(target), expected)
+
+    def test_whole_file_library(self):
+        """A library given as a whole file is loaded at the reported address."""
+        lib = self.getBuildArtifact("accelerator_lib.so")
+        self.yaml2obj("accelerator_lib.yaml", lib)
+        target = self.connect_accelerator(
+            [{"pathname": lib, "load": True, "load_address": 0x10000000}]
+        )
+
+        module = self.find_module(target, lib)
+        self.assertIsNotNone(module, "library should be loaded into the target")
+        # load_address slides the file, so .text (file address 0x1000) lands
+        # 0x1000 past the base.
+        self.assert_text_loaded_at(target, module, 0x10001000)
+
+    def test_library_unload(self):
+        """An unload clears section addresses and broadcasts the module."""
+        lib = self.getBuildArtifact("accelerator_lib.so")
+        self.yaml2obj("accelerator_lib.yaml", lib)
+        target = self.createTarget("accelerator.yaml")
+        module = target.AddModule(lib, None, None)
+        self.assertTrue(module.IsValid(), "library should be added to the target")
+
+        text = module.FindSection(".text")
+        self.assertTrue(text.IsValid(), "library should have a .text section")
+        error = target.SetModuleLoadAddress(module, 0x10000000)
+        self.assertSuccess(error)
+        self.assert_text_loaded_at(target, module, 0x10001000)
+
+        listener = lldb.SBListener("accelerator-module-unload")
+        listened = target.GetBroadcaster().AddListener(
+            listener, lldb.SBTarget.eBroadcastBitModulesUnloaded
+        )
+        self.assertEqual(listened, lldb.SBTarget.eBroadcastBitModulesUnloaded)
+
+        self.server.responder = AcceleratorResponder([{"pathname": lib, "load": False}])
+        process = self.connect(target)
+        self.assertTrue(process.IsValid(), "Process is valid")
+        self.assertEqual(self.server.responder.dyld_queries, 1)
+        self.assertEqual(text.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS)
+
+        event = lldb.SBEvent()
+        self.assertTrue(listener.WaitForEvent(1, event), "got module unload event")
+        self.assertEqual(event.GetType(), lldb.SBTarget.eBroadcastBitModulesUnloaded)
+        self.assertEqual(lldb.SBTarget.GetNumModulesFromEvent(event), 1)
+        unloaded = lldb.SBTarget.GetModuleAtIndexFromEvent(0, event)
+        self.assertEqual(unloaded.GetFileSpec().GetFilename(), os.path.basename(lib))
+
+    def test_accelerator_lldb_settings_not_supported(self):
+        """The loader is not used unless the server selects it by name."""
+        self.server.responder = AcceleratorResponder([], dyld_plugin_name=None)
+        target = self.createTarget("accelerator.yaml")
+        process = self.connect(target)
+        self.assertTrue(process.IsValid(), "Process is valid")
+
+        self.assertEqual(
+            self.server.responder.dyld_queries,
+            0,
+            "the target architecture must not select the accelerator loader",
+        )
+        self.assertIsNone(self.server.responder.last_dyld_packet)
diff --git a/lldb/test/API/accelerator/dynamic_loader/accelerator.yaml b/lldb/test/API/accelerator/dynamic_loader/accelerator.yaml
new file mode 100644
index 00000000000000..2c4fe0fcd752c0
--- /dev/null
+++ b/lldb/test/API/accelerator/dynamic_loader/accelerator.yaml
@@ -0,0 +1,23 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_AMDGPU
+  OSABI:           ELFOSABI_AMDGPU_HSA
+  ABIVersion:      0x1
+  Flags:           [ EF_AMDGPU_MACH_AMDGCN_GFX942 ]
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x1000
+    Content:         "00000000"
+ProgramHeaders:
+  - Type:            PT_LOAD
+    Flags:           [ PF_X, PF_R ]
+    VAddr:           0x1000
+    Align:           0x1000
+    FirstSec:        .text
+    LastSec:         .text
diff --git a/lldb/test/API/accelerator/dynamic_loader/accelerator_lib.yaml b/lldb/test/API/accelerator/dynamic_loader/accelerator_lib.yaml
new file mode 100644
index 00000000000000..ccdd8b34aa929e
--- /dev/null
+++ b/lldb/test/API/accelerator/dynamic_loader/accelerator_lib.yaml
@@ -0,0 +1,23 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_AMDGPU
+  OSABI:           ELFOSABI_AMDGPU_HSA
+  ABIVersion:      0x1
+  Flags:           [ EF_AMDGPU_MACH_AMDGCN_GFX942 ]
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x1000
+    Content:         "00000000"
+ProgramHeaders:
+  - Type:            PT_LOAD
+    Flags:           [ PF_X, PF_R ]
+    VAddr:           0x1000
+    Align:           0x1000
+    FirstSec:        .text
+    LastSec:         .text
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorDynamicLoader.py b/lldb/test/API/accelerator/mock/TestMockAcceleratorDynamicLoader.py
new file mode 100644
index 00000000000000..dc325c737fd36b
--- /dev/null
+++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorDynamicLoader.py
@@ -0,0 +1,148 @@
+"""End-to-end test for the mock accelerator's dynamic loader."""
+
+import os
+
+import lldb
+from lldbsuite.test import configuration
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+
+class MockAcceleratorDynamicLoaderTestCase(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 set_mock_env(self, name, value):
+        """Set an environment variable inherited by lldb-server."""
+        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)
+
+    def accelerator_target(self, native_target):
+        for candidate in self.dbg:
+            if candidate != native_target:
+                return candidate
+        return None
+
+    def run_library_test(self, dyld_connection, use_native_memory=False):
+        self.build()
+
+        library_path = self.getBuildArtifact("accelerator_lib.so")
+        self.yaml2obj("accelerator_lib.yaml", library_path)
+        with open(library_path, "rb") as library_file:
+            library_data = library_file.read()
+
+        # No installed platform claims AMDGPU, so retain the selected host
+        # platform while creating a target with the requested architecture.
+        self.set_mock_env("LLDB_MOCK_ACCELERATOR_PLATFORM", "")
+        self.set_mock_env("LLDB_MOCK_ACCELERATOR_TRIPLE", "amdgpu-amd-amdhsa--gfx942")
+        self.set_mock_env("LLDB_MOCK_ACCELERATOR_DYLD_CONNECTION", dyld_connection)
+        reported_path = library_path
+        if dyld_connection == "accelerator":
+            if use_native_memory:
+                reported_path = self.getBuildArtifact("missing-accelerator-lib.so")
+                self.assertFalse(os.path.exists(reported_path))
+                self.assertLessEqual(len(library_data), 8192)
+                self.set_mock_env(
+                    "LLDB_MOCK_ACCELERATOR_NATIVE_MEMORY_SIZE",
+                    str(len(library_data)),
+                )
+            self.set_mock_env("LLDB_MOCK_ACCELERATOR_LIBRARY_PATH", reported_path)
+        else:
+            self.set_mock_env("LLDB_MOCK_ACCELERATOR_NATIVE_LIBRARY_PATH", library_path)
+
+        # This test does not exercise instruction decoding. Avoid asking the
+        # generic AMDGPU target to disassemble its synthetic stop PC.
+        self.runCmd("settings set stop-disassembly-display never")
+
+        native_target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+        self.assertTrue(native_target, VALID_TARGET)
+
+        # The first stop initializes the plugin. Continuing to its connection
+        # hook synchronously creates the accelerator target and queries for its
+        # loaded libraries using the selected connection.
+        native_process = native_target.LaunchSimple(
+            None, None, self.get_process_working_directory()
+        )
+        self.assertTrue(native_process, PROCESS_IS_VALID)
+        self.assertState(native_process.GetState(), lldb.eStateStopped)
+        if use_native_memory:
+            symbols = native_target.FindSymbols("mock_gpu_accelerator_image")
+            self.assertEqual(symbols.GetSize(), 1)
+            symbol = symbols.GetContextAtIndex(0).GetSymbol()
+            image_address = symbol.GetStartAddress().GetLoadAddress(native_target)
+            self.assertNotEqual(image_address, lldb.LLDB_INVALID_ADDRESS)
+            error = lldb.SBError()
+            bytes_written = native_process.WriteMemory(
+                image_address, library_data, error
+            )
+            self.assertSuccess(error)
+            self.assertEqual(bytes_written, len(library_data))
+        native_process.Continue()
+        self.assertState(native_process.GetState(), lldb.eStateStopped)
+
+        self.assertEqual(self.dbg.GetNumTargets(), 2)
+        accelerator_target = self.accelerator_target(native_target)
+        self.assertIsNotNone(accelerator_target)
+        self.assertTrue(accelerator_target.IsValid())
+        accelerator_process = accelerator_target.GetProcess()
+        self.assertTrue(accelerator_process.IsValid())
+        self.assertState(accelerator_process.GetState(), lldb.eStateStopped)
+
+        self.dbg.SetSelectedTarget(accelerator_target)
+        self.expect(
+            "process plugin packet send jLLDBSettings",
+            substrs=[
+                '"accelerator_plugin_name":"mock"',
+                '"dyld_plugin_name":"accelerator-gdb-remote"',
+                '"send_dyld_packet_to_accelerator":'
+                + ("true" if dyld_connection == "accelerator" else "false"),
+            ],
+        )
+
+        module = None
+        library_basename = os.path.basename(reported_path)
+        for candidate in accelerator_target.module_iter():
+            if candidate.GetFileSpec().GetFilename() == library_basename:
+                module = candidate
+                break
+        self.assertIsNotNone(module, "accelerator library should be loaded")
+
+        text = module.FindSection(".text")
+        self.assertTrue(text.IsValid())
+        expected_load_address = (
+            0x10001000 if dyld_connection == "accelerator" else 0x7F001000
+        )
+        self.assertEqual(text.GetLoadAddress(accelerator_target), expected_load_address)
+
+    @skipIfRemote
+    @skipIfDarwin  # qProcessInfo cannot encode an AMDGPU architecture on Darwin.
+    @add_test_categories(["llgs"])
+    def test_library_from_accelerator_process(self):
+        """The accelerator loader queries the second LLGS process directly."""
+        self.run_library_test("accelerator")
+
+    @skipIfRemote
+    @skipIfDarwin  # qProcessInfo cannot encode an AMDGPU architecture on Darwin.
+    @add_test_categories(["llgs"])
+    def test_library_from_native_plugin(self):
+        """The accelerator loader routes through the native LLGS plugin."""
+        self.run_library_test("native")
+
+    @skipIfRemote
+    @skipIfDarwin  # qProcessInfo cannot encode an AMDGPU architecture on Darwin.
+    @add_test_categories(["llgs"])
+    def test_library_from_native_memory(self):
+        """An image in native memory is loaded over the accelerator connection."""
+        self.run_library_test("accelerator", use_native_memory=True)
diff --git a/lldb/test/API/accelerator/mock/accelerator_lib.yaml b/lldb/test/API/accelerator/mock/accelerator_lib.yaml
new file mode 100644
index 00000000000000..ccdd8b34aa929e
--- /dev/null
+++ b/lldb/test/API/accelerator/mock/accelerator_lib.yaml
@@ -0,0 +1,23 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_AMDGPU
+  OSABI:           ELFOSABI_AMDGPU_HSA
+  ABIVersion:      0x1
+  Flags:           [ EF_AMDGPU_MACH_AMDGCN_GFX942 ]
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x1000
+    Content:         "00000000"
+ProgramHeaders:
+  - Type:            PT_LOAD
+    Flags:           [ PF_X, PF_R ]
+    VAddr:           0x1000
+    Align:           0x1000
+    FirstSec:        .text
+    LastSec:         .text
diff --git a/lldb/test/API/accelerator/mock/main.c b/lldb/test/API/accelerator/mock/main.c
index 18aed944b8d8fb..5bafe26ba231e4 100644
--- a/lldb/test/API/accelerator/mock/main.c
+++ b/lldb/test/API/accelerator/mock/main.c
@@ -1,5 +1,7 @@
 // The mock accelerator plugin sets its breakpoints on these dedicated, uniquely
 // named functions.
+unsigned char mock_gpu_accelerator_image[8192];
+
 void mock_gpu_accelerator_initialize(void) {}
 
 int mock_gpu_accelerator_compute(int x) { return x * 2; }
diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
index 069bee0e4ef52b..3d0fb3ec747f30 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp
@@ -31,7 +31,7 @@ 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.
+// configure the mock; falls back to default_value.
 static std::string GetMockEnvSetting(const char *env_var,
                                      std::string default_value) {
   if (const char *value = ::getenv(env_var))
@@ -60,6 +60,16 @@ llvm::StringRef LLDBServerMockAcceleratorPlugin::GetPluginName() {
   return "mock";
 }
 
+std::optional<LLDBSettings> LLDBServerMockAcceleratorPlugin::GetLLDBSettings() {
+  LLDBSettings settings;
+  settings.dyld_plugin_name = "accelerator-gdb-remote";
+  settings.accelerator_plugin_name = GetPluginName();
+  settings.send_dyld_packet_to_accelerator =
+      GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_DYLD_CONNECTION",
+                        "accelerator") != "native";
+  return settings;
+}
+
 std::optional<AcceleratorActions>
 LLDBServerMockAcceleratorPlugin::GetInitializeActions() {
   AcceleratorActions actions = GetNewAcceleratorAction();
@@ -67,6 +77,7 @@ LLDBServerMockAcceleratorPlugin::GetInitializeActions() {
   // Set a breakpoint by function name (no shared library scope) on the
   // dedicated "mock_gpu_accelerator_initialize" hook and ask for the load
   // address of "mock_gpu_accelerator_compute" to be delivered when it is hit.
+  // The native-memory test also requests its image buffer's load address.
   // Using a dedicated, uniquely named function (rather than "main") keeps this
   // mock from affecting other inferiors that lldb-server launches when the
   // plugin is compiled in.
@@ -75,6 +86,9 @@ LLDBServerMockAcceleratorPlugin::GetInitializeActions() {
   bp.by_name = AcceleratorBreakpointByName{std::nullopt,
                                            "mock_gpu_accelerator_initialize"};
   bp.symbol_names.push_back("mock_gpu_accelerator_compute");
+  if (!GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_NATIVE_MEMORY_SIZE", "")
+           .empty())
+    bp.symbol_names.push_back("mock_gpu_accelerator_image");
   actions.breakpoints.push_back(std::move(bp));
 
   return actions;
@@ -87,6 +101,8 @@ LLDBServerMockAcceleratorPlugin::BreakpointWasHit(
 
   switch (args.breakpoint.identifier) {
   case kBreakpointIDInitialize: {
+    m_native_memory_address = args.GetSymbolValue("mock_gpu_accelerator_image");
+
     // The initialize breakpoint was hit. Arm the remaining test breakpoints:
     // two more breakpoint types, plus the connection hook now that the
     // accelerator has initialized.
@@ -150,10 +166,24 @@ std::optional<AcceleratorConnectionInfo>
 LLDBServerMockAcceleratorPlugin::CreateConnection() {
   Log *log = GetLog(GDBRLog::Plugin);
 
+  std::string triple =
+      GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_TRIPLE",
+                        HostInfo::GetArchitecture().GetTriple().str());
+  std::string dynamic_loader_library_path = GetMockEnvSetting(
+      "LLDB_MOCK_ACCELERATOR_LIBRARY_PATH", "/path/to/lib.so");
+  std::optional<uint64_t> native_memory_size;
+  std::string native_memory_size_str =
+      GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_NATIVE_MEMORY_SIZE", "");
+  uint64_t size;
+  if (!native_memory_size_str.empty() &&
+      !llvm::StringRef(native_memory_size_str).getAsInteger(0, size))
+    native_memory_size = size;
+
   // An in-process gdb-remote server backed by a synthetic
   // ProcessMockAccelerator; no real process is launched.
-  m_process_manager_up =
-      std::make_unique<ProcessMockAccelerator::Manager>(m_mock_main_loop);
+  m_process_manager_up = std::make_unique<ProcessMockAccelerator::Manager>(
+      m_mock_main_loop, ArchSpec(triple), dynamic_loader_library_path,
+      m_native_memory_address, native_memory_size);
   m_accelerator_gdb_server = std::make_unique<GDBRemoteCommunicationServerLLGS>(
       m_mock_main_loop, *m_process_manager_up);
   m_accelerator_gdb_server->SetConnectionAcceleratorPlugin(*this);
@@ -218,9 +248,7 @@ LLDBServerMockAcceleratorPlugin::CreateConnection() {
   // 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.triple = std::move(triple);
   info.synchronous = true;
   return info;
 }
@@ -230,7 +258,8 @@ LLDBServerMockAcceleratorPlugin::GetDynamicLoaderLibraryInfos(
     const AcceleratorDynamicLoaderArgs &args) {
   AcceleratorDynamicLoaderResponse response;
   AcceleratorDynamicLoaderLibraryInfo lib;
-  lib.pathname = "/path/to/lib.so";
+  lib.pathname = GetMockEnvSetting("LLDB_MOCK_ACCELERATOR_NATIVE_LIBRARY_PATH",
+                                   "/path/to/lib.so");
   lib.load = true;
   lib.load_address = 0x7f000000;
   response.library_infos.push_back(std::move(lib));
diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
index 36f6aa2500ba80..a76197352aa25a 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h
@@ -15,6 +15,7 @@
 #include "lldb/Host/MainLoopBase.h"
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 namespace lldb_private {
@@ -30,6 +31,7 @@ class LLDBServerMockAcceleratorPlugin : public LLDBServerAcceleratorPlugin {
   ~LLDBServerMockAcceleratorPlugin() override;
 
   llvm::StringRef GetPluginName() override;
+  std::optional<LLDBSettings> GetLLDBSettings() override;
   std::optional<AcceleratorActions> GetInitializeActions() override;
   llvm::Expected<AcceleratorBreakpointHitResponse>
   BreakpointWasHit(AcceleratorBreakpointHitArgs &args) override;
@@ -44,7 +46,8 @@ class LLDBServerMockAcceleratorPlugin : public LLDBServerAcceleratorPlugin {
   std::optional<AcceleratorConnectionInfo> CreateConnection();
 
   // Breakpoint set during initialization, by function name with no shared
-  // library. Requests the "compute" symbol value when hit.
+  // library. Requests the "compute" symbol value and, when configured, the
+  // native-memory image buffer's value when hit.
   static constexpr int64_t kBreakpointIDInitialize = 1;
   // Breakpoint set by address, using the "compute" symbol value delivered when
   // the initialize breakpoint was hit.
@@ -62,6 +65,7 @@ class LLDBServerMockAcceleratorPlugin : public LLDBServerAcceleratorPlugin {
   HostThread m_mock_main_loop_thread;
   std::unique_ptr<TCPSocket> m_listen_socket;
   std::vector<MainLoopBase::ReadHandleUP> m_read_handles;
+  std::optional<uint64_t> m_native_memory_address;
 };
 
 } // 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
index 6ae74d290d7150..ec270ba1832a17 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.cpp
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.cpp
@@ -9,7 +9,6 @@
 #include "ProcessMockAccelerator.h"
 #include "ThreadMockAccelerator.h"
 
-#include "lldb/Host/HostInfo.h"
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "llvm/Support/Error.h"
 
@@ -26,7 +25,9 @@ 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);
+  return std::make_unique<ProcessMockAccelerator>(
+      kMockPid, m_arch, m_dynamic_loader_library_path, m_native_memory_address,
+      m_native_memory_size, native_delegate);
 }
 
 llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
@@ -36,9 +37,15 @@ ProcessMockAccelerator::Manager::Attach(lldb::pid_t pid,
                                  "accelerator process");
 }
 
-ProcessMockAccelerator::ProcessMockAccelerator(lldb::pid_t pid,
-                                               NativeDelegate &delegate)
-    : NativeProcessProtocol(pid, /*terminal_fd=*/-1, delegate) {
+ProcessMockAccelerator::ProcessMockAccelerator(
+    lldb::pid_t pid, ArchSpec arch, std::string dynamic_loader_library_path,
+    std::optional<uint64_t> native_memory_address,
+    std::optional<uint64_t> native_memory_size, NativeDelegate &delegate)
+    : NativeProcessProtocol(pid, /*terminal_fd=*/-1, delegate),
+      m_arch(std::move(arch)),
+      m_dynamic_loader_library_path(std::move(dynamic_loader_library_path)),
+      m_native_memory_address(native_memory_address),
+      m_native_memory_size(native_memory_size) {
   m_state = eStateStopped;
   UpdateThreads();
 }
@@ -99,8 +106,6 @@ size_t ProcessMockAccelerator::UpdateThreads() {
 }
 
 const ArchSpec &ProcessMockAccelerator::GetArchitecture() const {
-  if (!m_arch.IsValid())
-    m_arch = HostInfo::GetArchitecture();
   return m_arch;
 }
 
@@ -125,7 +130,29 @@ ProcessMockAccelerator::GetFileLoadAddress(const llvm::StringRef &file_name,
   return Status::FromErrorString("unimplemented");
 }
 
+bool ProcessMockAccelerator::GetProcessInfo(ProcessInstanceInfo &proc_info) {
+  proc_info.SetProcessID(m_pid);
+  proc_info.SetArchitecture(GetArchitecture());
+  return true;
+}
+
 std::vector<AddressSpaceInfo> ProcessMockAccelerator::GetAddressSpaces() {
   return {{"global", 1, /*is_thread_specific=*/false},
           {"local", 2, /*is_thread_specific=*/true}};
 }
+
+std::optional<AcceleratorDynamicLoaderResponse>
+ProcessMockAccelerator::GetAcceleratorDynamicLoaderLibraryInfos(
+    const AcceleratorDynamicLoaderArgs &args) {
+  AcceleratorDynamicLoaderResponse response;
+  AcceleratorDynamicLoaderLibraryInfo info;
+  info.pathname = m_dynamic_loader_library_path;
+  if (m_native_memory_address && m_native_memory_size) {
+    info.native_memory_address = m_native_memory_address;
+    info.native_memory_size = m_native_memory_size;
+  }
+  info.load = true;
+  info.load_address = 0x10000000;
+  response.library_infos.push_back(std::move(info));
+  return response;
+}
diff --git a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
index 7b88bd36f2ea53..6e15b701770af4 100644
--- a/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
+++ b/lldb/tools/lldb-server/Plugins/Accelerator/Mock/ProcessMockAccelerator.h
@@ -12,6 +12,10 @@
 #include "lldb/Host/common/NativeProcessProtocol.h"
 #include "lldb/Utility/ArchSpec.h"
 
+#include <optional>
+#include <string>
+#include <utility>
+
 namespace lldb_private {
 namespace lldb_server {
 
@@ -22,7 +26,14 @@ class ProcessMockAccelerator : public NativeProcessProtocol {
 public:
   class Manager : public NativeProcessProtocol::Manager {
   public:
-    using NativeProcessProtocol::Manager::Manager;
+    Manager(MainLoop &mainloop, ArchSpec arch,
+            std::string dynamic_loader_library_path,
+            std::optional<uint64_t> native_memory_address,
+            std::optional<uint64_t> native_memory_size)
+        : NativeProcessProtocol::Manager(mainloop), m_arch(std::move(arch)),
+          m_dynamic_loader_library_path(std::move(dynamic_loader_library_path)),
+          m_native_memory_address(native_memory_address),
+          m_native_memory_size(native_memory_size) {}
 
     llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
     Launch(ProcessLaunchInfo &launch_info,
@@ -34,9 +45,19 @@ class ProcessMockAccelerator : public NativeProcessProtocol {
     Extension GetSupportedExtensions() const override {
       return Extension::address_spaces | Extension::lldb_settings;
     }
+
+  private:
+    ArchSpec m_arch;
+    std::string m_dynamic_loader_library_path;
+    std::optional<uint64_t> m_native_memory_address;
+    std::optional<uint64_t> m_native_memory_size;
   };
 
-  ProcessMockAccelerator(lldb::pid_t pid, NativeDelegate &delegate);
+  ProcessMockAccelerator(lldb::pid_t pid, ArchSpec arch,
+                         std::string dynamic_loader_library_path,
+                         std::optional<uint64_t> native_memory_address,
+                         std::optional<uint64_t> native_memory_size,
+                         NativeDelegate &delegate);
 
   Status Resume(const ResumeActionList &resume_actions) override;
   Status Halt() override;
@@ -64,10 +85,19 @@ class ProcessMockAccelerator : public NativeProcessProtocol {
   Status GetFileLoadAddress(const llvm::StringRef &file_name,
                             lldb::addr_t &load_addr) override;
 
+  bool GetProcessInfo(ProcessInstanceInfo &proc_info) override;
+
   std::vector<AddressSpaceInfo> GetAddressSpaces() override;
 
+  std::optional<AcceleratorDynamicLoaderResponse>
+  GetAcceleratorDynamicLoaderLibraryInfos(
+      const AcceleratorDynamicLoaderArgs &args) override;
+
 private:
-  mutable ArchSpec m_arch;
+  ArchSpec m_arch;
+  std::string m_dynamic_loader_library_path;
+  std::optional<uint64_t> m_native_memory_address;
+  std::optional<uint64_t> m_native_memory_size;
 };
 
 } // namespace lldb_server



More information about the lldb-commits mailing list