Skip to content

Commit b1b70f6

Browse files
gbuenoandradelabath
authored andcommitted
[lldb-server] Add setting to force 'g' packet use
Following up on https://reviews.llvm.org/D62221, this change introduces the settings plugin.process.gdb-remote.use-g-packet-for-reading. When they are on, 'g' packets are used for reading registers. Using 'g' packets can improve performance by reducing the number of packets exchanged between client and server when a large number of registers needs to be fetched. Differential revision: https://reviews.llvm.org/D62931
1 parent 118f783 commit b1b70f6

File tree

10 files changed

+127
-21
lines changed

10 files changed

+127
-21
lines changed

lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestGDBRemoteClient.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@
77

88
class TestGDBRemoteClient(GDBRemoteTestBase):
99

10+
class gPacketResponder(MockGDBServerResponder):
11+
def readRegisters(self):
12+
return '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
13+
14+
def setUp(self):
15+
super(TestGDBRemoteClient, self).setUp()
16+
self._initial_platform = lldb.DBG.GetSelectedPlatform()
17+
18+
def tearDown(self):
19+
lldb.DBG.SetSelectedPlatform(self._initial_platform)
20+
super(TestGDBRemoteClient, self).tearDown()
21+
1022
def test_connect(self):
1123
"""Test connecting to a remote gdb server"""
1224
target = self.createTarget("a.yaml")
@@ -37,3 +49,75 @@ def vAttach(self, pid):
3749
error = lldb.SBError()
3850
target.AttachToProcessWithID(lldb.SBListener(), 47, error)
3951
self.assertEquals(error_msg, error.GetCString())
52+
53+
def test_read_registers_using_g_packets(self):
54+
"""Test reading registers using 'g' packets (default behavior)"""
55+
self.server.responder = self.gPacketResponder()
56+
target = self.createTarget("a.yaml")
57+
process = self.connect(target)
58+
59+
self.assertEquals(1, self.server.responder.packetLog.count("g"))
60+
self.server.responder.packetLog = []
61+
self.read_registers(process)
62+
# Reading registers should not cause any 'p' packets to be exchanged.
63+
self.assertEquals(
64+
0, len([p for p in self.server.responder.packetLog if p.startswith("p")]))
65+
66+
def test_read_registers_using_p_packets(self):
67+
"""Test reading registers using 'p' packets"""
68+
self.dbg.HandleCommand(
69+
"settings set plugin.process.gdb-remote.use-g-packet-for-reading false")
70+
target = self.createTarget("a.yaml")
71+
process = self.connect(target)
72+
73+
self.read_registers(process)
74+
self.assertFalse("g" in self.server.responder.packetLog)
75+
self.assertGreater(
76+
len([p for p in self.server.responder.packetLog if p.startswith("p")]), 0)
77+
78+
def test_write_registers_using_P_packets(self):
79+
"""Test writing registers using 'P' packets (default behavior)"""
80+
self.server.responder = self.gPacketResponder()
81+
target = self.createTarget("a.yaml")
82+
process = self.connect(target)
83+
84+
self.write_registers(process)
85+
self.assertEquals(0, len(
86+
[p for p in self.server.responder.packetLog if p.startswith("G")]))
87+
self.assertGreater(
88+
len([p for p in self.server.responder.packetLog if p.startswith("P")]), 0)
89+
90+
def test_write_registers_using_G_packets(self):
91+
"""Test writing registers using 'G' packets"""
92+
93+
class MyResponder(self.gPacketResponder):
94+
def readRegister(self, register):
95+
# empty string means unsupported
96+
return ""
97+
98+
self.server.responder = MyResponder()
99+
target = self.createTarget("a.yaml")
100+
process = self.connect(target)
101+
102+
self.write_registers(process)
103+
self.assertEquals(0, len(
104+
[p for p in self.server.responder.packetLog if p.startswith("P")]))
105+
self.assertGreater(len(
106+
[p for p in self.server.responder.packetLog if p.startswith("G")]), 0)
107+
108+
def read_registers(self, process):
109+
self.for_each_gpr(
110+
process, lambda r: self.assertEquals("0x00000000", r.GetValue()))
111+
112+
def write_registers(self, process):
113+
self.for_each_gpr(
114+
process, lambda r: r.SetValueFromCString("0x00000000"))
115+
116+
def for_each_gpr(self, process, operation):
117+
registers = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetRegisters()
118+
self.assertGreater(registers.GetSize(), 0)
119+
regSet = registers[0]
120+
numChildren = regSet.GetNumChildren()
121+
self.assertGreater(numChildren, 0)
122+
for i in range(numChildren):
123+
operation(regSet.GetChildAtIndex(i))

lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/gdbclientutils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def respond(self, packet):
115115
return self.readRegister(int(regnum, 16))
116116
if packet[0] == "P":
117117
register, value = packet[1:].split("=")
118-
return self.readRegister(int(register, 16), value)
118+
return self.writeRegister(int(register, 16), value)
119119
if packet[0] == "m":
120120
addr, length = [int(x, 16) for x in packet[1:].split(',')]
121121
return self.readMemory(addr, length)

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -543,21 +543,24 @@ GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse(
543543
//
544544
// Takes a valid thread ID because p needs to apply to a thread.
545545
bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) {
546-
if (m_supports_p == eLazyBoolCalculate) {
547-
m_supports_p = eLazyBoolNo;
548-
StreamString payload;
549-
payload.PutCString("p0");
550-
StringExtractorGDBRemote response;
551-
if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload),
552-
response, false) ==
553-
PacketResult::Success &&
554-
response.IsNormalResponse()) {
555-
m_supports_p = eLazyBoolYes;
556-
}
557-
}
546+
if (m_supports_p == eLazyBoolCalculate)
547+
m_supports_p = GetThreadPacketSupported(tid, "p0");
558548
return m_supports_p;
559549
}
560550

