Index: lldb/trunk/include/lldb/Target/Target.h =================================================================== --- lldb/trunk/include/lldb/Target/Target.h +++ lldb/trunk/include/lldb/Target/Target.h @@ -189,6 +189,9 @@ void SetUserSpecifiedTrapHandlerNames (const Args &args); + + bool + GetNonStopModeEnabled () const; bool GetDisplayRuntimeSupportValues () const; Index: lldb/trunk/source/Commands/CommandObjectThread.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectThread.cpp +++ lldb/trunk/source/Commands/CommandObjectThread.cpp @@ -433,6 +433,12 @@ m_step_in_avoid_no_debug = eLazyBoolCalculate; m_step_out_avoid_no_debug = eLazyBoolCalculate; m_run_mode = eOnlyDuringStepping; + + // Check if we are in Non-Stop mode + lldb::TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget(); + if (target_sp.get() != nullptr && target_sp->GetNonStopModeEnabled()) + m_run_mode = eOnlyThisThread; + m_avoid_regexp.clear(); m_step_in_target.clear(); m_class_name.clear(); Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -424,6 +424,7 @@ content_length = total_length = 1; // The command is one byte long... break; + case '%': // Async notify packet case '$': // Look for a standard gdb packet? { @@ -466,6 +467,7 @@ case '+': case '-': case '\x03': + case '%': case '$': done = true; break; @@ -586,7 +588,7 @@ } } - if (m_bytes[0] == '$') + if (m_bytes[0] == '$' || m_bytes[0] == '%') { assert (checksum_idx < m_bytes.size()); if (::isxdigit (m_bytes[checksum_idx+0]) || Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -318,6 +318,9 @@ bool GetHostInfo (bool force = false); + + bool + GetDefaultThreadId (lldb::tid_t &tid); bool GetOSVersion (uint32_t &major, @@ -393,6 +396,9 @@ lldb::addr_t addr, // Address of breakpoint or watchpoint uint32_t length); // Byte Size of breakpoint or watchpoint + bool + SetNonStopMode (const bool enable); + void TestPacketSpeed (const uint32_t num_packets); Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1621,6 +1621,22 @@ } bool +GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid) +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success) + return false; + + if (!response.IsNormalResponse()) + return false; + + if (response.GetChar() == 'Q' && response.GetChar() == 'C') + tid = response.GetHexMaxU32(true, -1); + + return true; +} + +bool GDBRemoteCommunicationClient::GetHostInfo (bool force) { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); @@ -2759,6 +2775,25 @@ return false; } +bool +GDBRemoteCommunicationClient::SetNonStopMode (const bool enable) +{ + // Form non-stop packet request + char packet[32]; + const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); + assert(packet_len < (int)sizeof(packet)); + + StringExtractorGDBRemote response; + // Send to target + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) + if (response.IsOKResponse()) + return true; + + // Failed or not supported + return false; + +} + void GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) { Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -358,6 +358,7 @@ bool m_destroy_tried_resuming; lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; + lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach bool StartAsyncThread (); @@ -379,6 +380,9 @@ SetThreadStopInfo (StringExtractor& stop_packet); void + HandleStopReplySequence (); + + void ClearThreadIDList (); bool Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -391,7 +391,8 @@ m_waiting_for_attach (false), m_destroy_tried_resuming (false), m_command_sp (), - m_breakpoint_pc_offset (0) + m_breakpoint_pc_offset (0), + m_initial_tid (LLDB_INVALID_THREAD_ID) { m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); @@ -769,8 +770,13 @@ // We have a valid process SetID (pid); GetThreadList(); - if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success) + if (m_gdb_comm.GetStopReply(m_last_stop_packet)) { + + // '?' Packets must be handled differently in non-stop mode + if (GetTarget().GetNonStopModeEnabled()) + HandleStopReplySequence(); + if (!m_target.GetArchitecture().IsValid()) { if (m_gdb_comm.GetProcessArchitecture().IsValid()) @@ -1052,8 +1058,13 @@ return error; } - if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success) + if (m_gdb_comm.GetStopReply(m_last_stop_packet)) { + + // '?' Packets must be handled differently in non-stop mode + if (GetTarget().GetNonStopModeEnabled()) + HandleStopReplySequence(); + const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture(); if (process_arch.IsValid()) @@ -1153,12 +1164,22 @@ error.SetErrorString("not connected to remote gdb server"); return error; } + + // Send $QNonStop:1 packet on startup if required + if (GetTarget().GetNonStopModeEnabled()) + m_gdb_comm.SetNonStopMode(true); + m_gdb_comm.GetThreadSuffixSupported (); m_gdb_comm.GetListThreadsInStopReplySupported (); m_gdb_comm.GetHostInfo (); m_gdb_comm.GetVContSupported ('c'); m_gdb_comm.GetVAttachOrWaitSupported(); - + + // Ask the remote server for the default thread id + if (GetTarget().GetNonStopModeEnabled()) + m_gdb_comm.GetDefaultThreadId(m_initial_tid); + + size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); for (size_t idx = 0; idx < num_cmds; idx++) { @@ -1430,11 +1451,12 @@ bool continue_packet_error = false; if (m_gdb_comm.HasAnyVContSupport ()) { - if (m_continue_c_tids.size() == num_threads || + if (!GetTarget().GetNonStopModeEnabled() && + (m_continue_c_tids.size() == num_threads || (m_continue_c_tids.empty() && m_continue_C_tids.empty() && m_continue_s_tids.empty() && - m_continue_S_tids.empty())) + m_continue_S_tids.empty()))) { // All threads are continuing, just send a "c" packet continue_packet.PutCString ("c"); @@ -1662,6 +1684,27 @@ } void +ProcessGDBRemote::HandleStopReplySequence () +{ + while(true) + { + // Send vStopped + StringExtractorGDBRemote response; + m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); + + // OK represents end of signal list + if (response.IsOKResponse()) + break; + + // If not OK or a normal packet we have a problem + if (!response.IsNormalResponse()) + break; + + SetLastStopPacket(response); + } +} + +void ProcessGDBRemote::ClearThreadIDList () { Mutex::Locker locker(m_thread_list_real.GetMutex()); @@ -2095,6 +2138,13 @@ UpdateThreadIDList(); } + // If we have queried for a default thread id + if (m_initial_tid != LLDB_INVALID_THREAD_ID) + { + m_thread_list.SetSelectedThreadByID(m_initial_tid); + m_initial_tid = LLDB_INVALID_THREAD_ID; + } + // Let all threads recover from stopping and do any clean up based // on the previous thread state (if any). m_thread_list_real.RefreshStateAfterStop(); Index: lldb/trunk/source/Target/Target.cpp =================================================================== --- lldb/trunk/source/Target/Target.cpp +++ lldb/trunk/source/Target/Target.cpp @@ -2978,6 +2978,7 @@ { "display-expression-in-crashlogs" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "Expressions that crash will show up in crash logs if the host system supports executable specific crash log strings and this setting is set to true." }, { "trap-handler-names" , OptionValue::eTypeArray , true, OptionValue::eTypeString, NULL, NULL, "A list of trap handler function names, e.g. a common Unix user process one is _sigtramp." }, { "display-runtime-support-values" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "If true, LLDB will show variables that are meant to support the operation of a language's runtime support." }, + { "non-stop-mode" , OptionValue::eTypeBoolean , false, 0, NULL, NULL, "Disable lock-step debugging, instead control threads independently." }, { NULL , OptionValue::eTypeInvalid , false, 0 , NULL, NULL, NULL } }; @@ -3016,7 +3017,8 @@ ePropertyMemoryModuleLoadLevel, ePropertyDisplayExpressionsInCrashlogs, ePropertyTrapHandlerNames, - ePropertyDisplayRuntimeSupportValues + ePropertyDisplayRuntimeSupportValues, + ePropertyNonStopModeEnabled }; @@ -3515,6 +3517,13 @@ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); } +bool +TargetProperties::GetNonStopModeEnabled () const +{ + const uint32_t idx = ePropertyNonStopModeEnabled; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, false); +} + const ProcessLaunchInfo & TargetProperties::GetProcessLaunchInfo () { Index: lldb/trunk/source/Utility/StringExtractorGDBRemote.h =================================================================== --- lldb/trunk/source/Utility/StringExtractorGDBRemote.h +++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h @@ -145,6 +145,7 @@ eServerPacketType__M, eServerPacketType__m, + eServerPacketType_notify, // '%' notification }; ServerPacketType Index: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp +++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp @@ -64,6 +64,10 @@ const char *packet_cstr = m_packet.c_str(); switch (m_packet[0]) { + + case '%': + return eServerPacketType_notify; + case '\x03': if (packet_size == 1) return eServerPacketType_interrupt; break;