summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2016-08-17 08:53:31 +0000
committerPavel Labath <labath@google.com>2016-08-17 08:53:31 +0000
commit56d7262b698024ba95afe5df5355e7cc23933049 (patch)
treef4587b04e46d7bf09ff90afa9e7aa3c6ca1c7cf4 /lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
parent206fffa1926a0a3741210edb35897f4546c90dd3 (diff)
downloadbcm5719-llvm-56d7262b698024ba95afe5df5355e7cc23933049.tar.gz
bcm5719-llvm-56d7262b698024ba95afe5df5355e7cc23933049.zip
Move packet construction from GDBRemoteRegisterContext go the communication class
Summary: When saving/restoring registers the GDBRemoteRegisterContext class was manually constructing the register save/restore packets. This creates appropriate helper functions in GDBRemoteCommunicationClient, and switches the class to use those. It also removes what a duplicate packet send in some of those functions, a thing that I can only attribute to a bad merge artefact. I also add a test framework for testing gdb-remote client functionality and add tests for the new functions I introduced. I'd like to be able to test the register context changes in isolation as well, but currently there doesn't seem to be a way to reasonably construct a standalone register context object, so we'll have to rely on the end-to-end tests to verify that. Reviewers: clayborg Subscribers: lldb-commits Differential Revision: https://reviews.llvm.org/D23553 llvm-svn: 278915
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp426
1 files changed, 157 insertions, 269 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 3e249341d07..05b2a324568 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -576,70 +576,40 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
if (lock)
{
SyncThreadState(process);
-
- char packet[32];
- 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()))
+
+ if (use_g_packet && gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
{
- int packet_len = 0;
- if (thread_suffix_supported)
- packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
- else
- packet_len = ::snprintf (packet, sizeof(packet), "g");
- assert (packet_len < ((int)sizeof(packet) - 1));
+ if (response.IsErrorResponse())
+ return false;
- if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
- {
- int packet_len = 0;
- if (thread_suffix_supported)
- packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
- else
- packet_len = ::snprintf (packet, sizeof(packet), "g");
- assert (packet_len < ((int)sizeof(packet) - 1));
-
- if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
- {
- if (response.IsErrorResponse())
- return false;
-
- std::string &response_str = response.GetStringRef();
- if (isxdigit(response_str[0]))
- {
- response_str.insert(0, 1, 'G');
- if (thread_suffix_supported)
- {
- char thread_id_cstr[64];
- ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
- response_str.append (thread_id_cstr);
- }
- data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
- 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;
+ std::string &response_str = response.GetStringRef();
+ if (!isxdigit(response_str[0]))
+ return false;
- // data_sp will take ownership of this DataBufferHeap pointer soon.
- DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
+ data_sp.reset(new DataBufferHeap(response_str.c_str(), response_str.size()));
+ 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;
- for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
- {
- if (reg_info->value_regs) // skip registers that are slices of real registers
- continue;
- 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 will take ownership of this DataBufferHeap pointer soon.
+ DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
- data_sp = reg_ctx;
- return true;
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; i++)
+ {
+ if (reg_info->value_regs) // skip registers that are slices of real registers
+ continue;
+ 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;
+ return true;
}
}
else
@@ -684,236 +654,154 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &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()))
+ // 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)
{
- // The data_sp contains the entire G response packet including the
- // G, and if the thread suffix is supported, it has the thread suffix
- // as well.
- const char *G_packet = (const char *)data_sp->GetBytes();
- size_t G_packet_len = data_sp->GetByteSize();
- if (use_g_packet
- && gdb_comm.SendPacketAndWaitForResponse (G_packet,
- G_packet_len,
- response,
- false) == GDBRemoteCommunication::PacketResult::Success)
- {
- // The data_sp contains the entire G response packet including the
- // G, and if the thread suffix is supported, it has the thread suffix
- // as well.
- const char *G_packet = (const char *)data_sp->GetBytes();
- size_t G_packet_len = data_sp->GetByteSize();
- if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
- G_packet_len,
- response,
- false) == GDBRemoteCommunication::PacketResult::Success)
- {
- if (response.IsOKResponse())
- return true;
- else if (response.IsErrorResponse())
- {
- uint32_t num_restored = 0;
- // We need to manually go through all of the registers and
- // restore them manually
-
- response.GetStringRef().assign (G_packet, G_packet_len);
- response.SetFilePos(1); // Skip the leading 'G'
+ if (gdb_comm.WriteAllRegisters(m_thread.GetProtocolID(), data))
+ return true;
- // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier.
- // This means buffer will be a little more than 2x larger than necessary but we resize
- // it down once we've extracted all hex ascii chars from the packet.
- DataBufferHeap buffer (G_packet_len, 0);
+ uint32_t num_restored = 0;
+ // We need to manually go through all of the registers and
+ // restore them manually
- const uint32_t bytes_extracted = response.GetHexBytes (buffer.GetBytes(),
- buffer.GetByteSize(),
- '\xcc');
+ response.GetStringRef() = data;
+ DataBufferHeap buffer(data.size() / 2, 0);
- DataExtractor restore_data (buffer.GetBytes(),
- buffer.GetByteSize(),
- m_reg_data.GetByteOrder(),
- m_reg_data.GetAddressByteSize());
+ const uint32_t bytes_extracted = response.GetHexBytes(buffer.GetBytes(), buffer.GetByteSize(), '\xcc');
- if (bytes_extracted < restore_data.GetByteSize())
- restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
-
- const RegisterInfo *reg_info;
-
- // The g packet contents may either include the slice registers (registers defined in
- // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers
- // should NOT be in the g packet, but some implementations may incorrectly include them.
- //
- // If the slice registers are included in the packet, we must step over the slice registers
- // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect.
- // If the slice registers are not included, then using the byte_offset values into the
- // data buffer is the best way to find individual register values.
-
- uint64_t size_including_slice_registers = 0;
- uint64_t size_not_including_slice_registers = 0;
- uint64_t size_by_highest_offset = 0;
-
- for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx)
- {
- size_including_slice_registers += reg_info->byte_size;
- if (reg_info->value_regs == NULL)
- size_not_including_slice_registers += reg_info->byte_size;
- if (reg_info->byte_offset >= size_by_highest_offset)
- size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size;
- }
+ DataExtractor restore_data(buffer.GetBytes(), buffer.GetByteSize(), m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
- bool use_byte_offset_into_buffer;
- if (size_by_highest_offset == restore_data.GetByteSize())
- {
- // The size of the packet agrees with the highest offset: + size in the register file
- use_byte_offset_into_buffer = true;
- }
- else if (size_not_including_slice_registers == restore_data.GetByteSize())
- {
- // The size of the packet is the same as concatenating all of the registers sequentially,
- // skipping the slice registers
- use_byte_offset_into_buffer = true;
- }
- else if (size_including_slice_registers == restore_data.GetByteSize())
- {
- // The slice registers are present in the packet (when they shouldn't be).
- // Don't try to use the RegisterInfo byte_offset into the restore_data, it will
- // point to the wrong place.
- use_byte_offset_into_buffer = false;
- }
- else {
- // None of our expected sizes match the actual g packet data we're looking at.
- // The most conservative approach here is to use the running total byte offset.
- use_byte_offset_into_buffer = false;
- }
+ if (bytes_extracted < restore_data.GetByteSize())
+ restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
- // In case our register definitions don't include the correct offsets,
- // keep track of the size of each reg & compute offset based on that.
- uint32_t running_byte_offset = 0;
- for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size)
- {
- // Skip composite aka slice registers (e.g. eax is a slice of rax).
- if (reg_info->value_regs)
- continue;
+ const RegisterInfo *reg_info;
- const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ // The g packet contents may either include the slice registers (registers defined in
+ // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers
+ // should NOT be in the g packet, but some implementations may incorrectly include them.
+ //
+ // If the slice registers are included in the packet, we must step over the slice registers
+ // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect.
+ // If the slice registers are not included, then using the byte_offset values into the
+ // data buffer is the best way to find individual register values.
- uint32_t register_offset;
- if (use_byte_offset_into_buffer)
- {
- register_offset = reg_info->byte_offset;
- }
- else
- {
- register_offset = running_byte_offset;
- }
-
- // Only write down the registers that need to be written
- // if we are going to be doing registers individually.
- bool write_reg = true;
- const uint32_t reg_byte_size = reg_info->byte_size;
-
- const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size);
- if (restore_src)
- {
- StreamString packet;
- packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]);
- packet.PutBytesAsRawHex8 (restore_src,
- reg_byte_size,
- endian::InlHostByteOrder(),
- endian::InlHostByteOrder());
-
- if (thread_suffix_supported)
- packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
-
- SetRegisterIsValid(reg, false);
- if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
- packet.GetString().size(),
- response,
- false) == GDBRemoteCommunication::PacketResult::Success)
- {
- const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size);
- if (current_src)
- write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
- }
-
- if (write_reg)
- {
- StreamString packet;
- packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]);
- packet.PutBytesAsRawHex8 (restore_src,
- reg_byte_size,
- endian::InlHostByteOrder(),
- endian::InlHostByteOrder());
-
- if (thread_suffix_supported)
- packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
-
- SetRegisterIsValid(reg, false);
- if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
- packet.GetString().size(),
- response,
- false) == GDBRemoteCommunication::PacketResult::Success)
- {
- if (response.IsOKResponse())
- ++num_restored;
- }
- }
- }
- }
- return num_restored > 0;
- }
- }
+ uint64_t size_including_slice_registers = 0;
+ uint64_t size_not_including_slice_registers = 0;
+ uint64_t size_by_highest_offset = 0;
+
+ for (uint32_t reg_idx = 0; (reg_info = GetRegisterInfoAtIndex(reg_idx)) != NULL; ++reg_idx)
+ {
+ size_including_slice_registers += reg_info->byte_size;
+ if (reg_info->value_regs == NULL)
+ size_not_including_slice_registers += reg_info->byte_size;
+ if (reg_info->byte_offset >= size_by_highest_offset)
+ size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size;
+ }
+
+ bool use_byte_offset_into_buffer;
+ if (size_by_highest_offset == restore_data.GetByteSize())
+ {
+ // The size of the packet agrees with the highest offset: + size in the register file
+ use_byte_offset_into_buffer = true;
+ }
+ else if (size_not_including_slice_registers == restore_data.GetByteSize())
+ {
+ // The size of the packet is the same as concatenating all of the registers sequentially,
+ // skipping the slice registers
+ use_byte_offset_into_buffer = true;
+ }
+ else if (size_including_slice_registers == restore_data.GetByteSize())
+ {
+ // The slice registers are present in the packet (when they shouldn't be).
+ // Don't try to use the RegisterInfo byte_offset into the restore_data, it will
+ // point to the wrong place.
+ use_byte_offset_into_buffer = false;
}
else
{
- // For the use_g_packet == false case, we're going to write each register
- // individually. The data buffer is binary data in this case, instead of
- // ascii characters.
+ // None of our expected sizes match the actual g packet data we're looking at.
+ // The most conservative approach here is to use the running total byte offset.
+ use_byte_offset_into_buffer = false;
+ }
+
+ // In case our register definitions don't include the correct offsets,
+ // keep track of the size of each reg & compute offset based on that.
+ uint32_t running_byte_offset = 0;
+ for (uint32_t reg_idx = 0; (reg_info = GetRegisterInfoAtIndex(reg_idx)) != NULL;
+ ++reg_idx, running_byte_offset += reg_info->byte_size)
+ {
+ // Skip composite aka slice registers (e.g. eax is a slice of rax).
+ if (reg_info->value_regs)
+ continue;
- bool arm64_debugserver = false;
- if (m_thread.GetProcess().get())
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ uint32_t register_offset;
+ if (use_byte_offset_into_buffer)
{
- const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
- if (arch.IsValid()
- && arch.GetMachine() == llvm::Triple::aarch64
- && arch.GetTriple().getVendor() == llvm::Triple::Apple
- && arch.GetTriple().getOS() == llvm::Triple::IOS)
- {
- arm64_debugserver = true;
- }
+ register_offset = reg_info->byte_offset;
}
- uint32_t num_restored = 0;
- const RegisterInfo *reg_info;
- for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
+ else
{
- if (reg_info->value_regs) // skip registers that are slices of real registers
- continue;
- // Skip the fpsr and fpcr floating point status/control register writing to
- // work around a bug in an older version of debugserver that would lead to
- // register context corruption when writing fpsr/fpcr.
- if (arm64_debugserver &&
- (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0))
- {
- continue;
- }
- StreamString packet;
- packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]);
- packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder());
- if (thread_suffix_supported)
- packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ register_offset = running_byte_offset;
+ }
- SetRegisterIsValid(reg_info, false);
- if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
- packet.GetString().size(),
- response,
- false) == GDBRemoteCommunication::PacketResult::Success)
- {
- if (response.IsOKResponse())
- ++num_restored;
- }
+ const uint32_t reg_byte_size = reg_info->byte_size;
+
+ const char *restore_src = (const char *)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)))
+ ++num_restored;
+ }
+ }
+ return num_restored > 0;
+ }
+ else
+ {
+ // For the use_g_packet == false case, we're going to write each register
+ // individually. The data buffer is binary data in this case, instead of
+ // ascii characters.
+
+ bool arm64_debugserver = false;
+ if (m_thread.GetProcess().get())
+ {
+ const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
+ if (arch.IsValid() && arch.GetMachine() == llvm::Triple::aarch64 &&
+ arch.GetTriple().getVendor() == llvm::Triple::Apple &&
+ arch.GetTriple().getOS() == llvm::Triple::IOS)
+ {
+ arm64_debugserver = true;
+ }
+ }
+ uint32_t num_restored = 0;
+ const RegisterInfo *reg_info;
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex(i)) != NULL; i++)
+ {
+ if (reg_info->value_regs) // skip registers that are slices of real registers
+ continue;
+ // Skip the fpsr and fpcr floating point status/control register writing to
+ // work around a bug in an older version of debugserver that would lead to
+ // register context corruption when writing fpsr/fpcr.
+ if (arm64_debugserver && (strcmp(reg_info->name, "fpsr") == 0 || strcmp(reg_info->name, "fpcr") == 0))
+ {
+ continue;
+ }
+
+ 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)))
+ {
+ ++num_restored;
}
- return num_restored > 0;
}
+ return num_restored > 0;
}
}
else
OpenPOWER on IntegriCloud