Skip to content

Commit

Permalink
Add handling of async notify packets
Browse files Browse the repository at this point in the history
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
  • Loading branch information
EwanC committed Jun 23, 2015
1 parent 3fd2270 commit 76df288
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 53 deletions.
Expand Up @@ -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
(
Expand Down
Expand Up @@ -78,6 +78,11 @@ class GDBRemoteCommunicationClient : public GDBRemoteCommunication
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;
Expand Down
180 changes: 127 additions & 53 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Expand Up @@ -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 &&
Expand Down Expand Up @@ -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)
Expand All @@ -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)
{
Expand Down Expand Up @@ -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:
Expand All @@ -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;
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
Expand Up @@ -360,6 +360,9 @@ class ProcessGDBRemote : public Process
int64_t m_breakpoint_pc_offset;
lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach

bool
HandleNotifyPacket(StringExtractorGDBRemote &packet);

bool
StartAsyncThread ();

Expand Down

0 comments on commit 76df288

Please sign in to comment.