551+
LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported(
552+
lldb::tid_t tid, llvm::StringRef packetStr) {
553+
StreamString payload;
554+
payload.PutCString(packetStr);
555+
StringExtractorGDBRemote response;
556+
if (SendThreadSpecificPacketAndWaitForResponse(
557+
tid, std::move(payload), response, false) == PacketResult::Success &&
558+
response.IsNormalResponse()) {
559+
return eLazyBoolYes;
560+
}
561+
return eLazyBoolNo;
562+
}
563+
561564
StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() {
562565
// Get information on all threads at one using the "jThreadsInfo" packet
563566
StructuredData::ObjectSP object_sp;

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
596596
Status GetQXferMemoryMapRegionInfo(lldb::addr_t addr,
597597
MemoryRegionInfo &region);
598598

599+
LazyBool GetThreadPacketSupported(lldb::tid_t tid, llvm::StringRef packetStr);
600+
599601
private:
600602
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient);
601603
};

lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ using namespace lldb_private::process_gdb_remote;
3131
// GDBRemoteRegisterContext constructor
3232
GDBRemoteRegisterContext::GDBRemoteRegisterContext(
3333
ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
34-
GDBRemoteDynamicRegisterInfo &reg_info, bool read_all_at_once)
34+
GDBRemoteDynamicRegisterInfo &reg_info, bool read_all_at_once,
35+
bool write_all_at_once)
3536
: RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info),
36-
m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once) {
37+
m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once),
38+
m_write_all_at_once(write_all_at_once) {
3739
// Resize our vector of bools to contain one bool for every register. We will
3840
// use these boolean values to know when a register value is valid in
3941
// m_reg_data.
@@ -333,7 +335,7 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
333335
{
334336
GDBRemoteClientBase::Lock lock(gdb_comm, false);
335337
if (lock) {
336-
if (m_read_all_at_once) {
338+
if (m_write_all_at_once) {
337339
// Invalidate all register values
338340
InvalidateIfNeeded(true);
339341

lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class GDBRemoteRegisterContext : public RegisterContext {
4141
public:
4242
GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
4343
GDBRemoteDynamicRegisterInfo &reg_info,
44-
bool read_all_at_once);
44+
bool read_all_at_once, bool write_all_at_once);
4545

4646
~GDBRemoteRegisterContext() override;
4747

@@ -114,6 +114,7 @@ class GDBRemoteRegisterContext : public RegisterContext {
114114
std::vector<bool> m_reg_valid;
115115
DataExtractor m_reg_data;
116116
bool m_read_all_at_once;
117+
bool m_write_all_at_once;
117118

118119
private:
119120
// Helper function for ReadRegisterBytes().

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ class PluginProperties : public Properties {
154154
nullptr, idx,
155155
g_processgdbremote_properties[idx].default_uint_value != 0);
156156
}
157+
158+
bool GetUseGPacketForReading() const {
159+
const uint32_t idx = ePropertyUseGPacketForReading;
160+
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
161+
}
157162
};
158163

159164
typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
@@ -309,6 +314,9 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
309314
GetGlobalPluginProperties()->GetPacketTimeout();
310315
if (timeout_seconds > 0)
311316
m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds));
317+
318+
m_use_g_packet_for_reading =
319+
GetGlobalPluginProperties()->GetUseGPacketForReading();
312320
}
313321

314322
// Destructor

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ class ProcessGDBRemote : public Process,
284284
lldb::CommandObjectSP m_command_sp;
285285
int64_t m_breakpoint_pc_offset;
286286
lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach
287+
bool m_use_g_packet_for_reading;
287288

288289
bool m_replay_mode;
289290
bool m_allow_flash_writes;

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ let Definition = "processgdbremote" in {
1313
Global,
1414
DefaultFalse,
1515
Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules.">;
16+
def UseGPacketForReading: Property<"use-g-packet-for-reading", "Boolean">,
17+
Global,
18+
DefaultTrue,
19+
Desc<"Specify if the server should use 'g' packets to read registers.">;
1620
}

lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,14 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) {
301301
if (process_sp) {
302302
ProcessGDBRemote *gdb_process =
303303
static_cast<ProcessGDBRemote *>(process_sp.get());
304-
// read_all_registers_at_once will be true if 'p' packet is not
305-
// supported.
304+
bool pSupported =
305+
gdb_process->GetGDBRemote().GetpPacketSupported(GetID());
306306
bool read_all_registers_at_once =
307-
!gdb_process->GetGDBRemote().GetpPacketSupported(GetID());
307+
!pSupported || gdb_process->m_use_g_packet_for_reading;
308+
bool write_all_registers_at_once = !pSupported;
308309
reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>(
309310
*this, concrete_frame_idx, gdb_process->m_register_info,
310-
read_all_registers_at_once);
311+
read_all_registers_at_once, write_all_registers_at_once);
311312
}
312313
} else {
313314
Unwind *unwinder = GetUnwinder();

0 commit comments

Comments
 (0)