Skip to content

Commit

Permalink
lldb-server: add support for binary memory reads
Browse files Browse the repository at this point in the history
Summary:
This commit adds support for binary memory reads ($x) to lldb-server. It also removes the "0x"
prefix from the $x client packet, to make it more compatible with the old $m packet. This allows
us to use almost the same code for handling both packet types. I have verified that debugserver
correctly handles $x packets even without the leading "0x". I have added a test which verifies
that the stub returns the same memory contents for both kinds of memory reads ($x and $m).

Reviewers: tberghammer, jasonmolenda

Subscribers: iancottrell, lldb-commits

Differential Revision: http://reviews.llvm.org/D13695

llvm-svn: 250295
  • Loading branch information
labath committed Oct 14, 2015
1 parent c888e19 commit 3bf1125
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 14 deletions.
Expand Up @@ -113,7 +113,7 @@ GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers()
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
&GDBRemoteCommunicationServerLLGS::Handle_interrupt);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_m,
&GDBRemoteCommunicationServerLLGS::Handle_m);
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
&GDBRemoteCommunicationServerLLGS::Handle_M);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
Expand Down Expand Up @@ -164,6 +164,8 @@ GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers()
&GDBRemoteCommunicationServerLLGS::Handle_vCont);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont_actions,
&GDBRemoteCommunicationServerLLGS::Handle_vCont_actions);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_x,
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z,
&GDBRemoteCommunicationServerLLGS::Handle_Z);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
Expand Down Expand Up @@ -1975,7 +1977,7 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &pa
}

GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet)
GDBRemoteCommunicationServerLLGS::Handle_memory_read(StringExtractorGDBRemote &packet)
{
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));

Expand Down Expand Up @@ -2008,7 +2010,7 @@ GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet)
{
if (log)
log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet", __FUNCTION__);
return PacketResult::Success;
return SendOKResponse();
}

// Allocate the response buffer.
Expand All @@ -2035,8 +2037,16 @@ GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet)
}

StreamGDBRemote response;
for (size_t i = 0; i < bytes_read; ++i)
response.PutHex8(buf[i]);
packet.SetFilePos(0);
char kind = packet.GetChar('?');
if (kind == 'x')
response.PutEscapedBytes(buf.data(), byte_count);
else
{
assert(kind == 'm');
for (size_t i = 0; i < bytes_read; ++i)
response.PutHex8(buf[i]);
}

return SendPacketNoLock(response.GetData(), response.GetSize());
}
Expand Down
Expand Up @@ -202,8 +202,9 @@ class GDBRemoteCommunicationServerLLGS :
PacketResult
Handle_interrupt (StringExtractorGDBRemote &packet);

// Handles $m and $x packets.
PacketResult
Handle_m (StringExtractorGDBRemote &packet);
Handle_memory_read (StringExtractorGDBRemote &packet);

PacketResult
Handle_M (StringExtractorGDBRemote &packet);
Expand Down
10 changes: 2 additions & 8 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Expand Up @@ -3043,14 +3043,8 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro
char packet[64];
int packet_len;
bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
if (binary_memory_read)
{
packet_len = ::snprintf (packet, sizeof(packet), "x0x%" PRIx64 ",0x%" PRIx64, (uint64_t)addr, (uint64_t)size);
}
else
{
packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);
}
packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64,
binary_memory_read ? 'x' : 'm', (uint64_t)addr, (uint64_t)size);
assert (packet_len + 1 < (int)sizeof(packet));
StringExtractorGDBRemote response;
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success)
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Utility/StringExtractorGDBRemote.cpp
Expand Up @@ -310,6 +310,12 @@ StringExtractorGDBRemote::GetServerPacketType () const
case 'S':
return eServerPacketType_S;

case 'x':
return eServerPacketType_x;

case 'X':
return eServerPacketType_X;

case 'T':
return eServerPacketType_T;

Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Utility/StringExtractorGDBRemote.h
Expand Up @@ -145,6 +145,8 @@ class StringExtractorGDBRemote : public StringExtractor
eServerPacketType_s,
eServerPacketType_S,
eServerPacketType_T,
eServerPacketType_x,
eServerPacketType_X,
eServerPacketType_Z,
eServerPacketType_z,

Expand Down
45 changes: 45 additions & 0 deletions lldb/test/tools/lldb-server/TestGDBRemoteMemoryRead.py
@@ -0,0 +1,45 @@
"""
Tests the binary ($x) and hex ($m) memory read packets of the remote stub
"""

import os
import unittest2
import lldb
from lldbtest import *
import lldbutil
import binascii


class MemoryReadTestCase(TestBase):

mydir = TestBase.compute_mydir(__file__)

@skipUnlessPlatform(getDarwinOSTriples()+["linux"])
def test_memory_read(self):
self.build()
exe = os.path.join (os.getcwd(), "a.out")

target = self.dbg.CreateTarget(exe)
lldbutil.run_break_set_by_symbol(self, "main")

process = target.LaunchSimple (None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
self.assertEqual(process.GetState(), lldb.eStateStopped, "Process is stopped")

pc = process.GetSelectedThread().GetSelectedFrame().GetPC()
for size in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]:
error = lldb.SBError()
memory = process.ReadMemory(pc, size, error)
self.assertTrue(error.Success())
self.match("process plugin packet send x%x,%x" % (pc, size), ["response:", memory])
self.match("process plugin packet send m%x,%x" % (pc, size), ["response:", binascii.hexlify(memory)])

process.Continue()
self.assertEqual(process.GetState(), lldb.eStateExited, "Process exited")


if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

0 comments on commit 3bf1125

Please sign in to comment.