[llvm-branch-commits] [lldb] [lldbremote] Implement support for MultiBreakpoint packet (PR #192919)
Felipe de Azevedo Piovezan via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Apr 23 05:44:21 PDT 2026
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/192919
>From 90705247766d49e3d2e662c4cac5343b5394ab25 Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Mon, 23 Mar 2026 09:26:32 +0000
Subject: [PATCH] [lldb-server] Implement support for MultiBreakpoint packet
This is fairly straightforward, thanks to the helper functions created
in the previous commit.
https://github.com/llvm/llvm-project/pull/192910
---
.../lldb/Utility/StringExtractorGDBRemote.h | 1 +
.../tools/lldb-server/gdbremote_testcase.py | 1 +
.../GDBRemoteCommunicationServerLLGS.cpp | 57 +++++++++++++++++++
.../GDBRemoteCommunicationServerLLGS.h | 2 +
.../Utility/StringExtractorGDBRemote.cpp | 2 +
.../multi-breakpoint/TestMultiBreakpoint.py | 1 -
6 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
index 439245fdc3083..9aeac03a54bee 100644
--- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
+++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h
@@ -172,6 +172,7 @@ class StringExtractorGDBRemote : public StringExtractor {
eServerPacketType_jLLDBTraceStop,
eServerPacketType_jLLDBTraceGetState,
eServerPacketType_jLLDBTraceGetBinaryData,
+ eServerPacketType_jMultiBreakpoint,
eServerPacketType_qMemTags, // read memory tags
eServerPacketType_QMemTags, // write memory tags
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 5ba642bbedf74..de5cb63f034e7 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
@@ -932,6 +932,7 @@ def add_qSupported_packets(self, client_features=[]):
"SupportedWatchpointTypes",
"SupportedCompressions",
"MultiMemRead",
+ "jMultiBreakpoint",
]
def parse_qSupported_response(self, context):
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 4c77de9f34adc..26cfcc9a396eb 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -217,6 +217,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetBinaryData,
&GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jMultiBreakpoint,
+ &GDBRemoteCommunicationServerLLGS::Handle_jMultiBreakpoint);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
&GDBRemoteCommunicationServerLLGS::Handle_g);
@@ -3123,6 +3126,59 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
ExecuteRemoveBreakpoint(packet.GetStringRef()));
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jMultiBreakpoint(
+ StringExtractorGDBRemote &packet) {
+ llvm::StringRef packet_str = packet.GetStringRef();
+ if (!packet_str.consume_front("jMultiBreakpoint:"))
+ return SendIllFormedResponse(packet,
+ "Invalid jMultiBreakpoint packet prefix");
+
+ llvm::Expected<llvm::json::Value> parsed = llvm::json::parse(packet_str);
+ if (!parsed) {
+ llvm::consumeError(parsed.takeError());
+ return SendIllFormedResponse(
+ packet, "jMultiBreakpoint did not contain a JSON dictionary");
+ }
+ llvm::json::Object *request_dict = parsed->getAsObject();
+ if (!request_dict)
+ return SendIllFormedResponse(
+ packet, "jMultiBreakpoint did not contain a JSON dictionary");
+
+ llvm::json::Array *request_array =
+ request_dict->getArray("breakpoint_requests");
+ if (!request_array)
+ return SendIllFormedResponse(
+ packet,
+ "jMultiBreakpoint did not contain a valid 'breakpoint_requests' field");
+
+ llvm::json::Array reply_array;
+ for (const llvm::json::Value &value : *request_array) {
+ std::optional<llvm::StringRef> request = value.getAsString();
+ if (!request)
+ return SendIllFormedResponse(packet,
+ "jMultiBreakpoint had a non-string entry");
+ BreakpointResult result = request->starts_with("Z")
+ ? ExecuteSetBreakpoint(*request)
+ : ExecuteRemoveBreakpoint(*request);
+ switch (result.kind) {
+ case BreakpointResult::Kind::OK:
+ reply_array.push_back("OK");
+ break;
+ case BreakpointResult::Kind::Error:
+ reply_array.push_back(llvm::formatv("E{0:X-2}", result.error_code).str());
+ break;
+ case BreakpointResult::Kind::IllFormed:
+ reply_array.push_back("E03");
+ break;
+ }
+ }
+
+ StreamString response;
+ response.AsRawOstream() << llvm::json::Value(std::move(reply_array));
+ return SendPacketNoLock(response.GetString());
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
@@ -4338,6 +4394,7 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures(
"QListThreadsInStopReply+",
"qXfer:features:read+",
"QNonStop+",
+ "jMultiBreakpoint+",
});
// report server-only features
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index a663c0b949744..f35ae8a3c23b6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -276,6 +276,8 @@ class GDBRemoteCommunicationServerLLGS
PacketResult Handle_T(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jMultiBreakpoint(StringExtractorGDBRemote &packet);
+
void SetCurrentThreadID(lldb::tid_t tid);
lldb::tid_t GetCurrentThreadID() const;
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 40b5d037d0463..17e36398fc218 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -330,6 +330,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_jLLDBTraceGetState;
if (PACKET_STARTS_WITH("jLLDBTraceGetBinaryData:"))
return eServerPacketType_jLLDBTraceGetBinaryData;
+ if (PACKET_STARTS_WITH("jMultiBreakpoint:"))
+ return eServerPacketType_jMultiBreakpoint;
break;
case 'v':
diff --git a/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py b/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py
index 144563e89850c..d7399200a6a94 100644
--- a/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py
+++ b/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py
@@ -11,7 +11,6 @@
from lldbsuite.test import lldbutil
- at skipUnlessDarwin # Remove once lldbsever support is implemented.
@skipIfOutOfTreeDebugserver
class TestMultiBreakpoint(TestBase):
def send_packet(self, packet_str):
More information about the llvm-branch-commits
mailing list