Index: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -1492,7 +1492,7 @@ 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); Index: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -87,10 +87,7 @@ SetStoppedByTrace (); void - SetCrashedWithException (const siginfo_t& info); - - void - SetSuspended (); + SetStoppedWithNoReason (); void SetExited (); Index: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -362,14 +362,14 @@ } 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 Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -537,6 +537,86 @@ 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(); + + // 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(); + threads_array_sp->AppendObject(thread_obj_sp); + + thread_obj_sp->SetObject("tid", std::make_shared(tid)); + if (signum != 0) + thread_obj_sp->SetObject("signal", std::make_shared(uint64_t(signum))); + + const std::string thread_name = thread_sp->GetName (); + if (! thread_name.empty()) + thread_obj_sp->SetObject("name", std::make_shared(thread_name)); + + if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) + thread_obj_sp->SetObject("reason", std::make_shared(stop_reason_str)); + + if (! description.empty()) + thread_obj_sp->SetObject("description", std::make_shared(description)); + + if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) + { + thread_obj_sp->SetObject("metype", + std::make_shared(tid_stop_info.details.exception.type)); + + JSONArray::SP medata_array_sp = std::make_shared(); + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) + { + medata_array_sp->AppendObject(std::make_shared( + 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) { @@ -630,6 +710,31 @@ 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()); + + } } // @@ -2719,74 +2824,20 @@ 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(); - - 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(tid)); - if (signum != LLDB_INVALID_SIGNAL_NUMBER) - thread_obj_sp->SetObject("signal", std::make_shared(uint64_t(signum))); - - const std::string thread_name = thread_sp->GetName (); - if (! thread_name.empty()) - thread_obj_sp->SetObject("name", std::make_shared(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(stop_reason_str)); - - if (! description.empty()) - thread_obj_sp->SetObject("description", std::make_shared(description)); - - if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) - { - thread_obj_sp->SetObject("metype", - std::make_shared(tid_stop_info.details.exception.type)); - - JSONArray::SP medata_array_sp = std::make_shared(); - for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - { - medata_array_sp->AppendObject(std::make_shared( - 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());