diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py @@ -545,8 +545,7 @@ self.set_inferior_startup_attach() self.qThreadInfo_matches_qC() - def p_returns_correct_data_size_for_each_qRegisterInfo(self): - procs = self.prep_debug_monitor_and_inferior() + def generateValidRegisterInfoEntries(self): self.add_register_info_collection_packets() # Run the packet stream. @@ -563,7 +562,6 @@ byte_order = Target.GetByteOrder() # Read value for each register. - reg_index = 0 for reg_info in reg_infos: # Skip registers that don't have a register set. For x86, these are # the DRx registers, which have no LLDB-kind register number and thus @@ -572,6 +570,49 @@ if not "set" in reg_info: continue + if "dynamic_size_dwarf_expr_bytes" in reg_info: + self.updateRegInfoBitsize(reg_info, byte_order) + + yield reg_info + + def assertRegisterValue(self, expected, reg_info, reg_bank): + reg_offset = int(reg_info["offset"])*2 + reg_byte_size = int(2 * int(reg_info["bitsize"]) / 8) + + # Extract the register from the bank and verify it is equal to expected. + self.assertEqual(expected, reg_bank[reg_offset:reg_offset+reg_byte_size]) + + def g_returns_correct_data(self): + procs = self.prep_debug_monitor_and_inferior() + + # Get register bank using 'g' packet + self.test_sequence.add_log_lines( + ["read packet: $g#67", + {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$", + "capture": {1: "register_bank"}}], + True) + context = self.expect_gdbremote_sequence() + reg_bank = context.get("register_bank") + self.assertTrue(reg_bank[0] != 'E') + + reg_infos = { + info['name']: info for info in self.generateValidRegisterInfoEntries()} + + self.assertRegisterValue('0000000000000000', reg_infos['r8'], reg_bank) + self.assertRegisterValue('0000000000000000', reg_infos['r9'], reg_bank) + self.assertRegisterValue('0000000000000000', reg_infos['r10'], reg_bank) + + @llgs_test + def test_g_returns_correct_data(self): + self.init_llgs_test() + self.build() + self.set_inferior_startup_launch() + self.g_returns_correct_data() + + def p_returns_correct_data_size_for_each_qRegisterInfo(self): + procs = self.prep_debug_monitor_and_inferior() + + for reg_index, reg_info in enumerate(self.generateValidRegisterInfoEntries()): # Clear existing packet expectations. self.reset_test_sequence() @@ -587,13 +628,8 @@ p_response = context.get("p_response") self.assertIsNotNone(p_response) - if "dynamic_size_dwarf_expr_bytes" in reg_info: - self.updateRegInfoBitsize(reg_info, byte_order) self.assertEqual(len(p_response), 2 * int(reg_info["bitsize"]) / 8) - # Increment loop - reg_index += 1 - @debugserver_test @skipIfDarwinEmbedded # lldb-server tests not updated to work on ios etc yet def test_p_returns_correct_data_size_for_each_qRegisterInfo_launch_debugserver( diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -178,6 +178,8 @@ PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet); + PacketResult Handle_g(StringExtractorGDBRemote &packet); + void SetCurrentThreadID(lldb::tid_t tid); lldb::tid_t GetCurrentThreadID() const; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -187,6 +187,9 @@ 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) { @@ -1891,6 +1894,68 @@ return SendPacketNoLock("l"); } +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(); + + // As the register offsets are not necessarily sorted, + // use a map to store all registers data. + std::map 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); + } + + // Write the register data to the buffer. + const uint8_t *const data = + reinterpret_cast(reg_value.GetBytes()); + for (uint32_t i = 0; i < reg_info->byte_size; ++i) + regs_buffer[reg_info->byte_offset + i] = data[i]; + } + + // Write the response. + StreamGDBRemote response; + uint32_t next_pos = 0; + for (const auto &it : regs_buffer) { + // Populate the gap between the last and the current position + // with zeroes. + while (next_pos++ < it.first) + response.PutHex8(0); + + response.PutHex8(it.second); + } + + return SendPacketNoLock(response.GetString()); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -377,9 +377,7 @@ break; case 'g': - if (packet_size == 1) - return eServerPacketType_g; - break; + return eServerPacketType_g; case 'G': return eServerPacketType_G;