diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteGPacket.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteGPacket.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteGPacket.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteGPacket.py @@ -11,31 +11,39 @@ mydir = TestBase.compute_mydir(__file__) - def run_test_g_packet(self): + def run_test_g_packet(self, read, write): 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') + if read: + 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() + register_bank = context.get("register_bank") + self.assertTrue(register_bank[0] != 'E') + + if write: + 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.run_test_g_packet(read=True, write=True) + + @llgs_test + @skipIfDarwinEmbedded + def test_g_packet_llgs(self): + self.init_llgs_test() + self.run_test_g_packet(read=True, write=False) 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/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -303,10 +303,17 @@ if (process_sp) { ProcessGDBRemote *gdb_process = static_cast(process_sp.get()); + +#ifdef LLDB_REMOTE_SHOULD_READ_ALL_REGISTERS_AT_ONCE + // Always fetch the registers at once when the flag has been defined. + bool read_all_registers_at_once = true; +#else // read_all_registers_at_once will be true if 'p' packet is not // supported. bool read_all_registers_at_once = !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); +#endif + reg_ctx_sp = std::make_shared( *this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once); 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;