diff options
Diffstat (limited to 'lldb/source/Plugins/Process')
5 files changed, 192 insertions, 107 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index eaa03984f50..e308f915d1c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -262,10 +262,9 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse 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 (SendInterrupt(locker, 2, timed_out)) { - if (sent_interrupt) + if (m_interrupt_sent) { TimeValue timeout_time; timeout_time = TimeValue::Now(); @@ -309,9 +308,18 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse else { // We had a racy condition where we went to send the interrupt - // yet we were able to get the lock + // yet we were able to get the lock, so the process must have + // just stopped? if (log) - log->Printf ("async: got lock but failed to send interrupt"); + log->Printf ("async: got lock without sending interrupt"); + // Send the packet normally since we got the lock + if (SendPacketNoLock (payload, payload_length)) + response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); + else + { + if (log) + log->Printf("error: failed to send '%*s'", (int) payload_length, payload); + } } } else @@ -412,98 +420,152 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse { case 'T': case 'S': - if (process->GetStopID() == 0) { - if (process->GetID() == LLDB_INVALID_PROCESS_ID) + if (process->GetStopID() == 0) { - lldb::pid_t pid = GetCurrentProcessID (); - if (pid != LLDB_INVALID_PROCESS_ID) - process->SetID (pid); + if (process->GetID() == LLDB_INVALID_PROCESS_ID) + { + lldb::pid_t pid = GetCurrentProcessID (); + if (pid != LLDB_INVALID_PROCESS_ID) + process->SetID (pid); + } + process->BuildDynamicRegisterInfo (true); } - 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)); + // 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); - // We already stopped with a signal that we wanted - // to stop with, so we are done - response.SetFilePos (0); - } - else + const uint8_t signo = response.GetHexU8 (UINT8_MAX); + + bool continue_after_aync = false; + if (m_async_signal != -1 || m_async_packet_predicate.GetValue()) { - // 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; + continue_after_aync = true; + // We sent an interrupt packet to stop the inferior process + // for an async signal or to send an async packet while running + // but we might have been single stepping and received the + // stop packet for the step instead of for the interrupt packet. + // Typically when an interrupt is sent a SIGINT or SIGSTOP + // is used, so if we get anything else, we need to try and + // get another stop reply packet that may have been sent + // due to sending the interrupt when the target is stopped + // which will just re-send a copy of the last stop reply + // packet. If we don't do this, then the reply for our + // async packet will be the repeat stop reply packet and cause + // a lot of trouble for us! + if (signo != SIGINT && signo != SIGSTOP) + { + continue_after_aync = false; + + // We didn't get a a SIGINT or SIGSTOP, so try for a + // very brief time (1 ms) to get another stop reply + // packet to make sure it doesn't get in the way + StringExtractorGDBRemote extra_stop_reply_packet; + uint32_t timeout_usec = 1000; + if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec)) + { + switch (extra_stop_reply_packet.GetChar()) + { + case 'T': + case 'S': + // We did get an extra stop reply, which means + // our interrupt didn't stop the target so we + // shouldn't continue after the async signal + // or packet is sent... + continue_after_aync = false; + break; + } + } + } } - } - 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 (m_async_signal != -1) { - if (log) - log->Printf ("async: error: empty async packet"); + 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 + 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 + } + 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 even if the + // interrupt didn't cause our stop (ignore continue_after_aync) + continue_packet.assign(signal_packet, signal_packet_len); + continue; + } } - else + else if (m_async_packet_predicate.GetValue()) { - 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); + LogSP packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); + + // We are supposed to send an asynchronous packet while + // we are running. + m_async_response.Clear(); + if (m_async_packet.empty()) + { + if (packet_log) + packet_log->Printf ("async: error: empty async packet"); + + } + else + { + if (packet_log) + packet_log->Printf ("async: sending packet"); + + 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); + + if (packet_log) + packet_log->Printf ("async: sent packet, continue_after_aync = %i", continue_after_aync); + + // Set the continue packet to resume if our interrupt + // for the async packet did cause the stop + if (continue_after_aync) + { + continue_packet.assign (1, 'c'); + continue; + } } - // 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; } - // Stop with signal and thread info - state = eStateStopped; break; case 'W': @@ -556,11 +618,11 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse bool GDBRemoteCommunicationClient::SendAsyncSignal (int signo) { + Mutex::Locker async_locker (m_async_mutex); m_async_signal = signo; bool timed_out = false; - bool sent_interrupt = false; Mutex::Locker locker; - if (SendInterrupt (locker, 1, sent_interrupt, timed_out)) + if (SendInterrupt (locker, 1, timed_out)) return true; m_async_signal = -1; return false; @@ -577,17 +639,16 @@ GDBRemoteCommunicationClient::SendAsyncSignal (int signo) // (gdb remote protocol requires this), and do what we need to do, then resume. bool -GDBRemoteCommunicationClient::SendInterrupt +GDBRemoteCommunicationClient::SendInterrupt ( Mutex::Locker& locker, uint32_t seconds_to_wait_for_stop, - bool &sent_interrupt, bool &timed_out ) { - sent_interrupt = false; + m_interrupt_sent = false; timed_out = false; - LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + LogSP log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); if (IsRunning()) { @@ -598,51 +659,57 @@ GDBRemoteCommunicationClient::SendInterrupt // 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 (log) + log->PutCString("send packet: \\x03"); if (bytes_written > 0) { - sent_interrupt = true; + m_interrupt_sent = true; if (seconds_to_wait_for_stop) { + TimeValue timeout; + if (seconds_to_wait_for_stop) + { + timeout = TimeValue::Now(); + timeout.OffsetWithSeconds (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__); + log->PutCString ("SendInterrupt () - sent interrupt, private state stopped"); return true; } else { if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, timed out wating for async thread resume", __FUNCTION__); + log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume"); } } else { if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, not waiting for stop...", __FUNCTION__); + log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop..."); return true; } } else { if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () - failed to write interrupt", __FUNCTION__); + log->Printf ("SendInterrupt () - failed to write interrupt"); } return false; } else { if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () - got sequence mutex without having to interrupt", __FUNCTION__); + log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt"); } } + else + { + if (log) + log->Printf ("SendInterrupt () - not running"); + } return true; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 30d6fb0707e..dd0eea9f4a1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -77,7 +77,6 @@ public: bool SendInterrupt (lldb_private::Mutex::Locker &locker, uint32_t seconds_to_wait_for_stop, - bool &sent_interrupt, bool &timed_out); lldb::pid_t @@ -322,6 +321,11 @@ public: GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids, bool &sequence_mutex_unavailable); + bool + GetInterruptWasSent () const + { + return m_interrupt_sent; + } protected: //------------------------------------------------------------------ @@ -363,6 +367,7 @@ protected: std::string m_async_packet; StringExtractorGDBRemote m_async_response; int m_async_signal; // We were asked to deliver a signal to the inferior process. + bool m_interrupt_sent; lldb_private::ArchSpec m_host_arch; uint32_t m_os_version_major; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 5bc0e5e201e..47ebf22a97a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1426,13 +1426,15 @@ ProcessGDBRemote::DoHalt (bool &caused_stop) } else { - if (!m_gdb_comm.SendInterrupt (locker, 2, caused_stop, timed_out)) + if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out)) { if (timed_out) error.SetErrorString("timed out sending interrupt packet"); else error.SetErrorString("unknown error sending interrupt packet"); } + + caused_stop = m_gdb_comm.GetInterruptWasSent (); } return error; } @@ -1474,10 +1476,9 @@ ProcessGDBRemote::InterruptIfRunning } bool timed_out = false; - bool sent_interrupt = false; Mutex::Locker locker; - if (!m_gdb_comm.SendInterrupt (locker, 1, sent_interrupt, timed_out)) + if (!m_gdb_comm.SendInterrupt (locker, 1, timed_out)) { if (timed_out) error.SetErrorString("timed out sending interrupt packet"); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp index f16966bed3e..cb764238683 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp @@ -42,6 +42,15 @@ ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask) return log; } +LogSP +ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask) +{ + LogSP log(GetLog ()); + if (log && log->GetMask().Get() & mask) + return log; + return LogSP(); +} + void ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm) { diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index 4f6f39c5576..cf5e176a213 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -37,6 +37,9 @@ class ProcessGDBRemoteLog public: static lldb::LogSP GetLogIfAllCategoriesSet(uint32_t mask = 0); + + static lldb::LogSP + GetLogIfAnyCategoryIsSet (uint32_t mask); static void DisableLog (const char **categories, lldb_private::Stream *feedback_strm); |