Remove the last manually constructed packet from gdb-remote register context + small refactor

Summary:
The tricky part here was that the exisiting implementation of WriteAllRegisters was expecting
hex-encoded data (as that was what the first implementation I replaced was using, but here we had
binary data to begin with. I thought the read/write register functions would be more useful if
they handled the hex-encoding themselves (all the other client functions provide the responses in
a more-or-less digested form). The read functions return a DataBuffer, so they can allocate as
much memory as they need to, while the write functions functions take an llvm::ArrayRef, as that
can be constructed from pretty much anything.

Reviewers: clayborg

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D23659

llvm-svn: 279232
This commit is contained in:
Pavel Labath 2016-08-19 12:31:49 +00:00
parent b8824a5d3f
commit b42b48e051
8 changed files with 115 additions and 146 deletions

View File

@ -24,6 +24,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamGDBRemote.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/TimeValue.h"
@ -3494,45 +3495,58 @@ GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process)
return m_avoid_g_packets == eLazyBoolYes;
}
bool
GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
DataBufferSP
GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg)
{
StreamString payload;
payload.Printf("p%x", reg);
return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) ==
PacketResult::Success;
StringExtractorGDBRemote response;
if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) != PacketResult::Success ||
!response.IsNormalResponse())
return nullptr;
DataBufferSP buffer_sp(new DataBufferHeap(response.GetStringRef().size() / 2, 0));
response.GetHexBytes(buffer_sp->GetBytes(), buffer_sp->GetByteSize(), '\xcc');
return buffer_sp;
}
bool
GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response)
DataBufferSP
GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid)
{
StreamString payload;
payload.PutChar('g');
return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) ==
PacketResult::Success;
StringExtractorGDBRemote response;
if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) != PacketResult::Success ||
!response.IsNormalResponse())
return nullptr;
DataBufferSP buffer_sp(new DataBufferHeap(response.GetStringRef().size() / 2, 0));
response.GetHexBytes(buffer_sp->GetBytes(), buffer_sp->GetByteSize(), '\xcc');
return buffer_sp;
}
bool
GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, uint32_t reg_num, llvm::StringRef data)
GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, uint32_t reg_num, llvm::ArrayRef<uint8_t> data)
{
StreamString payload;
payload.Printf("P%x=", reg_num);
payload.PutBytesAsRawHex8(data.data(), data.size(), endian::InlHostByteOrder(), endian::InlHostByteOrder());
StringExtractorGDBRemote response;
return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) ==
PacketResult::Success;
PacketResult::Success &&
response.IsOKResponse();
}
bool
GDBRemoteCommunicationClient::WriteAllRegisters(lldb::tid_t tid, llvm::StringRef data)
GDBRemoteCommunicationClient::WriteAllRegisters(lldb::tid_t tid, llvm::ArrayRef<uint8_t> data)
{
StreamString payload;
payload.PutChar('G');
payload.Write(data.data(), data.size());
payload.PutBytesAsRawHex8(data.data(), data.size(), endian::InlHostByteOrder(), endian::InlHostByteOrder());
StringExtractorGDBRemote response;
return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) ==
PacketResult::Success;
PacketResult::Success &&
response.IsOKResponse();
}
bool

View File

@ -10,6 +10,8 @@
#ifndef liblldb_GDBRemoteCommunicationClient_h_
#define liblldb_GDBRemoteCommunicationClient_h_
#include "GDBRemoteClientBase.h"
// C Includes
// C++ Includes
#include <chrono>
@ -24,8 +26,6 @@
#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
#include "GDBRemoteClientBase.h"
namespace lldb_private {
namespace process_gdb_remote {
@ -486,22 +486,19 @@ public:
bool
CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low);
bool
lldb::DataBufferSP
ReadRegister(lldb::tid_t tid,
uint32_t reg_num, // Must be the eRegisterKindProcessPlugin register number, to be sent to the remote
StringExtractorGDBRemote &response);
uint32_t reg_num); // Must be the eRegisterKindProcessPlugin register number
bool
ReadAllRegisters (lldb::tid_t tid,
StringExtractorGDBRemote &response);
lldb::DataBufferSP
ReadAllRegisters(lldb::tid_t tid);
bool
WriteRegister(lldb::tid_t tid, uint32_t reg_num, // eRegisterKindProcessPlugin register number
llvm::StringRef data);
llvm::ArrayRef<uint8_t> data);
bool
WriteAllRegisters(lldb::tid_t tid, llvm::StringRef data);
WriteAllRegisters(lldb::tid_t tid, llvm::ArrayRef<uint8_t> data);
bool
SaveRegisterState(lldb::tid_t tid, uint32_t &save_id);

