diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 703 |
1 files changed, 472 insertions, 231 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 123a8198a89b..63174ef55219 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -35,6 +35,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" @@ -106,6 +107,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_P); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, &GDBRemoteCommunicationServerLLGS::Handle_qC); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_T, + &GDBRemoteCommunicationServerLLGS::Handle_T); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); @@ -232,8 +235,22 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { }); RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vKill, + &GDBRemoteCommunicationServerLLGS::Handle_vKill); + + RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore, &GDBRemoteCommunicationServerLLGS::Handle_qSaveCore); + + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QNonStop, + &GDBRemoteCommunicationServerLLGS::Handle_QNonStop); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vStopped, + &GDBRemoteCommunicationServerLLGS::Handle_vStopped); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vCtrlC, + &GDBRemoteCommunicationServerLLGS::Handle_vCtrlC); } void GDBRemoteCommunicationServerLLGS::SetLaunchInfo(const ProcessLaunchInfo &info) { @@ -241,7 +258,7 @@ void GDBRemoteCommunicationServerLLGS::SetLaunchInfo(const ProcessLaunchInfo &in } Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (!m_process_launch_info.GetArguments().GetArgumentCount()) return Status("%s: no process command line specified to launch", @@ -323,7 +340,7 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { } Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, __FUNCTION__, pid); @@ -370,7 +387,7 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess( llvm::StringRef process_name, bool include_existing) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1); @@ -440,7 +457,7 @@ Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess( void GDBRemoteCommunicationServerLLGS::InitializeDelegate( NativeProcessProtocol *process) { assert(process && "process cannot be NULL"); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (log) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called with " @@ -454,7 +471,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendWResponse( NativeProcessProtocol *process) { assert(process && "process cannot be NULL"); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // send W notification auto wait_status = process->GetExitStatus(); @@ -471,8 +488,17 @@ GDBRemoteCommunicationServerLLGS::SendWResponse( LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(), *wait_status); + // If the process was killed through vKill, return "OK". + if (m_vkilled_processes.find(process->GetID()) != m_vkilled_processes.end()) + return SendOKResponse(); + StreamGDBRemote response; response.Format("{0:g}", *wait_status); + if (bool(m_extensions_supported & NativeProcessProtocol::Extension::multiprocess)) + response.Format(";process:{0:x-}", process->GetID()); + if (m_non_stop) + return SendNotificationPacketNoLock("Stop", m_stop_notification_queue, + response.GetString()); return SendPacketNoLock(response.GetString()); } @@ -608,7 +634,7 @@ static void WriteRegisterValueInHexFixedWidth( static llvm::Optional<json::Object> GetRegistersAsJSON(NativeThreadProtocol &thread) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); NativeRegisterContext& reg_ctx = thread.GetRegisterContext(); @@ -693,26 +719,21 @@ static const char *GetStopReasonString(StopReason stop_reason) { static llvm::Expected<json::Array> GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); json::Array threads_array; // Ensure we can get info on the given thread. - uint32_t thread_idx = 0; - for (NativeThreadProtocol *thread; - (thread = process.GetThreadAtIndex(thread_idx)) != nullptr; - ++thread_idx) { - - lldb::tid_t tid = thread->GetID(); - + for (NativeThreadProtocol &thread : process.Threads()) { + lldb::tid_t tid = thread.GetID(); // Grab the reason this thread stopped. struct ThreadStopInfo tid_stop_info; std::string description; - if (!thread->GetStopReason(tid_stop_info, description)) + if (!thread.GetStopReason(tid_stop_info, description)) return llvm::make_error<llvm::StringError>( "failed to get stop reason", llvm::inconvertibleErrorCode()); - const int signum = tid_stop_info.details.signal.signo; + const int signum = tid_stop_info.signo; if (log) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 @@ -725,7 +746,7 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { json::Object thread_obj; if (!abridged) { - if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(*thread)) + if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(thread)) thread_obj.try_emplace("registers", std::move(*registers)); } @@ -734,7 +755,7 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { if (signum != 0) thread_obj.try_emplace("signal", signum); - const std::string thread_name = thread->GetName(); + const std::string thread_name = thread.GetName(); if (!thread_name.empty()) thread_obj.try_emplace("name", thread_name); @@ -763,29 +784,22 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { return threads_array; } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( - lldb::tid_t tid) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); +StreamString +GDBRemoteCommunicationServerLLGS::PrepareStopReplyPacketForThread( + NativeThreadProtocol &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); - // Ensure we have a debugged process. - if (!m_current_process || - (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(50); + NativeProcessProtocol &process = thread.GetProcess(); - LLDB_LOG(log, "preparing packet for pid {0} tid {1}", - m_current_process->GetID(), tid); - - // Ensure we can get info on the given thread. - NativeThreadProtocol *thread = m_current_process->GetThreadByID(tid); - if (!thread) - return SendErrorResponse(51); + LLDB_LOG(log, "preparing packet for pid {0} tid {1}", process.GetID(), + thread.GetID()); // Grab the reason this thread stopped. + StreamString response; struct ThreadStopInfo tid_stop_info; std::string description; - if (!thread->GetStopReason(tid_stop_info, description)) - return SendErrorResponse(52); + if (!thread.GetStopReason(tid_stop_info, description)) + return response; // FIXME implement register handling for exec'd inferiors. // if (tid_stop_info.reason == eStopReasonExec) { @@ -793,24 +807,25 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( // InitializeRegisters(force); // } - StreamString response; // Output the T packet with the thread response.PutChar('T'); - int signum = tid_stop_info.details.signal.signo; + int signum = tid_stop_info.signo; LLDB_LOG( log, "pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}", - m_current_process->GetID(), tid, signum, int(tid_stop_info.reason), + process.GetID(), thread.GetID(), signum, int(tid_stop_info.reason), tid_stop_info.details.exception.type); // Print the signal number. response.PutHex8(signum & 0xff); - // Include the tid. - response.Printf("thread:%" PRIx64 ";", tid); + // Include the (pid and) tid. + response.PutCString("thread:"); + AppendThreadIDToResponse(response, process.GetID(), thread.GetID()); + response.PutChar(';'); // Include the thread name if there is one. - const std::string thread_name = thread->GetName(); + const std::string thread_name = thread.GetName(); if (!thread_name.empty()) { size_t thread_name_len = thread_name.length(); @@ -836,14 +851,12 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( if (m_list_threads_in_stop_reply) { response.PutCString("threads:"); - uint32_t thread_index = 0; - NativeThreadProtocol *listed_thread; - for (listed_thread = m_current_process->GetThreadAtIndex(thread_index); - listed_thread; ++thread_index, - listed_thread = m_current_process->GetThreadAtIndex(thread_index)) { - if (thread_index > 0) + uint32_t thread_num = 0; + for (NativeThreadProtocol &listed_thread : process.Threads()) { + if (thread_num > 0) response.PutChar(','); - response.Printf("%" PRIx64, listed_thread->GetID()); + response.Printf("%" PRIx64, listed_thread.GetID()); + ++thread_num; } response.PutChar(';'); @@ -852,7 +865,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( // 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 > 1) { + if (thread_num > 1) { const bool threads_with_valid_stop_info_only = true; llvm::Expected<json::Array> threads_info = GetJSONThreadsInfo( *m_current_process, threads_with_valid_stop_info_only); @@ -865,16 +878,14 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } else { LLDB_LOG_ERROR(log, threads_info.takeError(), "failed to prepare a jstopinfo field for pid {1}: {0}", - m_current_process->GetID()); + process.GetID()); } } - uint32_t i = 0; response.PutCString("thread-pcs"); char delimiter = ':'; - for (NativeThreadProtocol *thread; - (thread = m_current_process->GetThreadAtIndex(i)) != nullptr; ++i) { - NativeRegisterContext& reg_ctx = thread->GetRegisterContext(); + for (NativeThreadProtocol &thread : process.Threads()) { + NativeRegisterContext ®_ctx = thread.GetRegisterContext(); uint32_t reg_to_read = reg_ctx.ConvertRegisterKindToRegisterNumber( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); @@ -905,7 +916,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( // // Grab the register context. - NativeRegisterContext& reg_ctx = thread->GetRegisterContext(); + NativeRegisterContext ®_ctx = thread.GetRegisterContext(); const auto expedited_regs = reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full); @@ -922,8 +933,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( ®_value, lldb::eByteOrderBig); response.PutChar(';'); } else { - LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to read " - "register '%s' index %" PRIu32 ": %s", + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s failed to read " + "register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", reg_num, error.AsCString()); @@ -972,17 +984,53 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( tid_stop_info.details.fork.child_tid); } + return response; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( + NativeProcessProtocol &process, lldb::tid_t tid, bool force_synchronous) { + // Ensure we can get info on the given thread. + NativeThreadProtocol *thread = process.GetThreadByID(tid); + if (!thread) + return SendErrorResponse(51); + + StreamString response = PrepareStopReplyPacketForThread(*thread); + if (response.Empty()) + return SendErrorResponse(42); + + if (m_non_stop && !force_synchronous) { + PacketResult ret = SendNotificationPacketNoLock( + "Stop", m_stop_notification_queue, response.GetString()); + // Queue notification events for the remaining threads. + EnqueueStopReplyPackets(tid); + return ret; + } + return SendPacketNoLock(response.GetString()); } +void GDBRemoteCommunicationServerLLGS::EnqueueStopReplyPackets( + lldb::tid_t thread_to_skip) { + if (!m_non_stop) + return; + + for (NativeThreadProtocol &listed_thread : m_current_process->Threads()) { + if (listed_thread.GetID() != thread_to_skip) + m_stop_notification_queue.push_back( + PrepareStopReplyPacketForThread(listed_thread).GetString().str()); + } +} + void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( NativeProcessProtocol *process) { assert(process && "process cannot be NULL"); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); - PacketResult result = SendStopReasonForState(StateType::eStateExited); + PacketResult result = SendStopReasonForState( + *process, StateType::eStateExited, /*force_synchronous=*/false); if (result != PacketResult::Success) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to send stop " @@ -990,20 +1038,37 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( __FUNCTION__, process->GetID()); } - // Close the pipe to the inferior terminal i/o if we launched it and set one - // up. - MaybeCloseInferiorTerminalConnection(); - - // We are ready to exit the debug monitor. - m_exit_now = true; - m_mainloop.RequestTermination(); + if (m_current_process == process) + m_current_process = nullptr; + if (m_continue_process == process) + m_continue_process = nullptr; + + lldb::pid_t pid = process->GetID(); + m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) { + m_debugged_processes.erase(pid); + auto vkill_it = m_vkilled_processes.find(pid); + if (vkill_it != m_vkilled_processes.end()) + m_vkilled_processes.erase(vkill_it); + // Terminate the main loop only if vKill has not been used. + // When running in non-stop mode, wait for the vStopped to clear + // the notification queue. + else if (m_debugged_processes.empty() && !m_non_stop) { + // Close the pipe to the inferior terminal i/o if we launched it and set + // one up. + MaybeCloseInferiorTerminalConnection(); + + // We are ready to exit the debug monitor. + m_exit_now = true; + loop.RequestTermination(); + } + }); } void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( NativeProcessProtocol *process) { assert(process && "process cannot be NULL"); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Send the stop reason unless this is the stop after the launch or attach. @@ -1014,7 +1079,8 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( break; default: // In all other cases, send the stop reason. - PacketResult result = SendStopReasonForState(StateType::eStateStopped); + PacketResult result = SendStopReasonForState( + *process, StateType::eStateStopped, /*force_synchronous=*/false); if (result != PacketResult::Success) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to send stop " @@ -1028,7 +1094,7 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped( void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( NativeProcessProtocol *process, lldb::StateType state) { assert(process && "process cannot be NULL"); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (log) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called with " @@ -1038,7 +1104,6 @@ void GDBRemoteCommunicationServerLLGS::ProcessStateChanged( switch (state) { case StateType::eStateRunning: - StartSTDIOForwarding(); break; case StateType::eStateStopped: @@ -1163,7 +1228,7 @@ void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() { return; Status error; - lldbassert(!m_stdio_handle_up); + assert(!m_stdio_handle_up); m_stdio_handle_up = m_mainloop.RegisterReadObject( m_stdio_communication.GetConnection()->GetReadObject(), [this](MainLoopBase &) { SendProcessOutput(); }, error); @@ -1171,11 +1236,8 @@ void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() { if (!m_stdio_handle_up) { // Not much we can do about the failure. Log it and continue without // forwarding. - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio " - "forwarding: %s", - __FUNCTION__, error.AsCString()); + if (Log *log = GetLog(LLDBLog::Process)) + LLDB_LOG(log, "Failed to set up stdio forwarding: {0}", error); } } @@ -1198,7 +1260,7 @@ void GDBRemoteCommunicationServerLLGS::SendProcessOutput() { case eConnectionStatusEndOfFile: case eConnectionStatusError: case eConnectionStatusNoConnection: - if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) + if (Log *log = GetLog(LLDBLog::Process)) LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s Stopping stdio " "forwarding as communication returned status %d (error: " @@ -1349,29 +1411,61 @@ GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { return SendErrorResponse(69); StreamString response; - response.Printf("QC%" PRIx64, thread->GetID()); + response.PutCString("QC"); + AppendThreadIDToResponse(response, m_current_process->GetID(), + thread->GetID()); return SendPacketNoLock(response.GetString()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); StopSTDIOForwarding(); - if (!m_current_process) { + if (m_debugged_processes.empty()) { LLDB_LOG(log, "No debugged process found."); return PacketResult::Success; } - Status error = m_current_process->Kill(); + for (auto it = m_debugged_processes.begin(); it != m_debugged_processes.end(); + ++it) { + LLDB_LOG(log, "Killing process {0}", it->first); + Status error = it->second->Kill(); + if (error.Fail()) + LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", it->first, + error); + } + + // The response to kill packet is undefined per the spec. LLDB + // follows the same rules as for continue packets, i.e. no response + // in all-stop mode, and "OK" in non-stop mode; in both cases this + // is followed by the actual stop reason. + return SendContinueSuccessResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vKill( + StringExtractorGDBRemote &packet) { + StopSTDIOForwarding(); + + packet.SetFilePos(6); // vKill; + uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse(packet, + "vKill failed to parse the process id"); + + auto it = m_debugged_processes.find(pid); + if (it == m_debugged_processes.end()) + return SendErrorResponse(42); + + Status error = it->second->Kill(); if (error.Fail()) - LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", - m_current_process->GetID(), error); + return SendErrorResponse(error.ToError()); - // No OK response for kill packet. - // return SendOKResponse (); + // OK response is sent when the process dies. + m_vkilled_processes.insert(pid); return PacketResult::Success; } @@ -1425,7 +1519,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Ensure we have a native process. @@ -1500,13 +1594,14 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { return SendErrorResponse(0x38); } - // Don't send an "OK" packet; response is the stopped/exited message. - return PacketResult::Success; + // Don't send an "OK" packet, except in non-stop mode; + // otherwise, the response is the stopped/exited message. + return SendContinueSuccessResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); packet.SetFilePos(packet.GetFilePos() + ::strlen("c")); @@ -1540,15 +1635,15 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { } LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); - // No response required from continue. - return PacketResult::Success; + + return SendContinueSuccessResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vCont_actions( StringExtractorGDBRemote &packet) { StreamString response; - response.Printf("vCont;c;C;s;S"); + response.Printf("vCont;c;C;s;S;t"); return SendPacketNoLock(response.GetString()); } @@ -1556,7 +1651,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont_actions( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vCont( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s handling vCont packet", __FUNCTION__); @@ -1570,24 +1665,16 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( return SendIllFormedResponse(packet, "Missing action from vCont package"); } - // Check if this is all continue (no options or ";c"). - if (::strcmp(packet.Peek(), ";c") == 0) { - // Move past the ';', then do a simple 'c'. - packet.SetFilePos(packet.GetFilePos() + 1); - return Handle_c(packet); - } else if (::strcmp(packet.Peek(), ";s") == 0) { + if (::strcmp(packet.Peek(), ";s") == 0) { // Move past the ';', then do a simple 's'. packet.SetFilePos(packet.GetFilePos() + 1); return Handle_s(packet); + } else if (m_non_stop && ::strcmp(packet.Peek(), ";t") == 0) { + // TODO: add full support for "t" action + return SendOKResponse(); } - // Ensure we have a native process. - if (!m_continue_process) { - LLDB_LOG(log, "no debugged process"); - return SendErrorResponse(0x36); - } - - ResumeActionList thread_actions; + std::unordered_map<lldb::pid_t, ResumeActionList> thread_actions; while (packet.GetBytesLeft() && *packet.Peek() == ';') { // Skip the semi-colon. @@ -1625,43 +1712,78 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( thread_action.state = eStateStepping; break; + case 't': + // Stop + thread_action.state = eStateSuspended; + break; + default: return SendIllFormedResponse(packet, "Unsupported vCont action"); break; } + lldb::pid_t pid = StringExtractorGDBRemote::AllProcesses; + lldb::tid_t tid = StringExtractorGDBRemote::AllThreads; + // Parse out optional :{thread-id} value. if (packet.GetBytesLeft() && (*packet.Peek() == ':')) { // Consume the separator. packet.GetChar(); - llvm::Expected<lldb::tid_t> tid_ret = - ReadTid(packet, /*allow_all=*/true, m_continue_process->GetID()); - if (!tid_ret) - return SendErrorResponse(tid_ret.takeError()); + auto pid_tid = packet.GetPidTid(StringExtractorGDBRemote::AllProcesses); + if (!pid_tid) + return SendIllFormedResponse(packet, "Malformed thread-id"); + + pid = pid_tid->first; + tid = pid_tid->second; + } - thread_action.tid = tid_ret.get(); - if (thread_action.tid == StringExtractorGDBRemote::AllThreads) - thread_action.tid = LLDB_INVALID_THREAD_ID; + if (pid == StringExtractorGDBRemote::AllProcesses) { + if (m_debugged_processes.size() > 1) + return SendIllFormedResponse( + packet, "Resuming multiple processes not supported yet"); + if (!m_continue_process) { + LLDB_LOG(log, "no debugged process"); + return SendErrorResponse(0x36); + } + pid = m_continue_process->GetID(); } - thread_actions.Append(thread_action); + if (tid == StringExtractorGDBRemote::AllThreads) + tid = LLDB_INVALID_THREAD_ID; + + thread_action.tid = tid; + + thread_actions[pid].Append(thread_action); } - Status error = m_continue_process->Resume(thread_actions); - if (error.Fail()) { - LLDB_LOG(log, "vCont failed for process {0}: {1}", - m_continue_process->GetID(), error); - return SendErrorResponse(GDBRemoteServerError::eErrorResume); + assert(thread_actions.size() >= 1); + if (thread_actions.size() > 1) + return SendIllFormedResponse( + packet, "Resuming multiple processes not supported yet"); + + for (std::pair<lldb::pid_t, ResumeActionList> x : thread_actions) { + auto process_it = m_debugged_processes.find(x.first); + if (process_it == m_debugged_processes.end()) { + LLDB_LOG(log, "vCont failed for process {0}: process not debugged", + x.first); + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } + + Status error = process_it->second->Resume(x.second); + if (error.Fail()) { + LLDB_LOG(log, "vCont failed for process {0}: {1}", x.first, error); + return SendErrorResponse(GDBRemoteServerError::eErrorResume); + } + + LLDB_LOG(log, "continued process {0}", x.first); } - LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); - // No response required from vCont. - return PacketResult::Success; + return SendContinueSuccessResponse(); } void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOG(log, "setting current thread id to {0}", tid); m_current_tid = tid; @@ -1670,7 +1792,7 @@ void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { } void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); LLDB_LOG(log, "setting continue thread id to {0}", tid); m_continue_tid = tid; @@ -1681,17 +1803,47 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason( StringExtractorGDBRemote &packet) { // Handle the $? gdbremote command. + if (m_non_stop) { + // Clear the notification queue first, except for pending exit + // notifications. + llvm::erase_if(m_stop_notification_queue, [](const std::string &x) { + return x.front() != 'W' && x.front() != 'X'; + }); + + if (m_current_process) { + // Queue stop reply packets for all active threads. Start with + // the current thread (for clients that don't actually support multiple + // stop reasons). + NativeThreadProtocol *thread = m_current_process->GetCurrentThread(); + if (thread) + m_stop_notification_queue.push_back( + PrepareStopReplyPacketForThread(*thread).GetString().str()); + EnqueueStopReplyPackets(thread ? thread->GetID() + : LLDB_INVALID_THREAD_ID); + } + + // If the notification queue is empty (i.e. everything is running), send OK. + if (m_stop_notification_queue.empty()) + return SendOKResponse(); + + // Send the first item from the new notification queue synchronously. + return SendPacketNoLock(m_stop_notification_queue.front()); + } + // If no process, indicate error if (!m_current_process) return SendErrorResponse(02); - return SendStopReasonForState(m_current_process->GetState()); + return SendStopReasonForState(*m_current_process, + m_current_process->GetState(), + /*force_synchronous=*/true); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendStopReasonForState( - lldb::StateType process_state) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + NativeProcessProtocol &process, lldb::StateType process_state, + bool force_synchronous) { + Log *log = GetLog(LLDBLog::Process); switch (process_state) { case eStateAttaching: @@ -1706,22 +1858,21 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateSuspended: case eStateStopped: case eStateCrashed: { - assert(m_current_process != nullptr); - lldb::tid_t tid = m_current_process->GetCurrentThreadID(); + lldb::tid_t tid = process.GetCurrentThreadID(); // Make sure we set the current thread so g and p packets return the data // the gdb will expect. SetCurrentThreadID(tid); - return SendStopReplyPacketForThread(tid); + return SendStopReplyPacketForThread(process, tid, force_synchronous); } case eStateInvalid: case eStateUnloaded: case eStateExited: - return SendWResponse(m_current_process); + return SendWResponse(&process); default: LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}", - m_current_process->GetID(), process_state); + process.GetID(), process_state); break; } @@ -1819,38 +1970,38 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( return SendPacketNoLock(response.GetString()); } +void GDBRemoteCommunicationServerLLGS::AddProcessThreads( + StreamGDBRemote &response, NativeProcessProtocol &process, bool &had_any) { + Log *log = GetLog(LLDBLog::Thread); + + lldb::pid_t pid = process.GetID(); + if (pid == LLDB_INVALID_PROCESS_ID) + return; + + LLDB_LOG(log, "iterating over threads of process {0}", process.GetID()); + for (NativeThreadProtocol &thread : process.Threads()) { + LLDB_LOG(log, "iterated thread tid={0}", thread.GetID()); + response.PutChar(had_any ? ',' : 'm'); + AppendThreadIDToResponse(response, pid, thread.GetID()); + had_any = true; + } +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_current_process || - (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { - LLDB_LOG(log, "no process ({0}), returning OK", - m_current_process ? "invalid process id" - : "null m_current_process"); - return SendOKResponse(); - } + assert(m_debugged_processes.size() == 1 || + bool(m_extensions_supported & + NativeProcessProtocol::Extension::multiprocess)); + bool had_any = false; StreamGDBRemote response; - response.PutChar('m'); - LLDB_LOG(log, "starting thread iteration"); - NativeThreadProtocol *thread; - uint32_t thread_index; - for (thread_index = 0, - thread = m_current_process->GetThreadAtIndex(thread_index); - thread; ++thread_index, - thread = m_current_process->GetThreadAtIndex(thread_index)) { - LLDB_LOG(log, "iterated thread {0}(tid={2})", thread_index, - thread->GetID()); - if (thread_index > 0) - response.PutChar(','); - response.Printf("%" PRIx64, thread->GetID()); - } + for (auto &pid_ptr : m_debugged_processes) + AddProcessThreads(response, *pid_ptr.second, had_any); - LLDB_LOG(log, "finished thread iteration"); + if (!had_any) + return SendOKResponse(); return SendPacketNoLock(response.GetString()); } @@ -1864,7 +2015,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Move past packet name. packet.SetFilePos(strlen("g")); @@ -1919,7 +2070,7 @@ GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Parse out the register number from the request. packet.SetFilePos(strlen("p")); @@ -1995,7 +2146,7 @@ GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Ensure there is more content. if (packet.GetBytesLeft() < 1) @@ -2075,7 +2226,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Parse out which variant of $H is requested. packet.SetFilePos(strlen("H")); @@ -2166,7 +2317,7 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Fail if we don't have a current process. if (!m_current_process || @@ -2202,7 +2353,7 @@ GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_interrupt( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); // Fail if we don't have a current process. if (!m_current_process || @@ -2228,7 +2379,7 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_memory_read( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (!m_current_process || (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { @@ -2308,7 +2459,7 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (!m_current_process || (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { @@ -2357,7 +2508,7 @@ GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (!m_current_process || (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { @@ -2385,7 +2536,7 @@ GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); if (!m_current_process || (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { @@ -2465,7 +2616,7 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Currently only the NativeProcessProtocol knows if it can handle a // qMemoryRegionInfoSupported request, but we're not guaranteed to be @@ -2498,7 +2649,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Ensure we have a process. if (!m_current_process || @@ -2580,7 +2731,7 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { // Ensure we have a process. if (!m_current_process || (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } @@ -2652,7 +2803,7 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { m_current_process->SetBreakpoint(addr, size, want_hardware); if (error.Success()) return SendOKResponse(); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}", m_current_process->GetID(), error); return SendErrorResponse(0x09); @@ -2662,7 +2813,7 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { addr, size, watch_flags, want_hardware); if (error.Success()) return SendOKResponse(); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}", m_current_process->GetID(), error); return SendErrorResponse(0x09); @@ -2674,7 +2825,7 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { // Ensure we have a process. if (!m_current_process || (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } @@ -2740,7 +2891,7 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { m_current_process->RemoveBreakpoint(addr, want_hardware); if (error.Success()) return SendOKResponse(); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}", m_current_process->GetID(), error); return SendErrorResponse(0x09); @@ -2749,7 +2900,7 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { const Status error = m_current_process->RemoveWatchpoint(addr); if (error.Success()) return SendOKResponse(); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + Log *log = GetLog(LLDBLog::Watchpoints); LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}", m_current_process->GetID(), error); return SendErrorResponse(0x09); @@ -2758,7 +2909,7 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); // Ensure we have a process. if (!m_continue_process || @@ -2803,8 +2954,9 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { return SendErrorResponse(0x49); } - // No response here - the stop or exit will come from the resulting action. - return PacketResult::Success; + // No response here, unless in non-stop mode. + // Otherwise, the stop or exit will come from the resulting action. + return SendContinueSuccessResponse(); } llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> @@ -2815,7 +2967,7 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { return llvm::createStringError(llvm::inconvertibleErrorCode(), "No thread available"); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); // Get the register context for the first thread. NativeRegisterContext ®_context = thread->GetRegisterContext(); @@ -3032,7 +3184,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qXfer( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Move past packet name. packet.SetFilePos(strlen("QSaveRegisterState")); @@ -3052,7 +3204,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( NativeRegisterContext& reg_context = thread->GetRegisterContext(); // Save registers to a buffer. - DataBufferSP register_data_sp; + WritableDataBufferSP register_data_sp; Status error = reg_context.ReadAllRegisterValues(register_data_sp); if (error.Fail()) { LLDB_LOG(log, "pid {0} failed to save all register values: {1}", @@ -3080,7 +3232,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Parse out save id. packet.SetFilePos(strlen("QRestoreRegisterState:")); @@ -3141,7 +3293,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vAttach( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Consume the ';' after vAttach. packet.SetFilePos(strlen("vAttach")); @@ -3171,13 +3323,16 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_current_process->GetState()); + assert(m_current_process); + return SendStopReasonForState(*m_current_process, + m_current_process->GetState(), + /*force_synchronous=*/false); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vAttachWait( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Consume the ';' after the identifier. packet.SetFilePos(strlen("vAttachWait")); @@ -3201,7 +3356,10 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttachWait( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_current_process->GetState()); + assert(m_current_process); + return SendStopReasonForState(*m_current_process, + m_current_process->GetState(), + /*force_synchronous=*/false); } GDBRemoteCommunication::PacketResult @@ -3213,7 +3371,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Consume the ';' after the identifier. packet.SetFilePos(strlen("vAttachOrWait")); @@ -3237,13 +3395,16 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_current_process->GetState()); + assert(m_current_process); + return SendStopReasonForState(*m_current_process, + m_current_process->GetState(), + /*force_synchronous=*/false); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vRun( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); llvm::StringRef s = packet.GetStringRef(); if (!s.consume_front("vRun;")) @@ -3265,8 +3426,12 @@ GDBRemoteCommunicationServerLLGS::Handle_vRun( m_process_launch_info.GetExecutableFile().SetFile( m_process_launch_info.GetArguments()[0].ref(), FileSpec::Style::native); m_process_launch_error = LaunchProcess(); - if (m_process_launch_error.Success()) - return SendStopReasonForState(m_current_process->GetState()); + if (m_process_launch_error.Success()) { + assert(m_current_process); + return SendStopReasonForState(*m_current_process, + m_current_process->GetState(), + /*force_synchronous=*/true); + } LLDB_LOG(log, "failed to launch exe: {0}", m_process_launch_error); } return SendErrorResponse(8); @@ -3274,6 +3439,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vRun( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { + Log *log = GetLog(LLDBLog::Process); StopSTDIOForwarding(); lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; @@ -3297,6 +3463,9 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { for (auto it = m_debugged_processes.begin(); it != m_debugged_processes.end();) { if (pid == LLDB_INVALID_PROCESS_ID || pid == it->first) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s detaching %" PRId64, + __FUNCTION__, it->first); if (llvm::Error e = it->second->Detach().ToError()) detach_error = llvm::joinErrors(std::move(detach_error), std::move(e)); else { @@ -3322,7 +3491,11 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); + + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(50); packet.SetFilePos(strlen("qThreadStopInfo")); const lldb::tid_t tid = packet.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); @@ -3333,13 +3506,14 @@ GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo( __FUNCTION__, packet.GetStringRef().data()); return SendErrorResponse(0x15); } - return SendStopReplyPacketForThread(tid); + return SendStopReplyPacketForThread(*m_current_process, tid, + /*force_synchronous=*/true); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( StringExtractorGDBRemote &) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); // Ensure we have a debugged process. if (!m_current_process || @@ -3455,7 +3629,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QPassSignals( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qMemTags( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Ensure we have a process. if (!m_current_process || @@ -3536,7 +3710,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemTags( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QMemTags( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Ensure we have a process. if (!m_current_process || @@ -3656,8 +3830,91 @@ GDBRemoteCommunicationServerLLGS::Handle_qSaveCore( return SendPacketNoLock(response.GetString()); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QNonStop( + StringExtractorGDBRemote &packet) { + StringRef packet_str{packet.GetStringRef()}; + assert(packet_str.startswith("QNonStop:")); + packet_str.consume_front("QNonStop:"); + if (packet_str == "0") { + m_non_stop = false; + // TODO: stop all threads + } else if (packet_str == "1") { + m_non_stop = true; + } else + return SendErrorResponse(Status("Invalid QNonStop packet")); + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vStopped( + StringExtractorGDBRemote &packet) { + // Per the protocol, the first message put into the queue is sent + // immediately. However, it remains the queue until the client ACKs + // it via vStopped -- then we pop it and send the next message. + // The process repeats until the last message in the queue is ACK-ed, + // in which case the vStopped packet sends an OK response. + + if (m_stop_notification_queue.empty()) + return SendErrorResponse(Status("No pending notification to ack")); + m_stop_notification_queue.pop_front(); + if (!m_stop_notification_queue.empty()) + return SendPacketNoLock(m_stop_notification_queue.front()); + // If this was the last notification and all the processes exited, + // terminate the server. + if (m_debugged_processes.empty()) { + m_exit_now = true; + m_mainloop.RequestTermination(); + } + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vCtrlC( + StringExtractorGDBRemote &packet) { + if (!m_non_stop) + return SendErrorResponse(Status("vCtrl is only valid in non-stop mode")); + + PacketResult interrupt_res = Handle_interrupt(packet); + // If interrupting the process failed, pass the result through. + if (interrupt_res != PacketResult::Success) + return interrupt_res; + // Otherwise, vCtrlC should issue an OK response (normal interrupts do not). + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_T(StringExtractorGDBRemote &packet) { + packet.SetFilePos(strlen("T")); + auto pid_tid = packet.GetPidTid(m_current_process ? m_current_process->GetID() + : LLDB_INVALID_PROCESS_ID); + if (!pid_tid) + return SendErrorResponse(llvm::make_error<StringError>( + inconvertibleErrorCode(), "Malformed thread-id")); + + lldb::pid_t pid = pid_tid->first; + lldb::tid_t tid = pid_tid->second; + + // Technically, this would also be caught by the PID check but let's be more + // explicit about the error. + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(llvm::make_error<StringError>( + inconvertibleErrorCode(), "No current process and no PID provided")); + + // Check the process ID and find respective process instance. + auto new_process_it = m_debugged_processes.find(pid); + if (new_process_it == m_debugged_processes.end()) + return SendErrorResponse(1); + + // Check the thread ID + if (!new_process_it->second->GetThreadByID(tid)) + return SendErrorResponse(2); + + return SendOKResponse(); +} + void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); // Tell the stdio connection to shut down. if (m_stdio_communication.IsConnected()) { @@ -3701,7 +3958,7 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( return m_current_process->GetThreadByID(current_tid); } - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + Log *log = GetLog(LLDBLog::Thread); // Parse out the ';'. if (packet.GetBytesLeft() < 1 || packet.GetChar() != ';') { @@ -3752,7 +4009,7 @@ uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() { } void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOG(log, "clearing {0} xfer buffers", m_xfer_buffer_map.size()); m_xfer_buffer_map.clear(); @@ -3799,38 +4056,6 @@ std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue( return result; } -llvm::Expected<lldb::tid_t> GDBRemoteCommunicationServerLLGS::ReadTid( - StringExtractorGDBRemote &packet, bool allow_all, lldb::pid_t default_pid) { - assert(m_current_process); - assert(m_current_process->GetID() != LLDB_INVALID_PROCESS_ID); - - auto pid_tid = packet.GetPidTid(default_pid); - if (!pid_tid) - return llvm::make_error<StringError>(inconvertibleErrorCode(), - "Malformed thread-id"); - - lldb::pid_t pid = pid_tid->first; - lldb::tid_t tid = pid_tid->second; - - if (!allow_all && pid == StringExtractorGDBRemote::AllProcesses) - return llvm::make_error<StringError>( - inconvertibleErrorCode(), - llvm::formatv("PID value {0} not allowed", pid == 0 ? 0 : -1)); - - if (!allow_all && tid == StringExtractorGDBRemote::AllThreads) - return llvm::make_error<StringError>( - inconvertibleErrorCode(), - llvm::formatv("TID value {0} not allowed", tid == 0 ? 0 : -1)); - - if (pid != StringExtractorGDBRemote::AllProcesses) { - if (pid != m_current_process->GetID()) - return llvm::make_error<StringError>( - inconvertibleErrorCode(), llvm::formatv("PID {0} not debugged", pid)); - } - - return tid; -} - std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( const llvm::ArrayRef<llvm::StringRef> client_features) { std::vector<std::string> ret = @@ -3839,6 +4064,7 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( "QThreadSuffixSupported+", "QListThreadsInStopReply+", "qXfer:features:read+", + "QNonStop+", }); // report server-only features @@ -3893,6 +4119,21 @@ void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions( process.SetEnabledExtensions(flags); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::SendContinueSuccessResponse() { + // TODO: how to handle forwarding in non-stop mode? + StartSTDIOForwarding(); + return m_non_stop ? SendOKResponse() : PacketResult::Success; +} + +void GDBRemoteCommunicationServerLLGS::AppendThreadIDToResponse( + Stream &response, lldb::pid_t pid, lldb::tid_t tid) { + if (bool(m_extensions_supported & + NativeProcessProtocol::Extension::multiprocess)) + response.Format("p{0:x-}.", pid); + response.Format("{0:x-}", tid); +} + std::string lldb_private::process_gdb_remote::LLGSArgToURL(llvm::StringRef url_arg, bool reverse_connect) { |