+++ /dev/null
-from __future__ import print_function
-
-
-import gdbremote_testcase
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class TestGdbRemoteGPacket(gdbremote_testcase.GdbRemoteTestCaseBase):
-
- mydir = TestBase.compute_mydir(__file__)
-
- def run_test_g_packet(self):
- self.build()
- self.prep_debug_monitor_and_inferior()
- self.test_sequence.add_log_lines(
- ["read packet: $g#67",
- {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
- "capture": {1: "register_bank"}}],
- True)
- self.connect_to_debug_monitor()
- context = self.expect_gdbremote_sequence()
- register_bank = context.get("register_bank")
- self.assertTrue(register_bank[0] != 'E')
-
- self.test_sequence.add_log_lines(
- ["read packet: $G" + register_bank + "#00",
- {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
- "capture": {1: "G_reply"}}],
- True)
- context = self.expect_gdbremote_sequence()
- self.assertTrue(context.get("G_reply")[0] != 'E')
-
-
- @skipIfOutOfTreeDebugserver
- @debugserver_test
- @skipIfDarwinEmbedded
- def test_g_packet_debugserver(self):
- self.init_debugserver_test()
- self.run_test_g_packet()
self.assertIsNotNone(reg_infos)
self.assertTrue(len(reg_infos) > 0)
- inferior_exe_path = self.getBuildArtifact("a.out")
- Target = self.dbg.CreateTarget(inferior_exe_path)
- byte_order = Target.GetByteOrder()
+ byte_order = self.get_target_byte_order()
# Read value for each register.
reg_index = 0
commandline_args += ["--named-pipe", self.named_pipe_path]
return commandline_args
+ def get_target_byte_order(self):
+ inferior_exe_path = self.getBuildArtifact("a.out")
+ target = self.dbg.CreateTarget(inferior_exe_path)
+ return target.GetByteOrder()
+
def launch_debug_monitor(self, attach_pid=None, logfile=None):
# Create the command line.
commandline_args = self.get_debug_monitor_command_line_args(
--- /dev/null
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
--- /dev/null
+from __future__ import print_function
+
+
+import gdbremote_testcase
+import textwrap
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+def _extract_register_value(reg_info, reg_bank, byte_order, bytes_per_entry=8):
+ reg_offset = int(reg_info["offset"])*2
+ reg_byte_size = int(2 * int(reg_info["bitsize"]) / 8)
+ # Create slice with the contents of the register.
+ reg_slice = reg_bank[reg_offset:reg_offset+reg_byte_size]
+
+ reg_value = []
+ # Wrap slice according to bytes_per_entry.
+ for entry in textwrap.wrap(reg_slice, 2 * bytes_per_entry):
+ # Invert the bytes order if target uses little-endian.
+ if byte_order == lldb.eByteOrderLittle:
+ entry = "".join(reversed([entry[i:i+2] for i in range(0,
+ len(entry),2)]))
+ reg_value.append("0x" + entry)
+
+ return reg_value
+
+
+class TestGdbRemoteGPacket(gdbremote_testcase.GdbRemoteTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def run_test_g_packet(self):
+ self.build()
+ self.prep_debug_monitor_and_inferior()
+ self.test_sequence.add_log_lines(
+ ["read packet: $g#67",
+ {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
+ "capture": {1: "register_bank"}}],
+ True)
+ self.connect_to_debug_monitor()
+ context = self.expect_gdbremote_sequence()
+ register_bank = context.get("register_bank")
+ self.assertTrue(register_bank[0] != 'E')
+
+ self.test_sequence.add_log_lines(
+ ["read packet: $G" + register_bank + "#00",
+ {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
+ "capture": {1: "G_reply"}}],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertTrue(context.get("G_reply")[0] != 'E')
+
+ @skipIfOutOfTreeDebugserver
+ @debugserver_test
+ @skipIfDarwinEmbedded
+ def test_g_packet_debugserver(self):
+ self.init_debugserver_test()
+ self.run_test_g_packet()
+
+ @skipIf(archs=no_match(["x86_64"]))
+ def g_returns_correct_data(self, with_suffix):
+ procs = self.prep_debug_monitor_and_inferior()
+
+ self.add_register_info_collection_packets()
+ if with_suffix:
+ self.add_thread_suffix_request_packets()
+ self.add_threadinfo_collection_packets()
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Gather register info.
+ reg_infos = self.parse_register_info_packets(context)
+ self.assertIsNotNone(reg_infos)
+ self.add_lldb_register_index(reg_infos)
+ # Index register info entries by name.
+ reg_infos = {info['name']: info for info in reg_infos}
+
+ # Gather thread info.
+ if with_suffix:
+ threads = self.parse_threadinfo_packets(context)
+ self.assertIsNotNone(threads)
+ thread_id = threads[0]
+ self.assertIsNotNone(thread_id)
+ else:
+ thread_id = None
+
+ # Send vCont packet to resume the inferior.
+ self.test_sequence.add_log_lines(["read packet: $vCont;c#a8",
+ {"direction": "send",
+ "regex": r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$",
+ "capture": {1: "hex_exit_code"}},
+ ],
+ True)
+
+ # Send g packet to retrieve the register bank
+ if thread_id:
+ g_request = "read packet: $g;thread:{:x}#00".format(thread_id)
+ else:
+ g_request = "read packet: $g#00"
+ self.test_sequence.add_log_lines(
+ [g_request,
+ {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
+ "capture": {1: "register_bank"}}],
+ True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+ reg_bank = context.get("register_bank")
+ self.assertTrue(reg_bank[0] != 'E')
+
+ byte_order = self.get_target_byte_order()
+ get_reg_value = lambda reg_name : _extract_register_value(
+ reg_infos[reg_name], reg_bank, byte_order)
+
+ self.assertEqual(['0x0102030405060708'], get_reg_value('r8'))
+ self.assertEqual(['0x1112131415161718'], get_reg_value('r9'))
+ self.assertEqual(['0x2122232425262728'], get_reg_value('r10'))
+ self.assertEqual(['0x3132333435363738'], get_reg_value('r11'))
+ self.assertEqual(['0x4142434445464748'], get_reg_value('r12'))
+ self.assertEqual(['0x5152535455565758'], get_reg_value('r13'))
+ self.assertEqual(['0x6162636465666768'], get_reg_value('r14'))
+ self.assertEqual(['0x7172737475767778'], get_reg_value('r15'))
+
+ self.assertEqual(
+ ['0x020406080a0c0e01', '0x030507090b0d0f00'], get_reg_value('xmm8'))
+ self.assertEqual(
+ ['0x121416181a1c1e11', '0x131517191b1d1f10'], get_reg_value('xmm9'))
+ self.assertEqual(
+ ['0x222426282a2c2e21', '0x232527292b2d2f20'], get_reg_value('xmm10'))
+ self.assertEqual(
+ ['0x323436383a3c3e31', '0x333537393b3d3f30'], get_reg_value('xmm11'))
+ self.assertEqual(
+ ['0x424446484a4c4e41', '0x434547494b4d4f40'], get_reg_value('xmm12'))
+ self.assertEqual(
+ ['0x525456585a5c5e51', '0x535557595b5d5f50'], get_reg_value('xmm13'))
+ self.assertEqual(
+ ['0x626466686a6c6e61', '0x636567696b6d6f60'], get_reg_value('xmm14'))
+ self.assertEqual(
+ ['0x727476787a7c7e71', '0x737577797b7d7f70'], get_reg_value('xmm15'))
+
+ @llgs_test
+ def test_g_returns_correct_data_with_suffix_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.g_returns_correct_data(True)
+
+ @llgs_test
+ def test_g_returns_correct_data_no_suffix_llgs(self):
+ self.init_llgs_test()
+ self.build()
+ self.set_inferior_startup_launch()
+ self.g_returns_correct_data(False)
--- /dev/null
+#include <cstdint>
+
+struct alignas(16) xmm_t {
+ uint64_t a, b;
+};
+
+int main() {
+ uint64_t r8 = 0x0102030405060708;
+ uint64_t r9 = 0x1112131415161718;
+ uint64_t r10 = 0x2122232425262728;
+ uint64_t r11 = 0x3132333435363738;
+ uint64_t r12 = 0x4142434445464748;
+ uint64_t r13 = 0x5152535455565758;
+ uint64_t r14 = 0x6162636465666768;
+ uint64_t r15 = 0x7172737475767778;
+
+ xmm_t xmm8 = {0x020406080A0C0E01, 0x030507090B0D0F00};
+ xmm_t xmm9 = {0x121416181A1C1E11, 0x131517191B1D1F10};
+ xmm_t xmm10 = {0x222426282A2C2E21, 0x232527292B2D2F20};
+ xmm_t xmm11 = {0x323436383A3C3E31, 0x333537393B3D3F30};
+ xmm_t xmm12 = {0x424446484A4C4E41, 0x434547494B4D4F40};
+ xmm_t xmm13 = {0x525456585A5C5E51, 0x535557595B5D5F50};
+ xmm_t xmm14 = {0x626466686A6C6E61, 0x636567696B6D6F60};
+ xmm_t xmm15 = {0x727476787A7C7E71, 0x737577797B7D7F70};
+
+ asm volatile("movq %0, %%r8\n\t"
+ "movq %1, %%r9\n\t"
+ "movq %2, %%r10\n\t"
+ "movq %3, %%r11\n\t"
+ "movq %4, %%r12\n\t"
+ "movq %5, %%r13\n\t"
+ "movq %6, %%r14\n\t"
+ "movq %7, %%r15\n\t"
+ "\n\t"
+ "movaps %8, %%xmm8\n\t"
+ "movaps %9, %%xmm9\n\t"
+ "movaps %10, %%xmm10\n\t"
+ "movaps %11, %%xmm11\n\t"
+ "movaps %12, %%xmm12\n\t"
+ "movaps %13, %%xmm13\n\t"
+ "movaps %14, %%xmm14\n\t"
+ "movaps %15, %%xmm15\n\t"
+ "\n\t"
+ "int3"
+ :
+ : "g"(r8), "g"(r9), "g"(r10), "g"(r11), "g"(r12), "g"(r13),
+ "g"(r14), "g"(r15), "m"(xmm8), "m"(xmm9), "m"(xmm10),
+ "m"(xmm11), "m"(xmm12), "m"(xmm13), "m"(xmm14), "m"(xmm15)
+ : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+ "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13",
+ "%xmm14", "%xmm15");
+
+ return 0;
+}
StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
&GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
+ &GDBRemoteCommunicationServerLLGS::Handle_g);
+
RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
[this](StringExtractorGDBRemote packet, Status &error,
bool &interrupt, bool &quit) {
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Move past packet name.
+ packet.SetFilePos(strlen("g"));
+
+ // Get the thread to use.
+ NativeThreadProtocol *thread = GetThreadFromSuffix(packet);
+ if (!thread) {
+ LLDB_LOG(log, "failed, no thread available");
+ return SendErrorResponse(0x15);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContext ®_ctx = thread->GetRegisterContext();
+
+ std::vector<uint8_t> regs_buffer;
+ for (uint32_t reg_num = 0; reg_num < reg_ctx.GetUserRegisterCount();
+ ++reg_num) {
+ const RegisterInfo *reg_info = reg_ctx.GetRegisterInfoAtIndex(reg_num);
+
+ if (reg_info == nullptr) {
+ LLDB_LOG(log, "failed to get register info for register index {0}",
+ reg_num);
+ return SendErrorResponse(0x15);
+ }
+
+ if (reg_info->value_regs != nullptr)
+ continue; // skip registers that are contained in other registers
+
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info, reg_value);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to read register at index {0}", reg_num);
+ return SendErrorResponse(0x15);
+ }
+
+ if (reg_info->byte_offset + reg_info->byte_size >= regs_buffer.size())
+ // Resize the buffer to guarantee it can store the register offsetted
+ // data.
+ regs_buffer.resize(reg_info->byte_offset + reg_info->byte_size);
+
+ // Copy the register offsetted data to the buffer.
+ memcpy(regs_buffer.data() + reg_info->byte_offset, reg_value.GetBytes(),
+ reg_info->byte_size);
+ }
+
+ // Write the response.
+ StreamGDBRemote response;
+ response.PutBytesAsRawHex8(regs_buffer.data(), regs_buffer.size());
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet);
+ PacketResult Handle_g(StringExtractorGDBRemote &packet);
+
void SetCurrentThreadID(lldb::tid_t tid);
lldb::tid_t GetCurrentThreadID() const;
break;
case 'g':
- if (packet_size == 1)
- return eServerPacketType_g;
- break;
+ return eServerPacketType_g;
case 'G':
return eServerPacketType_G;