summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp813
1 files changed, 813 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 00000000000..cac2101e4c0
--- /dev/null
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,813 @@
+//===-- GDBRemoteCommunication.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunication.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/TimeValue.h"
+
+// Project includes
+#include "StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunication constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::GDBRemoteCommunication() :
+ Communication("gdb-remote.packets"),
+ m_send_acks (true),
+ m_rx_packet_listener ("gdbremote.rx_packet"),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_is_running (false),
+ m_async_mutex (Mutex::eMutexTypeRecursive),
+ m_async_packet_predicate (false),
+ m_async_packet (),
+ m_async_response (),
+ m_async_timeout (UINT32_MAX),
+ m_async_signal (-1),
+ m_arch(),
+ m_os(),
+ m_vendor(),
+ m_byte_order(eByteOrderHost),
+ m_pointer_byte_size(0)
+{
+ m_rx_packet_listener.StartListeningForEvents(this,
+ Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::~GDBRemoteCommunication()
+{
+ m_rx_packet_listener.StopListeningForEvents(this,
+ Communication::eBroadcastBitPacketAvailable |
+ Communication::eBroadcastBitReadThreadDidExit);
+ if (IsConnected())
+ {
+ StopReadThread();
+ Disconnect();
+ }
+}
+
+
+char
+GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length)
+{
+ int checksum = 0;
+
+ // We only need to compute the checksum if we are sending acks
+ if (m_send_acks)
+ {
+ for (int i = 0; i < payload_length; ++i)
+ checksum += payload[i];
+ }
+ return checksum & 255;
+}
+
+size_t
+GDBRemoteCommunication::SendAck (char ack_char)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: %c", ack_char);
+ ConnectionStatus status = eConnectionStatusSuccess;
+ return Write (&ack_char, 1, status, NULL) == 1;
+}
+
+size_t
+GDBRemoteCommunication::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async
+)
+{
+ return SendPacketAndWaitForResponse (payload,
+ ::strlen (payload),
+ response,
+ timeout_seconds,
+ send_async);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response,
+ uint32_t timeout_seconds,
+ bool send_async
+)
+{
+ Mutex::Locker locker;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (timeout_seconds);
+
+ if (locker.TryLock (m_sequence_mutex.GetMutex()))
+ {
+ if (SendPacketNoLock (payload, strlen(payload)))
+ return WaitForPacketNoLock (response, &timeout_time);
+ }
+ else
+ {
+ if (send_async)
+ {
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_packet.assign(payload, payload_length);
+ m_async_timeout = timeout_seconds;
+ m_async_packet_predicate.SetValue (true, eBroadcastNever);
+
+ bool timed_out = false;
+ if (SendInterrupt(1, &timed_out))
+ {
+ if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
+ {
+ response = m_async_response;
+ return response.GetStringRef().size();
+ }
+ }
+// if (timed_out)
+// m_error.SetErrorString("Timeout.");
+// else
+// m_error.SetErrorString("Unknown error.");
+ }
+ else
+ {
+// m_error.SetErrorString("Sequence mutex is locked.");
+ }
+ }
+ return 0;
+}
+
+//template<typename _Tp>
+//class ScopedValueChanger
+//{
+//public:
+// // Take a value reference and the value to assing it to when this class
+// // instance goes out of scope.
+// ScopedValueChanger (_Tp &value_ref, _Tp value) :
+// m_value_ref (value_ref),
+// m_value (value)
+// {
+// }
+//
+// // This object is going out of scope, change the value pointed to by
+// // m_value_ref to the value we got during construction which was stored in
+// // m_value;
+// ~ScopedValueChanger ()
+// {
+// m_value_ref = m_value;
+// }
+//protected:
+// _Tp &m_value_ref; // A reference to the value we wil change when this object destructs
+// _Tp m_value; // The value to assign to m_value_ref when this goes out of scope.
+//};
+
+StateType
+GDBRemoteCommunication::SendContinuePacketAndWaitForResponse
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+ Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s ()", __FUNCTION__);
+
+ Mutex::Locker locker(m_sequence_mutex);
+ m_is_running.SetValue (true, eBroadcastNever);
+
+// ScopedValueChanger<bool> restore_running_to_false (m_is_running, false);
+ StateType state = eStateRunning;
+
+ if (SendPacket(payload, packet_length) == 0)
+ state = eStateInvalid;
+
+ while (state == eStateRunning)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(...)", __FUNCTION__);
+
+ if (WaitForPacket (response, (TimeValue*)NULL))
+ {
+ if (response.Empty())
+ state = eStateInvalid;
+ else
+ {
+ const char stop_type = response.GetChar();
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () got '%c' packet", __FUNCTION__, stop_type);
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ if (m_async_signal != -1)
+ {
+ // Save off the async signal we are supposed to send
+ const int async_signal = m_async_signal;
+ // Clear the async signal member so we don't end up
+ // sending the signal multiple times...
+ m_async_signal = -1;
+ // Check which signal we stopped with
+ uint8_t signo = response.GetHexU8(255);
+ if (signo == async_signal)
+ {
+ // We already stopped with a signal that we wanted
+ // to stop with, so we are done
+ response.SetFilePos (0);
+ }
+ else
+ {
+ // We stopped with a different signal that the one
+ // we wanted to stop with, so now we must resume
+ // with the signal we want
+ char signal_packet[32];
+ int signal_packet_len = 0;
+ signal_packet_len = ::snprintf (signal_packet,
+ sizeof (signal_packet),
+ "C%2.2x",
+ async_signal);
+
+ if (SendPacket(signal_packet, signal_packet_len) == 0)
+ {
+ state = eStateInvalid;
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else if (m_async_packet_predicate.GetValue())
+ {
+ // We are supposed to send an asynchronous packet while
+ // we are running.
+ m_async_response.Clear();
+ if (!m_async_packet.empty())
+ {
+ SendPacketAndWaitForResponse (m_async_packet.data(),
+ m_async_packet.size(),
+ m_async_response,
+ m_async_timeout,
+ false);
+ }
+ // Let the other thread that was trying to send the async
+ // packet know that the packet has been sent.
+ m_async_packet_predicate.SetValue(false, eBroadcastAlways);
+
+ // Continue again
+ if (SendPacket("c", 1) == 0)
+ {
+ state = eStateInvalid;
+ break;
+ }
+ else
+ continue;
+ }
+ // Stop with signal and thread info
+ state = eStateStopped;
+ break;
+
+ case 'W':
+ // process exited
+ state = eStateExited;
+ break;
+
+ case 'O':
+ // STDOUT
+ {
+ std::string inferior_stdout;
+ inferior_stdout.reserve(response.GetBytesLeft () / 2);
+ char ch;
+ while ((ch = response.GetHexU8()) != '\0')
+ inferior_stdout.append(1, ch);
+ process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size());
+ }
+ break;
+
+ case 'E':
+ // ERROR
+ state = eStateInvalid;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () got unrecognized async packet: '%s'", __FUNCTION__, stop_type);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(...) => false", __FUNCTION__);
+ state = eStateInvalid;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s () => %s", __FUNCTION__, StateAsCString(state));
+ response.SetFilePos(0);
+ m_is_running.SetValue (false, eBroadcastOnChange);
+ return state;
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, ::strlen (payload));
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, payload_length);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)
+{
+ if (IsConnected())
+ {
+ StreamString packet(0, 4, eByteOrderBig);
+
+ packet.PutChar('$');
+ packet.Write (payload, payload_length);
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum (payload, payload_length));
+
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: %s", packet.GetData());
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+ if (bytes_written == packet.GetSize())
+ {
+ if (m_send_acks)
+ GetAck (1) == '+';
+ }
+ return bytes_written;
+ }
+ //m_error.SetErrorString("Not connected.");
+ return 0;
+}
+
+char
+GDBRemoteCommunication::GetAck (uint32_t timeout_seconds)
+{
+ StringExtractorGDBRemote response;
+ if (WaitForPacket (response, timeout_seconds) == 1)
+ return response.GetChar();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker)
+{
+ return locker.TryLock (m_sequence_mutex.GetMutex());
+}
+
+bool
+GDBRemoteCommunication::SendAsyncSignal (int signo)
+{
+ m_async_signal = signo;
+ bool timed_out = false;
+ if (SendInterrupt(1, &timed_out))
+ return true;
+ m_async_signal = -1;
+ return false;
+}
+
+bool
+GDBRemoteCommunication::SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out)
+{
+ if (timed_out)
+ *timed_out = false;
+
+ if (IsConnected() && IsRunning())
+ {
+ // Only send an interrupt if our debugserver is running...
+ if (m_sequence_mutex.TryLock() != 0)
+ {
+ // Someone has the mutex locked waiting for a response or for the
+ // inferior to stop, so send the interrupt on the down low...
+ char ctrl_c = '\x03';
+ ConnectionStatus status = eConnectionStatusSuccess;
+ TimeValue timeout;
+ if (seconds_to_wait_for_stop)
+ {
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
+ }
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "send packet: \\x03");
+ if (Write (&ctrl_c, 1, status, NULL) > 0)
+ {
+ if (seconds_to_wait_for_stop)
+ m_is_running.WaitForValueEqualTo (false, &timeout, timed_out);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint32_t timeout_seconds)
+{
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (timeout_seconds);
+ return WaitForPacketNoLock (response, &timeout_time);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return WaitForPacketNoLock (response, timeout_time_ptr);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+{
+ bool checksum_error = false;
+ response.Clear ();
+
+ EventSP event_sp;
+
+ if (m_rx_packet_listener.WaitForEvent (timeout_time_ptr, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_type | Communication::eBroadcastBitPacketAvailable)
+ {
+ const EventDataBytes *event_bytes = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+ if (event_bytes)
+ {
+ const char * packet_data = (const char *)event_bytes->GetBytes();
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS, "read packet: %s", packet_data);
+ const size_t packet_size = event_bytes->GetByteSize();
+ if (packet_data && packet_size > 0)
+ {
+ std::string &response_str = response.GetStringRef();
+ if (packet_data[0] == '$')
+ {
+ assert (packet_size >= 4); // Must have at least '$#CC' where CC is checksum
+ assert (packet_data[packet_size-3] == '#');
+ assert (::isxdigit (packet_data[packet_size-2])); // Must be checksum hex byte
+ assert (::isxdigit (packet_data[packet_size-1])); // Must be checksum hex byte
+ response_str.assign (packet_data + 1, packet_size - 4);
+ if (m_send_acks)
+ {
+ char packet_checksum = strtol (&packet_data[packet_size-2], NULL, 16);
+ char actual_checksum = CalculcateChecksum (response_str.data(), response_str.size());
+ checksum_error = packet_checksum != actual_checksum;
+ // Send the ack or nack if needed
+ if (checksum_error)
+ SendAck('-');
+ else
+ SendAck('+');
+ }
+ }
+ else
+ {
+ response_str.assign (packet_data, packet_size);
+ }
+ return response_str.size();
+ }
+ }
+ }
+ else if (Communication::eBroadcastBitReadThreadDidExit)
+ {
+ // Our read thread exited on us so just fall through and return zero...
+ }
+ }
+ return 0;
+}
+
+void
+GDBRemoteCommunication::AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+ m_bytes.append ((const char *)src, src_len);
+
+ // Parse up the packets into gdb remote packets
+ while (!m_bytes.empty())
+ {
+ // end_idx must be one past the last valid packet byte. Start
+ // it off with an invalid value that is the same as the current
+ // index.
+ size_t end_idx = 0;
+
+ switch (m_bytes[0])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ end_idx = 1; // The command is one byte long...
+ break;
+
+ case '$':
+ // Look for a standard gdb packet?
+ end_idx = m_bytes.find('#');
+ if (end_idx != std::string::npos)
+ {
+ if (end_idx + 2 < m_bytes.size())
+ {
+ end_idx += 3;
+ }
+ else
+ {
+ // Checksum bytes aren't all here yet
+ end_idx = std::string::npos;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (end_idx == std::string::npos)
+ {
+ //ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE, "GDBRemoteCommunication::%s packet not yet complete: '%s'",__FUNCTION__, m_bytes.c_str());
+ return;
+ }
+ else if (end_idx > 0)
+ {
+ // We have a valid packet...
+ assert (end_idx <= m_bytes.size());
+ std::auto_ptr<EventDataBytes> event_bytes_ap (new EventDataBytes (&m_bytes[0], end_idx));
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_COMM, "got full packet: %s", event_bytes_ap->GetBytes());
+ BroadcastEvent (eBroadcastBitPacketAvailable, event_bytes_ap.release());
+ m_bytes.erase(0, end_idx);
+ }
+ else
+ {
+ assert (1 <= m_bytes.size());
+ ProcessGDBRemoteLog::LogIf (GDBR_LOG_COMM, "GDBRemoteCommunication::%s tossing junk byte at %c",__FUNCTION__, m_bytes[0]);
+ m_bytes.erase(0, 1);
+ }
+ }
+}
+
+lldb::pid_t
+GDBRemoteCommunication::GetCurrentProcessID (uint32_t timeout_seconds)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, timeout_seconds, false))
+ {
+ if (response.GetChar() == 'Q')
+ if (response.GetChar() == 'C')
+ return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+bool
+GDBRemoteCommunication::GetLaunchSuccess (uint32_t timeout_seconds, std::string &error_str)
+{
+ error_str.clear();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return true;
+ if (response.GetChar() == 'E')
+ {
+ // A string the describes what failed when launching...
+ error_str = response.GetStringRef().substr(1);
+ }
+ else
+ {
+ error_str.assign ("unknown error occurred launching process");
+ }
+ }
+ else
+ {
+ error_str.assign ("failed to send the qLaunchSuccess packet");
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunication::SendArgumentsPacket (char const *argv[], uint32_t timeout_seconds)
+{
+ if (argv && argv[0])
+ {
+ StreamString packet;
+ packet.PutChar('A');
+ const char *arg;
+ for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i)
+ {
+ const int arg_len = strlen(arg);
+ if (i > 0)
+ packet.PutChar(',');
+ packet.Printf("%i,%i,", arg_len * 2, i);
+ packet.PutBytesAsRawHex8(arg, arg_len, eByteOrderHost, eByteOrderHost);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunication::SendEnvironmentPacket (char const *name_equal_value, uint32_t timeout_seconds)
+{
+ if (name_equal_value && name_equal_value[0])
+ {
+ StreamString packet;
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsOKPacket())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunication::GetHostInfo (uint32_t timeout_seconds)
+{
+ m_arch.Clear();
+ m_os.Clear();
+ m_vendor.Clear();
+ m_byte_order = eByteOrderHost;
+ m_pointer_byte_size = 0;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qHostInfo", response, timeout_seconds, false))
+ {
+ if (response.IsUnsupportedPacket())
+ return false;
+
+
+ std::string name;
+ std::string value;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ // exception type in big endian hex
+ m_arch.SetCPUType(Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0));
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ // exception count in big endian hex
+ m_arch.SetCPUSubtype(Args::StringToUInt32 (value.c_str(), 0, 0));
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ // exception data in big endian hex
+ m_os.SetCString(value.c_str());
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ m_vendor.SetCString(value.c_str());
+ }
+ else if (name.compare("endian") == 0)
+ {
+ if (value.compare("little") == 0)
+ m_byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ m_byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ m_byte_order = eByteOrderPDP;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ m_pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0);
+ }
+ }
+ }
+ return HostInfoIsValid();
+}
+
+int
+GDBRemoteCommunication::SendAttach
+(
+ lldb::pid_t pid,
+ uint32_t timeout_seconds,
+ StringExtractorGDBRemote& response
+)
+{
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ StreamString packet;
+ packet.Printf("vAttach;%x", pid);
+
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, timeout_seconds, false))
+ {
+ if (response.IsErrorPacket())
+ return response.GetError();
+ return 0;
+ }
+ }
+ return -1;
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunication::GetHostArchitecture ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_arch;
+}
+
+const lldb_private::ConstString &
+GDBRemoteCommunication::GetOSString ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_os;
+}
+
+const lldb_private::ConstString &
+GDBRemoteCommunication::GetVendorString()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_vendor;
+}
+
+lldb::ByteOrder
+GDBRemoteCommunication::GetByteOrder ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_byte_order;
+}
+
+uint32_t
+GDBRemoteCommunication::GetAddressByteSize ()
+{
+ if (!HostInfoIsValid ())
+ GetHostInfo (1);
+ return m_pointer_byte_size;
+}
+
+addr_t
+GDBRemoteCommunication::AllocateMemory (size_t size, uint32_t permissions, uint32_t timeout_seconds)
+{
+ char packet[64];
+ ::snprintf (packet, sizeof(packet), "_M%zx,%s%s%s", size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false))
+ {
+ if (!response.IsErrorPacket())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+GDBRemoteCommunication::DeallocateMemory (addr_t addr, uint32_t timeout_seconds)
+{
+ char packet[64];
+ snprintf(packet, sizeof(packet), "_m%llx", (uint64_t)addr);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false))
+ {
+ if (!response.IsOKPacket())
+ return true;
+ }
+ return false;
+}
OpenPOWER on IntegriCloud