summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2014-03-29 18:54:20 +0000
committerJason Molenda <jmolenda@apple.com>2014-03-29 18:54:20 +0000
commita332978b2ab53306acdef10858c7e954e605ab37 (patch)
treedb0802288ce9a50156d440b82ae606eae60cf129 /lldb/source/Plugins/Process/gdb-remote
parent61e595be4dcd9e63bc3a2b6787ffb647457969cd (diff)
downloadbcm5719-llvm-a332978b2ab53306acdef10858c7e954e605ab37.tar.gz
bcm5719-llvm-a332978b2ab53306acdef10858c7e954e605ab37.zip
lldb arm64 import.
These changes were written by Greg Clayton, Jim Ingham, Jason Molenda. It builds cleanly against TOT llvm with xcodebuild. I updated the cmake files by visual inspection but did not try a build. I haven't built these sources on any non-Mac platforms - I don't think this patch adds any code that requires darwin, but please let me know if I missed something. In debugserver, MachProcess.cpp and MachTask.cpp were renamed to MachProcess.mm and MachTask.mm as they picked up some new Objective-C code needed to launch processes when running on iOS. llvm-svn: 205113
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp149
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h20
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp7
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp303
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp50
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h4
6 files changed, 460 insertions, 73 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index e27186ff86c..f436799a86a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -27,6 +27,7 @@
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Target.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -57,6 +58,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_vCont_S (eLazyBoolCalculate),
m_qHostInfo_is_valid (eLazyBoolCalculate),
m_qProcessInfo_is_valid (eLazyBoolCalculate),
+ m_qGDBServerVersion_is_valid (eLazyBoolCalculate),
m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
m_supports_memory_region_info (eLazyBoolCalculate),
m_supports_watchpoint_support_info (eLazyBoolCalculate),
@@ -65,6 +67,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_attach_or_wait_reply(eLazyBoolCalculate),
m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
m_supports_p (eLazyBoolCalculate),
+ m_avoid_g_packets (eLazyBoolCalculate),
m_supports_QSaveRegisterState (eLazyBoolCalculate),
m_supports_qXfer_auxv_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_read (eLazyBoolCalculate),
@@ -100,6 +103,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_os_build (),
m_os_kernel (),
m_hostname (),
+ m_gdb_server_name(),
+ m_gdb_server_version(UINT32_MAX),
m_default_packet_timeout (0),
m_max_packet_size (0)
{
@@ -301,10 +306,12 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_QSaveRegisterState = eLazyBoolCalculate;
m_qHostInfo_is_valid = eLazyBoolCalculate;
m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
m_supports_memory_region_info = eLazyBoolCalculate;
m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
m_attach_or_wait_reply = eLazyBoolCalculate;
+ m_avoid_g_packets = eLazyBoolCalculate;
m_supports_qXfer_auxv_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
@@ -322,8 +329,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_z4 = true;
m_supports_QEnvironment = true;
m_supports_QEnvironmentHexEncoded = true;
+
m_host_arch.Clear();
m_process_arch.Clear();
+ m_os_version_major = UINT32_MAX;
+ m_os_version_minor = UINT32_MAX;
+ m_os_version_update = UINT32_MAX;
+ m_os_build.clear();
+ m_os_kernel.clear();
+ m_hostname.clear();
+ m_gdb_server_name.clear();
+ m_gdb_server_version = UINT32_MAX;
+ m_default_packet_timeout = 0;
m_max_packet_size = 0;
}
@@ -1314,6 +1331,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)
return -1;
}
+int
+GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported)
+{
+ if (data && *data != '\0')
+ {
+ StreamString packet;
+ packet.Printf("QSetProcessEvent:%s", data);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ if (was_supported)
+ *was_supported = true;
+ return 0;
+ }
+ else if (response.IsUnsupportedResponse())
+ {
+ if (was_supported)
+ *was_supported = false;
+ return -1;
+ }
+ else
+ {
+ uint8_t error = response.GetError();
+ if (was_supported)
+ *was_supported = true;
+ if (error)
+ return error;
+ }
+ }
+ }
+ return -1;
+}
+
bool
GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,
uint32_t &minor,
@@ -1394,6 +1446,69 @@ GDBRemoteCommunicationClient::GetProcessArchitecture ()
return m_process_arch;
}
+bool
+GDBRemoteCommunicationClient::GetGDBServerVersion()
+{
+ if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate)
+ {
+ m_gdb_server_name.clear();
+ m_gdb_server_version = 0;
+ m_qGDBServerVersion_is_valid = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ bool success = false;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ success = true;
+ m_gdb_server_name.swap(value);
+ }
+ else if (name.compare("version") == 0)
+ {
+ size_t dot_pos = value.find('.');
+ if (dot_pos != std::string::npos)
+ value[dot_pos] = '\0';
+ const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (version != UINT32_MAX)
+ {
+ success = true;
+ m_gdb_server_version = version;
+ }
+ }
+ }
+ if (success)
+ m_qGDBServerVersion_is_valid = eLazyBoolYes;
+ }
+ }
+ }
+ return m_qGDBServerVersion_is_valid == eLazyBoolYes;
+}
+
+const char *
+GDBRemoteCommunicationClient::GetGDBServerProgramName()
+{
+ if (GetGDBServerVersion())
+ {
+ if (!m_gdb_server_name.empty())
+ return m_gdb_server_name.c_str();
+ }
+ return NULL;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetGDBServerProgramVersion()
+{
+ if (GetGDBServerVersion())
+ return m_gdb_server_version;
+ return 0;
+}
bool
GDBRemoteCommunicationClient::GetHostInfo (bool force)
@@ -1558,6 +1673,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
switch (m_host_arch.GetMachine())
{
+ case llvm::Triple::arm64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
os_name = "ios";
@@ -1598,6 +1714,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
switch (m_host_arch.GetMachine())
{
+ case llvm::Triple::arm64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
host_triple.setOS(llvm::Triple::IOS);
@@ -3229,6 +3346,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s
}
bool
+GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process)
+{
+ // Some targets have issues with g/G packets and we need to avoid using them
+ if (m_avoid_g_packets == eLazyBoolCalculate)
+ {
+ if (process)
+ {
+ m_avoid_g_packets = eLazyBoolNo;
+ const ArchSpec &arch = process->GetTarget().GetArchitecture();
+ if (arch.IsValid()
+ && arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && arch.GetTriple().getOS() == llvm::Triple::IOS
+ && arch.GetTriple().getArch() == llvm::Triple::arm64)
+ {
+ m_avoid_g_packets = eLazyBoolYes;
+ uint32_t gdb_server_version = GetGDBServerProgramVersion();
+ if (gdb_server_version != 0)
+ {
+ const char *gdb_server_name = GetGDBServerProgramName();
+ if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0)
+ {
+ if (gdb_server_version >= 310)
+ m_avoid_g_packets = eLazyBoolNo;
+ }
+ }
+ }
+ }
+ }
+ return m_avoid_g_packets == eLazyBoolYes;
+}
+
+bool
GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
{
Mutex::Locker locker;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 4e404b6ab44..8de845fa5fe 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -159,6 +159,10 @@ public:
int
SendLaunchArchPacket (const char *arch);
+
+ int
+ SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL);
+
//------------------------------------------------------------------
/// Sends a "vAttach:PID" where PID is in hex.
///
@@ -494,7 +498,16 @@ public:
bool
RestoreRegisterState (lldb::tid_t tid, uint32_t save_id);
+
+ const char *
+ GetGDBServerProgramName();
+ uint32_t
+ GetGDBServerProgramVersion();
+
+ bool
+ AvoidGPackets(ProcessGDBRemote *process);
+
protected:
PacketResult
@@ -505,6 +518,9 @@ protected:
bool
GetCurrentProcessInfo ();
+ bool
+ GetGDBServerVersion();
+
//------------------------------------------------------------------
// Classes that inherit from GDBRemoteCommunicationClient can see and modify these
//------------------------------------------------------------------
@@ -519,6 +535,7 @@ protected:
lldb_private::LazyBool m_supports_vCont_S;
lldb_private::LazyBool m_qHostInfo_is_valid;
lldb_private::LazyBool m_qProcessInfo_is_valid;
+ lldb_private::LazyBool m_qGDBServerVersion_is_valid;
lldb_private::LazyBool m_supports_alloc_dealloc_memory;
lldb_private::LazyBool m_supports_memory_region_info;
lldb_private::LazyBool m_supports_watchpoint_support_info;
@@ -527,6 +544,7 @@ protected:
lldb_private::LazyBool m_attach_or_wait_reply;
lldb_private::LazyBool m_prepare_for_reg_writing_reply;
lldb_private::LazyBool m_supports_p;
+ lldb_private::LazyBool m_avoid_g_packets;
lldb_private::LazyBool m_supports_QSaveRegisterState;
lldb_private::LazyBool m_supports_qXfer_auxv_read;
lldb_private::LazyBool m_supports_qXfer_libraries_read;
@@ -574,6 +592,8 @@ protected:
std::string m_os_build;
std::string m_os_kernel;
std::string m_hostname;
+ std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported
+ uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported
uint32_t m_default_packet_timeout;
uint64_t m_max_packet_size; // as returned by qSupported
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 5542f7915a1..2fadf3359f5 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -447,22 +447,21 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
}
#if defined(__APPLE__)
-#if defined(__arm__)
+#if defined(__arm__) || defined(__arm64__)
// For iOS devices, we are connected through a USB Mux so we never pretend
// to actually have a hostname as far as the remote lldb that is connecting
// to this lldb-platform is concerned
response.PutCString ("hostname:");
response.PutCStringAsRawHex8("127.0.0.1");
response.PutChar(';');
-#else // #if defined(__arm__)
+#else // #if defined(__arm__) || defined(__arm64__)
if (Host::GetHostname (s))
{
response.PutCString ("hostname:");
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
-
-#endif // #if defined(__arm__)
+#endif // #if defined(__arm__) || defined(__arm64__)
#else // #if defined(__APPLE__)
if (Host::GetHostname (s))
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 73b9b3e8267..9e5b0d79e10 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -21,6 +21,7 @@
#include "lldb/Interpreter/PythonDataObjects.h"
#endif
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
#include "lldb/Utility/Utils.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -502,6 +503,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
StringExtractorGDBRemote response;
+ const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
+
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
{
@@ -519,29 +522,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
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 (use_g_packet && 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]))
+ 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)
{
- response_str.insert(0, 1, 'G');
- if (thread_suffix_supported)
+ if (response.IsErrorResponse())
+ return false;
+
+ std::string &response_str = response.GetStringRef();
+ if (isxdigit(response_str[0]))
{
- 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);
+ 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;
}
- 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;
+
+ // data_sp will take ownership of this DataBufferHeap pointer soon.
+ DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
+
+ 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
{
+
Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
if (log)
{
@@ -575,6 +611,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+ const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
+
StringExtractorGDBRemote response;
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
@@ -588,63 +626,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
// 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 (use_g_packet
+ && gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
{
- if (response.IsOKResponse())
- return true;
- else if (response.IsErrorResponse())
+ // 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)
{
- 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'
- DataBufferHeap buffer (m_reg_data.GetByteSize(), 0);
- DataExtractor restore_data (buffer.GetBytes(),
- buffer.GetByteSize(),
- m_reg_data.GetByteOrder(),
- m_reg_data.GetAddressByteSize());
-
- const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
- restore_data.GetByteSize(),
- '\xcc');
-
- if (bytes_extracted < restore_data.GetByteSize())
- restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
-
- //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data)
- const RegisterInfo *reg_info;
- // We have to march the offset of each register along in the
- // buffer to make sure we get the right offset.
- uint32_t reg_byte_offset = 0;
- for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size)
+ if (response.IsOKResponse())
+ return true;
+ else if (response.IsErrorResponse())
{
- const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
-
- // Skip composite registers.
- if (reg_info->value_regs)
- continue;
+ 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'
+
+ // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix therad 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);
+ DataExtractor restore_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
+
+ const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
+ restore_data.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.
+
+ int size_including_slice_registers = 0;
+ int size_not_including_slice_registers = 0;
+ int 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;
+ }
- // 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;
+ 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 concenating 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;
+ }
- const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
- if (restore_src)
+ // 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)
{
- if (GetRegisterIsValid(reg))
+ // Skip composite aka slice registers (e.g. eax is a slice of rax).
+ if (reg_info->value_regs)
+ continue;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ uint32_t register_offset;
+ if (use_byte_offset_into_buffer)
+ {
+ register_offset = reg_info->byte_offset;
+ }
+ else
{
- const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size);
- if (current_src)
- write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
+ register_offset = running_byte_offset;
}
- if (write_reg)
+ // 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);
@@ -662,14 +763,88 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
- if (response.IsOKResponse())
- ++num_restored;
+ 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);
+ packet.PutBytesAsRawHex8 (restore_src,
+ reg_byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::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;
+ }
+ }
+ }
+ 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::arm64
+ && 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;
+ }
+ StreamString packet;
+ packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]);
+ packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ 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;
}
- return num_restored > 0;
}
+ return num_restored > 0;
}
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 1bee5806e5f..48db3b0ffae 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -800,6 +800,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName());
+ const char * launch_event_data = launch_info.GetLaunchEventData();
+ if (launch_event_data != NULL && *launch_event_data != '\0')
+ m_gdb_comm.SendLaunchEventDataPacket (launch_event_data);
+
if (working_dir && working_dir[0])
{
m_gdb_comm.SetWorkingDir (working_dir);
@@ -2608,7 +2612,7 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info
debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
debugserver_launch_info.SetUserID(process_info.GetUserID());
-#if defined (__APPLE__) && defined (__arm__)
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__))
// On iOS, still do a local connection using a random port
const char *hostname = "127.0.0.1";
uint16_t port = get_random_port ();
@@ -2924,13 +2928,33 @@ ProcessGDBRemote::AsyncThread (void *arg)
break;
case eStateExited:
+ {
process->SetLastStopPacket (response);
process->ClearThreadIDList();
response.SetFilePos(1);
- process->SetExitStatus(response.GetHexU8(), NULL);
+
+ int exit_status = response.GetHexU8();
+ const char *desc_cstr = NULL;
+ StringExtractor extractor;
+ std::string desc_string;
+ if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';')
+ {
+ std::string desc_token;
+ while (response.GetNameColonValue (desc_token, desc_string))
+ {
+ if (desc_token == "description")
+ {
+ extractor.GetStringRef().swap(desc_string);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (desc_string);
+ desc_cstr = desc_string.c_str();
+ }
+ }
+ }
+ process->SetExitStatus(exit_status, desc_cstr);
done = true;
break;
-
+ }
case eStateInvalid:
process->SetExitStatus(-1, "lost connection");
break;
@@ -3066,6 +3090,25 @@ ProcessGDBRemote::GetDynamicLoader ()
return m_dyld_ap.get();
}
+Error
+ProcessGDBRemote::SendEventData(const char *data)
+{
+ int return_value;
+ bool was_supported;
+
+ Error error;
+
+ return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported);
+ if (return_value != 0)
+ {
+ if (!was_supported)
+ error.SetErrorString("Sending events is not supported for this process.");
+ else
+ error.SetErrorStringWithFormat("Error sending event data: %d.", return_value);
+ }
+ return error;
+}
+
const DataBufferSP
ProcessGDBRemote::GetAuxvData()
{
@@ -3079,7 +3122,6 @@ ProcessGDBRemote::GetAuxvData()
return buf;
}
-
class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
{
private:
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 1d4a23509e6..4f5cca57659 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -221,13 +221,15 @@ public:
return m_gdb_comm;
}
+ virtual lldb_private::Error
+ SendEventData(const char *data);
+
//----------------------------------------------------------------------
// Override SetExitStatus so we can disconnect from the remote GDB server
//----------------------------------------------------------------------
virtual bool
SetExitStatus (int exit_status, const char *cstr);
-
protected:
friend class ThreadGDBRemote;
friend class GDBRemoteCommunicationClient;
OpenPOWER on IntegriCloud