Skip to content

Commit

Permalink
Add jstopinfo support to llgs
Browse files Browse the repository at this point in the history
Summary:
This adds support for jstopinfo field of stop-reply packets. This field enables us to avoid
querying full thread stop data on most stops  (see r242593 for more details).

Reviewers: ovyalov, clayborg

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D11415

llvm-svn: 242997
  • Loading branch information
labath committed Jul 23, 2015
1 parent 5a95b0a commit 05569f6
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 71 deletions.
2 changes: 1 addition & 1 deletion lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
Expand Up @@ -1492,7 +1492,7 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
if (m_pending_notification_up && m_pending_notification_up->triggering_tid == pid)
linux_thread_sp->SetStoppedBySignal(SIGSTOP, info);
else
linux_thread_sp->SetStoppedBySignal(0);
linux_thread_sp->SetStoppedWithNoReason();

SetCurrentThreadID (thread_sp->GetID ());
ThreadDidStop (thread_sp->GetID (), true);
Expand Down
6 changes: 3 additions & 3 deletions lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
Expand Up @@ -362,14 +362,14 @@ NativeThreadLinux::SetStoppedByTrace ()
}

void
NativeThreadLinux::SetSuspended ()
NativeThreadLinux::SetStoppedWithNoReason ()
{
const StateType new_state = StateType::eStateSuspended;
const StateType new_state = StateType::eStateStopped;
MaybeLogStateChange (new_state);
m_state = new_state;

// FIXME what makes sense here? Do we need a suspended StopReason?
m_stop_info.reason = StopReason::eStopReasonNone;
m_stop_info.details.signal.signo = 0;
}

void
Expand Down
5 changes: 1 addition & 4 deletions lldb/source/Plugins/Process/Linux/NativeThreadLinux.h
Expand Up @@ -87,10 +87,7 @@ namespace process_linux {
SetStoppedByTrace ();

void
SetCrashedWithException (const siginfo_t& info);

void
SetSuspended ();
SetStoppedWithNoReason ();

void
SetExited ();
Expand Down
Expand Up @@ -537,6 +537,86 @@ GetStopReasonString(StopReason stop_reason)
return nullptr;
}

static JSONArray::SP
GetJSONThreadsInfo(NativeProcessProtocol &process, bool threads_with_valid_stop_info_only)
{
Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));

JSONArray::SP threads_array_sp = std::make_shared<JSONArray>();

// Ensure we can get info on the given thread.
uint32_t thread_idx = 0;
for ( NativeThreadProtocolSP thread_sp;
(thread_sp = process.GetThreadAtIndex(thread_idx)) != nullptr;
++thread_idx)
{

lldb::tid_t tid = thread_sp->GetID();

// Grab the reason this thread stopped.
struct ThreadStopInfo tid_stop_info;
std::string description;
if (!thread_sp->GetStopReason (tid_stop_info, description))
return nullptr;

const int signum = tid_stop_info.details.signal.signo;
if (log)
{
log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
__FUNCTION__,
process.GetID (),
tid,
signum,
tid_stop_info.reason,
tid_stop_info.details.exception.type);
}

if (threads_with_valid_stop_info_only && tid_stop_info.reason == eStopReasonNone)
continue; // No stop reason, skip this thread completely.

JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>();
threads_array_sp->AppendObject(thread_obj_sp);

thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid));
if (signum != 0)
thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(uint64_t(signum)));

const std::string thread_name = thread_sp->GetName ();
if (! thread_name.empty())
thread_obj_sp->SetObject("name", std::make_shared<JSONString>(thread_name));

if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason))
thread_obj_sp->SetObject("reason", std::make_shared<JSONString>(stop_reason_str));

if (! description.empty())
thread_obj_sp->SetObject("description", std::make_shared<JSONString>(description));

if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type)
{
thread_obj_sp->SetObject("metype",
std::make_shared<JSONNumber>(tid_stop_info.details.exception.type));

JSONArray::SP medata_array_sp = std::make_shared<JSONArray>();
for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i)
{
medata_array_sp->AppendObject(std::make_shared<JSONNumber>(
tid_stop_info.details.exception.data[i]));
}
thread_obj_sp->SetObject("medata", medata_array_sp);
}

