[Lldb-commits] [lldb] [lldb][NFC] Add test utility for sending gdbremote packets (PR #195247)
Felipe de Azevedo Piovezan via lldb-commits
lldb-commits at lists.llvm.org
Fri May 1 04:42:04 PDT 2026
https://github.com/felipepiovezan updated https://github.com/llvm/llvm-project/pull/195247
>From a4b867f7ac70c09187d25ac23ce2e543d0f1f44b Mon Sep 17 00:00:00 2001
From: Felipe de Azevedo Piovezan <fpiovezan at apple.com>
Date: Fri, 1 May 2026 11:00:40 +0100
Subject: [PATCH] [lldb][NFC] Add test utility for sending gdbremote packets
This removes some duplicated code, and also helps future tests. It's
also surprisingly not easy to write these, as there are a few footguns.
---
.../Python/lldbsuite/test/lldbutil.py | 23 ++++++++++++++
.../multi-breakpoint/TestMultiBreakpoint.py | 31 +++++--------------
.../TestDebugserverMultiMemRead.py | 22 ++++---------
3 files changed, 36 insertions(+), 40 deletions(-)
diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py
index 00230036a0e71..520e7e5079d19 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbutil.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py
@@ -18,6 +18,7 @@
import lldb
from . import lldbtest_config
from . import configuration
+from lldbsuite.test.gdbclientutils import escape_binary
# How often failed simulator process launches are retried.
SIMULATOR_RETRY = 3
@@ -1869,3 +1870,25 @@ def launch_exe_in_apple_simulator(
break
return exe_path, matched_strings
+
+
+# Binary escapes `packet_str`, sends it to the remote and returns the reply.
+def send_packet_get_reply(test, packet_str):
+ packet_str = escape_binary(packet_str)
+ test.runCmd(f"proc plugin packet send '{packet_str}'", check=False)
+ # The output is of the form:
+ # packet: <packet_str>
+ # response: <response>
+ output = test.res.GetOutput()
+ reply = output.split("\n")
+ packet = reply[0].strip()
+ response = reply[1].strip()
+
+ test.assertTrue(packet.startswith("packet: "))
+ test.assertTrue(response.startswith("response: "))
+ return response[len("response: ") :].strip()
+
+
+def get_qsupported_capabilities(test):
+ reply = send_packet_get_reply(test, "qSupported")
+ return reply.strip().split(";")
diff --git a/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py b/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py
index d0d187970c81d..eb9e2952d5a49 100644
--- a/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py
+++ b/lldb/test/API/functionalities/multi-breakpoint/TestMultiBreakpoint.py
@@ -12,38 +12,21 @@
from lldbsuite.test.gdbclientutils import *
- at skipIfWindows # No server on Windows.
+ at skipIfWindows # No server on Windows.
@skipIfOutOfTreeDebugserver
# Runs on systems where we can always predict the software break size
@skipIf(archs=no_match(["x86_64", "arm64", "aarch64"]))
class TestMultiBreakpoint(TestBase):
- def send_packet(self, packet_str):
- packet_str = escape_binary(packet_str)
- self.runCmd(f"process plugin packet send '{packet_str}'", check=False)
- output = self.res.GetOutput()
- reply = output.split("\n")
- # The output is of the form:
- # packet: <packet_str>
- # response: <response>
- packet_line = None
- response_line = None
- for line in reply:
- line = line.strip()
- if line.startswith("packet:"):
- packet_line = line
- elif line.startswith("response:"):
- response_line = line
- self.assertIsNotNone(packet_line, f'No "packet:" line in output: {output}')
- self.assertIsNotNone(response_line, f'No "response:" line in output: {output}')
- return response_line[len("response:") :].strip()
-
def check_invalid_packet(self, packet_str):
- reply = self.send_packet(packet_str)
+ reply = lldbutil.send_packet_get_reply(self, packet_str)
if reply.startswith("E"):
return
else:
self.assertMultiResponse(reply, ["error"])
+ def send_packet(self, packet_str):
+ return lldbutil.send_packet_get_reply(self, packet_str)
+
def assertMultiResponse(self, reply, expected):
"""Assert a JSON-array multi-response matches the expected pattern.
@@ -84,8 +67,8 @@ def test_multi_breakpoint(self):
)
# Verify the server advertises jMultiBreakpoint support.
- reply = self.send_packet("qSupported")
- self.assertIn("jMultiBreakpoint+", reply)
+ capabilities = lldbutil.get_qsupported_capabilities(self)
+ self.assertIn("jMultiBreakpoint+", capabilities)
addr_a = self.get_function_address("func_a")
addr_b = self.get_function_address("func_b")
diff --git a/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py b/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py
index 6caa5f85c2848..ab6e952fb7dd1 100644
--- a/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py
+++ b/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py
@@ -11,23 +11,13 @@
@skipUnlessDarwin
@skipIfOutOfTreeDebugserver
class TestCase(TestBase):
- def send_process_packet(self, packet_str):
- self.runCmd(f"proc plugin packet send {packet_str}", check=False)
- # The output is of the form:
- # packet: <packet_str>
- # response: <response>
- reply = self.res.GetOutput().split("\n")
- packet = reply[0].strip()
- response = reply[1].strip()
-
- self.assertTrue(packet.startswith("packet: "))
- self.assertTrue(response.startswith("response: "))
- return response[len("response: ") :]
-
def check_invalid_packet(self, packet_str):
- reply = self.send_process_packet("packet_str")
+ reply = lldbutil.send_packet_get_reply(self, "packet_str")
self.assertEqual(reply, "E03")
+ def send_process_packet(self, packet_str):
+ return lldbutil.send_packet_get_reply(self, packet_str)
+
def test_packets(self):
self.build()
source_file = lldb.SBFileSpec("main.c")
@@ -35,8 +25,8 @@ def test_packets(self):
self, "break here", source_file
)
- reply = self.send_process_packet("qSupported")
- self.assertIn("MultiMemRead+", reply)
+ capabilities = lldbutil.get_qsupported_capabilities(self)
+ self.assertIn("MultiMemRead+", capabilities)
mem_address_var = thread.frames[0].FindVariable("memory")
self.assertTrue(mem_address_var)
More information about the lldb-commits
mailing list