[Lldb-commits] [lldb] [lldb] Split some tests to avoid timeout (PR #129614)
David Peixotto via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 12 20:04:07 PDT 2025
https://github.com/dmpots updated https://github.com/llvm/llvm-project/pull/129614
>From b1d0ee1495e2e6314ad70f2953c8d0e2aaf58c67 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Mon, 3 Mar 2025 15:39:20 -0800
Subject: [PATCH 1/9] Split test to avoid timeout
This test is running right up to the 600s timeout limit. Split it
in two to avoid hitting a timeout.
---
.../tools/lldb-server/TestLldbGdbServer.py | 901 +----------------
.../tools/lldb-server/TestLldbGdbServer2.py | 922 ++++++++++++++++++
2 files changed, 925 insertions(+), 898 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index 12c97bc62dcef..e2daff164eeeb 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -5,9 +5,9 @@
lldb-server tests run where the lldb-server exe is
available.
-This class will be broken into smaller test case classes by
-gdb remote packet functional areas. For now it contains
-the initial set of tests implemented.
+The tests are split between the LldbGdbServerTestCase and
+LldbGdbServerTestCase2 classes to avoid timeouts in the
+test suite.
"""
import binascii
@@ -611,898 +611,3 @@ def test_Hc_then_Csignal_signals_correct_thread_launch(self):
self.Hc_then_Csignal_signals_correct_thread(
lldbutil.get_signal_number("SIGSEGV")
)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_m_packet_reads_memory(self):
- self.build()
- self.set_inferior_startup_launch()
- # This is the memory we will write into the inferior and then ensure we
- # can read back with $m.
- MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=[
- "set-message:%s" % MEMORY_CONTENTS,
- "get-data-address-hex:g_message",
- "sleep:5",
- ]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"data address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "message_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the message address.
- self.assertIsNotNone(context.get("message_address"))
- message_address = int(context.get("message_address"), 16)
-
- # Grab contents from the inferior.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $m{0:x},{1:x}#00".format(
- message_address, len(MEMORY_CONTENTS)
- ),
- {
- "direction": "send",
- "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
- "capture": {1: "read_contents"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Ensure what we read from inferior memory is what we wrote.
- self.assertIsNotNone(context.get("read_contents"))
- read_contents = seven.unhexlify(context.get("read_contents"))
- self.assertEqual(read_contents, MEMORY_CONTENTS)
-
- def test_qMemoryRegionInfo_is_supported(self):
- self.build()
- self.set_inferior_startup_launch()
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior()
-
- # Ask if it supports $qMemoryRegionInfo.
- self.test_sequence.add_log_lines(
- ["read packet: $qMemoryRegionInfo#00", "send packet: $OK#00"], True
- )
- self.expect_gdbremote_sequence()
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-code-address-hex:hello", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"code address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "code_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the code address.
- self.assertIsNotNone(context.get("code_address"))
- code_address = int(context.get("code_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(code_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure code address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("x", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(code_address, mem_region_dict)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_stack_address_as_rw(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-stack-address-hex:", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"stack address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "stack_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the address.
- self.assertIsNotNone(context.get("stack_address"))
- stack_address = int(context.get("stack_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(stack_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("w", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(stack_address, mem_region_dict)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_heap_address_as_rw(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-heap-address-hex:", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"heap address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "heap_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the address.
- self.assertIsNotNone(context.get("heap_address"))
- heap_address = int(context.get("heap_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(heap_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("w", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(heap_address, mem_region_dict)
-
- def breakpoint_set_and_remove_work(self, want_hardware):
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=[
- "get-code-address-hex:hello",
- "sleep:1",
- "call-function:hello",
- ]
- )
-
- # Run the process
- self.add_register_info_collection_packets()
- self.add_process_info_collection_packets()
- self.test_sequence.add_log_lines(
- [ # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the function call entry point.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"code address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "function_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Gather process info - we need endian of target to handle register
- # value conversions.
- process_info = self.parse_process_info_response(context)
- endian = process_info.get("endian")
- self.assertIsNotNone(endian)
-
- # Gather register info entries.
- reg_infos = self.parse_register_info_packets(context)
- (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)
- self.assertIsNotNone(pc_lldb_reg_index)
- self.assertIsNotNone(pc_reg_info)
-
- # Grab the function address.
- self.assertIsNotNone(context.get("function_address"))
- function_address = int(context.get("function_address"), 16)
-
- # Get current target architecture
- target_arch = self.getArchitecture()
-
- # Set the breakpoint.
- if target_arch in ["arm", "arm64", "aarch64"]:
- # TODO: Handle case when setting breakpoint in thumb code
- BREAKPOINT_KIND = 4
- else:
- BREAKPOINT_KIND = 1
-
- # Set default packet type to Z0 (software breakpoint)
- z_packet_type = 0
-
- # If hardware breakpoint is requested set packet type to Z1
- if want_hardware:
- z_packet_type = 1
-
- self.reset_test_sequence()
- self.add_set_breakpoint_packets(
- function_address,
- z_packet_type,
- do_continue=True,
- breakpoint_kind=BREAKPOINT_KIND,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Verify the stop signal reported was the breakpoint signal number.
- stop_signo = context.get("stop_signo")
- self.assertIsNotNone(stop_signo)
- self.assertEqual(int(stop_signo, 16), lldbutil.get_signal_number("SIGTRAP"))
-
- # Ensure we did not receive any output. If the breakpoint was not set, we would
- # see output (from a launched process with captured stdio) printing a hello, world message.
- # That would indicate the breakpoint didn't take.
- self.assertEqual(len(context["O_content"]), 0)
-
- # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.
- # This acts as a another validation on the register reading code.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- # Print the PC. This should match the breakpoint address.
- "read packet: $p{0:x}#00".format(pc_lldb_reg_index),
- # Capture $p results.
- {
- "direction": "send",
- "regex": r"^\$([0-9a-fA-F]+)#",
- "capture": {1: "p_response"},
- },
- ],
- True,
- )
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Verify the PC is where we expect. Note response is in endianness of
- # the inferior.
- p_response = context.get("p_response")
- self.assertIsNotNone(p_response)
-
- # Convert from target endian to int.
- returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(
- endian, p_response
- )
- self.assertEqual(returned_pc, function_address)
-
- # Verify that a breakpoint remove and continue gets us the expected
- # output.
- self.reset_test_sequence()
-
- # Add breakpoint remove packets
- self.add_remove_breakpoint_packets(
- function_address, z_packet_type, breakpoint_kind=BREAKPOINT_KIND
- )
-
- self.test_sequence.add_log_lines(
- [
- # Continue running.
- "read packet: $c#63",
- # We should now receive the output from the call.
- {"type": "output_match", "regex": r"^hello, world\r\n$"},
- # And wait for program completion.
- {"direction": "send", "regex": r"^\$W00(.*)#[0-9a-fA-F]{2}$"},
- ],
- True,
- )
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_software_breakpoint_set_and_remove_work(self):
- if self.getArchitecture() == "arm":
- # TODO: Handle case when setting breakpoint in thumb code
- self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
- else:
- self.build()
- self.set_inferior_startup_launch()
- self.breakpoint_set_and_remove_work(want_hardware=False)
-
- @skipUnlessPlatform(oslist=["linux"])
- @skipIf(archs=no_match(["arm", "aarch64"]))
- def test_hardware_breakpoint_set_and_remove_work(self):
- if self.getArchitecture() == "arm":
- # TODO: Handle case when setting breakpoint in thumb code
- self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
- else:
- self.build()
- self.set_inferior_startup_launch()
- self.breakpoint_set_and_remove_work(want_hardware=True)
-
- def get_qSupported_dict(self, features=[]):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the stub and start/prep the inferior.
- procs = self.prep_debug_monitor_and_inferior()
- self.add_qSupported_packets(features)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Retrieve the qSupported features.
- return self.parse_qSupported_response(context)
-
- def test_qSupported_returns_known_stub_features(self):
- supported_dict = self.get_qSupported_dict()
- self.assertIsNotNone(supported_dict)
- self.assertGreater(len(supported_dict), 0)
-
- def test_qSupported_auvx(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:auxv:read", "-"), expected)
-
- def test_qSupported_libraries_svr4(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:libraries-svr4:read", "-"), expected)
-
- def test_qSupported_siginfo_read(self):
- expected = (
- "+" if lldbplatformutil.getPlatform() in ["freebsd", "linux"] else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:siginfo:read", "-"), expected)
-
- def test_qSupported_QPassSignals(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("QPassSignals", "-"), expected)
-
- @add_test_categories(["fork"])
- def test_qSupported_fork_events(self):
- supported_dict = self.get_qSupported_dict(["multiprocess+", "fork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
- self.assertEqual(supported_dict.get("fork-events", "-"), "+")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- @add_test_categories(["fork"])
- def test_qSupported_fork_events_without_multiprocess(self):
- supported_dict = self.get_qSupported_dict(["fork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- @add_test_categories(["fork"])
- def test_qSupported_vfork_events(self):
- supported_dict = self.get_qSupported_dict(["multiprocess+", "vfork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "+")
-
- @add_test_categories(["fork"])
- def test_qSupported_vfork_events_without_multiprocess(self):
- supported_dict = self.get_qSupported_dict(["vfork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- # We need to be able to self.runCmd to get cpuinfo,
- # which is not possible when using a remote platform.
- @skipIfRemote
- def test_qSupported_memory_tagging(self):
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(
- supported_dict.get("memory-tagging", "-"),
- "+" if self.isAArch64MTE() else "-",
- )
-
- @skipIfWindows # No pty support to test any inferior output
- def test_written_M_content_reads_back_correctly(self):
- self.build()
- self.set_inferior_startup_launch()
-
- TEST_MESSAGE = "Hello, memory"
-
- # Start up the stub and start/prep the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=[
- "set-message:xxxxxxxxxxxxxX",
- "get-data-address-hex:g_message",
- "sleep:1",
- "print-message:",
- ]
- )
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"data address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "message_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the message address.
- self.assertIsNotNone(context.get("message_address"))
- message_address = int(context.get("message_address"), 16)
-
- # Hex-encode the test message, adding null termination.
- hex_encoded_message = seven.hexlify(TEST_MESSAGE)
-
- # Write the message to the inferior. Verify that we can read it with the hex-encoded (m)
- # and binary (x) memory read packets.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $M{0:x},{1:x}:{2}#00".format(
- message_address, len(TEST_MESSAGE), hex_encoded_message
- ),
- "send packet: $OK#00",
- "read packet: $m{0:x},{1:x}#00".format(
- message_address, len(TEST_MESSAGE)
- ),
- "send packet: ${0}#00".format(hex_encoded_message),
- "read packet: $x{0:x},{1:x}#00".format(
- message_address, len(TEST_MESSAGE)
- ),
- "send packet: ${0}#00".format(TEST_MESSAGE),
- "read packet: $m{0:x},4#00".format(message_address),
- "send packet: ${0}#00".format(hex_encoded_message[0:8]),
- "read packet: $x{0:x},4#00".format(message_address),
- "send packet: ${0}#00".format(TEST_MESSAGE[0:4]),
- "read packet: $c#63",
- {
- "type": "output_match",
- "regex": r"^message: (.+)\r\n$",
- "capture": {1: "printed_message"},
- },
- "send packet: $W00#00",
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Ensure what we read from inferior memory is what we wrote.
- printed_message = context.get("printed_message")
- self.assertIsNotNone(printed_message)
- self.assertEqual(printed_message, TEST_MESSAGE + "X")
-
- # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
- # Come back to this. I have the test rigged to verify that at least some
- # of the bit-flip writes work.
- def test_P_writes_all_gpr_registers(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start inferior debug session, grab all register info.
- procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
- self.add_register_info_collection_packets()
- self.add_process_info_collection_packets()
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Process register infos.
- reg_infos = self.parse_register_info_packets(context)
- self.assertIsNotNone(reg_infos)
- self.add_lldb_register_index(reg_infos)
-
- # Process endian.
- process_info = self.parse_process_info_response(context)
- endian = process_info.get("endian")
- self.assertIsNotNone(endian)
-
- # Pull out the register infos that we think we can bit flip
- # successfully,.
- gpr_reg_infos = [
- reg_info
- for reg_info in reg_infos
- if self.is_bit_flippable_register(reg_info)
- ]
- self.assertGreater(len(gpr_reg_infos), 0)
-
- # Write flipped bit pattern of existing value to each register.
- (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(
- gpr_reg_infos, endian
- )
- self.trace(
- "successful writes: {}, failed writes: {}".format(
- successful_writes, failed_writes
- )
- )
- self.assertGreater(successful_writes, 0)
-
- # Note: as of this moment, a hefty number of the GPR writes are failing
- # with E32 (everything except rax-rdx, rdi, rsi, rbp).
- @skipIfWindows
- def test_P_and_p_thread_suffix_work(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Startup the inferior with three threads.
- _, threads = self.launch_with_threads(3)
-
- self.reset_test_sequence()
- self.add_thread_suffix_request_packets()
- self.add_register_info_collection_packets()
- self.add_process_info_collection_packets()
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- process_info = self.parse_process_info_response(context)
- self.assertIsNotNone(process_info)
- endian = process_info.get("endian")
- self.assertIsNotNone(endian)
-
- reg_infos = self.parse_register_info_packets(context)
- self.assertIsNotNone(reg_infos)
- self.add_lldb_register_index(reg_infos)
-
- reg_index = self.select_modifiable_register(reg_infos)
- self.assertIsNotNone(reg_index)
- reg_byte_size = int(reg_infos[reg_index]["bitsize"]) // 8
- self.assertGreater(reg_byte_size, 0)
-
- expected_reg_values = []
- register_increment = 1
- next_value = None
-
- # Set the same register in each of 3 threads to a different value.
- # Verify each one has the unique value.
- for thread in threads:
- # If we don't have a next value yet, start it with the initial read
- # value + 1
- if not next_value:
- # Read pre-existing register value.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $p{0:x};thread:{1:x}#00".format(
- reg_index, thread
- ),
- {
- "direction": "send",
- "regex": r"^\$([0-9a-fA-F]+)#",
- "capture": {1: "p_response"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Set the next value to use for writing as the increment plus
- # current value.
- p_response = context.get("p_response")
- self.assertIsNotNone(p_response)
- next_value = lldbgdbserverutils.unpack_register_hex_unsigned(
- endian, p_response
- )
-
- # Set new value using P and thread suffix.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $P{0:x}={1};thread:{2:x}#00".format(
- reg_index,
- lldbgdbserverutils.pack_register_hex(
- endian, next_value, byte_size=reg_byte_size
- ),
- thread,
- ),
- "send packet: $OK#00",
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Save the value we set.
- expected_reg_values.append(next_value)
-
- # Increment value for next thread to use (we want them all
- # different so we can verify they wrote to each thread correctly
- # next.)
- next_value += register_increment
-
- # Revisit each thread and verify they have the expected value set for
- # the register we wrote.
- thread_index = 0
- for thread in threads:
- # Read pre-existing register value.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
- {
- "direction": "send",
- "regex": r"^\$([0-9a-fA-F]+)#",
- "capture": {1: "p_response"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Get the register value.
- p_response = context.get("p_response")
- self.assertIsNotNone(p_response)
- read_value = lldbgdbserverutils.unpack_register_hex_unsigned(
- endian, p_response
- )
-
- # Make sure we read back what we wrote.
- self.assertEqual(read_value, expected_reg_values[thread_index])
- thread_index += 1
-
- @skipUnlessPlatform(oslist=["freebsd", "linux"])
- @add_test_categories(["llgs"])
- def test_qXfer_siginfo_read(self):
- self.build()
- self.set_inferior_startup_launch()
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["thread:segfault", "thread:new", "sleep:10"]
- )
- self.test_sequence.add_log_lines(["read packet: $c#63"], True)
- self.expect_gdbremote_sequence()
-
- # Run until SIGSEGV comes in.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "signo", 2: "thread_id"},
- }
- ],
- True,
- )
-
- # Figure out which thread crashed.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- self.assertEqual(
- int(context["signo"], 16), lldbutil.get_signal_number("SIGSEGV")
- )
- crashing_thread = int(context["thread_id"], 16)
-
- # Grab siginfo for the crashing thread.
- self.reset_test_sequence()
- self.add_process_info_collection_packets()
- self.test_sequence.add_log_lines(
- [
- "read packet: $Hg{:x}#00".format(crashing_thread),
- "send packet: $OK#00",
- "read packet: $qXfer:siginfo:read::0,80:#00",
- {
- "direction": "send",
- "regex": re.compile(
- r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL
- ),
- "capture": {1: "response_type", 2: "content_raw"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Ensure we end up with all data in one packet.
- self.assertEqual(context.get("response_type"), "l")
-
- # Decode binary data.
- content_raw = context.get("content_raw")
- self.assertIsNotNone(content_raw)
- content = self.decode_gdbremote_binary(content_raw).encode("latin1")
-
- # Decode siginfo_t.
- process_info = self.parse_process_info_response(context)
- pad = ""
- if process_info["ptrsize"] == "8":
- pad = "i"
- signo_idx = 0
- errno_idx = 1
- code_idx = 2
- addr_idx = -1
- SEGV_MAPERR = 1
- if process_info["ostype"] == "linux":
- # si_signo, si_errno, si_code, [pad], _sifields._sigfault.si_addr
- format_str = "iii{}P".format(pad)
- elif process_info["ostype"].startswith("freebsd"):
- # si_signo, si_errno, si_code, si_pid, si_uid, si_status, si_addr
- format_str = "iiiiiiP"
- elif process_info["ostype"].startswith("netbsd"):
- # _signo, _code, _errno, [pad], _reason._fault._addr
- format_str = "iii{}P".format(pad)
- errno_idx = 2
- code_idx = 1
- else:
- assert False, "unknown ostype"
-
- decoder = struct.Struct(format_str)
- decoded = decoder.unpack(content[: decoder.size])
- self.assertEqual(decoded[signo_idx], lldbutil.get_signal_number("SIGSEGV"))
- self.assertEqual(decoded[errno_idx], 0) # si_errno
- self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code
- self.assertEqual(decoded[addr_idx], 0) # si_addr
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
new file mode 100644
index 0000000000000..d40aa1fb792a0
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
@@ -0,0 +1,922 @@
+"""
+Test case for testing the gdbremote protocol.
+
+Tests run against debugserver and lldb-server (llgs).
+lldb-server tests run where the lldb-server exe is
+available.
+
+The tests are split between the LldbGdbServerTestCase and
+LldbGdbServerTestCase2 classes to avoid timeouts in the
+test suite.
+"""
+
+import binascii
+import itertools
+import struct
+
+import gdbremote_testcase
+import lldbgdbserverutils
+from lldbsuite.support import seven
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbdwarf import *
+from lldbsuite.test import lldbutil, lldbplatformutil
+
+
+class LldbGdbServerTestCase2(
+ gdbremote_testcase.GdbRemoteTestCaseBase, DwarfOpcodeParser
+):
+ @skipIfWindows # No pty support to test any inferior output
+ def test_m_packet_reads_memory(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ # This is the memory we will write into the inferior and then ensure we
+ # can read back with $m.
+ MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=[
+ "set-message:%s" % MEMORY_CONTENTS,
+ "get-data-address-hex:g_message",
+ "sleep:5",
+ ]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"data address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "message_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the message address.
+ self.assertIsNotNone(context.get("message_address"))
+ message_address = int(context.get("message_address"), 16)
+
+ # Grab contents from the inferior.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $m{0:x},{1:x}#00".format(
+ message_address, len(MEMORY_CONTENTS)
+ ),
+ {
+ "direction": "send",
+ "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
+ "capture": {1: "read_contents"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure what we read from inferior memory is what we wrote.
+ self.assertIsNotNone(context.get("read_contents"))
+ read_contents = seven.unhexlify(context.get("read_contents"))
+ self.assertEqual(read_contents, MEMORY_CONTENTS)
+
+ def test_qMemoryRegionInfo_is_supported(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+
+ # Ask if it supports $qMemoryRegionInfo.
+ self.test_sequence.add_log_lines(
+ ["read packet: $qMemoryRegionInfo#00", "send packet: $OK#00"], True
+ )
+ self.expect_gdbremote_sequence()
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:hello", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"code address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "code_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the code address.
+ self.assertIsNotNone(context.get("code_address"))
+ code_address = int(context.get("code_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(code_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure code address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("x", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(code_address, mem_region_dict)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_stack_address_as_rw(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-stack-address-hex:", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"stack address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "stack_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("stack_address"))
+ stack_address = int(context.get("stack_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(stack_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("w", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(stack_address, mem_region_dict)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_heap_address_as_rw(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-heap-address-hex:", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"heap address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "heap_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("heap_address"))
+ heap_address = int(context.get("heap_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(heap_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("w", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(heap_address, mem_region_dict)
+
+ def breakpoint_set_and_remove_work(self, want_hardware):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=[
+ "get-code-address-hex:hello",
+ "sleep:1",
+ "call-function:hello",
+ ]
+ )
+
+ # Run the process
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+ self.test_sequence.add_log_lines(
+ [ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the function call entry point.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"code address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "function_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info - we need endian of target to handle register
+ # value conversions.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+ (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)
+ self.assertIsNotNone(pc_lldb_reg_index)
+ self.assertIsNotNone(pc_reg_info)
+
+ # Grab the function address.
+ self.assertIsNotNone(context.get("function_address"))
+ function_address = int(context.get("function_address"), 16)
+
+ # Get current target architecture
+ target_arch = self.getArchitecture()
+
+ # Set the breakpoint.
+ if target_arch in ["arm", "arm64", "aarch64"]:
+ # TODO: Handle case when setting breakpoint in thumb code
+ BREAKPOINT_KIND = 4
+ else:
+ BREAKPOINT_KIND = 1
+
+ # Set default packet type to Z0 (software breakpoint)
+ z_packet_type = 0
+
+ # If hardware breakpoint is requested set packet type to Z1
+ if want_hardware:
+ z_packet_type = 1
+
+ self.reset_test_sequence()
+ self.add_set_breakpoint_packets(
+ function_address,
+ z_packet_type,
+ do_continue=True,
+ breakpoint_kind=BREAKPOINT_KIND,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the stop signal reported was the breakpoint signal number.
+ stop_signo = context.get("stop_signo")
+ self.assertIsNotNone(stop_signo)
+ self.assertEqual(int(stop_signo, 16), lldbutil.get_signal_number("SIGTRAP"))
+
+ # Ensure we did not receive any output. If the breakpoint was not set, we would
+ # see output (from a launched process with captured stdio) printing a hello, world message.
+ # That would indicate the breakpoint didn't take.
+ self.assertEqual(len(context["O_content"]), 0)
+
+ # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.
+ # This acts as a another validation on the register reading code.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Print the PC. This should match the breakpoint address.
+ "read packet: $p{0:x}#00".format(pc_lldb_reg_index),
+ # Capture $p results.
+ {
+ "direction": "send",
+ "regex": r"^\$([0-9a-fA-F]+)#",
+ "capture": {1: "p_response"},
+ },
+ ],
+ True,
+ )
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the PC is where we expect. Note response is in endianness of
+ # the inferior.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+
+ # Convert from target endian to int.
+ returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(
+ endian, p_response
+ )
+ self.assertEqual(returned_pc, function_address)
+
+ # Verify that a breakpoint remove and continue gets us the expected
+ # output.
+ self.reset_test_sequence()
+
+ # Add breakpoint remove packets
+ self.add_remove_breakpoint_packets(
+ function_address, z_packet_type, breakpoint_kind=BREAKPOINT_KIND
+ )
+
+ self.test_sequence.add_log_lines(
+ [
+ # Continue running.
+ "read packet: $c#63",
+ # We should now receive the output from the call.
+ {"type": "output_match", "regex": r"^hello, world\r\n$"},
+ # And wait for program completion.
+ {"direction": "send", "regex": r"^\$W00(.*)#[0-9a-fA-F]{2}$"},
+ ],
+ True,
+ )
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_software_breakpoint_set_and_remove_work(self):
+ if self.getArchitecture() == "arm":
+ # TODO: Handle case when setting breakpoint in thumb code
+ self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
+ else:
+ self.build()
+ self.set_inferior_startup_launch()
+ self.breakpoint_set_and_remove_work(want_hardware=False)
+
+ @skipUnlessPlatform(oslist=["linux"])
+ @skipIf(archs=no_match(["arm", "aarch64"]))
+ def test_hardware_breakpoint_set_and_remove_work(self):
+ if self.getArchitecture() == "arm":
+ # TODO: Handle case when setting breakpoint in thumb code
+ self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
+ else:
+ self.build()
+ self.set_inferior_startup_launch()
+ self.breakpoint_set_and_remove_work(want_hardware=True)
+
+ def get_qSupported_dict(self, features=[]):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_qSupported_packets(features)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Retrieve the qSupported features.
+ return self.parse_qSupported_response(context)
+
+ def test_qSupported_returns_known_stub_features(self):
+ supported_dict = self.get_qSupported_dict()
+ self.assertIsNotNone(supported_dict)
+ self.assertGreater(len(supported_dict), 0)
+
+ def test_qSupported_auvx(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:auxv:read", "-"), expected)
+
+ def test_qSupported_libraries_svr4(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:libraries-svr4:read", "-"), expected)
+
+ def test_qSupported_siginfo_read(self):
+ expected = (
+ "+" if lldbplatformutil.getPlatform() in ["freebsd", "linux"] else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:siginfo:read", "-"), expected)
+
+ def test_qSupported_QPassSignals(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("QPassSignals", "-"), expected)
+
+ @add_test_categories(["fork"])
+ def test_qSupported_fork_events(self):
+ supported_dict = self.get_qSupported_dict(["multiprocess+", "fork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "+")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_fork_events_without_multiprocess(self):
+ supported_dict = self.get_qSupported_dict(["fork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_vfork_events(self):
+ supported_dict = self.get_qSupported_dict(["multiprocess+", "vfork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "+")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_vfork_events_without_multiprocess(self):
+ supported_dict = self.get_qSupported_dict(["vfork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ # We need to be able to self.runCmd to get cpuinfo,
+ # which is not possible when using a remote platform.
+ @skipIfRemote
+ def test_qSupported_memory_tagging(self):
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(
+ supported_dict.get("memory-tagging", "-"),
+ "+" if self.isAArch64MTE() else "-",
+ )
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_written_M_content_reads_back_correctly(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ TEST_MESSAGE = "Hello, memory"
+
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=[
+ "set-message:xxxxxxxxxxxxxX",
+ "get-data-address-hex:g_message",
+ "sleep:1",
+ "print-message:",
+ ]
+ )
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"data address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "message_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the message address.
+ self.assertIsNotNone(context.get("message_address"))
+ message_address = int(context.get("message_address"), 16)
+
+ # Hex-encode the test message, adding null termination.
+ hex_encoded_message = seven.hexlify(TEST_MESSAGE)
+
+ # Write the message to the inferior. Verify that we can read it with the hex-encoded (m)
+ # and binary (x) memory read packets.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $M{0:x},{1:x}:{2}#00".format(
+ message_address, len(TEST_MESSAGE), hex_encoded_message
+ ),
+ "send packet: $OK#00",
+ "read packet: $m{0:x},{1:x}#00".format(
+ message_address, len(TEST_MESSAGE)
+ ),
+ "send packet: ${0}#00".format(hex_encoded_message),
+ "read packet: $x{0:x},{1:x}#00".format(
+ message_address, len(TEST_MESSAGE)
+ ),
+ "send packet: ${0}#00".format(TEST_MESSAGE),
+ "read packet: $m{0:x},4#00".format(message_address),
+ "send packet: ${0}#00".format(hex_encoded_message[0:8]),
+ "read packet: $x{0:x},4#00".format(message_address),
+ "send packet: ${0}#00".format(TEST_MESSAGE[0:4]),
+ "read packet: $c#63",
+ {
+ "type": "output_match",
+ "regex": r"^message: (.+)\r\n$",
+ "capture": {1: "printed_message"},
+ },
+ "send packet: $W00#00",
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure what we read from inferior memory is what we wrote.
+ printed_message = context.get("printed_message")
+ self.assertIsNotNone(printed_message)
+ self.assertEqual(printed_message, TEST_MESSAGE + "X")
+
+ # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
+ # Come back to this. I have the test rigged to verify that at least some
+ # of the bit-flip writes work.
+ def test_P_writes_all_gpr_registers(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start inferior debug session, grab all register info.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Process register infos.
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ # Process endian.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Pull out the register infos that we think we can bit flip
+ # successfully,.
+ gpr_reg_infos = [
+ reg_info
+ for reg_info in reg_infos
+ if self.is_bit_flippable_register(reg_info)
+ ]
+ self.assertGreater(len(gpr_reg_infos), 0)
+
+ # Write flipped bit pattern of existing value to each register.
+ (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(
+ gpr_reg_infos, endian
+ )
+ self.trace(
+ "successful writes: {}, failed writes: {}".format(
+ successful_writes, failed_writes
+ )
+ )
+ self.assertGreater(successful_writes, 0)
+
+ # Note: as of this moment, a hefty number of the GPR writes are failing
+ # with E32 (everything except rax-rdx, rdi, rsi, rbp).
+ @skipIfWindows
+ def test_P_and_p_thread_suffix_work(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Startup the inferior with three threads.
+ _, threads = self.launch_with_threads(3)
+
+ self.reset_test_sequence()
+ self.add_thread_suffix_request_packets()
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ reg_index = self.select_modifiable_register(reg_infos)
+ self.assertIsNotNone(reg_index)
+ reg_byte_size = int(reg_infos[reg_index]["bitsize"]) // 8
+ self.assertGreater(reg_byte_size, 0)
+
+ expected_reg_values = []
+ register_increment = 1
+ next_value = None
+
+ # Set the same register in each of 3 threads to a different value.
+ # Verify each one has the unique value.
+ for thread in threads:
+ # If we don't have a next value yet, start it with the initial read
+ # value + 1
+ if not next_value:
+ # Read pre-existing register value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $p{0:x};thread:{1:x}#00".format(
+ reg_index, thread
+ ),
+ {
+ "direction": "send",
+ "regex": r"^\$([0-9a-fA-F]+)#",
+ "capture": {1: "p_response"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Set the next value to use for writing as the increment plus
+ # current value.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ next_value = lldbgdbserverutils.unpack_register_hex_unsigned(
+ endian, p_response
+ )
+
+ # Set new value using P and thread suffix.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $P{0:x}={1};thread:{2:x}#00".format(
+ reg_index,
+ lldbgdbserverutils.pack_register_hex(
+ endian, next_value, byte_size=reg_byte_size
+ ),
+ thread,
+ ),
+ "send packet: $OK#00",
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Save the value we set.
+ expected_reg_values.append(next_value)
+
+ # Increment value for next thread to use (we want them all
+ # different so we can verify they wrote to each thread correctly
+ # next.)
+ next_value += register_increment
+
+ # Revisit each thread and verify they have the expected value set for
+ # the register we wrote.
+ thread_index = 0
+ for thread in threads:
+ # Read pre-existing register value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
+ {
+ "direction": "send",
+ "regex": r"^\$([0-9a-fA-F]+)#",
+ "capture": {1: "p_response"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Get the register value.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ read_value = lldbgdbserverutils.unpack_register_hex_unsigned(
+ endian, p_response
+ )
+
+ # Make sure we read back what we wrote.
+ self.assertEqual(read_value, expected_reg_values[thread_index])
+ thread_index += 1
+
+ @skipUnlessPlatform(oslist=["freebsd", "linux"])
+ @add_test_categories(["llgs"])
+ def test_qXfer_siginfo_read(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["thread:segfault", "thread:new", "sleep:10"]
+ )
+ self.test_sequence.add_log_lines(["read packet: $c#63"], True)
+ self.expect_gdbremote_sequence()
+
+ # Run until SIGSEGV comes in.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "signo", 2: "thread_id"},
+ }
+ ],
+ True,
+ )
+
+ # Figure out which thread crashed.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ self.assertEqual(
+ int(context["signo"], 16), lldbutil.get_signal_number("SIGSEGV")
+ )
+ crashing_thread = int(context["thread_id"], 16)
+
+ # Grab siginfo for the crashing thread.
+ self.reset_test_sequence()
+ self.add_process_info_collection_packets()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $Hg{:x}#00".format(crashing_thread),
+ "send packet: $OK#00",
+ "read packet: $qXfer:siginfo:read::0,80:#00",
+ {
+ "direction": "send",
+ "regex": re.compile(
+ r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL
+ ),
+ "capture": {1: "response_type", 2: "content_raw"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure we end up with all data in one packet.
+ self.assertEqual(context.get("response_type"), "l")
+
+ # Decode binary data.
+ content_raw = context.get("content_raw")
+ self.assertIsNotNone(content_raw)
+ content = self.decode_gdbremote_binary(content_raw).encode("latin1")
+
+ # Decode siginfo_t.
+ process_info = self.parse_process_info_response(context)
+ pad = ""
+ if process_info["ptrsize"] == "8":
+ pad = "i"
+ signo_idx = 0
+ errno_idx = 1
+ code_idx = 2
+ addr_idx = -1
+ SEGV_MAPERR = 1
+ if process_info["ostype"] == "linux":
+ # si_signo, si_errno, si_code, [pad], _sifields._sigfault.si_addr
+ format_str = "iii{}P".format(pad)
+ elif process_info["ostype"].startswith("freebsd"):
+ # si_signo, si_errno, si_code, si_pid, si_uid, si_status, si_addr
+ format_str = "iiiiiiP"
+ elif process_info["ostype"].startswith("netbsd"):
+ # _signo, _code, _errno, [pad], _reason._fault._addr
+ format_str = "iii{}P".format(pad)
+ errno_idx = 2
+ code_idx = 1
+ else:
+ assert False, "unknown ostype"
+
+ decoder = struct.Struct(format_str)
+ decoded = decoder.unpack(content[: decoder.size])
+ self.assertEqual(decoded[signo_idx], lldbutil.get_signal_number("SIGSEGV"))
+ self.assertEqual(decoded[errno_idx], 0) # si_errno
+ self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code
+ self.assertEqual(decoded[addr_idx], 0) # si_addr
>From b7dd4d0973ff79baa31fcec2ccd54c07183839e3 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 5 Mar 2025 10:07:13 -0800
Subject: [PATCH 2/9] Improve comment for reason we are splitting the tests
---
lldb/test/API/tools/lldb-server/TestLldbGdbServer.py | 8 +++++---
lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py | 8 +++++---
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index e2daff164eeeb..5a263a6e9d777 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -5,9 +5,11 @@
lldb-server tests run where the lldb-server exe is
available.
-The tests are split between the LldbGdbServerTestCase and
-LldbGdbServerTestCase2 classes to avoid timeouts in the
-test suite.
+When running these tests with lit, the test timeout applies
+to the time it takes to run the whole file, rather than each
+`test_` method. To avoid hitting timeouts we split the tests
+between the LldbGdbServerTestCase and LldbGdbServerTestCase2
+test classes.
"""
import binascii
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
index d40aa1fb792a0..65191dbb7c9a0 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
@@ -5,9 +5,11 @@
lldb-server tests run where the lldb-server exe is
available.
-The tests are split between the LldbGdbServerTestCase and
-LldbGdbServerTestCase2 classes to avoid timeouts in the
-test suite.
+When running these tests with lit, the test timeout applies
+to the time it takes to run the whole file, rather than each
+`test_` method. To avoid hitting timeouts we split the tests
+between the LldbGdbServerTestCase and LldbGdbServerTestCase2
+test classes.
"""
import binascii
>From b39e9ca48e0fe344c0be8820398cdb774cbcbe3f Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 16:15:06 -0700
Subject: [PATCH 3/9] Revert split of TestLldbGdbServer.py
---
.../tools/lldb-server/TestLldbGdbServer.py | 903 ++++++++++++++++-
.../tools/lldb-server/TestLldbGdbServer2.py | 924 ------------------
2 files changed, 898 insertions(+), 929 deletions(-)
delete mode 100644 lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index 5a263a6e9d777..12c97bc62dcef 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -5,11 +5,9 @@
lldb-server tests run where the lldb-server exe is
available.
-When running these tests with lit, the test timeout applies
-to the time it takes to run the whole file, rather than each
-`test_` method. To avoid hitting timeouts we split the tests
-between the LldbGdbServerTestCase and LldbGdbServerTestCase2
-test classes.
+This class will be broken into smaller test case classes by
+gdb remote packet functional areas. For now it contains
+the initial set of tests implemented.
"""
import binascii
@@ -613,3 +611,898 @@ def test_Hc_then_Csignal_signals_correct_thread_launch(self):
self.Hc_then_Csignal_signals_correct_thread(
lldbutil.get_signal_number("SIGSEGV")
)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_m_packet_reads_memory(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ # This is the memory we will write into the inferior and then ensure we
+ # can read back with $m.
+ MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=[
+ "set-message:%s" % MEMORY_CONTENTS,
+ "get-data-address-hex:g_message",
+ "sleep:5",
+ ]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"data address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "message_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the message address.
+ self.assertIsNotNone(context.get("message_address"))
+ message_address = int(context.get("message_address"), 16)
+
+ # Grab contents from the inferior.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $m{0:x},{1:x}#00".format(
+ message_address, len(MEMORY_CONTENTS)
+ ),
+ {
+ "direction": "send",
+ "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
+ "capture": {1: "read_contents"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure what we read from inferior memory is what we wrote.
+ self.assertIsNotNone(context.get("read_contents"))
+ read_contents = seven.unhexlify(context.get("read_contents"))
+ self.assertEqual(read_contents, MEMORY_CONTENTS)
+
+ def test_qMemoryRegionInfo_is_supported(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+
+ # Ask if it supports $qMemoryRegionInfo.
+ self.test_sequence.add_log_lines(
+ ["read packet: $qMemoryRegionInfo#00", "send packet: $OK#00"], True
+ )
+ self.expect_gdbremote_sequence()
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:hello", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"code address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "code_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the code address.
+ self.assertIsNotNone(context.get("code_address"))
+ code_address = int(context.get("code_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(code_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure code address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("x", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(code_address, mem_region_dict)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_stack_address_as_rw(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-stack-address-hex:", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"stack address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "stack_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("stack_address"))
+ stack_address = int(context.get("stack_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(stack_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("w", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(stack_address, mem_region_dict)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_heap_address_as_rw(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-heap-address-hex:", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"heap address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "heap_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("heap_address"))
+ heap_address = int(context.get("heap_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(heap_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("w", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(heap_address, mem_region_dict)
+
+ def breakpoint_set_and_remove_work(self, want_hardware):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=[
+ "get-code-address-hex:hello",
+ "sleep:1",
+ "call-function:hello",
+ ]
+ )
+
+ # Run the process
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+ self.test_sequence.add_log_lines(
+ [ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the function call entry point.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"code address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "function_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather process info - we need endian of target to handle register
+ # value conversions.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+ (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)
+ self.assertIsNotNone(pc_lldb_reg_index)
+ self.assertIsNotNone(pc_reg_info)
+
+ # Grab the function address.
+ self.assertIsNotNone(context.get("function_address"))
+ function_address = int(context.get("function_address"), 16)
+
+ # Get current target architecture
+ target_arch = self.getArchitecture()
+
+ # Set the breakpoint.
+ if target_arch in ["arm", "arm64", "aarch64"]:
+ # TODO: Handle case when setting breakpoint in thumb code
+ BREAKPOINT_KIND = 4
+ else:
+ BREAKPOINT_KIND = 1
+
+ # Set default packet type to Z0 (software breakpoint)
+ z_packet_type = 0
+
+ # If hardware breakpoint is requested set packet type to Z1
+ if want_hardware:
+ z_packet_type = 1
+
+ self.reset_test_sequence()
+ self.add_set_breakpoint_packets(
+ function_address,
+ z_packet_type,
+ do_continue=True,
+ breakpoint_kind=BREAKPOINT_KIND,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the stop signal reported was the breakpoint signal number.
+ stop_signo = context.get("stop_signo")
+ self.assertIsNotNone(stop_signo)
+ self.assertEqual(int(stop_signo, 16), lldbutil.get_signal_number("SIGTRAP"))
+
+ # Ensure we did not receive any output. If the breakpoint was not set, we would
+ # see output (from a launched process with captured stdio) printing a hello, world message.
+ # That would indicate the breakpoint didn't take.
+ self.assertEqual(len(context["O_content"]), 0)
+
+ # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.
+ # This acts as a another validation on the register reading code.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Print the PC. This should match the breakpoint address.
+ "read packet: $p{0:x}#00".format(pc_lldb_reg_index),
+ # Capture $p results.
+ {
+ "direction": "send",
+ "regex": r"^\$([0-9a-fA-F]+)#",
+ "capture": {1: "p_response"},
+ },
+ ],
+ True,
+ )
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the PC is where we expect. Note response is in endianness of
+ # the inferior.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+
+ # Convert from target endian to int.
+ returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(
+ endian, p_response
+ )
+ self.assertEqual(returned_pc, function_address)
+
+ # Verify that a breakpoint remove and continue gets us the expected
+ # output.
+ self.reset_test_sequence()
+
+ # Add breakpoint remove packets
+ self.add_remove_breakpoint_packets(
+ function_address, z_packet_type, breakpoint_kind=BREAKPOINT_KIND
+ )
+
+ self.test_sequence.add_log_lines(
+ [
+ # Continue running.
+ "read packet: $c#63",
+ # We should now receive the output from the call.
+ {"type": "output_match", "regex": r"^hello, world\r\n$"},
+ # And wait for program completion.
+ {"direction": "send", "regex": r"^\$W00(.*)#[0-9a-fA-F]{2}$"},
+ ],
+ True,
+ )
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_software_breakpoint_set_and_remove_work(self):
+ if self.getArchitecture() == "arm":
+ # TODO: Handle case when setting breakpoint in thumb code
+ self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
+ else:
+ self.build()
+ self.set_inferior_startup_launch()
+ self.breakpoint_set_and_remove_work(want_hardware=False)
+
+ @skipUnlessPlatform(oslist=["linux"])
+ @skipIf(archs=no_match(["arm", "aarch64"]))
+ def test_hardware_breakpoint_set_and_remove_work(self):
+ if self.getArchitecture() == "arm":
+ # TODO: Handle case when setting breakpoint in thumb code
+ self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
+ else:
+ self.build()
+ self.set_inferior_startup_launch()
+ self.breakpoint_set_and_remove_work(want_hardware=True)
+
+ def get_qSupported_dict(self, features=[]):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_qSupported_packets(features)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Retrieve the qSupported features.
+ return self.parse_qSupported_response(context)
+
+ def test_qSupported_returns_known_stub_features(self):
+ supported_dict = self.get_qSupported_dict()
+ self.assertIsNotNone(supported_dict)
+ self.assertGreater(len(supported_dict), 0)
+
+ def test_qSupported_auvx(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:auxv:read", "-"), expected)
+
+ def test_qSupported_libraries_svr4(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:libraries-svr4:read", "-"), expected)
+
+ def test_qSupported_siginfo_read(self):
+ expected = (
+ "+" if lldbplatformutil.getPlatform() in ["freebsd", "linux"] else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:siginfo:read", "-"), expected)
+
+ def test_qSupported_QPassSignals(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("QPassSignals", "-"), expected)
+
+ @add_test_categories(["fork"])
+ def test_qSupported_fork_events(self):
+ supported_dict = self.get_qSupported_dict(["multiprocess+", "fork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "+")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_fork_events_without_multiprocess(self):
+ supported_dict = self.get_qSupported_dict(["fork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_vfork_events(self):
+ supported_dict = self.get_qSupported_dict(["multiprocess+", "vfork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "+")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_vfork_events_without_multiprocess(self):
+ supported_dict = self.get_qSupported_dict(["vfork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ # We need to be able to self.runCmd to get cpuinfo,
+ # which is not possible when using a remote platform.
+ @skipIfRemote
+ def test_qSupported_memory_tagging(self):
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(
+ supported_dict.get("memory-tagging", "-"),
+ "+" if self.isAArch64MTE() else "-",
+ )
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_written_M_content_reads_back_correctly(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ TEST_MESSAGE = "Hello, memory"
+
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=[
+ "set-message:xxxxxxxxxxxxxX",
+ "get-data-address-hex:g_message",
+ "sleep:1",
+ "print-message:",
+ ]
+ )
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"data address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "message_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the message address.
+ self.assertIsNotNone(context.get("message_address"))
+ message_address = int(context.get("message_address"), 16)
+
+ # Hex-encode the test message, adding null termination.
+ hex_encoded_message = seven.hexlify(TEST_MESSAGE)
+
+ # Write the message to the inferior. Verify that we can read it with the hex-encoded (m)
+ # and binary (x) memory read packets.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $M{0:x},{1:x}:{2}#00".format(
+ message_address, len(TEST_MESSAGE), hex_encoded_message
+ ),
+ "send packet: $OK#00",
+ "read packet: $m{0:x},{1:x}#00".format(
+ message_address, len(TEST_MESSAGE)
+ ),
+ "send packet: ${0}#00".format(hex_encoded_message),
+ "read packet: $x{0:x},{1:x}#00".format(
+ message_address, len(TEST_MESSAGE)
+ ),
+ "send packet: ${0}#00".format(TEST_MESSAGE),
+ "read packet: $m{0:x},4#00".format(message_address),
+ "send packet: ${0}#00".format(hex_encoded_message[0:8]),
+ "read packet: $x{0:x},4#00".format(message_address),
+ "send packet: ${0}#00".format(TEST_MESSAGE[0:4]),
+ "read packet: $c#63",
+ {
+ "type": "output_match",
+ "regex": r"^message: (.+)\r\n$",
+ "capture": {1: "printed_message"},
+ },
+ "send packet: $W00#00",
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure what we read from inferior memory is what we wrote.
+ printed_message = context.get("printed_message")
+ self.assertIsNotNone(printed_message)
+ self.assertEqual(printed_message, TEST_MESSAGE + "X")
+
+ # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
+ # Come back to this. I have the test rigged to verify that at least some
+ # of the bit-flip writes work.
+ def test_P_writes_all_gpr_registers(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start inferior debug session, grab all register info.
+ procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Process register infos.
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ # Process endian.
+ process_info = self.parse_process_info_response(context)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ # Pull out the register infos that we think we can bit flip
+ # successfully,.
+ gpr_reg_infos = [
+ reg_info
+ for reg_info in reg_infos
+ if self.is_bit_flippable_register(reg_info)
+ ]
+ self.assertGreater(len(gpr_reg_infos), 0)
+
+ # Write flipped bit pattern of existing value to each register.
+ (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(
+ gpr_reg_infos, endian
+ )
+ self.trace(
+ "successful writes: {}, failed writes: {}".format(
+ successful_writes, failed_writes
+ )
+ )
+ self.assertGreater(successful_writes, 0)
+
+ # Note: as of this moment, a hefty number of the GPR writes are failing
+ # with E32 (everything except rax-rdx, rdi, rsi, rbp).
+ @skipIfWindows
+ def test_P_and_p_thread_suffix_work(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Startup the inferior with three threads.
+ _, threads = self.launch_with_threads(3)
+
+ self.reset_test_sequence()
+ self.add_thread_suffix_request_packets()
+ self.add_register_info_collection_packets()
+ self.add_process_info_collection_packets()
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ process_info = self.parse_process_info_response(context)
+ self.assertIsNotNone(process_info)
+ endian = process_info.get("endian")
+ self.assertIsNotNone(endian)
+
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+
+ reg_index = self.select_modifiable_register(reg_infos)
+ self.assertIsNotNone(reg_index)
+ reg_byte_size = int(reg_infos[reg_index]["bitsize"]) // 8
+ self.assertGreater(reg_byte_size, 0)
+
+ expected_reg_values = []
+ register_increment = 1
+ next_value = None
+
+ # Set the same register in each of 3 threads to a different value.
+ # Verify each one has the unique value.
+ for thread in threads:
+ # If we don't have a next value yet, start it with the initial read
+ # value + 1
+ if not next_value:
+ # Read pre-existing register value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $p{0:x};thread:{1:x}#00".format(
+ reg_index, thread
+ ),
+ {
+ "direction": "send",
+ "regex": r"^\$([0-9a-fA-F]+)#",
+ "capture": {1: "p_response"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Set the next value to use for writing as the increment plus
+ # current value.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ next_value = lldbgdbserverutils.unpack_register_hex_unsigned(
+ endian, p_response
+ )
+
+ # Set new value using P and thread suffix.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $P{0:x}={1};thread:{2:x}#00".format(
+ reg_index,
+ lldbgdbserverutils.pack_register_hex(
+ endian, next_value, byte_size=reg_byte_size
+ ),
+ thread,
+ ),
+ "send packet: $OK#00",
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Save the value we set.
+ expected_reg_values.append(next_value)
+
+ # Increment value for next thread to use (we want them all
+ # different so we can verify they wrote to each thread correctly
+ # next.)
+ next_value += register_increment
+
+ # Revisit each thread and verify they have the expected value set for
+ # the register we wrote.
+ thread_index = 0
+ for thread in threads:
+ # Read pre-existing register value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
+ {
+ "direction": "send",
+ "regex": r"^\$([0-9a-fA-F]+)#",
+ "capture": {1: "p_response"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Get the register value.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ read_value = lldbgdbserverutils.unpack_register_hex_unsigned(
+ endian, p_response
+ )
+
+ # Make sure we read back what we wrote.
+ self.assertEqual(read_value, expected_reg_values[thread_index])
+ thread_index += 1
+
+ @skipUnlessPlatform(oslist=["freebsd", "linux"])
+ @add_test_categories(["llgs"])
+ def test_qXfer_siginfo_read(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["thread:segfault", "thread:new", "sleep:10"]
+ )
+ self.test_sequence.add_log_lines(["read packet: $c#63"], True)
+ self.expect_gdbremote_sequence()
+
+ # Run until SIGSEGV comes in.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "signo", 2: "thread_id"},
+ }
+ ],
+ True,
+ )
+
+ # Figure out which thread crashed.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ self.assertEqual(
+ int(context["signo"], 16), lldbutil.get_signal_number("SIGSEGV")
+ )
+ crashing_thread = int(context["thread_id"], 16)
+
+ # Grab siginfo for the crashing thread.
+ self.reset_test_sequence()
+ self.add_process_info_collection_packets()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $Hg{:x}#00".format(crashing_thread),
+ "send packet: $OK#00",
+ "read packet: $qXfer:siginfo:read::0,80:#00",
+ {
+ "direction": "send",
+ "regex": re.compile(
+ r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL
+ ),
+ "capture": {1: "response_type", 2: "content_raw"},
+ },
+ ],
+ True,
+ )
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Ensure we end up with all data in one packet.
+ self.assertEqual(context.get("response_type"), "l")
+
+ # Decode binary data.
+ content_raw = context.get("content_raw")
+ self.assertIsNotNone(content_raw)
+ content = self.decode_gdbremote_binary(content_raw).encode("latin1")
+
+ # Decode siginfo_t.
+ process_info = self.parse_process_info_response(context)
+ pad = ""
+ if process_info["ptrsize"] == "8":
+ pad = "i"
+ signo_idx = 0
+ errno_idx = 1
+ code_idx = 2
+ addr_idx = -1
+ SEGV_MAPERR = 1
+ if process_info["ostype"] == "linux":
+ # si_signo, si_errno, si_code, [pad], _sifields._sigfault.si_addr
+ format_str = "iii{}P".format(pad)
+ elif process_info["ostype"].startswith("freebsd"):
+ # si_signo, si_errno, si_code, si_pid, si_uid, si_status, si_addr
+ format_str = "iiiiiiP"
+ elif process_info["ostype"].startswith("netbsd"):
+ # _signo, _code, _errno, [pad], _reason._fault._addr
+ format_str = "iii{}P".format(pad)
+ errno_idx = 2
+ code_idx = 1
+ else:
+ assert False, "unknown ostype"
+
+ decoder = struct.Struct(format_str)
+ decoded = decoder.unpack(content[: decoder.size])
+ self.assertEqual(decoded[signo_idx], lldbutil.get_signal_number("SIGSEGV"))
+ self.assertEqual(decoded[errno_idx], 0) # si_errno
+ self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code
+ self.assertEqual(decoded[addr_idx], 0) # si_addr
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
deleted file mode 100644
index 65191dbb7c9a0..0000000000000
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer2.py
+++ /dev/null
@@ -1,924 +0,0 @@
-"""
-Test case for testing the gdbremote protocol.
-
-Tests run against debugserver and lldb-server (llgs).
-lldb-server tests run where the lldb-server exe is
-available.
-
-When running these tests with lit, the test timeout applies
-to the time it takes to run the whole file, rather than each
-`test_` method. To avoid hitting timeouts we split the tests
-between the LldbGdbServerTestCase and LldbGdbServerTestCase2
-test classes.
-"""
-
-import binascii
-import itertools
-import struct
-
-import gdbremote_testcase
-import lldbgdbserverutils
-from lldbsuite.support import seven
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.lldbdwarf import *
-from lldbsuite.test import lldbutil, lldbplatformutil
-
-
-class LldbGdbServerTestCase2(
- gdbremote_testcase.GdbRemoteTestCaseBase, DwarfOpcodeParser
-):
- @skipIfWindows # No pty support to test any inferior output
- def test_m_packet_reads_memory(self):
- self.build()
- self.set_inferior_startup_launch()
- # This is the memory we will write into the inferior and then ensure we
- # can read back with $m.
- MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=[
- "set-message:%s" % MEMORY_CONTENTS,
- "get-data-address-hex:g_message",
- "sleep:5",
- ]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"data address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "message_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the message address.
- self.assertIsNotNone(context.get("message_address"))
- message_address = int(context.get("message_address"), 16)
-
- # Grab contents from the inferior.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $m{0:x},{1:x}#00".format(
- message_address, len(MEMORY_CONTENTS)
- ),
- {
- "direction": "send",
- "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
- "capture": {1: "read_contents"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Ensure what we read from inferior memory is what we wrote.
- self.assertIsNotNone(context.get("read_contents"))
- read_contents = seven.unhexlify(context.get("read_contents"))
- self.assertEqual(read_contents, MEMORY_CONTENTS)
-
- def test_qMemoryRegionInfo_is_supported(self):
- self.build()
- self.set_inferior_startup_launch()
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior()
-
- # Ask if it supports $qMemoryRegionInfo.
- self.test_sequence.add_log_lines(
- ["read packet: $qMemoryRegionInfo#00", "send packet: $OK#00"], True
- )
- self.expect_gdbremote_sequence()
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-code-address-hex:hello", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"code address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "code_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the code address.
- self.assertIsNotNone(context.get("code_address"))
- code_address = int(context.get("code_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(code_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure code address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("x", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(code_address, mem_region_dict)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_stack_address_as_rw(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-stack-address-hex:", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"stack address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "stack_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the address.
- self.assertIsNotNone(context.get("stack_address"))
- stack_address = int(context.get("stack_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(stack_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("w", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(stack_address, mem_region_dict)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_heap_address_as_rw(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-heap-address-hex:", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"heap address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "heap_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the address.
- self.assertIsNotNone(context.get("heap_address"))
- heap_address = int(context.get("heap_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(heap_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("w", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(heap_address, mem_region_dict)
-
- def breakpoint_set_and_remove_work(self, want_hardware):
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=[
- "get-code-address-hex:hello",
- "sleep:1",
- "call-function:hello",
- ]
- )
-
- # Run the process
- self.add_register_info_collection_packets()
- self.add_process_info_collection_packets()
- self.test_sequence.add_log_lines(
- [ # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the function call entry point.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"code address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "function_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Gather process info - we need endian of target to handle register
- # value conversions.
- process_info = self.parse_process_info_response(context)
- endian = process_info.get("endian")
- self.assertIsNotNone(endian)
-
- # Gather register info entries.
- reg_infos = self.parse_register_info_packets(context)
- (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)
- self.assertIsNotNone(pc_lldb_reg_index)
- self.assertIsNotNone(pc_reg_info)
-
- # Grab the function address.
- self.assertIsNotNone(context.get("function_address"))
- function_address = int(context.get("function_address"), 16)
-
- # Get current target architecture
- target_arch = self.getArchitecture()
-
- # Set the breakpoint.
- if target_arch in ["arm", "arm64", "aarch64"]:
- # TODO: Handle case when setting breakpoint in thumb code
- BREAKPOINT_KIND = 4
- else:
- BREAKPOINT_KIND = 1
-
- # Set default packet type to Z0 (software breakpoint)
- z_packet_type = 0
-
- # If hardware breakpoint is requested set packet type to Z1
- if want_hardware:
- z_packet_type = 1
-
- self.reset_test_sequence()
- self.add_set_breakpoint_packets(
- function_address,
- z_packet_type,
- do_continue=True,
- breakpoint_kind=BREAKPOINT_KIND,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Verify the stop signal reported was the breakpoint signal number.
- stop_signo = context.get("stop_signo")
- self.assertIsNotNone(stop_signo)
- self.assertEqual(int(stop_signo, 16), lldbutil.get_signal_number("SIGTRAP"))
-
- # Ensure we did not receive any output. If the breakpoint was not set, we would
- # see output (from a launched process with captured stdio) printing a hello, world message.
- # That would indicate the breakpoint didn't take.
- self.assertEqual(len(context["O_content"]), 0)
-
- # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.
- # This acts as a another validation on the register reading code.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- # Print the PC. This should match the breakpoint address.
- "read packet: $p{0:x}#00".format(pc_lldb_reg_index),
- # Capture $p results.
- {
- "direction": "send",
- "regex": r"^\$([0-9a-fA-F]+)#",
- "capture": {1: "p_response"},
- },
- ],
- True,
- )
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Verify the PC is where we expect. Note response is in endianness of
- # the inferior.
- p_response = context.get("p_response")
- self.assertIsNotNone(p_response)
-
- # Convert from target endian to int.
- returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(
- endian, p_response
- )
- self.assertEqual(returned_pc, function_address)
-
- # Verify that a breakpoint remove and continue gets us the expected
- # output.
- self.reset_test_sequence()
-
- # Add breakpoint remove packets
- self.add_remove_breakpoint_packets(
- function_address, z_packet_type, breakpoint_kind=BREAKPOINT_KIND
- )
-
- self.test_sequence.add_log_lines(
- [
- # Continue running.
- "read packet: $c#63",
- # We should now receive the output from the call.
- {"type": "output_match", "regex": r"^hello, world\r\n$"},
- # And wait for program completion.
- {"direction": "send", "regex": r"^\$W00(.*)#[0-9a-fA-F]{2}$"},
- ],
- True,
- )
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_software_breakpoint_set_and_remove_work(self):
- if self.getArchitecture() == "arm":
- # TODO: Handle case when setting breakpoint in thumb code
- self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
- else:
- self.build()
- self.set_inferior_startup_launch()
- self.breakpoint_set_and_remove_work(want_hardware=False)
-
- @skipUnlessPlatform(oslist=["linux"])
- @skipIf(archs=no_match(["arm", "aarch64"]))
- def test_hardware_breakpoint_set_and_remove_work(self):
- if self.getArchitecture() == "arm":
- # TODO: Handle case when setting breakpoint in thumb code
- self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})
- else:
- self.build()
- self.set_inferior_startup_launch()
- self.breakpoint_set_and_remove_work(want_hardware=True)
-
- def get_qSupported_dict(self, features=[]):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the stub and start/prep the inferior.
- procs = self.prep_debug_monitor_and_inferior()
- self.add_qSupported_packets(features)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Retrieve the qSupported features.
- return self.parse_qSupported_response(context)
-
- def test_qSupported_returns_known_stub_features(self):
- supported_dict = self.get_qSupported_dict()
- self.assertIsNotNone(supported_dict)
- self.assertGreater(len(supported_dict), 0)
-
- def test_qSupported_auvx(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:auxv:read", "-"), expected)
-
- def test_qSupported_libraries_svr4(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:libraries-svr4:read", "-"), expected)
-
- def test_qSupported_siginfo_read(self):
- expected = (
- "+" if lldbplatformutil.getPlatform() in ["freebsd", "linux"] else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:siginfo:read", "-"), expected)
-
- def test_qSupported_QPassSignals(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("QPassSignals", "-"), expected)
-
- @add_test_categories(["fork"])
- def test_qSupported_fork_events(self):
- supported_dict = self.get_qSupported_dict(["multiprocess+", "fork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
- self.assertEqual(supported_dict.get("fork-events", "-"), "+")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- @add_test_categories(["fork"])
- def test_qSupported_fork_events_without_multiprocess(self):
- supported_dict = self.get_qSupported_dict(["fork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- @add_test_categories(["fork"])
- def test_qSupported_vfork_events(self):
- supported_dict = self.get_qSupported_dict(["multiprocess+", "vfork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "+")
-
- @add_test_categories(["fork"])
- def test_qSupported_vfork_events_without_multiprocess(self):
- supported_dict = self.get_qSupported_dict(["vfork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- # We need to be able to self.runCmd to get cpuinfo,
- # which is not possible when using a remote platform.
- @skipIfRemote
- def test_qSupported_memory_tagging(self):
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(
- supported_dict.get("memory-tagging", "-"),
- "+" if self.isAArch64MTE() else "-",
- )
-
- @skipIfWindows # No pty support to test any inferior output
- def test_written_M_content_reads_back_correctly(self):
- self.build()
- self.set_inferior_startup_launch()
-
- TEST_MESSAGE = "Hello, memory"
-
- # Start up the stub and start/prep the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=[
- "set-message:xxxxxxxxxxxxxX",
- "get-data-address-hex:g_message",
- "sleep:1",
- "print-message:",
- ]
- )
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"data address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "message_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the message address.
- self.assertIsNotNone(context.get("message_address"))
- message_address = int(context.get("message_address"), 16)
-
- # Hex-encode the test message, adding null termination.
- hex_encoded_message = seven.hexlify(TEST_MESSAGE)
-
- # Write the message to the inferior. Verify that we can read it with the hex-encoded (m)
- # and binary (x) memory read packets.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $M{0:x},{1:x}:{2}#00".format(
- message_address, len(TEST_MESSAGE), hex_encoded_message
- ),
- "send packet: $OK#00",
- "read packet: $m{0:x},{1:x}#00".format(
- message_address, len(TEST_MESSAGE)
- ),
- "send packet: ${0}#00".format(hex_encoded_message),
- "read packet: $x{0:x},{1:x}#00".format(
- message_address, len(TEST_MESSAGE)
- ),
- "send packet: ${0}#00".format(TEST_MESSAGE),
- "read packet: $m{0:x},4#00".format(message_address),
- "send packet: ${0}#00".format(hex_encoded_message[0:8]),
- "read packet: $x{0:x},4#00".format(message_address),
- "send packet: ${0}#00".format(TEST_MESSAGE[0:4]),
- "read packet: $c#63",
- {
- "type": "output_match",
- "regex": r"^message: (.+)\r\n$",
- "capture": {1: "printed_message"},
- },
- "send packet: $W00#00",
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Ensure what we read from inferior memory is what we wrote.
- printed_message = context.get("printed_message")
- self.assertIsNotNone(printed_message)
- self.assertEqual(printed_message, TEST_MESSAGE + "X")
-
- # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
- # Come back to this. I have the test rigged to verify that at least some
- # of the bit-flip writes work.
- def test_P_writes_all_gpr_registers(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start inferior debug session, grab all register info.
- procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
- self.add_register_info_collection_packets()
- self.add_process_info_collection_packets()
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Process register infos.
- reg_infos = self.parse_register_info_packets(context)
- self.assertIsNotNone(reg_infos)
- self.add_lldb_register_index(reg_infos)
-
- # Process endian.
- process_info = self.parse_process_info_response(context)
- endian = process_info.get("endian")
- self.assertIsNotNone(endian)
-
- # Pull out the register infos that we think we can bit flip
- # successfully,.
- gpr_reg_infos = [
- reg_info
- for reg_info in reg_infos
- if self.is_bit_flippable_register(reg_info)
- ]
- self.assertGreater(len(gpr_reg_infos), 0)
-
- # Write flipped bit pattern of existing value to each register.
- (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(
- gpr_reg_infos, endian
- )
- self.trace(
- "successful writes: {}, failed writes: {}".format(
- successful_writes, failed_writes
- )
- )
- self.assertGreater(successful_writes, 0)
-
- # Note: as of this moment, a hefty number of the GPR writes are failing
- # with E32 (everything except rax-rdx, rdi, rsi, rbp).
- @skipIfWindows
- def test_P_and_p_thread_suffix_work(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Startup the inferior with three threads.
- _, threads = self.launch_with_threads(3)
-
- self.reset_test_sequence()
- self.add_thread_suffix_request_packets()
- self.add_register_info_collection_packets()
- self.add_process_info_collection_packets()
-
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- process_info = self.parse_process_info_response(context)
- self.assertIsNotNone(process_info)
- endian = process_info.get("endian")
- self.assertIsNotNone(endian)
-
- reg_infos = self.parse_register_info_packets(context)
- self.assertIsNotNone(reg_infos)
- self.add_lldb_register_index(reg_infos)
-
- reg_index = self.select_modifiable_register(reg_infos)
- self.assertIsNotNone(reg_index)
- reg_byte_size = int(reg_infos[reg_index]["bitsize"]) // 8
- self.assertGreater(reg_byte_size, 0)
-
- expected_reg_values = []
- register_increment = 1
- next_value = None
-
- # Set the same register in each of 3 threads to a different value.
- # Verify each one has the unique value.
- for thread in threads:
- # If we don't have a next value yet, start it with the initial read
- # value + 1
- if not next_value:
- # Read pre-existing register value.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $p{0:x};thread:{1:x}#00".format(
- reg_index, thread
- ),
- {
- "direction": "send",
- "regex": r"^\$([0-9a-fA-F]+)#",
- "capture": {1: "p_response"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Set the next value to use for writing as the increment plus
- # current value.
- p_response = context.get("p_response")
- self.assertIsNotNone(p_response)
- next_value = lldbgdbserverutils.unpack_register_hex_unsigned(
- endian, p_response
- )
-
- # Set new value using P and thread suffix.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $P{0:x}={1};thread:{2:x}#00".format(
- reg_index,
- lldbgdbserverutils.pack_register_hex(
- endian, next_value, byte_size=reg_byte_size
- ),
- thread,
- ),
- "send packet: $OK#00",
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Save the value we set.
- expected_reg_values.append(next_value)
-
- # Increment value for next thread to use (we want them all
- # different so we can verify they wrote to each thread correctly
- # next.)
- next_value += register_increment
-
- # Revisit each thread and verify they have the expected value set for
- # the register we wrote.
- thread_index = 0
- for thread in threads:
- # Read pre-existing register value.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- "read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),
- {
- "direction": "send",
- "regex": r"^\$([0-9a-fA-F]+)#",
- "capture": {1: "p_response"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Get the register value.
- p_response = context.get("p_response")
- self.assertIsNotNone(p_response)
- read_value = lldbgdbserverutils.unpack_register_hex_unsigned(
- endian, p_response
- )
-
- # Make sure we read back what we wrote.
- self.assertEqual(read_value, expected_reg_values[thread_index])
- thread_index += 1
-
- @skipUnlessPlatform(oslist=["freebsd", "linux"])
- @add_test_categories(["llgs"])
- def test_qXfer_siginfo_read(self):
- self.build()
- self.set_inferior_startup_launch()
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["thread:segfault", "thread:new", "sleep:10"]
- )
- self.test_sequence.add_log_lines(["read packet: $c#63"], True)
- self.expect_gdbremote_sequence()
-
- # Run until SIGSEGV comes in.
- self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "signo", 2: "thread_id"},
- }
- ],
- True,
- )
-
- # Figure out which thread crashed.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- self.assertEqual(
- int(context["signo"], 16), lldbutil.get_signal_number("SIGSEGV")
- )
- crashing_thread = int(context["thread_id"], 16)
-
- # Grab siginfo for the crashing thread.
- self.reset_test_sequence()
- self.add_process_info_collection_packets()
- self.test_sequence.add_log_lines(
- [
- "read packet: $Hg{:x}#00".format(crashing_thread),
- "send packet: $OK#00",
- "read packet: $qXfer:siginfo:read::0,80:#00",
- {
- "direction": "send",
- "regex": re.compile(
- r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL
- ),
- "capture": {1: "response_type", 2: "content_raw"},
- },
- ],
- True,
- )
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Ensure we end up with all data in one packet.
- self.assertEqual(context.get("response_type"), "l")
-
- # Decode binary data.
- content_raw = context.get("content_raw")
- self.assertIsNotNone(content_raw)
- content = self.decode_gdbremote_binary(content_raw).encode("latin1")
-
- # Decode siginfo_t.
- process_info = self.parse_process_info_response(context)
- pad = ""
- if process_info["ptrsize"] == "8":
- pad = "i"
- signo_idx = 0
- errno_idx = 1
- code_idx = 2
- addr_idx = -1
- SEGV_MAPERR = 1
- if process_info["ostype"] == "linux":
- # si_signo, si_errno, si_code, [pad], _sifields._sigfault.si_addr
- format_str = "iii{}P".format(pad)
- elif process_info["ostype"].startswith("freebsd"):
- # si_signo, si_errno, si_code, si_pid, si_uid, si_status, si_addr
- format_str = "iiiiiiP"
- elif process_info["ostype"].startswith("netbsd"):
- # _signo, _code, _errno, [pad], _reason._fault._addr
- format_str = "iii{}P".format(pad)
- errno_idx = 2
- code_idx = 1
- else:
- assert False, "unknown ostype"
-
- decoder = struct.Struct(format_str)
- decoded = decoder.unpack(content[: decoder.size])
- self.assertEqual(decoded[signo_idx], lldbutil.get_signal_number("SIGSEGV"))
- self.assertEqual(decoded[errno_idx], 0) # si_errno
- self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code
- self.assertEqual(decoded[addr_idx], 0) # si_addr
>From 9a92684b31f039884c5c741d230e46252ad69402 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 16:58:00 -0700
Subject: [PATCH 4/9] Split out qSupported tests
---
.../tools/lldb-server/TestLldbGdbServer.py | 91 ---------------
.../API/tools/lldb-server/supported/Makefile | 3 +
.../supported/TestGdbRemote_qSupported.py | 107 ++++++++++++++++++
.../API/tools/lldb-server/supported/main.c | 1 +
4 files changed, 111 insertions(+), 91 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-server/supported/Makefile
create mode 100644 lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
create mode 100644 lldb/test/API/tools/lldb-server/supported/main.c
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index 12c97bc62dcef..fa713d72924e1 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -1064,97 +1064,6 @@ def test_hardware_breakpoint_set_and_remove_work(self):
self.set_inferior_startup_launch()
self.breakpoint_set_and_remove_work(want_hardware=True)
- def get_qSupported_dict(self, features=[]):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the stub and start/prep the inferior.
- procs = self.prep_debug_monitor_and_inferior()
- self.add_qSupported_packets(features)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Retrieve the qSupported features.
- return self.parse_qSupported_response(context)
-
- def test_qSupported_returns_known_stub_features(self):
- supported_dict = self.get_qSupported_dict()
- self.assertIsNotNone(supported_dict)
- self.assertGreater(len(supported_dict), 0)
-
- def test_qSupported_auvx(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:auxv:read", "-"), expected)
-
- def test_qSupported_libraries_svr4(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:libraries-svr4:read", "-"), expected)
-
- def test_qSupported_siginfo_read(self):
- expected = (
- "+" if lldbplatformutil.getPlatform() in ["freebsd", "linux"] else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("qXfer:siginfo:read", "-"), expected)
-
- def test_qSupported_QPassSignals(self):
- expected = (
- "+"
- if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
- else "-"
- )
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(supported_dict.get("QPassSignals", "-"), expected)
-
- @add_test_categories(["fork"])
- def test_qSupported_fork_events(self):
- supported_dict = self.get_qSupported_dict(["multiprocess+", "fork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
- self.assertEqual(supported_dict.get("fork-events", "-"), "+")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- @add_test_categories(["fork"])
- def test_qSupported_fork_events_without_multiprocess(self):
- supported_dict = self.get_qSupported_dict(["fork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- @add_test_categories(["fork"])
- def test_qSupported_vfork_events(self):
- supported_dict = self.get_qSupported_dict(["multiprocess+", "vfork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "+")
-
- @add_test_categories(["fork"])
- def test_qSupported_vfork_events_without_multiprocess(self):
- supported_dict = self.get_qSupported_dict(["vfork-events+"])
- self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
- self.assertEqual(supported_dict.get("fork-events", "-"), "-")
- self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
-
- # We need to be able to self.runCmd to get cpuinfo,
- # which is not possible when using a remote platform.
- @skipIfRemote
- def test_qSupported_memory_tagging(self):
- supported_dict = self.get_qSupported_dict()
- self.assertEqual(
- supported_dict.get("memory-tagging", "-"),
- "+" if self.isAArch64MTE() else "-",
- )
@skipIfWindows # No pty support to test any inferior output
def test_written_M_content_reads_back_correctly(self):
diff --git a/lldb/test/API/tools/lldb-server/supported/Makefile b/lldb/test/API/tools/lldb-server/supported/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/supported/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py b/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
new file mode 100644
index 0000000000000..71f11ab630601
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
@@ -0,0 +1,107 @@
+import binascii
+import itertools
+import struct
+
+import gdbremote_testcase
+import lldbgdbserverutils
+from lldbsuite.support import seven
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbdwarf import *
+from lldbsuite.test import lldbutil, lldbplatformutil
+
+
+class TestGdbRemote_qSupported(
+ gdbremote_testcase.GdbRemoteTestCaseBase
+):
+ def get_qSupported_dict(self, features=[]):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the stub and start/prep the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+ self.add_qSupported_packets(features)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Retrieve the qSupported features.
+ return self.parse_qSupported_response(context)
+
+ def test_qSupported_returns_known_stub_features(self):
+ supported_dict = self.get_qSupported_dict()
+ self.assertIsNotNone(supported_dict)
+ self.assertGreater(len(supported_dict), 0)
+
+ def test_qSupported_auvx(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:auxv:read", "-"), expected)
+
+ def test_qSupported_libraries_svr4(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:libraries-svr4:read", "-"), expected)
+
+ def test_qSupported_siginfo_read(self):
+ expected = (
+ "+" if lldbplatformutil.getPlatform() in ["freebsd", "linux"] else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("qXfer:siginfo:read", "-"), expected)
+
+ def test_qSupported_QPassSignals(self):
+ expected = (
+ "+"
+ if lldbplatformutil.getPlatform() in ["freebsd", "linux", "netbsd"]
+ else "-"
+ )
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(supported_dict.get("QPassSignals", "-"), expected)
+
+ @add_test_categories(["fork"])
+ def test_qSupported_fork_events(self):
+ supported_dict = self.get_qSupported_dict(["multiprocess+", "fork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "+")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_fork_events_without_multiprocess(self):
+ supported_dict = self.get_qSupported_dict(["fork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_vfork_events(self):
+ supported_dict = self.get_qSupported_dict(["multiprocess+", "vfork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "+")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "+")
+
+ @add_test_categories(["fork"])
+ def test_qSupported_vfork_events_without_multiprocess(self):
+ supported_dict = self.get_qSupported_dict(["vfork-events+"])
+ self.assertEqual(supported_dict.get("multiprocess", "-"), "-")
+ self.assertEqual(supported_dict.get("fork-events", "-"), "-")
+ self.assertEqual(supported_dict.get("vfork-events", "-"), "-")
+
+ # We need to be able to self.runCmd to get cpuinfo,
+ # which is not possible when using a remote platform.
+ @skipIfRemote
+ def test_qSupported_memory_tagging(self):
+ supported_dict = self.get_qSupported_dict()
+ self.assertEqual(
+ supported_dict.get("memory-tagging", "-"),
+ "+" if self.isAArch64MTE() else "-",
+ )
diff --git a/lldb/test/API/tools/lldb-server/supported/main.c b/lldb/test/API/tools/lldb-server/supported/main.c
new file mode 100644
index 0000000000000..76e8197013aab
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/supported/main.c
@@ -0,0 +1 @@
+int main() { return 0; }
>From 1bf1a11bc7a9e5e82dcc5230ae3147a479a56f5b Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 17:15:55 -0700
Subject: [PATCH 5/9] Split out qMemoryRegion tests
---
.../TestGdbRemote_qMemoryRegion.py | 218 ++++++++++++++++++
.../tools/lldb-server/TestLldbGdbServer.py | 203 ----------------
2 files changed, 218 insertions(+), 203 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py b/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py
new file mode 100644
index 0000000000000..64559fb819f9d
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py
@@ -0,0 +1,218 @@
+import binascii
+import itertools
+import struct
+
+import gdbremote_testcase
+import lldbgdbserverutils
+from lldbsuite.support import seven
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbdwarf import *
+from lldbsuite.test import lldbutil, lldbplatformutil
+
+
+class TestGdbRemote_qMemoryRegion(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ def test_qMemoryRegionInfo_is_supported(self):
+ self.build()
+ self.set_inferior_startup_launch()
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior()
+
+ # Ask if it supports $qMemoryRegionInfo.
+ self.test_sequence.add_log_lines(
+ ["read packet: $qMemoryRegionInfo#00", "send packet: $OK#00"], True
+ )
+ self.expect_gdbremote_sequence()
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:hello", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"code address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "code_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the code address.
+ self.assertIsNotNone(context.get("code_address"))
+ code_address = int(context.get("code_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(code_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure code address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("x", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(code_address, mem_region_dict)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_stack_address_as_rw(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-stack-address-hex:", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"stack address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "stack_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("stack_address"))
+ stack_address = int(context.get("stack_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(stack_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("w", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(stack_address, mem_region_dict)
+
+ @skipIfWindows # No pty support to test any inferior output
+ def test_qMemoryRegionInfo_reports_heap_address_as_rw(self):
+ self.build()
+ self.set_inferior_startup_launch()
+
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-heap-address-hex:", "sleep:5"]
+ )
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#63",
+ # Match output line that prints the memory address of the message buffer within the inferior.
+ # Note we require launch-only testing so we can get inferior otuput.
+ {
+ "type": "output_match",
+ "regex": self.maybe_strict_output_regex(
+ r"heap address: 0x([0-9a-fA-F]+)\r\n"
+ ),
+ "capture": {1: "heap_address"},
+ },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(3)),
+ # And wait for the stop notification.
+ {
+ "direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "stop_signo", 2: "stop_thread_id"},
+ },
+ ],
+ True,
+ )
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("heap_address"))
+ heap_address = int(context.get("heap_address"), 16)
+
+ # Grab memory region info from the inferior.
+ self.reset_test_sequence()
+ self.add_query_memory_region_packets(heap_address)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ mem_region_dict = self.parse_memory_region_packet(context)
+
+ # Ensure there are no errors reported.
+ self.assertNotIn("error", mem_region_dict)
+
+ # Ensure address is readable and executable.
+ self.assertIn("permissions", mem_region_dict)
+ self.assertIn("r", mem_region_dict["permissions"])
+ self.assertIn("w", mem_region_dict["permissions"])
+
+ # Ensure the start address and size encompass the address we queried.
+ self.assert_address_within_memory_region(heap_address, mem_region_dict)
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index fa713d72924e1..e702a8b170f6d 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -688,209 +688,6 @@ def test_m_packet_reads_memory(self):
read_contents = seven.unhexlify(context.get("read_contents"))
self.assertEqual(read_contents, MEMORY_CONTENTS)
- def test_qMemoryRegionInfo_is_supported(self):
- self.build()
- self.set_inferior_startup_launch()
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior()
-
- # Ask if it supports $qMemoryRegionInfo.
- self.test_sequence.add_log_lines(
- ["read packet: $qMemoryRegionInfo#00", "send packet: $OK#00"], True
- )
- self.expect_gdbremote_sequence()
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_code_address_as_executable(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-code-address-hex:hello", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"code address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "code_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the code address.
- self.assertIsNotNone(context.get("code_address"))
- code_address = int(context.get("code_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(code_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure code address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("x", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(code_address, mem_region_dict)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_stack_address_as_rw(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-stack-address-hex:", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"stack address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "stack_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the address.
- self.assertIsNotNone(context.get("stack_address"))
- stack_address = int(context.get("stack_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(stack_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("w", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(stack_address, mem_region_dict)
-
- @skipIfWindows # No pty support to test any inferior output
- def test_qMemoryRegionInfo_reports_heap_address_as_rw(self):
- self.build()
- self.set_inferior_startup_launch()
-
- # Start up the inferior.
- procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-heap-address-hex:", "sleep:5"]
- )
-
- # Run the process
- self.test_sequence.add_log_lines(
- [
- # Start running after initial stop.
- "read packet: $c#63",
- # Match output line that prints the memory address of the message buffer within the inferior.
- # Note we require launch-only testing so we can get inferior otuput.
- {
- "type": "output_match",
- "regex": self.maybe_strict_output_regex(
- r"heap address: 0x([0-9a-fA-F]+)\r\n"
- ),
- "capture": {1: "heap_address"},
- },
- # Now stop the inferior.
- "read packet: {}".format(chr(3)),
- # And wait for the stop notification.
- {
- "direction": "send",
- "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
- "capture": {1: "stop_signo", 2: "stop_thread_id"},
- },
- ],
- True,
- )
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Grab the address.
- self.assertIsNotNone(context.get("heap_address"))
- heap_address = int(context.get("heap_address"), 16)
-
- # Grab memory region info from the inferior.
- self.reset_test_sequence()
- self.add_query_memory_region_packets(heap_address)
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
- mem_region_dict = self.parse_memory_region_packet(context)
-
- # Ensure there are no errors reported.
- self.assertNotIn("error", mem_region_dict)
-
- # Ensure address is readable and executable.
- self.assertIn("permissions", mem_region_dict)
- self.assertIn("r", mem_region_dict["permissions"])
- self.assertIn("w", mem_region_dict["permissions"])
-
- # Ensure the start address and size encompass the address we queried.
- self.assert_address_within_memory_region(heap_address, mem_region_dict)
def breakpoint_set_and_remove_work(self, want_hardware):
# Start up the inferior.
>From 5ee3a4c68cc24bd8794db7e5597250df440a56c6 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 17:32:19 -0700
Subject: [PATCH 6/9] Split out qRegisterInfo tests
---
.../TestGdbRemote_qRegisterInfo.py | 151 ++++++++++++++++++
.../tools/lldb-server/TestLldbGdbServer.py | 138 ----------------
2 files changed, 151 insertions(+), 138 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py b/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py
new file mode 100644
index 0000000000000..7f84ac323f181
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py
@@ -0,0 +1,151 @@
+import binascii
+import itertools
+import struct
+
+import gdbremote_testcase
+import lldbgdbserverutils
+from lldbsuite.support import seven
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbdwarf import *
+from lldbsuite.test import lldbutil, lldbplatformutil
+
+
+class TestGdbRemote_qMemoryRegion(gdbremote_testcase.GdbRemoteTestCaseBase):
+ def test_qRegisterInfo_returns_one_valid_result(self):
+ self.build()
+ self.prep_debug_monitor_and_inferior()
+ self.test_sequence.add_log_lines(
+ [
+ "read packet: $qRegisterInfo0#00",
+ {
+ "direction": "send",
+ "regex": r"^\$(.+);#[0-9A-Fa-f]{2}",
+ "capture": {1: "reginfo_0"},
+ },
+ ],
+ True,
+ )
+
+ # Run the stream
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ reg_info_packet = context.get("reginfo_0")
+ self.assertIsNotNone(reg_info_packet)
+ self.assert_valid_reg_info(
+ lldbgdbserverutils.parse_reg_info_response(reg_info_packet)
+ )
+
+ def test_qRegisterInfo_returns_all_valid_results(self):
+ self.build()
+ self.prep_debug_monitor_and_inferior()
+ self.add_register_info_collection_packets()
+
+ # Run the stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Validate that each register info returned validates.
+ for reg_info in self.parse_register_info_packets(context):
+ self.assert_valid_reg_info(reg_info)
+
+ def test_qRegisterInfo_contains_required_generics_debugserver(self):
+ self.build()
+ self.prep_debug_monitor_and_inferior()
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+
+ # Collect all generic registers found.
+ generic_regs = {
+ reg_info["generic"]: 1 for reg_info in reg_infos if "generic" in reg_info
+ }
+
+ # Ensure we have a program counter register.
+ self.assertIn("pc", generic_regs)
+
+ # Ensure we have a frame pointer register. PPC64le's FP is the same as SP
+ if self.getArchitecture() != "powerpc64le":
+ self.assertIn("fp", generic_regs)
+
+ # Ensure we have a stack pointer register.
+ self.assertIn("sp", generic_regs)
+
+ # Ensure we have a flags register. RISC-V doesn't have a flags register
+ if not self.isRISCV():
+ self.assertIn("flags", generic_regs)
+
+ if self.isRISCV() or self.isAArch64() or self.isARM():
+ # Specific register for a return address
+ self.assertIn("ra", generic_regs)
+
+ # Function arguments registers
+ for i in range(1, 5 if self.isARM() else 9):
+ self.assertIn(f"arg{i}", generic_regs)
+
+ def test_qRegisterInfo_contains_at_least_one_register_set(self):
+ self.build()
+ self.prep_debug_monitor_and_inferior()
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+
+ # Collect all register sets found.
+ register_sets = {
+ reg_info["set"]: 1 for reg_info in reg_infos if "set" in reg_info
+ }
+ self.assertGreaterEqual(len(register_sets), 1)
+
+ def targetHasAVX(self):
+ triple = self.dbg.GetSelectedPlatform().GetTriple()
+
+ # TODO other platforms, please implement this function
+ if not re.match(".*-.*-linux", triple):
+ return True
+
+ # Need to do something different for non-Linux/Android targets
+ if lldb.remote_platform:
+ self.runCmd('platform get-file "/proc/cpuinfo" "cpuinfo"')
+ cpuinfo_path = "cpuinfo"
+ self.addTearDownHook(lambda: os.unlink("cpuinfo"))
+ else:
+ cpuinfo_path = "/proc/cpuinfo"
+
+ f = open(cpuinfo_path, "r")
+ cpuinfo = f.read()
+ f.close()
+ return " avx " in cpuinfo
+
+ @expectedFailureAll(oslist=["windows"]) # no avx for now.
+ @skipIf(archs=no_match(["amd64", "i386", "x86_64"]))
+ @add_test_categories(["llgs"])
+ def test_qRegisterInfo_contains_avx_registers(self):
+ self.build()
+ self.prep_debug_monitor_and_inferior()
+ self.add_register_info_collection_packets()
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info entries.
+ reg_infos = self.parse_register_info_packets(context)
+
+ # Collect all generics found.
+ register_sets = {
+ reg_info["set"]: 1 for reg_info in reg_infos if "set" in reg_info
+ }
+ self.assertEqual(
+ self.targetHasAVX(), "Advanced Vector Extensions" in register_sets
+ )
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index e702a8b170f6d..0e9467f086101 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -130,144 +130,6 @@ def test_attach_commandline_continue_app_exits(self):
lldbgdbserverutils.process_is_running(procs["inferior"].pid, False)
)
- def test_qRegisterInfo_returns_one_valid_result(self):
- self.build()
- self.prep_debug_monitor_and_inferior()
- self.test_sequence.add_log_lines(
- [
- "read packet: $qRegisterInfo0#00",
- {
- "direction": "send",
- "regex": r"^\$(.+);#[0-9A-Fa-f]{2}",
- "capture": {1: "reginfo_0"},
- },
- ],
- True,
- )
-
- # Run the stream
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- reg_info_packet = context.get("reginfo_0")
- self.assertIsNotNone(reg_info_packet)
- self.assert_valid_reg_info(
- lldbgdbserverutils.parse_reg_info_response(reg_info_packet)
- )
-
- def test_qRegisterInfo_returns_all_valid_results(self):
- self.build()
- self.prep_debug_monitor_and_inferior()
- self.add_register_info_collection_packets()
-
- # Run the stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Validate that each register info returned validates.
- for reg_info in self.parse_register_info_packets(context):
- self.assert_valid_reg_info(reg_info)
-
- def test_qRegisterInfo_contains_required_generics_debugserver(self):
- self.build()
- self.prep_debug_monitor_and_inferior()
- self.add_register_info_collection_packets()
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Gather register info entries.
- reg_infos = self.parse_register_info_packets(context)
-
- # Collect all generic registers found.
- generic_regs = {
- reg_info["generic"]: 1 for reg_info in reg_infos if "generic" in reg_info
- }
-
- # Ensure we have a program counter register.
- self.assertIn("pc", generic_regs)
-
- # Ensure we have a frame pointer register. PPC64le's FP is the same as SP
- if self.getArchitecture() != "powerpc64le":
- self.assertIn("fp", generic_regs)
-
- # Ensure we have a stack pointer register.
- self.assertIn("sp", generic_regs)
-
- # Ensure we have a flags register. RISC-V doesn't have a flags register
- if not self.isRISCV():
- self.assertIn("flags", generic_regs)
-
- if self.isRISCV() or self.isAArch64() or self.isARM():
- # Specific register for a return address
- self.assertIn("ra", generic_regs)
-
- # Function arguments registers
- for i in range(1, 5 if self.isARM() else 9):
- self.assertIn(f"arg{i}", generic_regs)
-
- def test_qRegisterInfo_contains_at_least_one_register_set(self):
- self.build()
- self.prep_debug_monitor_and_inferior()
- self.add_register_info_collection_packets()
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Gather register info entries.
- reg_infos = self.parse_register_info_packets(context)
-
- # Collect all register sets found.
- register_sets = {
- reg_info["set"]: 1 for reg_info in reg_infos if "set" in reg_info
- }
- self.assertGreaterEqual(len(register_sets), 1)
-
- def targetHasAVX(self):
- triple = self.dbg.GetSelectedPlatform().GetTriple()
-
- # TODO other platforms, please implement this function
- if not re.match(".*-.*-linux", triple):
- return True
-
- # Need to do something different for non-Linux/Android targets
- if lldb.remote_platform:
- self.runCmd('platform get-file "/proc/cpuinfo" "cpuinfo"')
- cpuinfo_path = "cpuinfo"
- self.addTearDownHook(lambda: os.unlink("cpuinfo"))
- else:
- cpuinfo_path = "/proc/cpuinfo"
-
- f = open(cpuinfo_path, "r")
- cpuinfo = f.read()
- f.close()
- return " avx " in cpuinfo
-
- @expectedFailureAll(oslist=["windows"]) # no avx for now.
- @skipIf(archs=no_match(["amd64", "i386", "x86_64"]))
- @add_test_categories(["llgs"])
- def test_qRegisterInfo_contains_avx_registers(self):
- self.build()
- self.prep_debug_monitor_and_inferior()
- self.add_register_info_collection_packets()
-
- # Run the packet stream.
- context = self.expect_gdbremote_sequence()
- self.assertIsNotNone(context)
-
- # Gather register info entries.
- reg_infos = self.parse_register_info_packets(context)
-
- # Collect all generics found.
- register_sets = {
- reg_info["set"]: 1 for reg_info in reg_infos if "set" in reg_info
- }
- self.assertEqual(
- self.targetHasAVX(), "Advanced Vector Extensions" in register_sets
- )
-
def qThreadInfo_contains_thread(self):
procs = self.prep_debug_monitor_and_inferior()
self.add_threadinfo_collection_packets()
>From 5384d33bc4d99fdc6d47ba0f1bbcc5f66585f5c2 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 17:56:24 -0700
Subject: [PATCH 7/9] Split out fork resume tests
---
.../tools/lldb-server/TestGdbRemoteFork.py | 46 --------------
.../lldb-server/TestGdbRemoteForkResume.py | 62 +++++++++++++++++++
2 files changed, 62 insertions(+), 46 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
index ae98b4e0f6935..13c4a85f51f7f 100644
--- a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py
@@ -190,52 +190,6 @@ def test_vkill_parent(self):
def test_vkill_both(self):
self.vkill_test(kill_parent=True, kill_child=True)
- @add_test_categories(["fork"])
- def test_c_parent(self):
- self.resume_one_test(run_order=["parent", "parent"])
-
- @add_test_categories(["fork"])
- def test_c_child(self):
- self.resume_one_test(run_order=["child", "child"])
-
- @add_test_categories(["fork"])
- def test_c_parent_then_child(self):
- self.resume_one_test(run_order=["parent", "parent", "child", "child"])
-
- @add_test_categories(["fork"])
- def test_c_child_then_parent(self):
- self.resume_one_test(run_order=["child", "child", "parent", "parent"])
-
- @add_test_categories(["fork"])
- def test_c_interspersed(self):
- self.resume_one_test(run_order=["parent", "child", "parent", "child"])
-
- @add_test_categories(["fork"])
- def test_vCont_parent(self):
- self.resume_one_test(run_order=["parent", "parent"], use_vCont=True)
-
- @add_test_categories(["fork"])
- def test_vCont_child(self):
- self.resume_one_test(run_order=["child", "child"], use_vCont=True)
-
- @add_test_categories(["fork"])
- def test_vCont_parent_then_child(self):
- self.resume_one_test(
- run_order=["parent", "parent", "child", "child"], use_vCont=True
- )
-
- @add_test_categories(["fork"])
- def test_vCont_child_then_parent(self):
- self.resume_one_test(
- run_order=["child", "child", "parent", "parent"], use_vCont=True
- )
-
- @add_test_categories(["fork"])
- def test_vCont_interspersed(self):
- self.resume_one_test(
- run_order=["parent", "child", "parent", "child"], use_vCont=True
- )
-
@add_test_categories(["fork"])
def test_vCont_two_processes(self):
parent_pid, parent_tid, child_pid, child_tid = self.start_fork_test(
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py
new file mode 100644
index 0000000000000..13c62604d0a33
--- /dev/null
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py
@@ -0,0 +1,62 @@
+import random
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+from fork_testbase import GdbRemoteForkTestBase
+
+
+class TestGdbRemoteForkResume(GdbRemoteForkTestBase):
+ def setUp(self):
+ GdbRemoteForkTestBase.setUp(self)
+ if self.getPlatform() == "linux" and self.getArchitecture() in [
+ "arm",
+ "aarch64",
+ ]:
+ self.skipTest("Unsupported for Arm/AArch64 Linux")
+
+ @add_test_categories(["fork"])
+ def test_c_parent(self):
+ self.resume_one_test(run_order=["parent", "parent"])
+
+ @add_test_categories(["fork"])
+ def test_c_child(self):
+ self.resume_one_test(run_order=["child", "child"])
+
+ @add_test_categories(["fork"])
+ def test_c_parent_then_child(self):
+ self.resume_one_test(run_order=["parent", "parent", "child", "child"])
+
+ @add_test_categories(["fork"])
+ def test_c_child_then_parent(self):
+ self.resume_one_test(run_order=["child", "child", "parent", "parent"])
+
+ @add_test_categories(["fork"])
+ def test_c_interspersed(self):
+ self.resume_one_test(run_order=["parent", "child", "parent", "child"])
+
+ @add_test_categories(["fork"])
+ def test_vCont_parent(self):
+ self.resume_one_test(run_order=["parent", "parent"], use_vCont=True)
+
+ @add_test_categories(["fork"])
+ def test_vCont_child(self):
+ self.resume_one_test(run_order=["child", "child"], use_vCont=True)
+
+ @add_test_categories(["fork"])
+ def test_vCont_parent_then_child(self):
+ self.resume_one_test(
+ run_order=["parent", "parent", "child", "child"], use_vCont=True
+ )
+
+ @add_test_categories(["fork"])
+ def test_vCont_child_then_parent(self):
+ self.resume_one_test(
+ run_order=["child", "child", "parent", "parent"], use_vCont=True
+ )
+
+ @add_test_categories(["fork"])
+ def test_vCont_interspersed(self):
+ self.resume_one_test(
+ run_order=["parent", "child", "parent", "child"], use_vCont=True
+ )
>From 1307b323883b8abce510d96971eb5e2c578dc234 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 18:01:00 -0700
Subject: [PATCH 8/9] Cleanup imports
---
lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py | 2 --
.../API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py | 7 -------
.../API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py | 6 ------
.../lldb-server/supported/TestGdbRemote_qSupported.py | 7 -------
4 files changed, 22 deletions(-)
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py
index 13c62604d0a33..d7fe4d026dd8d 100644
--- a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkResume.py
@@ -1,5 +1,3 @@
-import random
-
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py b/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py
index 64559fb819f9d..391cc85492594 100644
--- a/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemote_qMemoryRegion.py
@@ -1,14 +1,7 @@
-import binascii
-import itertools
-import struct
-
import gdbremote_testcase
-import lldbgdbserverutils
-from lldbsuite.support import seven
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test.lldbdwarf import *
-from lldbsuite.test import lldbutil, lldbplatformutil
class TestGdbRemote_qMemoryRegion(gdbremote_testcase.GdbRemoteTestCaseBase):
diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py b/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py
index 7f84ac323f181..59ef3d379294d 100644
--- a/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemote_qRegisterInfo.py
@@ -1,14 +1,8 @@
-import binascii
-import itertools
-import struct
-
import gdbremote_testcase
import lldbgdbserverutils
-from lldbsuite.support import seven
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test.lldbdwarf import *
-from lldbsuite.test import lldbutil, lldbplatformutil
class TestGdbRemote_qMemoryRegion(gdbremote_testcase.GdbRemoteTestCaseBase):
diff --git a/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py b/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
index 71f11ab630601..f4be380adaabc 100644
--- a/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
+++ b/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
@@ -1,14 +1,7 @@
-import binascii
-import itertools
-import struct
-
import gdbremote_testcase
-import lldbgdbserverutils
-from lldbsuite.support import seven
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test.lldbdwarf import *
-from lldbsuite.test import lldbutil, lldbplatformutil
class TestGdbRemote_qSupported(
>From 2d0e40c45d5eaab313b91334065409bd869f0443 Mon Sep 17 00:00:00 2001
From: David Peixotto <peix at meta.com>
Date: Wed, 12 Mar 2025 20:03:52 -0700
Subject: [PATCH 9/9] Formatting
---
lldb/test/API/tools/lldb-server/TestLldbGdbServer.py | 2 --
.../tools/lldb-server/supported/TestGdbRemote_qSupported.py | 4 +---
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index 0e9467f086101..1bb5b8019274e 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -550,7 +550,6 @@ def test_m_packet_reads_memory(self):
read_contents = seven.unhexlify(context.get("read_contents"))
self.assertEqual(read_contents, MEMORY_CONTENTS)
-
def breakpoint_set_and_remove_work(self, want_hardware):
# Start up the inferior.
procs = self.prep_debug_monitor_and_inferior(
@@ -723,7 +722,6 @@ def test_hardware_breakpoint_set_and_remove_work(self):
self.set_inferior_startup_launch()
self.breakpoint_set_and_remove_work(want_hardware=True)
-
@skipIfWindows # No pty support to test any inferior output
def test_written_M_content_reads_back_correctly(self):
self.build()
diff --git a/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py b/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
index f4be380adaabc..28c07938410b9 100644
--- a/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
+++ b/lldb/test/API/tools/lldb-server/supported/TestGdbRemote_qSupported.py
@@ -4,9 +4,7 @@
from lldbsuite.test.lldbdwarf import *
-class TestGdbRemote_qSupported(
- gdbremote_testcase.GdbRemoteTestCaseBase
-):
+class TestGdbRemote_qSupported(gdbremote_testcase.GdbRemoteTestCaseBase):
def get_qSupported_dict(self, features=[]):
self.build()
self.set_inferior_startup_launch()
More information about the lldb-commits
mailing list