[Lldb-commits] [lldb] [lldb-server] Add breakpoint support to accelerator plugin protocol (PR #200584)

via lldb-commits lldb-commits at lists.llvm.org
Sat May 30 20:42:13 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: satyanarayana reddy janga (satyajanga)

<details>
<summary>Changes</summary>


This is the 2nd PR of many related to https://discourse.llvm.org/t/upstreaming-basic-support-for-accelerators/89827/6
Continuation to https://github.com/llvm/llvm-project/pull/198907

Extend the accelerator plugin infrastructure with breakpoint request and hit handling, allowing plugins to set breakpoints in the native process and respond when those breakpoints are hit.

This patch adds:

- Support for  jAcceleratorPluginBreakpointHit packet handler in GDBRemoteCommunicationServerLLGS that routes hits to the correct plugin by name and returns the plugin's response
- Many related struct for defining request packet and response packet.  New structs: AcceleratorBreakpointByName, AcceleratorBreakpointByAddress, AcceleratorBreakpointInfo, SymbolValue ,AcceleratorBreakpointHitArgs and AcceleratorBreakpointHitResponse structs with JSON encode/decode for the hit round-trip.
- breakpoints field in AcceleratorActions for plugins to request breakpoints during initialization
- Tests verifying breakpoints in initialize response and breakpoint hit round-trip with JSON validation
- Packet documentation in lldbgdbremote.md

---

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


11 Files Affected:

- (modified) lldb/docs/resources/lldbgdbremote.md (+42-2) 
- (modified) lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h (+84) 
- (modified) lldb/include/lldb/Utility/StringExtractorGDBRemote.h (+1) 
- (modified) lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp (+31) 
- (modified) lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h (+3) 
- (modified) lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h (+3) 
- (modified) lldb/source/Utility/AcceleratorGDBRemotePackets.cpp (+102-9) 
- (modified) lldb/source/Utility/StringExtractorGDBRemote.cpp (+2) 
- (modified) lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py (+61-23) 
- (modified) lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.cpp (+19-1) 
- (modified) lldb/tools/lldb-server/Plugins/Accelerator/Mock/LLDBServerMockAcceleratorPlugin.h (+5) 


``````````diff
diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md
index 59a68e34e73d0..3c73a87d71545 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -159,9 +159,49 @@ STUB REPLIES:  [{"plugin_name":"amdgpu","session_name":"AMD GPU Session","identi
 If no accelerator plugins are installed, the server does not advertise the
 `accelerator-plugins+` feature and this packet should not be sent.
 
+Each `accelerator_action` may include a `breakpoints` array requesting
+breakpoints to be set in the native process. See
+`jAcceleratorPluginBreakpointHit` for the callback when those breakpoints
+are hit.
+
 In future patches, each `accelerator_action` will include additional fields
-such as breakpoints to set in the native process, connection info for
-secondary debug sessions, and synchronization options.
+such as connection info for secondary debug sessions and synchronization
+options.
+
+**Priority To Implement:** Low. Only needed for hardware accelerator
+debugging support.
+
+## jAcceleratorPluginBreakpointHit
+
+Sent by the client when a breakpoint requested by an accelerator plugin
+(via `jAcceleratorPluginInitialize`) is hit in the native process. This
+packet requires the `accelerator-plugins+` feature from `qSupported`.
+
+```
+LLDB SENDS:    jAcceleratorPluginBreakpointHit:<json>
+STUB REPLIES:  <json_response>
+```
+
+The request JSON has the following fields:
+
+| Key             | Type   | Description |
+|-----------------|--------|-------------|
+| `plugin_name`   | string | Name of the plugin that requested the breakpoint. |
+| `breakpoint`    | object | The `AcceleratorBreakpointInfo` that was hit, including its `identifier`. |
+| `symbol_values` | array  | Array of `{"name": "<name>", "value": <addr>}` for each symbol requested in the breakpoint's `symbol_names`. |
+
+The response JSON has the following fields:
+
+| Key                  | Type | Description |
+|----------------------|------|-------------|
+| `disable_bp`         | bool | If true, the client should disable this breakpoint. |
+| `auto_resume_native` | bool | If true, the native process should automatically resume after handling the hit. |
+
+Example:
+```
+LLDB SENDS:    jAcceleratorPluginBreakpointHit:{"plugin_name":"mock","breakpoint":{"identifier":1,"symbol_names":[]},"symbol_values":[]}
+STUB REPLIES:  {"disable_bp":true,"auto_resume_native":false}
+```
 
 **Priority To Implement:** Low. Only needed for hardware accelerator
 debugging support.
diff --git a/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h b/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
index 479503bf47a3c..1618b1d80ea2e 100644
--- a/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/AcceleratorGDBRemotePackets.h
@@ -11,10 +11,92 @@
 
 #include "llvm/Support/JSON.h"
 #include <cstdint>
+#include <optional>
 #include <string>
+#include <vector>
 
 namespace lldb_private {
 
+struct SymbolValue {
+  /// Symbol name as requested in AcceleratorBreakpointInfo::symbol_names.
+  std::string name;
+  /// Load address of the symbol in the native process, or nullopt if not found.
+  std::optional<uint64_t> value;
+};
+
+bool fromJSON(const llvm::json::Value &value, SymbolValue &data,
+              llvm::json::Path path);
+llvm::json::Value toJSON(const SymbolValue &data);
+
+struct AcceleratorBreakpointByName {
+  /// Optional shared library name to limit the breakpoint scope.
+  std::optional<std::string> shlib;
+  /// Function name to set a breakpoint at.
+  std::string function_name;
+};
+
+bool fromJSON(const llvm::json::Value &value, AcceleratorBreakpointByName &data,
+              llvm::json::Path path);
+llvm::json::Value toJSON(const AcceleratorBreakpointByName &data);
+
+struct AcceleratorBreakpointByAddress {
+  /// Load address in the native debug target.
+  uint64_t load_address = 0;
+};
+
+bool fromJSON(const llvm::json::Value &value,
+              AcceleratorBreakpointByAddress &data, llvm::json::Path path);
+llvm::json::Value toJSON(const AcceleratorBreakpointByAddress &data);
+
+/// A breakpoint definition. Clients fill in either \a by_name or
+/// \a by_address. If the breakpoint callback needs symbol values from
+/// the native process, fill in \a symbol_names — those values will be
+/// delivered in the breakpoint hit callback.
+struct AcceleratorBreakpointInfo {
+  /// Unique breakpoint ID used to identify this breakpoint in the
+  /// BreakpointWasHit callback.
+  int64_t identifier = 0;
+  /// Breakpoint by function name.
+  std::optional<AcceleratorBreakpointByName> by_name;
+  /// Breakpoint by load address.
+  std::optional<AcceleratorBreakpointByAddress> by_address;
+  /// Symbol names whose values should be supplied when the breakpoint is hit.
+  std::vector<std::string> symbol_names;
+};
+
+bool fromJSON(const llvm::json::Value &value, AcceleratorBreakpointInfo &data,
+              llvm::json::Path path);
+llvm::json::Value toJSON(const AcceleratorBreakpointInfo &data);
+
+/// Sent by the client when a plugin-requested breakpoint is hit.
+struct AcceleratorBreakpointHitArgs {
+  AcceleratorBreakpointHitArgs() = default;
+  AcceleratorBreakpointHitArgs(llvm::StringRef plugin_name)
+      : plugin_name(plugin_name) {}
+
+  std::string plugin_name;
+  AcceleratorBreakpointInfo breakpoint;
+  std::vector<SymbolValue> symbol_values;
+
+  std::optional<uint64_t> GetSymbolValue(llvm::StringRef symbol_name) const;
+};
+
+bool fromJSON(const llvm::json::Value &value,
+              AcceleratorBreakpointHitArgs &data, llvm::json::Path path);
+llvm::json::Value toJSON(const AcceleratorBreakpointHitArgs &data);
+
+/// Response from the plugin when a breakpoint is hit.
+struct AcceleratorBreakpointHitResponse {
+  /// Set to true if this breakpoint should be disabled.
+  bool disable_bp = false;
+  /// Set to true if the native process should automatically resume.
+  bool auto_resume_native = true;
+};
+
+bool fromJSON(const llvm::json::Value &value,
+              AcceleratorBreakpointHitResponse &data, llvm::json::Path path);
+llvm::json::Value toJSON(const AcceleratorBreakpointHitResponse &data);
+
 struct AcceleratorActions {
   AcceleratorActions() = default;
   AcceleratorActions(llvm::StringRef plugin_name, int64_t action_id)
@@ -26,6 +108,8 @@ struct AcceleratorActions {
   std::string session_name;
   /// Unique identifier for this action within the plugin.
   int64_t identifier = 0;
+  /// Breakpoints to set in the native process.
+  std::vector<AcceleratorBreakpointInfo> breakpoints;
 };
 
 bool fromJSON(const llvm::json::Value &value, AcceleratorActions &data,
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 85ec27cac9ac0..ff3af73285427 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -174,6 +174,7 @@ class StringExtractorGDBRemote : public StringExtractor {
     eServerPacketType_jLLDBTraceGetBinaryData,
     eServerPacketType_jMultiBreakpoint,
     eServerPacketType_jAcceleratorPluginInitialize,
+    eServerPacketType_jAcceleratorPluginBreakpointHit,
 
     eServerPacketType_qMemTags, // read memory tags
     eServerPacketType_QMemTags, // write memory tags
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index a84e965b04bee..1f3598fe1c2d1 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -226,6 +226,11 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_jAcceleratorPluginInitialize,
       &GDBRemoteCommunicationServerLLGS::Handle_jAcceleratorPluginInitialize);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::
+          eServerPacketType_jAcceleratorPluginBreakpointHit,
+      &GDBRemoteCommunicationServerLLGS::
+          Handle_jAcceleratorPluginBreakpointHit);
 
   RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
                                 &GDBRemoteCommunicationServerLLGS::Handle_g);
@@ -4548,3 +4553,29 @@ GDBRemoteCommunicationServerLLGS::Handle_jAcceleratorPluginInitialize(
   response.PutAsJSONArray(accelerator_actions, /*hex_ascii=*/false);
   return SendPacketNoLock(response.GetString());
 }
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jAcceleratorPluginBreakpointHit(
+    StringExtractorGDBRemote &packet) {
+  packet.ConsumeFront("jAcceleratorPluginBreakpointHit:");
+  llvm::Expected<AcceleratorBreakpointHitArgs> args =
+      llvm::json::parse<AcceleratorBreakpointHitArgs>(
+          packet.Peek(), "AcceleratorBreakpointHitArgs");
+  if (!args)
+    return SendErrorResponse(args.takeError());
+
+  for (auto &plugin_up : m_accelerator_plugins) {
+    if (plugin_up->GetPluginName() == args->plugin_name) {
+      llvm::Expected<AcceleratorBreakpointHitResponse> bp_response =
+          plugin_up->BreakpointWasHit(*args);
+      if (!bp_response)
+        return SendErrorResponse(bp_response.takeError());
+
+      StreamGDBRemote response;
+      response.PutAsJSON(*bp_response, /*hex_ascii=*/false);
+      return SendPacketNoLock(response.GetString());
+    }
+  }
+  return SendErrorResponse(
+      Status::FromErrorString("unknown accelerator plugin name"));
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 5a088f8de2380..d582d2d77b639 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -287,6 +287,9 @@ class GDBRemoteCommunicationServerLLGS
   PacketResult
   Handle_jAcceleratorPluginInitialize(StringExtractorGDBRemote &packet);
 
+  PacketResult
+  Handle_jAcceleratorPluginBreakpointHit(StringExtractorGDBRemote &packet);
+
   void SetCurrentThreadID(lldb::tid_t tid);
 
   lldb::tid_t GetCurrentThreadID() const;
diff --git a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
index cdb9b20b435ca..0230b38e5b0fa 100644
--- a/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
+++ b/lldb/source/Plugins/Process/gdb-remote/LLDBServerAcceleratorPlugin.h
@@ -33,6 +33,9 @@ class LLDBServerAcceleratorPlugin {
 
   virtual std::optional<AcceleratorActions> GetInitializeActions() = 0;
 
+  virtual llvm::Expected<AcceleratorBreakpointHitResponse>
+  BreakpointWasHit(AcceleratorBreakpointHitArgs &args) = 0;
+
 protected:
   GDBServer &m_gdb_server;
   MainLoop &m_main_loop;
diff --git a/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp b/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
index 8019db4328c78..c05646c26b3bc 100644
--- a/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
+++ b/lldb/source/Utility/AcceleratorGDBRemotePackets.cpp
@@ -8,20 +8,113 @@
 
 #include "lldb/Utility/AcceleratorGDBRemotePackets.h"
 
-using namespace lldb_private;
+using namespace llvm;
+using namespace llvm::json;
 
-llvm::json::Value lldb_private::toJSON(const AcceleratorActions &data) {
-  return llvm::json::Object{
-      {"plugin_name", data.plugin_name},
-      {"session_name", data.session_name},
+namespace lldb_private {
+
+bool fromJSON(const Value &value, SymbolValue &data, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("name", data.name) && o.map("value", data.value);
+}
+
+json::Value toJSON(const SymbolValue &data) {
+  return Object{{"name", data.name}, {"value", data.value}};
+}
+
+bool fromJSON(const Value &value, AcceleratorBreakpointByName &data,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.mapOptional("shlib", data.shlib) &&
+         o.map("function_name", data.function_name);
+}
+
+json::Value toJSON(const AcceleratorBreakpointByName &data) {
+  return Object{{"shlib", data.shlib}, {"function_name", data.function_name}};
+}
+
+bool fromJSON(const Value &value, AcceleratorBreakpointByAddress &data,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("load_address", data.load_address);
+}
+
+json::Value toJSON(const AcceleratorBreakpointByAddress &data) {
+  return Object{{"load_address", static_cast<int64_t>(data.load_address)}};
+}
+
+bool fromJSON(const Value &value, AcceleratorBreakpointInfo &data, Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("identifier", data.identifier) &&
+         o.mapOptional("by_name", data.by_name) &&
+         o.mapOptional("by_address", data.by_address) &&
+         o.map("symbol_names", data.symbol_names);
+}
+
+json::Value toJSON(const AcceleratorBreakpointInfo &data) {
+  return Object{
       {"identifier", data.identifier},
+      {"by_name", data.by_name},
+      {"by_address", data.by_address},
+      {"symbol_names", data.symbol_names},
+  };
+}
+
+bool fromJSON(const Value &value, AcceleratorBreakpointHitArgs &data,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("plugin_name", data.plugin_name) &&
+         o.map("breakpoint", data.breakpoint) &&
+         o.map("symbol_values", data.symbol_values);
+}
+
+json::Value toJSON(const AcceleratorBreakpointHitArgs &data) {
+  return Object{
+      {"plugin_name", data.plugin_name},
+      {"breakpoint", data.breakpoint},
+      {"symbol_values", data.symbol_values},
   };
 }
 
-bool lldb_private::fromJSON(const llvm::json::Value &value,
-                            AcceleratorActions &data, llvm::json::Path path) {
-  llvm::json::ObjectMapper o(value, path);
+std::optional<uint64_t>
+AcceleratorBreakpointHitArgs::GetSymbolValue(StringRef symbol_name) const {
+  auto it = llvm::find_if(symbol_values, [&](const SymbolValue &symbol) {
+    return symbol.name == symbol_name;
+  });
+  if (it != symbol_values.end())
+    return it->value;
+  return std::nullopt;
+}
+
+bool fromJSON(const Value &value, AcceleratorBreakpointHitResponse &data,
+              Path path) {
+  ObjectMapper o(value, path);
+  return o && o.map("disable_bp", data.disable_bp) &&
+         o.map("auto_resume_native", data.auto_resume_native);
+}
+
+json::Value toJSON(const AcceleratorBreakpointHitResponse &data) {
+  return Object{
+      {"disable_bp", data.disable_bp},
+      {"auto_resume_native", data.auto_resume_native},
+  };
+}
+
+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("identifier", data.identifier) &&
+         o.map("breakpoints", data.breakpoints);
 }
+
+json::Value toJSON(const AcceleratorActions &data) {
+  return Object{
+      {"plugin_name", data.plugin_name},
+      {"session_name", data.session_name},
+      {"identifier", data.identifier},
+      {"breakpoints", data.breakpoints},
+  };
+}
+
+} // namespace lldb_private
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 7b46bef933ac2..683559bd0fcf8 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -334,6 +334,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
       return eServerPacketType_jMultiBreakpoint;
     if (PACKET_MATCHES("jAcceleratorPluginInitialize"))
       return eServerPacketType_jAcceleratorPluginInitialize;
+    if (PACKET_STARTS_WITH("jAcceleratorPluginBreakpointHit:"))
+      return eServerPacketType_jAcceleratorPluginBreakpointHit;
     break;
 
   case 'v':
diff --git a/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py b/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py
index 3e9ca174cd533..e0dabdf7874dd 100644
--- a/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py
+++ b/lldb/test/API/accelerator/mock/TestMockAcceleratorPlugin.py
@@ -1,14 +1,16 @@
 """
 Tests for the lldb-server mock accelerator plugin.
 
-Verifies the accelerator-plugins+ feature in qSupported and
-the jAcceleratorPluginInitialize packet response.
+Verifies the accelerator-plugins+ feature in qSupported,
+the jAcceleratorPluginInitialize packet response, and
+the jAcceleratorPluginBreakpointHit round-trip.
 """
 
 import json
 
 import gdbremote_testcase
 from lldbsuite.test.decorators import *
+from lldbsuite.test.gdbclientutils import escape_binary
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test import configuration
 
@@ -26,6 +28,24 @@ def setUp(self):
         if "mock-accelerator" not in configuration.enabled_plugins:
             self.skipTest("mock-accelerator plugin is not enabled")
 
+    def send_and_decode_json(self, packet):
+        """Send a packet and return the decoded JSON response."""
+        self.test_sequence.add_log_lines(
+            [
+                "read packet: $%s#00" % packet,
+                {
+                    "direction": "send",
+                    "regex": r"^\$(.+)#[0-9a-fA-F]{2}",
+                    "capture": {1: "response"},
+                },
+            ],
+            True,
+        )
+        context = self.expect_gdbremote_sequence()
+        raw = context.get("response")
+        self.assertIsNotNone(raw)
+        return json.loads(self.decode_gdbremote_binary(raw))
+
     @add_test_categories(["llgs"])
     def test_qSupported_reports_accelerator_plugins(self):
         self.build()
@@ -40,7 +60,7 @@ def test_qSupported_reports_accelerator_plugins(self):
         self.assertEqual(features["accelerator-plugins"], "+")
 
     @add_test_categories(["llgs"])
-    def test_jAcceleratorPluginInitialize_returns_mock_actions(self):
+    def test_jAcceleratorPluginInitialize_returns_breakpoints(self):
         self.build()
         self.set_inferior_startup_launch()
         self.prep_debug_monitor_and_inferior()
@@ -48,27 +68,45 @@ def test_jAcceleratorPluginInitialize_returns_mock_actions(self):
         self.add_qSupported_packets()
         self.expect_gdbremote_sequence()
 
-        self.test_sequence.add_log_lines(
-            [
-                "read packet: $jAcceleratorPluginInitialize#00",
-                {
-                    "direction": "send",
-                    "regex": r"^\$(.+)#[0-9a-fA-F]{2}",
-                    "capture": {1: "accel_init_response"},
-                },
-            ],
-            True,
-        )
-        context = self.expect_gdbremote_sequence()
-
-        raw_response = context.get("accel_init_response")
-        self.assertIsNotNone(raw_response)
-
-        decoded = self.decode_gdbremote_binary(raw_response)
-        actions = json.loads(decoded)
+        actions = self.send_and_decode_json("jAcceleratorPluginInitialize")
         self.assertIsInstance(actions, list)
 
         mock_action = get_accelerator_action(actions, "mock")
         self.assertIsNotNone(mock_action)
-        self.assertIn("session_name", mock_action)
-        self.assertIn("identifier", mock_action)
+        self.assertIn("breakpoints", mock_action)
+
+        breakpoints = mock_action["breakpoints"]
+        self.assertGreater(len(breakpoints), 0)
+
+        bp = breakpoints[0]
+        self.assertIn("identifier", bp)
+        self.assertIn("by_name", bp)
+        self.assertEqual(bp["by_name"]["function_name"], "main")
+
+    @add_test_categories(["llgs"])
+    def test_jAcceleratorPluginBreakpointHit_response(self):
+        self.build()
+        self.set_inferior_startup_launch()
+        self.prep_debug_monitor_and_inferior()
+
+        self.add_qSupported_packets()
+        self.expect_gdbremote_sequence()
+
+        hit_args = {
+            "plugin_name": "mock",
+            "breakpoint": {
+                "identifier": 1,
+                "symbol_names": [],
+            },
+            "symbol_values": [],
+        }
+        hit_json = json.dumps(hit_args, separators=(",", ":"))
+        escaped_json = escape_binary(hit_json)
+        response = self.send_and_decode_json(
+            "jAcceleratorPluginBreakpointHit:" + escape...
[truncated]

``````````

</details>


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


More information about the lldb-commits mailing list