if (threads_with_valid_stop_info_only)
continue; // Only send the abridged stop info.

if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp))
thread_obj_sp->SetObject("registers", registers_sp);

// TODO: Expedite interesting regions of inferior memory
}

return threads_array_sp;
}

GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid)
{
Expand Down Expand Up @@ -630,6 +710,31 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid)
response.Printf ("%" PRIx64, listed_thread_sp->GetID ());
}
response.PutChar (';');

// Include JSON info that describes the stop reason for any threads
// that actually have stop reasons. We use the new "jstopinfo" key
// whose values is hex ascii JSON that contains the thread IDs
// thread stop info only for threads that have stop reasons. Only send
// this if we have more than one thread otherwise this packet has all
// the info it needs.
if (thread_index > 0)
{
const bool threads_with_valid_stop_info_only = true;
JSONArray::SP threads_info_sp = GetJSONThreadsInfo(*m_debugged_process_sp,
threads_with_valid_stop_info_only);
if (threads_info_sp)
{
response.PutCString("jstopinfo:");
StreamString unescaped_response;
threads_info_sp->Write(unescaped_response);
response.PutCStringAsRawHex8(unescaped_response.GetData());
response.PutChar(';');
}
else if (log)
log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a jstopinfo field for pid %" PRIu64,
__FUNCTION__, m_debugged_process_sp->GetID());

}
}

//
Expand Down Expand Up @@ -2719,74 +2824,20 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo (StringExtractorGDBRemote
log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64,
__FUNCTION__, m_debugged_process_sp->GetID());

JSONArray threads_array;

// Ensure we can get info on the given thread.
uint32_t thread_idx = 0;
for ( NativeThreadProtocolSP thread_sp;
(thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_idx)) != nullptr;
++thread_idx)
StreamString response;
const bool threads_with_valid_stop_info_only = false;
JSONArray::SP threads_array_sp = GetJSONThreadsInfo(*m_debugged_process_sp,
threads_with_valid_stop_info_only);
if (! threads_array_sp)
{

JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>();

lldb::tid_t tid = thread_sp->GetID();

// Grab the reason this thread stopped.
struct ThreadStopInfo tid_stop_info;
std::string description;
if (!thread_sp->GetStopReason (tid_stop_info, description))
return SendErrorResponse (52);

const int signum = tid_stop_info.details.signal.signo;
if (log)
{
log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
__FUNCTION__,
m_debugged_process_sp->GetID (),
tid,
signum,
tid_stop_info.reason,
tid_stop_info.details.exception.type);
}

thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid));
if (signum != LLDB_INVALID_SIGNAL_NUMBER)
thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(uint64_t(signum)));

const std::string thread_name = thread_sp->GetName ();
if (! thread_name.empty())
thread_obj_sp->SetObject("name", std::make_shared<JSONString>(thread_name));

if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp))
thread_obj_sp->SetObject("registers", registers_sp);

if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason))
thread_obj_sp->SetObject("reason", std::make_shared<JSONString>(stop_reason_str));

if (! description.empty())
thread_obj_sp->SetObject("description", std::make_shared<JSONString>(description));

if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type)
{
thread_obj_sp->SetObject("metype",
std::make_shared<JSONNumber>(tid_stop_info.details.exception.type));

JSONArray::SP medata_array_sp = std::make_shared<JSONArray>();
for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i)
{
medata_array_sp->AppendObject(std::make_shared<JSONNumber>(
tid_stop_info.details.exception.data[i]));
}
thread_obj_sp->SetObject("medata", medata_array_sp);
}

threads_array.AppendObject(thread_obj_sp);
log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a packet for pid %" PRIu64,
__FUNCTION__, m_debugged_process_sp->GetID());
return SendErrorResponse(52);
}
// TODO: Expedite interesting regions of inferior memory

StreamString response;
threads_array.Write(response);
threads_array_sp->Write(response);
StreamGDBRemote escaped_response;
escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
return SendPacketNoLock (escaped_response.GetData(), escaped_response.GetSize());
Expand Down

0 comments on commit 05569f6

Please sign in to comment.