View File

@ -130,7 +130,7 @@ GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterVa
}
bool
GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
GDBRemoteRegisterContext::PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data)
{
const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
if (reg_info == NULL)
@ -139,14 +139,15 @@ GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor
// Invalidate if needed
InvalidateIfNeeded(false);
const uint32_t reg_byte_size = reg_info->byte_size;
const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc');
bool success = bytes_copied == reg_byte_size;
const size_t reg_byte_size = reg_info->byte_size;
memcpy(const_cast<uint8_t *>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), data.data(),
std::min(data.size(), reg_byte_size));
bool success = data.size() >= reg_byte_size;
if (success)
{
SetRegisterIsValid(reg, true);
}
else if (bytes_copied > 0)
else if (data.size() > 0)
{
// Only set register is valid to false if we copied some bytes, else
// leave it as it was.
@ -209,8 +210,9 @@ GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info,
const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB];
const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin];
StringExtractorGDBRemote response;
if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg, response))
return PrivateSetRegisterValue (lldb_reg, response);
if (DataBufferSP buffer_sp = gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg))
return PrivateSetRegisterValue(lldb_reg,
llvm::ArrayRef<uint8_t>(buffer_sp->GetBytes(), buffer_sp->GetByteSize()));
return false;
}
@ -234,15 +236,19 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE
{
if (m_read_all_at_once)
{
StringExtractorGDBRemote response;
if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
return false;
if (response.IsNormalResponse())
if (response.GetHexBytes(const_cast<void *>(reinterpret_cast<const void *>(m_reg_data.GetDataStart())),
m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
SetAllRegisterValid (true);
if (DataBufferSP buffer_sp = gdb_comm.ReadAllRegisters(m_thread.GetProtocolID()))
{
memcpy(const_cast<uint8_t *>(m_reg_data.GetDataStart()), buffer_sp->GetBytes(),
std::min(buffer_sp->GetByteSize(), m_reg_data.GetByteSize()));
if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize())
{
SetAllRegisterValid(true);
return true;
}
else if (reg_info->value_regs)
}
return false;
}
if (reg_info->value_regs)
{
// Process this composite register request by delegating to the constituent
// primordial registers.
@ -330,8 +336,7 @@ GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info,
return gdb_comm.WriteRegister(
m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
llvm::StringRef(reinterpret_cast<const char *>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)),
reg_info->byte_size));
{m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), reg_info->byte_size});
}
bool
@ -371,40 +376,20 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, Data
GDBRemoteClientBase::Lock lock(gdb_comm, false);
if (lock)
{
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
{
StreamString packet;
StringExtractorGDBRemote response;
if (m_read_all_at_once)
{
// Set all registers in one packet
packet.PutChar ('G');
packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
m_reg_data.GetByteSize(),
endian::InlHostByteOrder(),
endian::InlHostByteOrder());
if (thread_suffix_supported)
packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
// Invalidate all register values
InvalidateIfNeeded (true);
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false) == GDBRemoteCommunication::PacketResult::Success)
// Set all registers in one packet
if (gdb_comm.WriteAllRegisters(m_thread.GetProtocolID(),
{m_reg_data.GetDataStart(), m_reg_data.GetByteSize()}))
{
SetAllRegisterValid (false);
if (response.IsOKResponse())
{
return true;
}
}
}
else
{
bool success = true;
@ -452,7 +437,6 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, Data
return success;
}
}
}
else
{
Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
@ -533,8 +517,6 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
StringExtractorGDBRemote response;
const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
GDBRemoteClientBase::Lock lock(gdb_comm, false);
@ -543,27 +525,12 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
if (gdb_comm.SyncThreadState(m_thread.GetProtocolID()))
InvalidateAllRegisters();
if (use_g_packet && gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
{
if (response.IsErrorResponse())
return false;
std::string &response_str = response.GetStringRef();
if (!isxdigit(response_str[0]))
return false;
data_sp.reset(new DataBufferHeap(response_str.c_str(), response_str.size()));
if (use_g_packet && (data_sp = gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())))
return true;
}
else
{
// For the use_g_packet == false case, we're going to read each register
// individually and store them as binary data in a buffer instead of as ascii
// characters.
const RegisterInfo *reg_info;
// data_sp will take ownership of this DataBufferHeap pointer soon.
DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
// We're going to read each register
// individually and store them as binary data in a buffer.
const RegisterInfo *reg_info;
for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; i++)
{
@ -572,12 +539,9 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
ReadRegisterBytes(reg_info, m_reg_data);
// ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer
}
memcpy(reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize());
data_sp = reg_ctx;
data_sp.reset(new DataBufferHeap(m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()));
return true;
}
}
else
{
@ -616,31 +580,19 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
StringExtractorGDBRemote response;
GDBRemoteClientBase::Lock lock(gdb_comm, false);
if (lock)
{
// The data_sp contains the G response packet.
llvm::StringRef data(reinterpret_cast<const char *>(data_sp->GetBytes()), data_sp->GetByteSize());
if (use_g_packet)
{
if (gdb_comm.WriteAllRegisters(m_thread.GetProtocolID(), data))
if (gdb_comm.WriteAllRegisters(m_thread.GetProtocolID(), {data_sp->GetBytes(), data_sp->GetByteSize()}))
return true;
uint32_t num_restored = 0;
// We need to manually go through all of the registers and
// restore them manually
response.GetStringRef() = data;
DataBufferHeap buffer(data.size() / 2, 0);
const uint32_t bytes_extracted = response.GetHexBytes(buffer.GetBytes(), buffer.GetByteSize(), '\xcc');
DataExtractor restore_data(buffer.GetBytes(), buffer.GetByteSize(), m_reg_data.GetByteOrder(),
m_reg_data.GetAddressByteSize());
if (bytes_extracted < restore_data.GetByteSize())
restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
DataExtractor restore_data(data_sp, m_reg_data.GetByteOrder(), m_reg_data.GetAddressByteSize());
const RegisterInfo *reg_info;
@ -716,12 +668,12 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
const uint32_t reg_byte_size = reg_info->byte_size;
const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size);
const uint8_t *restore_src = restore_data.PeekData(register_offset, reg_byte_size);
if (restore_src)
{
SetRegisterIsValid(reg, false);
if (gdb_comm.WriteRegister(m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
llvm::StringRef(restore_src, reg_byte_size)))
{restore_src, reg_byte_size}))
++num_restored;
}
}
@ -759,14 +711,10 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
}
SetRegisterIsValid(reg_info, false);
if (gdb_comm.WriteRegister(
m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes() + reg_info->byte_offset),
reg_info->byte_size)))
{
if (gdb_comm.WriteRegister(m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
{data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size}))
++num_restored;
}
}
return num_restored > 0;
}
}

