diff options
author | Ewan Crawford <ewan@codeplay.com> | 2015-06-23 12:32:06 +0000 |
---|---|---|
committer | Ewan Crawford <ewan@codeplay.com> | 2015-06-23 12:32:06 +0000 |
commit | 76df2881ba4996ea728b985f8d7e13ba266e40f3 (patch) | |
tree | 03961d8906c6985e95ac79b1792b1c528fcdd908 /lldb/source/Plugins/Process/gdb-remote | |
parent | 3fd22703b69fed32345c786d70ef12471d784301 (diff) | |
download | bcm5719-llvm-76df2881ba4996ea728b985f8d7e13ba266e40f3.tar.gz bcm5719-llvm-76df2881ba4996ea728b985f8d7e13ba266e40f3.zip |
Add handling of async notify packets
This patch adds a listener to the AynscThread in ProcessGDBRemote, specifically for dealing with any async notification packets.
From the broadcast our listener receives we can process the notify packet from the event data. A handler function then sets the thread stop info from this packet, and updates lldb by setting the process private state to stopped. Allowing the async thread to go back to sleep and getting the main thread to handle the implications of a state change.
When sending a vCont in nonstop mode we also get a different reply from all-stop mode, an OK response as opposed to a stop reply. So a condition is added to handle this and set the process state without the stop-reply data.
Reviewers: clayborg
Subscribers: lldb-commits, labath, ted, aidan.dodds, deepak2427
Differential Revision: http://reviews.llvm.org/D10544
llvm-svn: 240397
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
4 files changed, 186 insertions, 53 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index d2a15b3152e..fe88de4c866 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -929,6 +929,57 @@ GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData return final_output.str(); } +bool +GDBRemoteCommunicationClient::SendvContPacket +( + ProcessGDBRemote *process, + const char *payload, + size_t packet_length, + StringExtractorGDBRemote &response +) +{ + + m_curr_tid = LLDB_INVALID_THREAD_ID; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + + // we want to lock down packet sending while we continue + Mutex::Locker locker(m_sequence_mutex); + + // here we broadcast this before we even send the packet!! + // this signals doContinue() to exit + BroadcastEvent(eBroadcastBitRunPacketSent, NULL); + + // set the public state to running + m_public_is_running.SetValue(true, eBroadcastNever); + + // Set the starting continue packet into "continue_packet". This packet + // may change if we are interrupted and we continue after an async packet... + std::string continue_packet(payload, packet_length); + + if (log) + log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str()); + + if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) + return false; + + // set the private state to running and broadcast this + m_private_is_running.SetValue(true, eBroadcastAlways); + + if (log) + log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); + + // wait for the response to the vCont + if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + return true; + } + + return false; +} + StateType GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse ( diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index ba34a313090..3e5d954c8af 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -78,6 +78,11 @@ public: const char *packet_payload, size_t packet_length, StringExtractorGDBRemote &response); + bool + SendvContPacket (ProcessGDBRemote *process, + const char *payload, + size_t packet_length, + StringExtractorGDBRemote &response); bool GetThreadSuffixSupported () override; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 64972dfda36..d41bdc70681 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1592,7 +1592,18 @@ ProcessGDBRemote::DoResume () { // All threads are resuming... m_gdb_comm.SetCurrentThreadForRun (-1); - continue_packet.PutChar ('s'); + + // If in Non-Stop-Mode use vCont when stepping + if (GetTarget().GetNonStopModeEnabled()) + { + if (m_gdb_comm.GetVContSupported('s')) + continue_packet.PutCString("vCont;s"); + else + continue_packet.PutChar('s'); + } + else + continue_packet.PutChar('s'); + continue_packet_error = false; } else if (num_continue_c_tids == 0 && @@ -3228,6 +3239,34 @@ ProcessGDBRemote::StopAsyncThread () log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__); } +bool +ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet) +{ + // get the packet at a string + const std::string &pkt = packet.GetStringRef(); + // skip %stop: + StringExtractorGDBRemote stop_info(pkt.c_str() + 5); + + // pass as a thread stop info packet + SetLastStopPacket(stop_info); + + // check for more stop reasons + HandleStopReplySequence(); + + // if the process is stopped then we need to fake a resume + // so that we can stop properly with the new break. This + // is possible due to SetPrivateState() broadcasting the + // state change as a side effect. + if (GetPrivateState() == lldb::StateType::eStateStopped) + { + SetPrivateState(lldb::StateType::eStateRunning); + } + + // since we have some stopped packets we can halt the process + SetPrivateState(lldb::StateType::eStateStopped); + + return true; +} thread_result_t ProcessGDBRemote::AsyncThread (void *arg) @@ -3245,8 +3284,9 @@ ProcessGDBRemote::AsyncThread (void *arg) if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask) { - listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit); - + listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit | + GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify); + bool done = false; while (!done) { @@ -3276,61 +3316,77 @@ ProcessGDBRemote::AsyncThread (void *arg) if (::strstr (continue_cstr, "vAttach") == NULL) process->SetPrivateState(eStateRunning); StringExtractorGDBRemote response; - StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response); - - // We need to immediately clear the thread ID list so we are sure to get a valid list of threads. - // The thread ID list might be contained within the "response", or the stop reply packet that - // caused the stop. So clear it now before we give the stop reply packet to the process - // using the process->SetLastStopPacket()... - process->ClearThreadIDList (); - - switch (stop_state) + + // If in Non-Stop-Mode + if (process->GetTarget().GetNonStopModeEnabled()) { - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - process->SetLastStopPacket (response); - process->SetPrivateState (stop_state); - break; - - case eStateExited: + // send the vCont packet + if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response)) + { + // Something went wrong + done = true; + break; + } + } + // If in All-Stop-Mode + else { - process->SetLastStopPacket (response); - process->ClearThreadIDList(); - response.SetFilePos(1); - - int exit_status = response.GetHexU8(); - const char *desc_cstr = NULL; - StringExtractor extractor; - std::string desc_string; - if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') + StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response); + + // We need to immediately clear the thread ID list so we are sure to get a valid list of threads. + // The thread ID list might be contained within the "response", or the stop reply packet that + // caused the stop. So clear it now before we give the stop reply packet to the process + // using the process->SetLastStopPacket()... + process->ClearThreadIDList (); + + switch (stop_state) + { + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + process->SetLastStopPacket (response); + process->SetPrivateState (stop_state); + break; + + case eStateExited: { - std::string desc_token; - while (response.GetNameColonValue (desc_token, desc_string)) + process->SetLastStopPacket (response); + process->ClearThreadIDList(); + response.SetFilePos(1); + + int exit_status = response.GetHexU8(); + const char *desc_cstr = NULL; + StringExtractor extractor; + std::string desc_string; + if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') { - if (desc_token == "description") + std::string desc_token; + while (response.GetNameColonValue (desc_token, desc_string)) { - extractor.GetStringRef().swap(desc_string); - extractor.SetFilePos(0); - extractor.GetHexByteString (desc_string); - desc_cstr = desc_string.c_str(); + if (desc_token == "description") + { + extractor.GetStringRef().swap(desc_string); + extractor.SetFilePos(0); + extractor.GetHexByteString (desc_string); + desc_cstr = desc_string.c_str(); + } } } + process->SetExitStatus(exit_status, desc_cstr); + done = true; + break; } - process->SetExitStatus(exit_status, desc_cstr); - done = true; - break; - } - case eStateInvalid: - process->SetExitStatus(-1, "lost connection"); - break; - - default: - process->SetPrivateState (stop_state); - break; - } - } - } + case eStateInvalid: + process->SetExitStatus(-1, "lost connection"); + break; + + default: + process->SetPrivateState (stop_state); + break; + } // switch(stop_state) + } // else // if in All-stop-mode + } // if (continue_packet) + } // case eBroadcastBitAysncContinue break; case eBroadcastBitAsyncThreadShouldExit: @@ -3348,10 +3404,28 @@ ProcessGDBRemote::AsyncThread (void *arg) } else if (event_sp->BroadcasterIs (&process->m_gdb_comm)) { - if (event_type & Communication::eBroadcastBitReadThreadDidExit) + switch (event_type) { - process->SetExitStatus (-1, "lost connection"); - done = true; + case Communication::eBroadcastBitReadThreadDidExit: + process->SetExitStatus (-1, "lost connection"); + done = true; + break; + + case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify: + { + lldb_private::Event *event = event_sp.get(); + const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event); + StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes()); + // Hand this over to the process to handle + process->HandleNotifyPacket(notify); + break; + } + + default: + if (log) + log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); + done = true; + break; } } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 02f449ffca4..174d9e7501f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -361,6 +361,9 @@ protected: lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach bool + HandleNotifyPacket(StringExtractorGDBRemote &packet); + + bool StartAsyncThread (); void |