diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestGDBRemoteClient.py b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestGDBRemoteClient.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -37,3 +37,17 @@ error = lldb.SBError() target.AttachToProcessWithID(lldb.SBListener(), 47, error) self.assertEquals(error_msg, error.GetCString()) + + def test_get_registers_uses_g_packet(self): + """Test if the client uses a 'g' packet to read registers by default""" + class MyResponder(MockGDBServerResponder): + def readRegisters(self): + return '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + + self.server.responder = MyResponder() + + target = self.createTarget("a.yaml") + process = self.connect(target) + registers = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters() + self.assertGreater(registers.GetSize(), 0) + self.assertPacketLogContains(["g"]) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -234,6 +234,8 @@ bool GetpPacketSupported(lldb::tid_t tid); + bool GetgPacketSupported(lldb::tid_t tid); + bool GetxPacketSupported(); bool GetVAttachOrWaitSupported(); @@ -514,6 +516,7 @@ LazyBool m_prepare_for_reg_writing_reply; LazyBool m_supports_p; LazyBool m_supports_x; + LazyBool m_supports_g; LazyBool m_avoid_g_packets; LazyBool m_supports_QSaveRegisterState; LazyBool m_supports_qXfer_auxv_read; @@ -592,6 +595,8 @@ Status GetQXferMemoryMapRegionInfo(lldb::addr_t addr, MemoryRegionInfo ®ion); + LazyBool GetThreadPacketSupported(lldb::tid_t tid, llvm::StringRef packetStr); + private: DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); }; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -72,7 +72,7 @@ m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply(eLazyBoolCalculate), m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate), - m_avoid_g_packets(eLazyBoolCalculate), + m_supports_g(eLazyBoolCalculate), m_avoid_g_packets(eLazyBoolCalculate), m_supports_QSaveRegisterState(eLazyBoolCalculate), m_supports_qXfer_auxv_read(eLazyBoolCalculate), m_supports_qXfer_libraries_read(eLazyBoolCalculate), @@ -546,21 +546,30 @@ // // Takes a valid thread ID because p needs to apply to a thread. bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { - if (m_supports_p == eLazyBoolCalculate) { - m_supports_p = eLazyBoolNo; - StreamString payload; - payload.PutCString("p0"); - StringExtractorGDBRemote response; - if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), - response, false) == - PacketResult::Success && - response.IsNormalResponse()) { - m_supports_p = eLazyBoolYes; - } - } + if (m_supports_p == eLazyBoolCalculate) + m_supports_p = GetThreadPacketSupported(tid, "p0"); return m_supports_p; } +bool GDBRemoteCommunicationClient::GetgPacketSupported(lldb::tid_t tid) { + if (m_supports_g == eLazyBoolCalculate) + m_supports_g = GetThreadPacketSupported(tid, "g"); + return m_supports_g; +} + +LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported( + lldb::tid_t tid, llvm::StringRef packetStr) { + StreamString payload; + payload.PutCString(packetStr); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) == PacketResult::Success && + response.IsNormalResponse()) { + return eLazyBoolYes; + } + return eLazyBoolNo; +} + StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { // Get information on all threads at one using the "jThreadsInfo" packet StructuredData::ObjectSP object_sp; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -283,6 +283,7 @@ lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach + bool m_use_g_packet; bool m_replay_mode; bool m_allow_flash_writes; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -153,6 +153,11 @@ nullptr, idx, g_processgdbremote_properties[idx].default_uint_value != 0); } + + bool GetUseGPacket() const { + const uint32_t idx = ePropertyUseGPacket; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); + } }; typedef std::shared_ptr ProcessKDPPropertiesSP; @@ -347,6 +352,8 @@ GetGlobalPluginProperties()->GetPacketTimeout(); if (timeout_seconds > 0) m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); + + m_use_g_packet = GetGlobalPluginProperties()->GetUseGPacket(); } // Destructor diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -13,4 +13,8 @@ Global, DefaultFalse, Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules.">; + def UseGPacket: Property<"use-g-packet", "Boolean">, + Global, + DefaultTrue, + Desc<"Specify if the server should use 'g' packets.">; } 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 @@ -301,10 +301,13 @@ if (process_sp) { ProcessGDBRemote *gdb_process = static_cast(process_sp.get()); - // read_all_registers_at_once will be true if 'p' packet is not - // supported. + // read_all_registers_at_once will be true if the server supports 'g' + // packet and either the flag gdb_process->m_use_g_packet is true or 'p' + // packet is not supported. bool read_all_registers_at_once = - !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); + gdb_process->GetGDBRemote().GetgPacketSupported(GetID()) && + (gdb_process->m_use_g_packet || + !gdb_process->GetGDBRemote().GetpPacketSupported(GetID())); reg_ctx_sp = std::make_shared( *this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once); diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp --- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -128,6 +128,12 @@ ASSERT_EQ(0, memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register)); + async_result = std::async(std::launch::async, + [&] { return client.GetgPacketSupported(tid); }); + Handle_QThreadSuffixSupported(server, true); + HandlePacket(server, "g;thread:0047;", all_registers_hex); + ASSERT_TRUE(async_result.get()); + read_result = std::async(std::launch::async, [&] { return client.ReadAllRegisters(tid); }); HandlePacket(server, "g;thread:0047;", all_registers_hex);