View File

@ -107,7 +107,7 @@ protected:
uint32_t data_offset);
bool
PrivateSetRegisterValue (uint32_t reg, StringExtractor &response);
PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
bool
PrivateSetRegisterValue (uint32_t reg, uint64_t val);

View File

@ -1991,7 +1991,10 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
{
StringExtractor reg_value_extractor;
reg_value_extractor.GetStringRef() = pair.second;
gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor);
DataBufferSP buffer_sp(new DataBufferHeap(reg_value_extractor.GetStringRef().size() / 2, 0));
reg_value_extractor.GetHexBytes(buffer_sp->GetBytes(), buffer_sp->GetByteSize(), '\xcc');
gdb_thread->PrivateSetRegisterValue(
pair.first, llvm::ArrayRef<uint8_t>(buffer_sp->GetBytes(), buffer_sp->GetByteSize()));
}
thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str());

View File

@ -380,11 +380,11 @@ ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame)
}
bool
ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
ThreadGDBRemote::PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data)
{
GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get());
assert (gdb_reg_ctx);
return gdb_reg_ctx->PrivateSetRegisterValue (reg, response);
return gdb_reg_ctx->PrivateSetRegisterValue(reg, data);
}
bool

View File

@ -130,8 +130,7 @@ protected:
lldb_private::LazyBool m_associated_with_libdispatch_queue;
bool
PrivateSetRegisterValue (uint32_t reg,
StringExtractor &response);
PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
bool
PrivateSetRegisterValue (uint32_t reg,

View File

@ -18,6 +18,9 @@
#include "gtest/gtest.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
#include "lldb/Core/DataBuffer.h"
#include "llvm/ADT/ArrayRef.h"
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
@ -54,7 +57,10 @@ HandlePacket(MockServer &server, llvm::StringRef expected, llvm::StringRef respo
ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
}
const char all_registers[] = "404142434445464748494a4b4c4d4e4f";
uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
uint8_t one_register[] = {'A', 'B', 'C', 'D'};
std::string one_register_hex = "41424344";
} // end anonymous namespace
@ -73,16 +79,16 @@ TEST_F(GDBRemoteCommunicationClientTest, WriteRegister)
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> write_result =
std::async(std::launch::async, [&] { return client.WriteRegister(tid, reg_num, "ABCD"); });
std::async(std::launch::async, [&] { return client.WriteRegister(tid, reg_num, one_register); });
Handle_QThreadSuffixSupported(server, true);
HandlePacket(server, "P4=41424344;thread:0047;", "OK");
HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
ASSERT_TRUE(write_result.get());
write_result = std::async(std::launch::async, [&] { return client.WriteAllRegisters(tid, all_registers); });
HandlePacket(server, std::string("G") + all_registers + ";thread:0047;", "OK");
HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
ASSERT_TRUE(write_result.get());
}
@ -97,16 +103,16 @@ TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix)
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> write_result =
std::async(std::launch::async, [&] { return client.WriteRegister(tid, reg_num, "ABCD"); });
std::async(std::launch::async, [&] { return client.WriteRegister(tid, reg_num, one_register); });
Handle_QThreadSuffixSupported(server, false);
HandlePacket(server, "Hg47", "OK");
HandlePacket(server, "P4=41424344", "OK");
HandlePacket(server, "P4=" + one_register_hex, "OK");
ASSERT_TRUE(write_result.get());
write_result = std::async(std::launch::async, [&] { return client.WriteAllRegisters(tid, all_registers); });
HandlePacket(server, std::string("G") + all_registers, "OK");
HandlePacket(server, "G" + all_registers_hex, "OK");
ASSERT_TRUE(write_result.get());
}
@ -122,19 +128,21 @@ TEST_F(GDBRemoteCommunicationClientTest, ReadRegister)
const uint32_t reg_num = 4;
std::future<bool> async_result = std::async(std::launch::async, [&] { return client.GetpPacketSupported(tid); });
Handle_QThreadSuffixSupported(server, true);
HandlePacket(server, "p0;thread:0047;", "41424344");
HandlePacket(server, "p0;thread:0047;", one_register_hex);
ASSERT_TRUE(async_result.get());
StringExtractorGDBRemote response;
async_result = std::async(std::launch::async, [&] { return client.ReadRegister(tid, reg_num, response); });
std::future<DataBufferSP> read_result =
std::async(std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
HandlePacket(server, "p4;thread:0047;", "41424344");
ASSERT_TRUE(async_result.get());
ASSERT_EQ("41424344", response.GetStringRef());
auto buffer_sp = read_result.get();
ASSERT_TRUE(bool(buffer_sp));
ASSERT_EQ(0, memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
async_result = std::async(std::launch::async, [&] { return client.ReadAllRegisters(tid, response); });
HandlePacket(server, "g;thread:0047;", all_registers);
ASSERT_TRUE(async_result.get());
ASSERT_EQ(all_registers, response.GetStringRef());
read_result = std::async(std::launch::async, [&] { return client.ReadAllRegisters(tid); });
HandlePacket(server, "g;thread:0047;", all_registers_hex);
buffer_sp = read_result.get();
ASSERT_TRUE(bool(buffer_sp));
ASSERT_EQ(0, memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
}
TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix)