Skip to content

Commit 13d0318

Browse files
authored
1 parent c242c7c commit 13d0318

File tree

5 files changed

+106
-24
lines changed

5 files changed

+106
-24
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ def respond(self, packet):
126126
if packet[0] == "m":
127127
addr, length = [int(x, 16) for x in packet[1:].split(",")]
128128
return self.readMemory(addr, length)
129+
if packet[0] == "x":
130+
addr, length = [int(x, 16) for x in packet[1:].split(",")]
131+
return self.x(addr, length)
129132
if packet[0] == "M":
130133
location, encoded_data = packet[1:].split(":")
131134
addr, length = [int(x, 16) for x in location.split(",")]
@@ -267,6 +270,9 @@ def writeRegister(self, register, value_hex):
267270
def readMemory(self, addr, length):
268271
return "00" * length
269272

273+
def x(self, addr, length):
274+
return ""
275+
270276
def writeMemory(self, addr, data_hex):
271277
return "OK"
272278

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

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
275275
m_supports_vCont_s = eLazyBoolCalculate;
276276
m_supports_vCont_S = eLazyBoolCalculate;
277277
m_supports_p = eLazyBoolCalculate;
278-
m_supports_x = eLazyBoolCalculate;
279278
m_supports_QSaveRegisterState = eLazyBoolCalculate;
280279
m_qHostInfo_is_valid = eLazyBoolCalculate;
281280
m_curr_pid_is_valid = eLazyBoolCalculate;
@@ -295,6 +294,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
295294
m_supports_qXfer_siginfo_read = eLazyBoolCalculate;
296295
m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
297296
m_uses_native_signals = eLazyBoolCalculate;
297+
m_x_packet_state.reset();
298298
m_supports_qProcessInfoPID = true;
299299
m_supports_qfProcessInfo = true;
300300
m_supports_qUserName = true;
@@ -348,6 +348,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
348348
m_supports_memory_tagging = eLazyBoolNo;
349349
m_supports_qSaveCore = eLazyBoolNo;
350350
m_uses_native_signals = eLazyBoolNo;
351+
m_x_packet_state.reset();
351352

352353
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
353354
// not, we assume no limit
@@ -401,6 +402,8 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
401402
m_supports_qSaveCore = eLazyBoolYes;
402403
else if (x == "native-signals+")
403404
m_uses_native_signals = eLazyBoolYes;
405+
else if (x == "binary-upload+")
406+
m_x_packet_state = xPacketState::Prefixed;
404407
// Look for a list of compressions in the features list e.g.
405408
// qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
406409
// deflate,lzma
@@ -715,19 +718,20 @@ Status GDBRemoteCommunicationClient::WriteMemoryTags(
715718
return status;
716719
}
717720

