diff options
Diffstat (limited to 'lldb/source/Plugins/Process')
9 files changed, 1474 insertions, 1151 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index a2c6a696cbf..707fe46c26f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -13,18 +13,11 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "llvm/ADT/Triple.h" -#include "lldb/Interpreter/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/Host.h" #include "lldb/Host/TimeValue.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" -#include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" using namespace lldb; @@ -33,32 +26,13 @@ using namespace lldb_private; //---------------------------------------------------------------------- // GDBRemoteCommunication constructor //---------------------------------------------------------------------- -GDBRemoteCommunication::GDBRemoteCommunication() : - Communication("gdb-remote.packets"), +GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, const char *listener_name) : + Communication(comm_name), m_packet_timeout (1), - m_supports_not_sending_acks (eLazyBoolCalculate), - m_supports_thread_suffix (eLazyBoolCalculate), - m_supports_qHostInfo (eLazyBoolCalculate), - m_supports_vCont_all (eLazyBoolCalculate), - m_supports_vCont_any (eLazyBoolCalculate), - m_supports_vCont_c (eLazyBoolCalculate), - m_supports_vCont_C (eLazyBoolCalculate), - m_supports_vCont_s (eLazyBoolCalculate), - m_supports_vCont_S (eLazyBoolCalculate), - m_rx_packet_listener ("gdbremote.rx_packet"), + m_rx_packet_listener (listener_name), m_sequence_mutex (Mutex::eMutexTypeRecursive), m_public_is_running (false), - m_private_is_running (false), - m_async_mutex (Mutex::eMutexTypeRecursive), - m_async_packet_predicate (false), - m_async_packet (), - m_async_response (), - m_async_signal (-1), - m_arch(), - m_os(), - m_vendor(), - m_byte_order(lldb::endian::InlHostByteOrder()), - m_pointer_byte_size(0) + m_private_is_running (false) { m_rx_packet_listener.StartListeningForEvents(this, Communication::eBroadcastBitPacketAvailable | @@ -117,419 +91,6 @@ GDBRemoteCommunication::SendNack () return Write (&nack_char, 1, status, NULL) == 1; } -bool -GDBRemoteCommunication::GetSendAcks () -{ - if (m_supports_not_sending_acks == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_not_sending_acks = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false)) - { - if (response.IsOKPacket()) - m_supports_not_sending_acks = eLazyBoolYes; - } - } - return m_supports_not_sending_acks != eLazyBoolYes; -} - -void -GDBRemoteCommunication::ResetDiscoverableSettings() -{ - m_supports_not_sending_acks = eLazyBoolCalculate; - m_supports_thread_suffix = eLazyBoolCalculate; - m_supports_qHostInfo = eLazyBoolCalculate; - m_supports_vCont_c = eLazyBoolCalculate; - m_supports_vCont_C = eLazyBoolCalculate; - m_supports_vCont_s = eLazyBoolCalculate; - m_supports_vCont_S = eLazyBoolCalculate; - m_arch.Clear(); - m_os.Clear(); - m_vendor.Clear(); - m_byte_order = lldb::endian::InlHostByteOrder(); - m_pointer_byte_size = 0; -} - - -bool -GDBRemoteCommunication::GetThreadSuffixSupported () -{ - if (m_supports_thread_suffix == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_thread_suffix = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false)) - { - if (response.IsOKPacket()) - m_supports_thread_suffix = eLazyBoolYes; - } - } - return m_supports_thread_suffix; -} -bool -GDBRemoteCommunication::GetVContSupported (char flavor) -{ - if (m_supports_vCont_c == eLazyBoolCalculate) - { - StringExtractorGDBRemote response; - m_supports_vCont_any = eLazyBoolNo; - m_supports_vCont_all = eLazyBoolNo; - m_supports_vCont_c = eLazyBoolNo; - m_supports_vCont_C = eLazyBoolNo; - m_supports_vCont_s = eLazyBoolNo; - m_supports_vCont_S = eLazyBoolNo; - if (SendPacketAndWaitForResponse("vCont?", response, false)) - { - const char *response_cstr = response.GetStringRef().c_str(); - if (::strstr (response_cstr, ";c")) - m_supports_vCont_c = eLazyBoolYes; - - if (::strstr (response_cstr, ";C")) - m_supports_vCont_C = eLazyBoolYes; - - if (::strstr (response_cstr, ";s")) - m_supports_vCont_s = eLazyBoolYes; - - if (::strstr (response_cstr, ";S")) - m_supports_vCont_S = eLazyBoolYes; - - if (m_supports_vCont_c == eLazyBoolYes && - m_supports_vCont_C == eLazyBoolYes && - m_supports_vCont_s == eLazyBoolYes && - m_supports_vCont_S == eLazyBoolYes) - { - m_supports_vCont_all = eLazyBoolYes; - } - - if (m_supports_vCont_c == eLazyBoolYes || - m_supports_vCont_C == eLazyBoolYes || - m_supports_vCont_s == eLazyBoolYes || - m_supports_vCont_S == eLazyBoolYes) - { - m_supports_vCont_any = eLazyBoolYes; - } - } - } - - switch (flavor) - { - case 'a': return m_supports_vCont_any; - case 'A': return m_supports_vCont_all; - case 'c': return m_supports_vCont_c; - case 'C': return m_supports_vCont_C; - case 's': return m_supports_vCont_s; - case 'S': return m_supports_vCont_S; - default: break; - } - return false; -} - - -size_t -GDBRemoteCommunication::SendPacketAndWaitForResponse -( - const char *payload, - StringExtractorGDBRemote &response, - bool send_async -) -{ - return SendPacketAndWaitForResponse (payload, - ::strlen (payload), - response, - send_async); -} - -size_t -GDBRemoteCommunication::SendPacketAndWaitForResponse -( - const char *payload, - size_t payload_length, - StringExtractorGDBRemote &response, - bool send_async -) -{ - Mutex::Locker locker; - TimeValue timeout_time; - timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds (m_packet_timeout); - LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - if (GetSequenceMutex (locker)) - { - 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_packet_predicate.SetValue (true, eBroadcastNever); - - if (log) - log->Printf ("async: async packet = %s", m_async_packet.c_str()); - - bool timed_out = false; - bool sent_interrupt = false; - if (SendInterrupt(locker, 2, sent_interrupt, timed_out)) - { - if (sent_interrupt) - { - if (log) - log->Printf ("async: sent interrupt"); - if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) - { - if (log) - log->Printf ("async: got response"); - response = m_async_response; - return response.GetStringRef().size(); - } - else - { - if (log) - log->Printf ("async: timed out waiting for response"); - } - - // Make sure we wait until the continue packet has been sent again... - if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out)) - { - if (log) - log->Printf ("async: timed out waiting for process to resume"); - } - } - else - { - // We had a racy condition where we went to send the interrupt - // yet we were able to get the loc - } - } - else - { - if (log) - log->Printf ("async: failed to interrupt"); - } - } - else - { - if (log) - log->Printf ("mutex taken and send_async == false, aborting packet"); - } - } - return 0; -} - -//template<typename _Tp> -//class ScopedValueChanger -//{ -//public: -// // Take a value reference and the value to assign 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 will 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 -) -{ - LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunication::%s ()", __FUNCTION__); - - Mutex::Locker locker(m_sequence_mutex); - StateType state = eStateRunning; - - BroadcastEvent(eBroadcastBitRunPacketSent, NULL); - m_public_is_running.SetValue (true, eBroadcastNever); - // Set the starting continue packet into "continue_packet". This packet - // make change if we are interrupted and we continue after an async packet... - std::string continue_packet(payload, packet_length); - - while (state == eStateRunning) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); - if (SendPacket(continue_packet.c_str(), continue_packet.size()) == 0) - state = eStateInvalid; - - m_private_is_running.SetValue (true, eBroadcastNever); - - if (log) - log->Printf ("GDBRemoteCommunication::%s () WaitForPacket(%.*s)", __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 packet: %s", __FUNCTION__, response.GetStringRef().c_str()); - switch (stop_type) - { - case 'T': - case 'S': - if (process->GetStopID() == 0) - { - if (process->GetID() == LLDB_INVALID_PROCESS_ID) - { - lldb::pid_t pid = GetCurrentProcessID (); - if (pid != LLDB_INVALID_PROCESS_ID) - process->SetID (pid); - } - process->BuildDynamicRegisterInfo (true); - } - - // Privately notify any internal threads that we have stopped - // in case we wanted to interrupt our process, yet we might - // send a packet and continue without returning control to the - // user. - m_private_is_running.SetValue (false, eBroadcastAlways); - if (m_async_signal != -1) - { - if (log) - log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal)); - - // 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) - { - if (log) - log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo)); - - // 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 (log) - log->Printf ("async: stopped with signal %s, resume with %s", - Host::GetSignalAsCString (signo), - Host::GetSignalAsCString (async_signal)); - - // Set the continue packet to resume... - continue_packet.assign(signal_packet, signal_packet_len); - 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()) - { - if (log) - log->Printf ("async: error: empty async packet"); - - } - else - { - if (log) - log->Printf ("async: sending packet: %s", - m_async_packet.c_str()); - - SendPacketAndWaitForResponse (&m_async_packet[0], - m_async_packet.size(), - m_async_response, - false); - } - // Let the other thread that was trying to send the async - // packet know that the packet has been sent and response is - // ready... - m_async_packet_predicate.SetValue(false, eBroadcastAlways); - - // Set the continue packet to resume... - continue_packet.assign (1, 'c'); - continue; - } - // Stop with signal and thread info - state = eStateStopped; - break; - - case 'W': - case 'X': - // 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 () unrecognized async packet", __FUNCTION__); - state = eStateInvalid; - 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_private_is_running.SetValue (false, eBroadcastAlways); - m_public_is_running.SetValue (false, eBroadcastAlways); - return state; -} - size_t GDBRemoteCommunication::SendPacket (const char *payload) { @@ -583,9 +144,9 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le char GDBRemoteCommunication::GetAck () { - StringExtractorGDBRemote response; - if (WaitForPacket (response, m_packet_timeout) == 1) - return response.GetChar(); + StringExtractorGDBRemote packet; + if (WaitForPacket (packet, m_packet_timeout) == 1) + return packet.GetChar(); return 0; } @@ -595,98 +156,6 @@ 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; - bool sent_interrupt = false; - Mutex::Locker locker; - if (SendInterrupt (locker, 1, sent_interrupt, timed_out)) - return true; - m_async_signal = -1; - return false; -} - -// This function takes a mutex locker as a parameter in case the GetSequenceMutex -// actually succeeds. If it doesn't succeed in acquiring the sequence mutex -// (the expected result), then it will send the halt packet. If it does succeed -// then the caller that requested the interrupt will want to keep the sequence -// locked down so that no one else can send packets while the caller has control. -// This function usually gets called when we are running and need to stop the -// target. It can also be used when we are running and and we need to do something -// else (like read/write memory), so we need to interrupt the running process -// (gdb remote protocol requires this), and do what we need to do, then resume. - -bool -GDBRemoteCommunication::SendInterrupt -( - Mutex::Locker& locker, - uint32_t seconds_to_wait_for_stop, - bool &sent_interrupt, - bool &timed_out -) -{ - sent_interrupt = false; - timed_out = false; - LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - if (IsRunning()) - { - // Only send an interrupt if our debugserver is running... - if (GetSequenceMutex (locker) == false) - { - // 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); - } - size_t bytes_written = Write (&ctrl_c, 1, status, NULL); - ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS | GDBR_LOG_PROCESS, "send packet: \\x03"); - if (bytes_written > 0) - { - sent_interrupt = true; - if (seconds_to_wait_for_stop) - { - if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out)) - { - if (log) - log->Printf ("GDBRemoteCommunication::%s () - sent interrupt, private state stopped", __FUNCTION__); - return true; - } - else - { - if (log) - log->Printf ("GDBRemoteCommunication::%s () - sent interrupt, timed out wating for async thread resume", __FUNCTION__); - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunication::%s () - sent interrupt, not waiting for stop...", __FUNCTION__); - return true; - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunication::%s () - failed to write interrupt", __FUNCTION__); - } - return false; - } - else - { - if (log) - log->Printf ("GDBRemoteCommunication::%s () - got sequence mutex without having to interrupt", __FUNCTION__); - } - } - return true; -} bool GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) @@ -695,27 +164,27 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) } size_t -GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint32_t timeout_seconds) +GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &packet, uint32_t timeout_seconds) { Mutex::Locker locker(m_sequence_mutex); TimeValue timeout_time; timeout_time = TimeValue::Now(); timeout_time.OffsetWithSeconds (timeout_seconds); - return WaitForPacketNoLock (response, &timeout_time); + return WaitForPacketNoLock (packet, &timeout_time); } size_t -GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, const TimeValue* timeout_time_ptr) +GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &packet, const TimeValue* timeout_time_ptr) { Mutex::Locker locker(m_sequence_mutex); - return WaitForPacketNoLock (response, timeout_time_ptr); + return WaitForPacketNoLock (packet, timeout_time_ptr); } size_t -GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, const TimeValue* timeout_time_ptr) +GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &packet, const TimeValue* timeout_time_ptr) { bool checksum_error = false; - response.Clear (); + packet.Clear (); EventSP event_sp; @@ -734,7 +203,7 @@ GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, const size_t packet_size = event_bytes->GetByteSize(); if (packet_data && packet_size > 0) { - std::string &response_str = response.GetStringRef(); + std::string &packet_str = packet.GetStringRef(); if (packet_data[0] == '$') { bool success = false; @@ -748,11 +217,11 @@ GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, success = true; if (success) - response_str.assign (packet_data + 1, packet_size - 4); + packet_str.assign (packet_data + 1, packet_size - 4); if (GetSendAcks ()) { char packet_checksum = strtol (&packet_data[packet_size-2], NULL, 16); - char actual_checksum = CalculcateChecksum (&response_str[0], response_str.size()); + char actual_checksum = CalculcateChecksum (&packet_str[0], packet_str.size()); checksum_error = packet_checksum != actual_checksum; // Send the ack or nack if needed if (checksum_error || !success) @@ -763,9 +232,9 @@ GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, } else { - response_str.assign (packet_data, packet_size); + packet_str.assign (packet_data, packet_size); } - return response_str.size(); + return packet_str.size(); } } } @@ -845,353 +314,3 @@ GDBRemoteCommunication::AppendBytesToCache (const uint8_t *src, size_t src_len, } } -lldb::pid_t -GDBRemoteCommunication::GetCurrentProcessID () -{ - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, 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 (std::string &error_str) -{ - error_str.clear(); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, 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[]) -{ - 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); - } - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, 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) -{ - 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, false)) - { - if (response.IsOKPacket()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} - -bool -GDBRemoteCommunication::GetHostInfo () -{ - if (m_supports_qHostInfo == eLazyBoolCalculate) - { - m_supports_qHostInfo = eLazyBoolNo; - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qHostInfo", response, false)) - { - if (response.IsUnsupportedPacket()) - return false; - - m_supports_qHostInfo = eLazyBoolYes; - - std::string name; - std::string value; - uint32_t cpu = LLDB_INVALID_CPUTYPE; - uint32_t sub = 0; - - while (response.GetNameColonValue(name, value)) - { - if (name.compare("cputype") == 0) - { - // exception type in big endian hex - cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0); - } - else if (name.compare("cpusubtype") == 0) - { - // exception count in big endian hex - sub = 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); - } - } - - if (cpu != LLDB_INVALID_CPUTYPE) - m_arch.SetArchitecture (lldb::eArchTypeMachO, cpu, sub); - } - } - return m_supports_qHostInfo == eLazyBoolYes; -} - -int -GDBRemoteCommunication::SendAttach -( - lldb::pid_t pid, - StringExtractorGDBRemote& response -) -{ - if (pid != LLDB_INVALID_PROCESS_ID) - { - StreamString packet; - packet.Printf("vAttach;%x", pid); - - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) - { - if (response.IsErrorPacket()) - return response.GetError(); - return 0; - } - } - return -1; -} - -const lldb_private::ArchSpec & -GDBRemoteCommunication::GetHostArchitecture () -{ - if (!HostInfoIsValid ()) - GetHostInfo (); - return m_arch; -} - -const lldb_private::ConstString & -GDBRemoteCommunication::GetOSString () -{ - if (!HostInfoIsValid ()) - GetHostInfo (); - return m_os; -} - -const lldb_private::ConstString & -GDBRemoteCommunication::GetVendorString() -{ - if (!HostInfoIsValid ()) - GetHostInfo (); - return m_vendor; -} - -lldb::ByteOrder -GDBRemoteCommunication::GetByteOrder () -{ - if (!HostInfoIsValid ()) - GetHostInfo (); - return m_byte_order; -} - -uint32_t -GDBRemoteCommunication::GetAddressByteSize () -{ - if (!HostInfoIsValid ()) - GetHostInfo (); - return m_pointer_byte_size; -} - -addr_t -GDBRemoteCommunication::AllocateMemory (size_t size, uint32_t permissions) -{ - 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, false)) - { - if (!response.IsErrorPacket()) - return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); - } - return LLDB_INVALID_ADDRESS; -} - -bool -GDBRemoteCommunication::DeallocateMemory (addr_t addr) -{ - char packet[64]; - snprintf(packet, sizeof(packet), "_m%llx", (uint64_t)addr); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, response, false)) - { - if (response.IsOKPacket()) - return true; - } - return false; -} - -int -GDBRemoteCommunication::SetSTDIN (char const *path) -{ - if (path && path[0]) - { - StreamString packet; - packet.PutCString("QSetSTDIN:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) - { - if (response.IsOKPacket()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} - -int -GDBRemoteCommunication::SetSTDOUT (char const *path) -{ - if (path && path[0]) - { - StreamString packet; - packet.PutCString("QSetSTDOUT:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) - { - if (response.IsOKPacket()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} - -int -GDBRemoteCommunication::SetSTDERR (char const *path) -{ - if (path && path[0]) - { - StreamString packet; - packet.PutCString("QSetSTDERR:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) - { - if (response.IsOKPacket()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} - -int -GDBRemoteCommunication::SetWorkingDir (char const *path) -{ - if (path && path[0]) - { - StreamString packet; - packet.PutCString("QSetWorkingDir:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) - { - if (response.IsOKPacket()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - } - return -1; -} - -int -GDBRemoteCommunication::SetDisableASLR (bool enable) -{ - StreamString packet; - packet.Printf("QSetDisableASLR:%i", enable ? 1 : 0); - - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) - { - if (response.IsOKPacket()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; - } - return -1; -} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index dbd1bd0e32b..858f67c6534 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -18,10 +18,7 @@ // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" -#include "lldb/Core/ArchSpec.h" #include "lldb/Core/Communication.h" -#include "lldb/Core/ConstString.h" -#include "lldb/Core/Error.h" #include "lldb/Core/Listener.h" #include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" @@ -30,8 +27,7 @@ class ProcessGDBRemote; -class GDBRemoteCommunication : - public lldb_private::Communication +class GDBRemoteCommunication : public lldb_private::Communication { public: enum @@ -41,7 +37,7 @@ public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunication(); + GDBRemoteCommunication(const char *comm_name, const char *listener_name); virtual ~GDBRemoteCommunication(); @@ -53,23 +49,6 @@ public: SendPacket (const char *payload, size_t payload_length); - size_t - SendPacketAndWaitForResponse (const char *send_payload, - StringExtractorGDBRemote &response, - bool send_async); - - size_t - SendPacketAndWaitForResponse (const char *send_payload, - size_t send_length, - StringExtractorGDBRemote &response, - bool send_async); - - lldb::StateType - SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process, - const char *packet_payload, - size_t packet_length, - StringExtractorGDBRemote &response); - // Wait for a packet within 'nsec' seconds size_t WaitForPacket (StringExtractorGDBRemote &response, @@ -90,24 +69,11 @@ public: size_t SendNack (); - char CalculcateChecksum (const char *payload, size_t payload_length); bool - GetThreadSuffixSupported (); - - bool - SendAsyncSignal (int signo); - - bool - SendInterrupt (lldb_private::Mutex::Locker &locker, - uint32_t seconds_to_wait_for_stop, - bool &sent_interrupt, - bool &timed_out); - - bool GetSequenceMutex(lldb_private::Mutex::Locker& locker); //------------------------------------------------------------------ @@ -116,167 +82,29 @@ public: virtual void AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast, lldb::ConnectionStatus status); - - lldb::pid_t - GetCurrentProcessID (); - - bool - GetLaunchSuccess (std::string &error_str); - - //------------------------------------------------------------------ - /// Sends a GDB remote protocol 'A' packet that delivers program - /// arguments to the remote server. - /// - /// @param[in] argv - /// A NULL terminated array of const C strings to use as the - /// arguments. - /// - /// @return - /// Zero if the response was "OK", a positive value if the - /// the response was "Exx" where xx are two hex digits, or - /// -1 if the call is unsupported or any other unexpected - /// response was received. - //------------------------------------------------------------------ - int - SendArgumentsPacket (char const *argv[]); - - //------------------------------------------------------------------ - /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the - /// environment that will get used when launching an application - /// in conjunction with the 'A' packet. This function can be called - /// multiple times in a row in order to pass on the desired - /// environment that the inferior should be launched with. - /// - /// @param[in] name_equal_value - /// A NULL terminated C string that contains a single environment - /// in the format "NAME=VALUE". - /// - /// @return - /// Zero if the response was "OK", a positive value if the - /// the response was "Exx" where xx are two hex digits, or - /// -1 if the call is unsupported or any other unexpected - /// response was received. - //------------------------------------------------------------------ - int - SendEnvironmentPacket (char const *name_equal_value); - - //------------------------------------------------------------------ - /// Sends a "vAttach:PID" where PID is in hex. - /// - /// @param[in] pid - /// A process ID for the remote gdb server to attach to. - /// - /// @param[out] response - /// The response received from the gdb server. If the return - /// value is zero, \a response will contain a stop reply - /// packet. - /// - /// @return - /// Zero if the attach was successful, or an error indicating - /// an error code. - //------------------------------------------------------------------ - int - SendAttach (lldb::pid_t pid, - StringExtractorGDBRemote& response); - - - //------------------------------------------------------------------ - /// Sets the path to use for stdin/out/err for a process - /// that will be launched with the 'A' packet. - /// - /// @param[in] path - /// The path to use for stdin/out/err - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetSTDIN (char const *path); - int - SetSTDOUT (char const *path); - int - SetSTDERR (char const *path); - - //------------------------------------------------------------------ - /// Sets the disable ASLR flag to \a enable for a process that will - /// be launched with the 'A' packet. - /// - /// @param[in] enable - /// A boolean value indicating wether to disable ASLR or not. - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetDisableASLR (bool enable); - - //------------------------------------------------------------------ - /// Sets the working directory to \a path for a process that will - /// be launched with the 'A' packet. - /// - /// @param[in] path - /// The path to a directory to use when launching our processs - /// - /// @return - /// Zero if the for success, or an error code for failure. - //------------------------------------------------------------------ - int - SetWorkingDir (char const *path); - - lldb::addr_t - AllocateMemory (size_t size, uint32_t permissions); - - bool - DeallocateMemory (lldb::addr_t addr); - bool IsRunning() const { return m_public_is_running.GetValue(); } - const lldb_private::ArchSpec & - GetHostArchitecture (); - - const lldb_private::ConstString & - GetOSString (); - - const lldb_private::ConstString & - GetVendorString(); - - lldb::ByteOrder - GetByteOrder (); - - uint32_t - GetAddressByteSize (); - - bool - GetVContSupported (char flavor); - - void - ResetDiscoverableSettings(); - - bool - GetHostInfo (); - - bool - GetSendAcks (); - - bool - GetSupportsThreadSuffix (); - - bool - HasFullVContSupport () - { - return GetVContSupported ('A'); - } + //------------------------------------------------------------------ + // Client and server must implement these pure virtual functions + //------------------------------------------------------------------ + virtual bool + GetThreadSuffixSupported () = 0; - bool - HasAnyVContSupport () - { - return GetVContSupported ('a'); - } + virtual bool + GetSendAcks () = 0; + //------------------------------------------------------------------ + // Set the global packet timeout. + // + // For clients, this is the timeout that gets used when sending + // packets and waiting for responses. For servers, this might not + // get used, and if it doesn't this should be moved to the + // GDBRemoteCommunicationClient. + //------------------------------------------------------------------ uint32_t SetPacketTimeout (uint32_t packet_timeout) { @@ -299,46 +127,15 @@ protected: bool WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr); - bool - HostInfoIsValid () const - { - return m_supports_qHostInfo != lldb::eLazyBoolCalculate; - } - //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunication can see and modify these //------------------------------------------------------------------ uint32_t m_packet_timeout; - lldb::LazyBool m_supports_not_sending_acks; - lldb::LazyBool m_supports_thread_suffix; - lldb::LazyBool m_supports_qHostInfo; - lldb::LazyBool m_supports_vCont_all; - lldb::LazyBool m_supports_vCont_any; - lldb::LazyBool m_supports_vCont_c; - lldb::LazyBool m_supports_vCont_C; - lldb::LazyBool m_supports_vCont_s; - lldb::LazyBool m_supports_vCont_S; lldb_private::Listener m_rx_packet_listener; lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time lldb_private::Predicate<bool> m_public_is_running; lldb_private::Predicate<bool> m_private_is_running; - // If we need to send a packet while the target is running, the m_async_XXX - // member variables take care of making this happen. - lldb_private::Mutex m_async_mutex; - lldb_private::Predicate<bool> m_async_packet_predicate; - std::string m_async_packet; - StringExtractorGDBRemote m_async_response; - int m_async_signal; // We were asked to deliver a signal to the inferior process. - - lldb_private::ArchSpec m_arch; // Results from the qHostInfo call - uint32_t m_cpusubtype; // Results from the qHostInfo call - lldb_private::ConstString m_os; // Results from the qHostInfo call - lldb_private::ConstString m_vendor; // Results from the qHostInfo call - lldb::ByteOrder m_byte_order; // Results from the qHostInfo call - uint32_t m_pointer_byte_size; // Results from the qHostInfo call - - private: //------------------------------------------------------------------ // For GDBRemoteCommunication only diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp new file mode 100644 index 00000000000..b4fb6f2ddfe --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -0,0 +1,934 @@ +//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "GDBRemoteCommunicationClient.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ADT/Triple.h" +#include "lldb/Interpreter/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/Endian.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/TimeValue.h" + +// Project includes +#include "Utility/StringExtractorGDBRemote.h" +#include "ProcessGDBRemote.h" +#include "ProcessGDBRemoteLog.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// GDBRemoteCommunicationClient constructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : + GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"), + m_supports_not_sending_acks (eLazyBoolCalculate), + m_supports_thread_suffix (eLazyBoolCalculate), + m_supports_qHostInfo (eLazyBoolCalculate), + m_supports_vCont_all (eLazyBoolCalculate), + m_supports_vCont_any (eLazyBoolCalculate), + m_supports_vCont_c (eLazyBoolCalculate), + m_supports_vCont_C (eLazyBoolCalculate), + m_supports_vCont_s (eLazyBoolCalculate), + m_supports_vCont_S (eLazyBoolCalculate), + m_async_mutex (Mutex::eMutexTypeRecursive), + m_async_packet_predicate (false), + m_async_packet (), + m_async_response (), + m_async_signal (-1), + m_arch(), + m_os(), + m_vendor(), + m_byte_order(lldb::endian::InlHostByteOrder()), + m_pointer_byte_size(0) +{ + m_rx_packet_listener.StartListeningForEvents(this, + Communication::eBroadcastBitPacketAvailable | + Communication::eBroadcastBitReadThreadDidExit); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() +{ + m_rx_packet_listener.StopListeningForEvents(this, + Communication::eBroadcastBitPacketAvailable | + Communication::eBroadcastBitReadThreadDidExit); + if (IsConnected()) + { + StopReadThread(); + Disconnect(); + } +} + +bool +GDBRemoteCommunicationClient::GetSendAcks () +{ + if (m_supports_not_sending_acks == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_not_sending_acks = eLazyBoolNo; + if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false)) + { + if (response.IsOKResponse()) + m_supports_not_sending_acks = eLazyBoolYes; + } + } + return m_supports_not_sending_acks != eLazyBoolYes; +} + +void +GDBRemoteCommunicationClient::ResetDiscoverableSettings() +{ + m_supports_not_sending_acks = eLazyBoolCalculate; + m_supports_thread_suffix = eLazyBoolCalculate; + m_supports_qHostInfo = eLazyBoolCalculate; + m_supports_vCont_c = eLazyBoolCalculate; + m_supports_vCont_C = eLazyBoolCalculate; + m_supports_vCont_s = eLazyBoolCalculate; + m_supports_vCont_S = eLazyBoolCalculate; + m_arch.Clear(); + m_os.Clear(); + m_vendor.Clear(); + m_byte_order = lldb::endian::InlHostByteOrder(); + m_pointer_byte_size = 0; +} + + +bool +GDBRemoteCommunicationClient::GetThreadSuffixSupported () +{ + if (m_supports_thread_suffix == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_thread_suffix = eLazyBoolNo; + if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false)) + { + if (response.IsOKResponse()) + m_supports_thread_suffix = eLazyBoolYes; + } + } + return m_supports_thread_suffix; +} +bool +GDBRemoteCommunicationClient::GetVContSupported (char flavor) +{ + if (m_supports_vCont_c == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_vCont_any = eLazyBoolNo; + m_supports_vCont_all = eLazyBoolNo; + m_supports_vCont_c = eLazyBoolNo; + m_supports_vCont_C = eLazyBoolNo; + m_supports_vCont_s = eLazyBoolNo; + m_supports_vCont_S = eLazyBoolNo; + if (SendPacketAndWaitForResponse("vCont?", response, false)) + { + const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr (response_cstr, ";c")) + m_supports_vCont_c = eLazyBoolYes; + + if (::strstr (response_cstr, ";C")) + m_supports_vCont_C = eLazyBoolYes; + + if (::strstr (response_cstr, ";s")) + m_supports_vCont_s = eLazyBoolYes; + + if (::strstr (response_cstr, ";S")) + m_supports_vCont_S = eLazyBoolYes; + + if (m_supports_vCont_c == eLazyBoolYes && + m_supports_vCont_C == eLazyBoolYes && + m_supports_vCont_s == eLazyBoolYes && + m_supports_vCont_S == eLazyBoolYes) + { + m_supports_vCont_all = eLazyBoolYes; + } + + if (m_supports_vCont_c == eLazyBoolYes || + m_supports_vCont_C == eLazyBoolYes || + m_supports_vCont_s == eLazyBoolYes || + m_supports_vCont_S == eLazyBoolYes) + { + m_supports_vCont_any = eLazyBoolYes; + } + } + } + + switch (flavor) + { + case 'a': return m_supports_vCont_any; + case 'A': return m_supports_vCont_all; + case 'c': return m_supports_vCont_c; + case 'C': return m_supports_vCont_C; + case 's': return m_supports_vCont_s; + case 'S': return m_supports_vCont_S; + default: break; + } + return false; +} + + +size_t +GDBRemoteCommunicationClient::SendPacketAndWaitForResponse +( + const char *payload, + StringExtractorGDBRemote &response, + bool send_async +) +{ + return SendPacketAndWaitForResponse (payload, + ::strlen (payload), + response, + send_async); +} + +size_t +GDBRemoteCommunicationClient::SendPacketAndWaitForResponse +( + const char *payload, + size_t payload_length, + StringExtractorGDBRemote &response, + bool send_async +) +{ + Mutex::Locker locker; + TimeValue timeout_time; + timeout_time = TimeValue::Now(); + timeout_time.OffsetWithSeconds (m_packet_timeout); + LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + + if (GetSequenceMutex (locker)) + { + 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_packet_predicate.SetValue (true, eBroadcastNever); + + if (log) + log->Printf ("async: async packet = %s", m_async_packet.c_str()); + + bool timed_out = false; + bool sent_interrupt = false; + if (SendInterrupt(locker, 2, sent_interrupt, timed_out)) + { + if (sent_interrupt) + { + if (log) + log->Printf ("async: sent interrupt"); + if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) + { + if (log) + log->Printf ("async: got response"); + response = m_async_response; + return response.GetStringRef().size(); + } + else + { + if (log) + log->Printf ("async: timed out waiting for response"); + } + + // Make sure we wait until the continue packet has been sent again... + if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out)) + { + if (log) + log->Printf ("async: timed out waiting for process to resume"); + } + } + else + { + // We had a racy condition where we went to send the interrupt + // yet we were able to get the loc + } + } + else + { + if (log) + log->Printf ("async: failed to interrupt"); + } + } + else + { + if (log) + log->Printf ("mutex taken and send_async == false, aborting packet"); + } + } + return 0; +} + +//template<typename _Tp> +//class ScopedValueChanger +//{ +//public: +// // Take a value reference and the value to assign 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 will change when this object destructs +// _Tp m_value; // The value to assign to m_value_ref when this goes out of scope. +//}; + +StateType +GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse +( + ProcessGDBRemote *process, + const char *payload, + size_t packet_length, + StringExtractorGDBRemote &response +) +{ + LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + + Mutex::Locker locker(m_sequence_mutex); + StateType state = eStateRunning; + + BroadcastEvent(eBroadcastBitRunPacketSent, NULL); + m_public_is_running.SetValue (true, eBroadcastNever); + // Set the starting continue packet into "continue_packet". This packet + // make change if we are interrupted and we continue after an async packet... + std::string continue_packet(payload, packet_length); + + while (state == eStateRunning) + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); + if (SendPacket(continue_packet.c_str(), continue_packet.size()) == 0) + state = eStateInvalid; + + m_private_is_running.SetValue (true, eBroadcastNever); + + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%.*s)", __FUNCTION__); + + if (WaitForPacket (response, (TimeValue*)NULL)) + { + if (response.Empty()) + state = eStateInvalid; + else + { + const char stop_type = response.GetChar(); + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str()); + switch (stop_type) + { + case 'T': + case 'S': + if (process->GetStopID() == 0) + { + if (process->GetID() == LLDB_INVALID_PROCESS_ID) + { + lldb::pid_t pid = GetCurrentProcessID (); + if (pid != LLDB_INVALID_PROCESS_ID) + process->SetID (pid); + } + process->BuildDynamicRegisterInfo (true); + } + + // Privately notify any internal threads that we have stopped + // in case we wanted to interrupt our process, yet we might + // send a packet and continue without returning control to the + // user. + m_private_is_running.SetValue (false, eBroadcastAlways); + if (m_async_signal != -1) + { + if (log) + log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal)); + + // 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) + { + if (log) + log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo)); + + // 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 (log) + log->Printf ("async: stopped with signal %s, resume with %s", + Host::GetSignalAsCString (signo), + Host::GetSignalAsCString (async_signal)); + + // Set the continue packet to resume... + continue_packet.assign(signal_packet, signal_packet_len); + 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()) + { + if (log) + log->Printf ("async: error: empty async packet"); + + } + else + { + if (log) + log->Printf ("async: sending packet: %s", + m_async_packet.c_str()); + + SendPacketAndWaitForResponse (&m_async_packet[0], + m_async_packet.size(), + m_async_response, + false); + } + // Let the other thread that was trying to send the async + // packet know that the packet has been sent and response is + // ready... + m_async_packet_predicate.SetValue(false, eBroadcastAlways); + + // Set the continue packet to resume... + continue_packet.assign (1, 'c'); + continue; + } + // Stop with signal and thread info + state = eStateStopped; + break; + + case 'W': + case 'X': + // 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 ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__); + state = eStateInvalid; + break; + } + } + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__); + state = eStateInvalid; + } + } + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state)); + response.SetFilePos(0); + m_private_is_running.SetValue (false, eBroadcastAlways); + m_public_is_running.SetValue (false, eBroadcastAlways); + return state; +} + +bool +GDBRemoteCommunicationClient::SendAsyncSignal (int signo) +{ + m_async_signal = signo; + bool timed_out = false; + bool sent_interrupt = false; + Mutex::Locker locker; + if (SendInterrupt (locker, 1, sent_interrupt, timed_out)) + return true; + m_async_signal = -1; + return false; +} + +// This function takes a mutex locker as a parameter in case the GetSequenceMutex +// actually succeeds. If it doesn't succeed in acquiring the sequence mutex +// (the expected result), then it will send the halt packet. If it does succeed +// then the caller that requested the interrupt will want to keep the sequence +// locked down so that no one else can send packets while the caller has control. +// This function usually gets called when we are running and need to stop the +// target. It can also be used when we are running and and we need to do something +// else (like read/write memory), so we need to interrupt the running process +// (gdb remote protocol requires this), and do what we need to do, then resume. + +bool +GDBRemoteCommunicationClient::SendInterrupt +( + Mutex::Locker& locker, + uint32_t seconds_to_wait_for_stop, + bool &sent_interrupt, + bool &timed_out +) +{ + sent_interrupt = false; + timed_out = false; + LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + + if (IsRunning()) + { + // Only send an interrupt if our debugserver is running... + if (GetSequenceMutex (locker) == false) + { + // 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); + } + size_t bytes_written = Write (&ctrl_c, 1, status, NULL); + ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS | GDBR_LOG_PROCESS, "send packet: \\x03"); + if (bytes_written > 0) + { + sent_interrupt = true; + if (seconds_to_wait_for_stop) + { + if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out)) + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, private state stopped", __FUNCTION__); + return true; + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, timed out wating for async thread resume", __FUNCTION__); + } + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, not waiting for stop...", __FUNCTION__); + return true; + } + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () - failed to write interrupt", __FUNCTION__); + } + return false; + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s () - got sequence mutex without having to interrupt", __FUNCTION__); + } + } + return true; +} + +lldb::pid_t +GDBRemoteCommunicationClient::GetCurrentProcessID () +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false)) + { + if (response.GetChar() == 'Q') + if (response.GetChar() == 'C') + return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); + } + return LLDB_INVALID_PROCESS_ID; +} + +bool +GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) +{ + error_str.clear(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false)) + { + if (response.IsOKResponse()) + 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 +GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[]) +{ + 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); + } + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + } + return -1; +} + +int +GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value) +{ + 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, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + } + return -1; +} + +bool +GDBRemoteCommunicationClient::GetHostInfo () +{ + if (m_supports_qHostInfo == eLazyBoolCalculate) + { + m_supports_qHostInfo = eLazyBoolNo; + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qHostInfo", response, false)) + { + if (response.IsUnsupportedResponse()) + return false; + + m_supports_qHostInfo = eLazyBoolYes; + + std::string name; + std::string value; + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + + while (response.GetNameColonValue(name, value)) + { + if (name.compare("cputype") == 0) + { + // exception type in big endian hex + cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0); + } + else if (name.compare("cpusubtype") == 0) + { + // exception count in big endian hex + sub = 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); + } + } + + if (cpu != LLDB_INVALID_CPUTYPE) + m_arch.SetArchitecture (lldb::eArchTypeMachO, cpu, sub); + } + } + return m_supports_qHostInfo == eLazyBoolYes; +} + +int +GDBRemoteCommunicationClient::SendAttach +( + lldb::pid_t pid, + StringExtractorGDBRemote& response +) +{ + if (pid != LLDB_INVALID_PROCESS_ID) + { + StreamString packet; + packet.Printf("vAttach;%x", pid); + + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsErrorResponse()) + return response.GetError(); + return 0; + } + } + return -1; +} + +const lldb_private::ArchSpec & +GDBRemoteCommunicationClient::GetHostArchitecture () +{ + if (!HostInfoIsValid ()) + GetHostInfo (); + return m_arch; +} + +const lldb_private::ConstString & +GDBRemoteCommunicationClient::GetOSString () +{ + if (!HostInfoIsValid ()) + GetHostInfo (); + return m_os; +} + +const lldb_private::ConstString & +GDBRemoteCommunicationClient::GetVendorString() +{ + if (!HostInfoIsValid ()) + GetHostInfo (); + return m_vendor; +} + +lldb::ByteOrder +GDBRemoteCommunicationClient::GetByteOrder () +{ + if (!HostInfoIsValid ()) + GetHostInfo (); + return m_byte_order; +} + +uint32_t +GDBRemoteCommunicationClient::GetAddressByteSize () +{ + if (!HostInfoIsValid ()) + GetHostInfo (); + return m_pointer_byte_size; +} + +addr_t +GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) +{ + 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, false)) + { + if (!response.IsErrorResponse()) + return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + } + return LLDB_INVALID_ADDRESS; +} + +bool +GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) +{ + char packet[64]; + snprintf(packet, sizeof(packet), "_m%llx", (uint64_t)addr); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet, response, false)) + { + if (response.IsOKResponse()) + return true; + } + return false; +} + +int +GDBRemoteCommunicationClient::SetSTDIN (char const *path) +{ + if (path && path[0]) + { + StreamString packet; + packet.PutCString("QSetSTDIN:"); + packet.PutBytesAsRawHex8(path, strlen(path)); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + } + return -1; +} + +int +GDBRemoteCommunicationClient::SetSTDOUT (char const *path) +{ + if (path && path[0]) + { + StreamString packet; + packet.PutCString("QSetSTDOUT:"); + packet.PutBytesAsRawHex8(path, strlen(path)); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + } + return -1; +} + +int +GDBRemoteCommunicationClient::SetSTDERR (char const *path) +{ + if (path && path[0]) + { + StreamString packet; + packet.PutCString("QSetSTDERR:"); + packet.PutBytesAsRawHex8(path, strlen(path)); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + } + return -1; +} + +int +GDBRemoteCommunicationClient::SetWorkingDir (char const *path) +{ + if (path && path[0]) + { + StreamString packet; + packet.PutCString("QSetWorkingDir:"); + packet.PutBytesAsRawHex8(path, strlen(path)); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + } + return -1; +} + +int +GDBRemoteCommunicationClient::SetDisableASLR (bool enable) +{ + StreamString packet; + packet.Printf("QSetDisableASLR:%i", enable ? 1 : 0); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h new file mode 100644 index 00000000000..604e09a9491 --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -0,0 +1,268 @@ +//===-- GDBRemoteCommunicationClient.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteCommunicationClient_h_ +#define liblldb_GDBRemoteCommunicationClient_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ArchSpec.h" + +#include "GDBRemoteCommunication.h" + +class GDBRemoteCommunicationClient : public GDBRemoteCommunication +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + GDBRemoteCommunicationClient(); + + virtual + ~GDBRemoteCommunicationClient(); + + size_t + SendPacketAndWaitForResponse (const char *send_payload, + StringExtractorGDBRemote &response, + bool send_async); + + size_t + SendPacketAndWaitForResponse (const char *send_payload, + size_t send_length, + StringExtractorGDBRemote &response, + bool send_async); + + lldb::StateType + SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process, + const char *packet_payload, + size_t packet_length, + StringExtractorGDBRemote &response); + + virtual bool + GetThreadSuffixSupported (); + + virtual bool + GetSendAcks (); + + bool + SendAsyncSignal (int signo); + + bool + SendInterrupt (lldb_private::Mutex::Locker &locker, + uint32_t seconds_to_wait_for_stop, + bool &sent_interrupt, + bool &timed_out); + + lldb::pid_t + GetCurrentProcessID (); + + bool + GetLaunchSuccess (std::string &error_str); + + //------------------------------------------------------------------ + /// Sends a GDB remote protocol 'A' packet that delivers program + /// arguments to the remote server. + /// + /// @param[in] argv + /// A NULL terminated array of const C strings to use as the + /// arguments. + /// + /// @return + /// Zero if the response was "OK", a positive value if the + /// the response was "Exx" where xx are two hex digits, or + /// -1 if the call is unsupported or any other unexpected + /// response was received. + //------------------------------------------------------------------ + int + SendArgumentsPacket (char const *argv[]); + + //------------------------------------------------------------------ + /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the + /// environment that will get used when launching an application + /// in conjunction with the 'A' packet. This function can be called + /// multiple times in a row in order to pass on the desired + /// environment that the inferior should be launched with. + /// + /// @param[in] name_equal_value + /// A NULL terminated C string that contains a single environment + /// in the format "NAME=VALUE". + /// + /// @return + /// Zero if the response was "OK", a positive value if the + /// the response was "Exx" where xx are two hex digits, or + /// -1 if the call is unsupported or any other unexpected + /// response was received. + //------------------------------------------------------------------ + int + SendEnvironmentPacket (char const *name_equal_value); + + //------------------------------------------------------------------ + /// Sends a "vAttach:PID" where PID is in hex. + /// + /// @param[in] pid + /// A process ID for the remote gdb server to attach to. + /// + /// @param[out] response + /// The response received from the gdb server. If the return + /// value is zero, \a response will contain a stop reply + /// packet. + /// + /// @return + /// Zero if the attach was successful, or an error indicating + /// an error code. + //------------------------------------------------------------------ + int + SendAttach (lldb::pid_t pid, + StringExtractorGDBRemote& response); + + + //------------------------------------------------------------------ + /// Sets the path to use for stdin/out/err for a process + /// that will be launched with the 'A' packet. + /// + /// @param[in] path + /// The path to use for stdin/out/err + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int + SetSTDIN (char const *path); + int + SetSTDOUT (char const *path); + int + SetSTDERR (char const *path); + + //------------------------------------------------------------------ + /// Sets the disable ASLR flag to \a enable for a process that will + /// be launched with the 'A' packet. + /// + /// @param[in] enable + /// A boolean value indicating wether to disable ASLR or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int + SetDisableASLR (bool enable); + + //------------------------------------------------------------------ + /// Sets the working directory to \a path for a process that will + /// be launched with the 'A' packet. + /// + /// @param[in] path + /// The path to a directory to use when launching our processs + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int + SetWorkingDir (char const *path); + + lldb::addr_t + AllocateMemory (size_t size, uint32_t permissions); + + bool + DeallocateMemory (lldb::addr_t addr); + + const lldb_private::ArchSpec & + GetHostArchitecture (); + + const lldb_private::ConstString & + GetOSString (); + + const lldb_private::ConstString & + GetVendorString(); + + lldb::ByteOrder + GetByteOrder (); + + uint32_t + GetAddressByteSize (); + + bool + GetVContSupported (char flavor); + + void + ResetDiscoverableSettings(); + + bool + GetHostInfo (); + + bool + GetSupportsThreadSuffix (); + + bool + HasFullVContSupport () + { + return GetVContSupported ('A'); + } + + bool + HasAnyVContSupport () + { + return GetVContSupported ('a'); + } + + uint32_t + SetPacketTimeout (uint32_t packet_timeout) + { + const uint32_t old_packet_timeout = m_packet_timeout; + m_packet_timeout = packet_timeout; + return old_packet_timeout; + } + +protected: + + bool + HostInfoIsValid () const + { + return m_supports_qHostInfo != lldb::eLazyBoolCalculate; + } + + //------------------------------------------------------------------ + // Classes that inherit from GDBRemoteCommunicationClient can see and modify these + //------------------------------------------------------------------ + lldb::LazyBool m_supports_not_sending_acks; + lldb::LazyBool m_supports_thread_suffix; + lldb::LazyBool m_supports_qHostInfo; + lldb::LazyBool m_supports_vCont_all; + lldb::LazyBool m_supports_vCont_any; + lldb::LazyBool m_supports_vCont_c; + lldb::LazyBool m_supports_vCont_C; + lldb::LazyBool m_supports_vCont_s; + lldb::LazyBool m_supports_vCont_S; + + // If we need to send a packet while the target is running, the m_async_XXX + // member variables take care of making this happen. + lldb_private::Mutex m_async_mutex; + lldb_private::Predicate<bool> m_async_packet_predicate; + std::string m_async_packet; + StringExtractorGDBRemote m_async_response; + int m_async_signal; // We were asked to deliver a signal to the inferior process. + + lldb_private::ArchSpec m_arch; + uint32_t m_cpusubtype; + lldb_private::ConstString m_os; + lldb_private::ConstString m_vendor; + lldb::ByteOrder m_byte_order; + uint32_t m_pointer_byte_size; + + + +private: + //------------------------------------------------------------------ + // For GDBRemoteCommunicationClient only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient); +}; + +#endif // liblldb_GDBRemoteCommunicationClient_h_ diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp new file mode 100644 index 00000000000..2e4ff70cf2d --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -0,0 +1,134 @@ +//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "GDBRemoteCommunicationServer.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ADT/Triple.h" +#include "lldb/Interpreter/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/Host.h" +#include "lldb/Host/TimeValue.h" + +// Project includes +#include "Utility/StringExtractorGDBRemote.h" +#include "ProcessGDBRemote.h" +#include "ProcessGDBRemoteLog.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// GDBRemoteCommunicationServer constructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer() : + GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet"), + m_async_thread (LLDB_INVALID_HOST_THREAD), + m_send_acks (true) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() +{ +} + + +//void * +//GDBRemoteCommunicationServer::AsyncThread (void *arg) +//{ +// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg; +// +// LogSP log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); +// if (log) +// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID()); +// +// StringExtractorGDBRemote packet; +// +// while () +// { +// if (packet. +// } +// +// if (log) +// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID()); +// +// process->m_async_thread = LLDB_INVALID_HOST_THREAD; +// return NULL; +//} +// +bool +GDBRemoteCommunicationServer::GetPacketAndSendResponse (const TimeValue* timeout_time_ptr) +{ + StringExtractorGDBRemote packet; + if (WaitForPacketNoLock (packet, timeout_time_ptr)) + { + const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); + switch (packet_type) + { + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + break; + + case StringExtractorGDBRemote::eServerPacketType_invalid: + case StringExtractorGDBRemote::eServerPacketType_unimplemented: + return SendUnimplementedResponse () > 0; + + case StringExtractorGDBRemote::eServerPacketType_qHostInfo: + return Handle_qHostInfo (); + } + return true; + } + return false; +} + +size_t +GDBRemoteCommunicationServer::SendUnimplementedResponse () +{ + return SendPacket (""); +} + + +bool +GDBRemoteCommunicationServer::Handle_qHostInfo () +{ + StreamString response; + + // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 + + ArchSpec host_arch (Host::GetArchitecture ()); + + const llvm::Triple &host_triple = host_arch.GetTriple(); + const llvm::StringRef arch_name (host_triple.getArchName()); + const llvm::StringRef vendor_name (host_triple.getOSName()); + const llvm::StringRef os_name (host_triple.getVendorName()); + response.Printf ("arch:%.*s;ostype:%.*s;vendor:%.*s;ptrsize:%u", + (int)arch_name.size(), arch_name.data(), + (int)os_name.size(), os_name.data(), + (int)vendor_name.size(), vendor_name.data(), + host_arch.GetAddressByteSize()); + + switch (lldb::endian::InlHostByteOrder()) + { + case eByteOrderBig: response.PutCString ("endian:big;"); break; + case eByteOrderLittle: response.PutCString ("endian:little;"); break; + case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; + default: response.PutCString ("endian:unknown;"); break; + } + + return SendPacket (response.GetString().c_str(),response.GetString().size()) > 0; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h new file mode 100644 index 00000000000..8ccfca2ee1d --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -0,0 +1,69 @@ +//===-- GDBRemoteCommunicationServer.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GDBRemoteCommunicationServer_h_ +#define liblldb_GDBRemoteCommunicationServer_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "GDBRemoteCommunication.h" + +class ProcessGDBRemote; + +class GDBRemoteCommunicationServer : public GDBRemoteCommunication +{ +public: + enum + { + eBroadcastBitRunPacketSent = kLoUserBroadcastBit + }; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + GDBRemoteCommunicationServer(); + + virtual + ~GDBRemoteCommunicationServer(); + + bool + GetPacketAndSendResponse (const lldb_private::TimeValue* timeout_time_ptr); + + virtual bool + GetThreadSuffixSupported () + { + return true; + } + + virtual bool + GetSendAcks () + { + return m_send_acks; + } + +protected: + lldb::thread_t m_async_thread; + bool m_send_acks; + + size_t + SendUnimplementedResponse (); + + + bool + Handle_qHostInfo (); + +private: + //------------------------------------------------------------------ + // For GDBRemoteCommunicationServer only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer); +}; + +#endif // liblldb_GDBRemoteCommunicationServer_h_ diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index bbda3c697d5..73d3535499a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -208,7 +208,7 @@ GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor bool GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) { - GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote(); + GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote()); InvalidateIfNeeded(false); @@ -235,7 +235,7 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) assert (packet_len < (sizeof(packet) - 1)); if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) { - if (response.IsNormalPacket()) + if (response.IsNormalResponse()) if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) SetAllRegisterValid (true); } @@ -290,7 +290,7 @@ GDBRemoteRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value) bool GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset) { - GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote(); + GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote()); // FIXME: This check isn't right because IsRunning checks the Public state, but this // is work you need to do - for instance in ShouldStop & friends - before the public // state has been changed. @@ -358,7 +358,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, false)) { SetAllRegisterValid (false); - if (response.IsOKPacket()) + if (response.IsOKResponse()) { return true; } @@ -383,7 +383,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, response, false)) { - if (response.IsOKPacket()) + if (response.IsOKResponse()) { return true; } @@ -399,7 +399,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, bool GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { - GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote(); + GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote()); StringExtractorGDBRemote response; Mutex::Locker locker; @@ -418,7 +418,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - if (response.IsErrorPacket()) + if (response.IsErrorResponse()) return false; response.GetStringRef().insert(0, 1, 'G'); @@ -443,7 +443,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0) return false; - GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote(); + GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote()); StringExtractorGDBRemote response; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker)) @@ -456,7 +456,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data response, false)) { - if (response.IsOKPacket()) + if (response.IsOKResponse()) return true; } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index d88c240f30c..79949669e77 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -170,18 +170,20 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) char packet[128]; m_register_info.Clear(); - StringExtractorGDBRemote::Type packet_type = StringExtractorGDBRemote::eResponse; uint32_t reg_offset = 0; uint32_t reg_num = 0; - for (; packet_type == StringExtractorGDBRemote::eResponse; ++reg_num) + StringExtractorGDBRemote::ResponseType response_type; + for (response_type = StringExtractorGDBRemote::eResponse; + response_type == StringExtractorGDBRemote::eResponse; + ++reg_num) { const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num); assert (packet_len < sizeof(packet)); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - packet_type = response.GetType(); - if (packet_type == StringExtractorGDBRemote::eResponse) + response_type = response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) { std::string name; std::string value; @@ -298,7 +300,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) } else { - packet_type = StringExtractorGDBRemote::eError; + response_type = StringExtractorGDBRemote::eError; } } @@ -1044,7 +1046,7 @@ ProcessGDBRemote::UpdateThreadListIfNeeded () Error err; StringExtractorGDBRemote response; for (m_gdb_comm.SendPacketAndWaitForResponse("qfThreadInfo", response, false); - response.IsNormalPacket(); + response.IsNormalResponse(); m_gdb_comm.SendPacketAndWaitForResponse("qsThreadInfo", response, false)) { char ch = response.GetChar(); @@ -1460,7 +1462,7 @@ ProcessGDBRemote::GetImageInfoAddress() StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false)) { - if (response.IsNormalPacket()) + if (response.IsNormalResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } } @@ -1487,14 +1489,14 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) { - if (response.IsNormalPacket()) + if (response.IsNormalResponse()) { error.Clear(); return response.GetHexBytes(buf, size, '\xdd'); } - else if (response.IsErrorPacket()) + else if (response.IsErrorResponse()) error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str()); - else if (response.IsUnsupportedPacket()) + else if (response.IsUnsupportedResponse()) error.SetErrorStringWithFormat("'%s' packet unsupported", packet); else error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet, response.GetStringRef().c_str()); @@ -1515,14 +1517,14 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true)) { - if (response.IsOKPacket()) + if (response.IsOKResponse()) { error.Clear(); return size; } - else if (response.IsErrorPacket()) + else if (response.IsErrorResponse()) error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str()); - else if (response.IsUnsupportedPacket()) + else if (response.IsUnsupportedResponse()) error.SetErrorStringWithFormat("'%s' packet unsupported", packet.GetString().c_str()); else error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str()); @@ -1640,13 +1642,13 @@ ProcessGDBRemote::EnableBreakpoint (BreakpointSite *bp_site) StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) { - if (response.IsUnsupportedPacket()) + if (response.IsUnsupportedResponse()) { // Disable z packet support and try again m_z0_supported = 0; return EnableBreakpoint (bp_site); } - else if (response.IsOKPacket()) + else if (response.IsOKResponse()) { bp_site->SetEnabled(true); bp_site->SetType (BreakpointSite::eExternal); @@ -1708,11 +1710,11 @@ ProcessGDBRemote::DisableBreakpoint (BreakpointSite *bp_site) StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) { - if (response.IsUnsupportedPacket()) + if (response.IsUnsupportedResponse()) { error.SetErrorString("Breakpoint site was set with Z packet, yet remote debugserver states z packets are not supported."); } - else if (response.IsOKPacket()) + else if (response.IsOKResponse()) { if (log) log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS", site_id, (uint64_t)addr); @@ -2121,7 +2123,7 @@ ProcessGDBRemote::SetCurrentGDBRemoteThread (int tid) StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - if (response.IsOKPacket()) + if (response.IsOKResponse()) { m_curr_tid = tid; return true; @@ -2147,7 +2149,7 @@ ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid) StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - if (response.IsOKPacket()) + if (response.IsOKResponse()) { m_curr_tid_run = tid; return true; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 6273041825a..e9ab4df70f0 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -27,7 +27,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" -#include "GDBRemoteCommunication.h" +#include "GDBRemoteCommunicationClient.h" #include "Utility/StringExtractor.h" #include "GDBRemoteRegisterContext.h" @@ -212,7 +212,7 @@ public: protected: friend class ThreadGDBRemote; - friend class GDBRemoteCommunication; + friend class GDBRemoteCommunicationClient; friend class GDBRemoteRegisterContext; bool @@ -289,7 +289,7 @@ protected: void BuildDynamicRegisterInfo (bool force); - GDBRemoteCommunication & + GDBRemoteCommunicationClient & GetGDBRemote() { return m_gdb_comm; @@ -306,7 +306,7 @@ protected: lldb_private::Flags m_flags; // Process specific flags (see eFlags enums) lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio - GDBRemoteCommunication m_gdb_comm; + GDBRemoteCommunicationClient m_gdb_comm; lldb::pid_t m_debugserver_pid; lldb::thread_t m_debugserver_thread; StringExtractor m_last_stop_packet; |