718-
bool GDBRemoteCommunicationClient::GetxPacketSupported() {
719-
if (m_supports_x == eLazyBoolCalculate) {
721+
GDBRemoteCommunicationClient::xPacketState
722+
GDBRemoteCommunicationClient::GetxPacketState() {
723+
if (!m_x_packet_state)
724+
GetRemoteQSupported();
725+
if (!m_x_packet_state) {
720726
StringExtractorGDBRemote response;
721-
m_supports_x = eLazyBoolNo;
722-
char packet[256];
723-
snprintf(packet, sizeof(packet), "x0,0");
724-
if (SendPacketAndWaitForResponse(packet, response) ==
727+
m_x_packet_state = xPacketState::Unimplemented;
728+
if (SendPacketAndWaitForResponse("x0,0", response) ==
725729
PacketResult::Success) {
726730
if (response.IsOKResponse())
727-
m_supports_x = eLazyBoolYes;
731+
m_x_packet_state = xPacketState::Bare;
728732
}
729733
}
730-
return m_supports_x;
734+
return *m_x_packet_state;
731735
}
732736

733737
lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) {

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,14 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
218218

219219
bool GetpPacketSupported(lldb::tid_t tid);
220220

221-
bool GetxPacketSupported();
221+
enum class xPacketState {
222+
Unimplemented,
223+
Prefixed, // Successful responses start with a 'b' character. This is the
224+
// style used by GDB.
225+
Bare, // No prefix, packets starts with the memory being read. This is
226+
// LLDB's original style.
227+
};
228+
xPacketState GetxPacketState();
222229

223230
bool GetVAttachOrWaitSupported();
224231

@@ -541,7 +548,6 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
541548
LazyBool m_attach_or_wait_reply = eLazyBoolCalculate;
542549
LazyBool m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
543550
LazyBool m_supports_p = eLazyBoolCalculate;
544-
LazyBool m_supports_x = eLazyBoolCalculate;
545551
LazyBool m_avoid_g_packets = eLazyBoolCalculate;
546552
LazyBool m_supports_QSaveRegisterState = eLazyBoolCalculate;
547553
LazyBool m_supports_qXfer_auxv_read = eLazyBoolCalculate;
@@ -561,6 +567,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
561567
LazyBool m_supports_memory_tagging = eLazyBoolCalculate;
562568
LazyBool m_supports_qSaveCore = eLazyBoolCalculate;
563569
LazyBool m_uses_native_signals = eLazyBoolCalculate;
570+
std::optional<xPacketState> m_x_packet_state;
564571

565572
bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
566573
m_supports_qUserName : 1, m_supports_qGroupName : 1,

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2609,11 +2609,15 @@ void ProcessGDBRemote::WillPublicStop() {
26092609
// Process Memory
26102610
size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
26112611
Status &error) {
2612+
using xPacketState = GDBRemoteCommunicationClient::xPacketState;
2613+
26122614
GetMaxMemorySize();
2613-
bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
2615+
xPacketState x_state = m_gdb_comm.GetxPacketState();
2616+
26142617
// M and m packets take 2 bytes for 1 byte of memory
2615-
size_t max_memory_size =
2616-
binary_memory_read ? m_max_memory_size : m_max_memory_size / 2;
2618+
size_t max_memory_size = x_state != xPacketState::Unimplemented
2619+
? m_max_memory_size
2620+
: m_max_memory_size / 2;
26172621
if (size > max_memory_size) {
26182622
// Keep memory read sizes down to a sane limit. This function will be
26192623
// called multiple times in order to complete the task by
@@ -2624,8 +2628,8 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
26242628
char packet[64];
26252629
int packet_len;
26262630
packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64,
2627-
binary_memory_read ? 'x' : 'm', (uint64_t)addr,
2628-
(uint64_t)size);
2631+
x_state != xPacketState::Unimplemented ? 'x' : 'm',
2632+
(uint64_t)addr, (uint64_t)size);
26292633
assert(packet_len + 1 < (int)sizeof(packet));
26302634
UNUSED_IF_ASSERT_DISABLED(packet_len);
26312635
StringExtractorGDBRemote response;
@@ -2634,19 +2638,25 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
26342638
GDBRemoteCommunication::PacketResult::Success) {
26352639
if (response.IsNormalResponse()) {
26362640
error.Clear();
2637-
if (binary_memory_read) {
2641+
if (x_state != xPacketState::Unimplemented) {
26382642
// The lower level GDBRemoteCommunication packet receive layer has
26392643
// already de-quoted any 0x7d character escaping that was present in
26402644
// the packet
26412645

2642-
size_t data_received_size = response.GetBytesLeft();
2643-
if (data_received_size > size) {
2644-
// Don't write past the end of BUF if the remote debug server gave us
2645-
// too much data for some reason.
2646-
data_received_size = size;
2646+
llvm::StringRef data_received = response.GetStringRef();
2647+
if (x_state == xPacketState::Prefixed &&
2648+
!data_received.consume_front("b")) {
2649+
error = Status::FromErrorStringWithFormatv(
2650+
"unexpected response to GDB server memory read packet '{0}': "
2651+
"'{1}'",
2652+
packet, data_received);
2653+
return 0;
26472654
}
2648-
memcpy(buf, response.GetStringRef().data(), data_received_size);
2649-
return data_received_size;
2655+
// Don't write past the end of BUF if the remote debug server gave us
2656+
// too much data for some reason.
2657+
size_t memcpy_size = std::min(size, data_received.size());
2658+
memcpy(buf, data_received.data(), memcpy_size);
2659+
return memcpy_size;
26502660
} else {
26512661
return response.GetHexBytes(
26522662
llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, size), '\xdd');
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import lldb
2+
from lldbsuite.support import seven
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test.decorators import *
5+
from lldbsuite.test.gdbclientutils import *
6+
from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
7+
8+
9+
class TestReadMemory(GDBRemoteTestBase):
10+
def test_x_with_prefix(self):
11+
class MyResponder(MockGDBServerResponder):
12+
def qSupported(self, client_features):
13+
# binary-upload+ indicates we use the gdb style of x packets
14+
return super().qSupported(client_features) + ";binary-upload+"
15+
16+
def x(self, addr, length):
17+
return "bfoobar" if addr == 0x1000 else "E01"
18+
19+
self.server.responder = MyResponder()
20+
target = self.dbg.CreateTargetWithFileAndTargetTriple("", "x86_64-pc-linux")
21+
process = self.connect(target)
22+
23+
error = lldb.SBError()
24+
self.assertEqual(b"foobar", process.ReadMemory(0x1000, 10, error))
25+
26+
def test_x_bare(self):
27+
class MyResponder(MockGDBServerResponder):
28+
def x(self, addr, length):
29+
# The OK response indicates we use the old lldb style.
30+
if addr == 0 and length == 0:
31+
return "OK"
32+
return "foobar" if addr == 0x1000 else "E01"
33+
34+
self.server.responder = MyResponder()
35+
target = self.dbg.CreateTargetWithFileAndTargetTriple("", "x86_64-pc-linux")
36+
process = self.connect(target)
37+
38+
error = lldb.SBError()
39+
self.assertEqual(b"foobar", process.ReadMemory(0x1000, 10, error))
40+
41+
def test_m_fallback(self):
42+
class MyResponder(MockGDBServerResponder):
43+
def x(self, addr, length):
44+
# If `x` is unsupported, we should fall back to `m`.
45+
return ""
46+
47+
def readMemory(self, addr, length):
48+
return seven.hexlify("foobar") if addr == 0x1000 else "E01"
49+
50+
self.server.responder = MyResponder()
51+
target = self.dbg.CreateTargetWithFileAndTargetTriple("", "x86_64-pc-linux")
52+
process = self.connect(target)
53+
54+
error = lldb.SBError()
55+
self.assertEqual(b"foobar", process.ReadMemory(0x1000, 10, error))

0 commit comments

Comments
 (0)