diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
15 files changed, 693 insertions, 499 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index 8364ffeef46f..e3a3cfc4f23e 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -347,7 +347,7 @@ GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, } void GDBRemoteClientBase::Lock::SyncWithContinueThread() { - Log *log = GetLog(GDBRLog::Process); + Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets); std::unique_lock<std::mutex> lock(m_comm.m_mutex); if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0)) return; // We were asked to avoid interrupting the sender. Lock is not diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 38d9e400978d..e5461c1899ec 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -125,6 +125,29 @@ GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { } GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::SendNotificationPacketNoLock( + llvm::StringRef notify_type, std::deque<std::string> &queue, + llvm::StringRef payload) { + PacketResult ret = PacketResult::Success; + + // If there are no notification in the queue, send the notification + // packet. + if (queue.empty()) { + StreamString packet(0, 4, eByteOrderBig); + packet.PutChar('%'); + packet.Write(notify_type.data(), notify_type.size()); + packet.PutChar(':'); + packet.Write(payload.data(), payload.size()); + packet.PutChar('#'); + packet.PutHex8(CalculcateChecksum(payload)); + ret = SendRawPacketNoLock(packet.GetString(), true); + } + + queue.push_back(payload.str()); + return ret; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet, bool skip_ack) { if (IsConnected()) { @@ -843,7 +866,7 @@ Status GDBRemoteCommunication::StartListenThread(const char *hostname, m_listen_url = listen_url; SetConnection(std::make_unique<ConnectionFileDescriptor>()); llvm::Expected<HostThread> listen_thread = ThreadLauncher::LaunchThread( - listen_url, GDBRemoteCommunication::ListenThread, this); + listen_url, [this] { return GDBRemoteCommunication::ListenThread(); }); if (!listen_thread) return Status(listen_thread.takeError()); m_listen_thread = *listen_thread; @@ -857,23 +880,22 @@ bool GDBRemoteCommunication::JoinListenThread() { return true; } -lldb::thread_result_t -GDBRemoteCommunication::ListenThread(lldb::thread_arg_t arg) { - GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; +lldb::thread_result_t GDBRemoteCommunication::ListenThread() { Status error; ConnectionFileDescriptor *connection = - (ConnectionFileDescriptor *)comm->GetConnection(); + (ConnectionFileDescriptor *)GetConnection(); if (connection) { // Do the listen on another thread so we can continue on... if (connection->Connect( - comm->m_listen_url.c_str(), [comm](llvm::StringRef port_str) { + m_listen_url.c_str(), + [this](llvm::StringRef port_str) { uint16_t port = 0; llvm::to_integer(port_str, port, 10); - comm->m_port_promise.set_value(port); + m_port_promise.set_value(port); }, &error) != eConnectionStatusSuccess) - comm->SetConnection(nullptr); + SetConnection(nullptr); } return {}; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index afc7e740d4c9..35e86c202b5b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -183,6 +183,9 @@ protected: CompressionType m_compression_type; PacketResult SendPacketNoLock(llvm::StringRef payload); + PacketResult SendNotificationPacketNoLock(llvm::StringRef notify_type, + std::deque<std::string>& queue, + llvm::StringRef payload); PacketResult SendRawPacketNoLock(llvm::StringRef payload, bool skip_ack = false); @@ -218,7 +221,7 @@ protected: bool JoinListenThread(); - static lldb::thread_result_t ListenThread(lldb::thread_arg_t arg); + lldb::thread_result_t ListenThread(); private: // Promise used to grab the port number from listening thread diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 91b9151328a8..700e6ebdf84c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -24,6 +24,7 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" @@ -642,7 +643,7 @@ DataBufferSP GDBRemoteCommunicationClient::ReadMemoryTags(lldb::addr_t addr, } size_t expected_bytes = response.GetBytesLeft() / 2; - DataBufferSP buffer_sp(new DataBufferHeap(expected_bytes, 0)); + WritableDataBufferSP buffer_sp(new DataBufferHeap(expected_bytes, 0)); size_t got_bytes = response.GetHexBytesAvail(buffer_sp->GetData()); // Check both because in some situations chars are consumed even // if the decoding fails. @@ -2227,8 +2228,10 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub); break; case llvm::Triple::GOFF: + case llvm::Triple::SPIRV: case llvm::Triple::Wasm: case llvm::Triple::XCOFF: + case llvm::Triple::DXContainer: LLDB_LOGF(log, "error: not supported target architecture"); return false; case llvm::Triple::UnknownObjectFormat: @@ -2245,9 +2248,6 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { m_process_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); m_process_arch.GetTriple().setOSName(llvm::StringRef(os_name)); m_process_arch.GetTriple().setEnvironmentName(llvm::StringRef(environment)); - m_host_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); - m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); - m_host_arch.GetTriple().setEnvironmentName(llvm::StringRef(environment)); } return true; } @@ -2697,8 +2697,8 @@ GDBRemoteCommunicationClient::SendSetCurrentThreadPacket(uint64_t tid, packet.Printf("%" PRIx64, tid); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response) - == PacketResult::Success) { + if (SendPacketAndWaitForResponse(packet.GetString(), response) == + PacketResult::Success) { if (response.IsOKResponse()) return {{pid, tid}}; @@ -2722,7 +2722,7 @@ bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid, return true; llvm::Optional<PidTid> ret = SendSetCurrentThreadPacket(tid, pid, 'g'); - if (ret.hasValue()) { + if (ret) { if (ret->pid != LLDB_INVALID_PROCESS_ID) m_curr_pid = ret->pid; m_curr_tid = ret->tid; @@ -2737,7 +2737,7 @@ bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid, return true; llvm::Optional<PidTid> ret = SendSetCurrentThreadPacket(tid, pid, 'c'); - if (ret.hasValue()) { + if (ret) { if (ret->pid != LLDB_INVALID_PROCESS_ID) m_curr_pid_run = ret->pid; m_curr_tid_run = ret->tid; @@ -2778,7 +2778,7 @@ bool GDBRemoteCommunicationClient::GetThreadStopInfo( uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( GDBStoppointType type, bool insert, addr_t addr, uint32_t length, std::chrono::seconds timeout) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + Log *log = GetLog(LLDBLog::Breakpoints); LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, __FUNCTION__, insert ? "add" : "remove", addr); @@ -2865,7 +2865,7 @@ GDBRemoteCommunicationClient::GetCurrentProcessAndThreadIDs( if (!pid_tid) break; - ids.push_back(pid_tid.getValue()); + ids.push_back(*pid_tid); ch = response.GetChar(); // Skip the command separator } while (ch == ','); // Make sure we got a comma separator } @@ -3443,7 +3443,7 @@ DataBufferSP GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, !response.IsNormalResponse()) return nullptr; - DataBufferSP buffer_sp( + WritableDataBufferSP buffer_sp( new DataBufferHeap(response.GetStringRef().size() / 2, 0)); response.GetHexBytes(buffer_sp->GetData(), '\xcc'); return buffer_sp; @@ -3458,7 +3458,7 @@ DataBufferSP GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid) { !response.IsNormalResponse()) return nullptr; - DataBufferSP buffer_sp( + WritableDataBufferSP buffer_sp( new DataBufferHeap(response.GetStringRef().size() / 2, 0)); response.GetHexBytes(buffer_sp->GetData(), '\xcc'); return buffer_sp; @@ -3701,9 +3701,6 @@ GDBRemoteCommunicationClient::SendTraceGetBinaryData( GDBRemoteCommunication::PacketResult::Success) { if (response.IsErrorResponse()) return response.GetStatus().ToError(); - if (response.IsUnsupportedResponse()) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "jLLDBTraceGetBinaryData is unsupported"); std::string data; response.GetEscapedBinaryData(data); return std::vector<uint8_t>(data.begin(), data.end()); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index f371649842e8..2a58f2028386 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -30,6 +30,7 @@ #include "lldb/Target/Platform.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" @@ -426,7 +427,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qUserName( StringExtractorGDBRemote &packet) { #if LLDB_ENABLE_POSIX - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); // Packet format: "qUserName:%i" where %i is the uid @@ -1020,7 +1021,7 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) { // encoded argument value list, but we will stay true to the documented // version of the 'A' packet here... - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log = GetLog(LLDBLog::Process); int actual_arg_index = 0; packet.SetFilePos(1); // Skip the 'A' diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index 029972348ef0..f696cb5c61c6 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -15,7 +15,6 @@ #include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationServer.h" -#include "GDBRemoteCommunicationServerCommon.h" class StringExtractorGDBRemote; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 123a8198a89b..63174ef55219 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/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)); - - // Ensure we have a debugged process. - if (!m_current_process || - (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(50); +StreamString +GDBRemoteCommunicationServerLLGS::PrepareStopReplyPacketForThread( + NativeThreadProtocol &thread) { + Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread); - LLDB_LOG(log, "preparing packet for pid {0} tid {1}", - m_current_process->GetID(), tid); + NativeProcessProtocol &process = thread.GetProcess(); - // 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(); + 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; - m_mainloop.RequestTermination(); + // 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) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 17ee4130dc34..5187a953f957 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -11,6 +11,7 @@ #include <mutex> #include <unordered_map> +#include <unordered_set> #include "lldb/Core/Communication.h" #include "lldb/Host/MainLoop.h" @@ -95,6 +96,7 @@ protected: std::recursive_mutex m_debugged_process_mutex; std::unordered_map<lldb::pid_t, std::unique_ptr<NativeProcessProtocol>> m_debugged_processes; + std::unordered_set<lldb::pid_t> m_vkilled_processes; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; @@ -106,6 +108,8 @@ protected: uint32_t m_next_saved_registers_id = 1; bool m_thread_suffix_supported = false; bool m_list_threads_in_stop_reply = false; + bool m_non_stop = false; + std::deque<std::string> m_stop_notification_queue; NativeProcessProtocol::Extension m_extensions_supported = {}; @@ -113,12 +117,22 @@ protected: PacketResult SendWResponse(NativeProcessProtocol *process); - PacketResult SendStopReplyPacketForThread(lldb::tid_t tid); + StreamString PrepareStopReplyPacketForThread(NativeThreadProtocol &thread); - PacketResult SendStopReasonForState(lldb::StateType process_state); + PacketResult SendStopReplyPacketForThread(NativeProcessProtocol &process, + lldb::tid_t tid, + bool force_synchronous); + + PacketResult SendStopReasonForState(NativeProcessProtocol &process, + lldb::StateType process_state, + bool force_synchronous); + + void EnqueueStopReplyPackets(lldb::tid_t thread_to_skip); PacketResult Handle_k(StringExtractorGDBRemote &packet); + PacketResult Handle_vKill(StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); PacketResult Handle_qC(StringExtractorGDBRemote &packet); @@ -145,6 +159,9 @@ protected: PacketResult Handle_qRegisterInfo(StringExtractorGDBRemote &packet); + void AddProcessThreads(StreamGDBRemote &response, + NativeProcessProtocol &process, bool &had_any); + PacketResult Handle_qfThreadInfo(StringExtractorGDBRemote &packet); PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet); @@ -217,12 +234,20 @@ protected: PacketResult Handle_qSaveCore(StringExtractorGDBRemote &packet); + PacketResult Handle_QNonStop(StringExtractorGDBRemote &packet); + + PacketResult Handle_vStopped(StringExtractorGDBRemote &packet); + + PacketResult Handle_vCtrlC(StringExtractorGDBRemote &packet); + PacketResult Handle_g(StringExtractorGDBRemote &packet); PacketResult Handle_qMemTags(StringExtractorGDBRemote &packet); PacketResult Handle_QMemTags(StringExtractorGDBRemote &packet); + PacketResult Handle_T(StringExtractorGDBRemote &packet); + void SetCurrentThreadID(lldb::tid_t tid); lldb::tid_t GetCurrentThreadID() const; @@ -241,9 +266,16 @@ protected: static std::string XMLEncodeAttributeValue(llvm::StringRef value); - virtual std::vector<std::string> HandleFeatures( + std::vector<std::string> HandleFeatures( const llvm::ArrayRef<llvm::StringRef> client_features) override; + // Provide a response for successful continue action, i.e. send "OK" + // in non-stop mode, no response otherwise. + PacketResult SendContinueSuccessResponse(); + + void AppendThreadIDToResponse(Stream &response, lldb::pid_t pid, + lldb::tid_t tid); + private: llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> BuildTargetXml(); @@ -269,15 +301,6 @@ private: void StopSTDIOForwarding(); - // Read thread-id from packet. If the thread-id is correct, returns it. - // Otherwise, returns the error. - // - // If allow_all is true, then the pid/tid value of -1 ('all') will be allowed. - // In any case, the function assumes that exactly one inferior is being - // debugged and rejects pid values that do no match that inferior. - llvm::Expected<lldb::tid_t> ReadTid(StringExtractorGDBRemote &packet, - bool allow_all, lldb::pid_t default_pid); - // Call SetEnabledExtensions() with appropriate flags on the process. void SetEnabledExtensions(NativeProcessProtocol &process); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index a63b98edec55..6f137d09fee4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -30,6 +30,7 @@ #include "lldb/Target/Platform.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" @@ -178,7 +179,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( if (hostname.empty()) hostname = "127.0.0.1"; - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(), *port); @@ -187,8 +188,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); debugserver_launch_info.SetMonitorProcessCallback( std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, - this, std::placeholders::_1), - false); + this, std::placeholders::_1)); std::ostringstream url; // debugserver does not accept the URL scheme prefix. @@ -228,7 +228,7 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( // Spawn a local debugserver as a platform so we can then attach or launch a // process... - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); @@ -244,7 +244,7 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( else if (name.equals("port")) { // Make the Optional valid so we can use its value port = 0; - value.getAsInteger(0, port.getValue()); + value.getAsInteger(0, *port); } } @@ -516,12 +516,11 @@ GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( return SendPacketNoLock(response.GetString()); } -bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( +void GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( lldb::pid_t pid) { std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); m_port_map.FreePortForProcess(pid); m_spawned_pids.erase(pid); - return true; } Status GDBRemoteCommunicationServerPlatform::LaunchProcess() { @@ -532,11 +531,9 @@ Status GDBRemoteCommunicationServerPlatform::LaunchProcess() { // specify the process monitor if not already set. This should generally be // what happens since we need to reap started processes. if (!m_process_launch_info.GetMonitorProcessCallback()) - m_process_launch_info.SetMonitorProcessCallback( - std::bind( - &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, - this, std::placeholders::_1), - false); + m_process_launch_info.SetMonitorProcessCallback(std::bind( + &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this, + std::placeholders::_1)); Status error = Host::LaunchProcess(m_process_launch_info); if (!error.Success()) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 6b964da4a279..8dbd5ba942f8 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -131,7 +131,7 @@ protected: private: bool KillSpawnedProcess(lldb::pid_t pid); - bool DebugserverProcessReaped(lldb::pid_t pid); + void DebugserverProcessReaped(lldb::pid_t pid); static const FileSpec &GetDomainSocketDir(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 1b66e8c16281..7ad4f4968eac 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -517,7 +517,7 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( } bool GDBRemoteRegisterContext::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { + lldb::WritableDataBufferSP &data_sp) { ExecutionContext exe_ctx(CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); @@ -536,9 +536,13 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues( if (gdb_comm.SyncThreadState(m_thread.GetProtocolID())) InvalidateAllRegisters(); - if (use_g_packet && - (data_sp = gdb_comm.ReadAllRegisters(m_thread.GetProtocolID()))) - return true; + if (use_g_packet) { + if (DataBufferSP data_buffer = + gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) { + data_sp = std::make_shared<DataBufferHeap>(*data_buffer); + return true; + } + } // We're going to read each register // individually and store them as binary data in a buffer. diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 83c809c5aab6..d185cb5aede1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -65,7 +65,7 @@ public: bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) override; - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 82357cd117d7..fe6a3f9ed6c1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -59,6 +59,7 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" @@ -73,7 +74,6 @@ #include "GDBRemoteRegisterContext.h" #include "GDBRemoteRegisterFallback.h" -#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" #include "Plugins/Process/Utility/StopInfoMachException.h" @@ -208,6 +208,10 @@ std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() { return std::chrono::seconds(GetGlobalPluginProperties().GetPacketTimeout()); } +ArchSpec ProcessGDBRemote::GetSystemArchitecture() { + return m_gdb_comm.GetHostArchitecture(); +} + bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { if (plugin_specified_by_name) @@ -252,7 +256,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_continue_C_tids(), m_continue_s_tids(), m_continue_S_tids(), m_max_memory_size(0), m_remote_stub_max_memory_size(0), m_addr_to_mmap_size(), m_thread_create_bp_sp(), - m_waiting_for_attach(false), m_destroy_tried_resuming(false), + m_waiting_for_attach(false), m_command_sp(), m_breakpoint_pc_offset(0), m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), m_erased_flash_ranges(), m_vfork_in_progress(false) { @@ -406,13 +410,13 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { } if (target_definition_fspec) { // See if we can get register definitions from a python file - if (ParsePythonTargetDefinition(target_definition_fspec)) { + if (ParsePythonTargetDefinition(target_definition_fspec)) return; - } else { - StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); - stream_sp->Printf("ERROR: target description file %s failed to parse.\n", - target_definition_fspec.GetPath().c_str()); - } + + Debugger::ReportError("target description file " + + target_definition_fspec.GetPath() + + " failed to parse", + GetTarget().GetDebugger().GetID()); } const ArchSpec &target_arch = GetTarget().GetArchitecture(); @@ -587,8 +591,10 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) { if (!module_sp) { // Force a an external lookup, if that tool is available. - if (!module_spec.GetSymbolFileSpec()) - Symbols::DownloadObjectAndSymbolFile(module_spec, true); + if (!module_spec.GetSymbolFileSpec()) { + Status error; + Symbols::DownloadObjectAndSymbolFile(module_spec, error, true); + } if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { module_sp = std::make_shared<Module>(module_spec); @@ -606,7 +612,7 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) { ReadModuleFromMemory(FileSpec(namebuf), standalone_value); } - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + Log *log = GetLog(LLDBLog::DynamicLoader); if (module_sp.get()) { target.GetImages().AppendIfNeeded(module_sp, false); @@ -948,12 +954,23 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { m_gdb_comm.GetVAttachOrWaitSupported(); m_gdb_comm.EnableErrorStringInPacket(); - size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); - for (size_t idx = 0; idx < num_cmds; idx++) { - StringExtractorGDBRemote response; - m_gdb_comm.SendPacketAndWaitForResponse( - GetExtraStartupCommands().GetArgumentAtIndex(idx), response); + // First dispatch any commands from the platform: + auto handle_cmds = [&] (const Args &args) -> void { + for (const Args::ArgEntry &entry : args) { + StringExtractorGDBRemote response; + m_gdb_comm.SendPacketAndWaitForResponse( + entry.c_str(), response); + } + }; + + PlatformSP platform_sp = GetTarget().GetPlatform(); + if (platform_sp) { + handle_cmds(platform_sp->GetExtraStartupCommands()); } + + // Then dispatch any process commands: + handle_cmds(GetExtraStartupCommands()); + return error; } @@ -1667,7 +1684,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( for (const auto &pair : expedited_register_map) { StringExtractor reg_value_extractor(pair.second); - DataBufferSP buffer_sp(new DataBufferHeap( + WritableDataBufferSP buffer_sp(new DataBufferHeap( reg_value_extractor.GetStringRef().size() / 2, 0)); reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); uint32_t lldb_regnum = @@ -2046,7 +2063,8 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { bytes.SetFilePos(0); const size_t byte_size = bytes.GetStringRef().size() / 2; - DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); + WritableDataBufferSP data_buffer_sp( + new DataBufferHeap(byte_size, 0)); const size_t bytes_copied = bytes.GetHexBytes(data_buffer_sp->GetData(), 0); if (bytes_copied == byte_size) @@ -2208,7 +2226,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { if (!addr_str.getAsInteger(0, mem_cache_addr)) { StringExtractor bytes(bytes_str); const size_t byte_size = bytes.GetBytesLeft() / 2; - DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); + WritableDataBufferSP data_buffer_sp( + new DataBufferHeap(byte_size, 0)); const size_t bytes_copied = bytes.GetHexBytes(data_buffer_sp->GetData(), 0); if (bytes_copied == byte_size) @@ -2379,110 +2398,6 @@ Status ProcessGDBRemote::DoDestroy() { Log *log = GetLog(GDBRLog::Process); LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy()"); - // There is a bug in older iOS debugservers where they don't shut down the - // process they are debugging properly. If the process is sitting at a - // breakpoint or an exception, this can cause problems with restarting. So - // we check to see if any of our threads are stopped at a breakpoint, and if - // so we remove all the breakpoints, resume the process, and THEN destroy it - // again. - // - // Note, we don't have a good way to test the version of debugserver, but I - // happen to know that the set of all the iOS debugservers which don't - // support GetThreadSuffixSupported() and that of the debugservers with this - // bug are equal. There really should be a better way to test this! - // - // We also use m_destroy_tried_resuming to make sure we only do this once, if - // we resume and then halt and get called here to destroy again and we're - // still at a breakpoint or exception, then we should just do the straight- - // forward kill. - // - // And of course, if we weren't able to stop the process by the time we get - // here, it isn't necessary (or helpful) to do any of this. - - if (!m_gdb_comm.GetThreadSuffixSupported() && - m_public_state.GetValue() != eStateRunning) { - PlatformSP platform_sp = GetTarget().GetPlatform(); - - if (platform_sp && platform_sp->GetName() && - platform_sp->GetName().GetStringRef() == - PlatformRemoteiOS::GetPluginNameStatic()) { - if (m_destroy_tried_resuming) { - if (log) - log->PutCString("ProcessGDBRemote::DoDestroy() - Tried resuming to " - "destroy once already, not doing it again."); - } else { - // At present, the plans are discarded and the breakpoints disabled - // Process::Destroy, but we really need it to happen here and it - // doesn't matter if we do it twice. - m_thread_list.DiscardThreadPlans(); - DisableAllBreakpointSites(); - - bool stop_looks_like_crash = false; - ThreadList &threads = GetThreadList(); - - { - std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); - - size_t num_threads = threads.GetSize(); - for (size_t i = 0; i < num_threads; i++) { - ThreadSP thread_sp = threads.GetThreadAtIndex(i); - StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); - StopReason reason = eStopReasonInvalid; - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); - if (reason == eStopReasonBreakpoint || - reason == eStopReasonException) { - LLDB_LOGF(log, - "ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 - " stopped with reason: %s.", - thread_sp->GetProtocolID(), - stop_info_sp->GetDescription()); - stop_looks_like_crash = true; - break; - } - } - } - - if (stop_looks_like_crash) { - if (log) - log->PutCString("ProcessGDBRemote::DoDestroy() - Stopped at a " - "breakpoint, continue and then kill."); - m_destroy_tried_resuming = true; - - // If we are going to run again before killing, it would be good to - // suspend all the threads before resuming so they won't get into - // more trouble. Sadly, for the threads stopped with the breakpoint - // or exception, the exception doesn't get cleared if it is - // suspended, so we do have to run the risk of letting those threads - // proceed a bit. - - { - std::lock_guard<std::recursive_mutex> guard(threads.GetMutex()); - - size_t num_threads = threads.GetSize(); - for (size_t i = 0; i < num_threads; i++) { - ThreadSP thread_sp = threads.GetThreadAtIndex(i); - StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); - StopReason reason = eStopReasonInvalid; - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); - if (reason != eStopReasonBreakpoint && - reason != eStopReasonException) { - LLDB_LOGF(log, - "ProcessGDBRemote::DoDestroy() - Suspending " - "thread: 0x%4.4" PRIx64 " before running.", - thread_sp->GetProtocolID()); - thread_sp->SetResumeState(eStateSuspended); - } - } - } - Resume(); - return Destroy(false); - } - } - } - } - // Interrupt if our inferior is running... int exit_status = SIGABRT; std::string exit_string; @@ -2919,8 +2834,7 @@ size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf, lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size, uint32_t permissions, Status &error) { - Log *log( - GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_EXPRESSIONS)); + Log *log = GetLog(LLDBLog::Process | LLDBLog::Expressions); addr_t allocated_addr = LLDB_INVALID_ADDRESS; if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) { @@ -2962,8 +2876,8 @@ lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size, return allocated_addr; } -Status ProcessGDBRemote::GetMemoryRegionInfo(addr_t load_addr, - MemoryRegionInfo ®ion_info) { +Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr, + MemoryRegionInfo ®ion_info) { Status error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info)); return error; @@ -3366,7 +3280,7 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( const std::weak_ptr<ProcessGDBRemote> this_wp = std::static_pointer_cast<ProcessGDBRemote>(shared_from_this()); debugserver_launch_info.SetMonitorProcessCallback( - std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), false); + std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3)); debugserver_launch_info.SetUserID(process_info.GetUserID()); #if defined(__APPLE__) @@ -3445,16 +3359,14 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver( return error; } -bool ProcessGDBRemote::MonitorDebugserverProcess( +void ProcessGDBRemote::MonitorDebugserverProcess( std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid, - bool exited, // True if the process did exit int signo, // Zero for no signal int exit_status // Exit value of process if signal is zero ) { // "debugserver_pid" argument passed in is the process ID for debugserver // that we are tracking... Log *log = GetLog(GDBRLog::Process); - const bool handled = true; LLDB_LOGF(log, "ProcessGDBRemote::%s(process_wp, pid=%" PRIu64 @@ -3465,7 +3377,7 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( LLDB_LOGF(log, "ProcessGDBRemote::%s(process = %p)", __FUNCTION__, static_cast<void *>(process_sp.get())); if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) - return handled; + return; // Sleep for a half a second to make sure our inferior process has time to // set its exit status before we set it incorrectly when both the debugserver @@ -3499,7 +3411,6 @@ bool ProcessGDBRemote::MonitorDebugserverProcess( // Debugserver has exited we need to let our ProcessGDBRemote know that it no // longer has a debugserver instance process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - return handled; } void ProcessGDBRemote::KillDebugserverProcess() { @@ -3541,11 +3452,12 @@ bool ProcessGDBRemote::StartAsyncThread() { // Create a thread that watches our internal state and controls which // events make it to clients (into the DCProcess event queue). - llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( - "<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this); + llvm::Expected<HostThread> async_thread = + ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", [this] { + return ProcessGDBRemote::AsyncThread(); + }); if (!async_thread) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - async_thread.takeError(), + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), async_thread.takeError(), "failed to launch host thread: {}"); return false; } @@ -3581,14 +3493,10 @@ void ProcessGDBRemote::StopAsyncThread() { __FUNCTION__); } -thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { - ProcessGDBRemote *process = (ProcessGDBRemote *)arg; - +thread_result_t ProcessGDBRemote::AsyncThread() { Log *log = GetLog(GDBRLog::Process); - LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 - ") thread starting...", - __FUNCTION__, arg, process->GetID()); + LLDB_LOGF(log, "ProcessGDBRemote::%s(pid = %" PRIu64 ") thread starting...", + __FUNCTION__, GetID()); EventSP event_sp; @@ -3604,19 +3512,19 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { // fetch loop. bool done = false; - while (!done && process->GetPrivateState() != eStateExited) { + while (!done && GetPrivateState() != eStateExited) { LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", - __FUNCTION__, arg, process->GetID()); + __FUNCTION__, GetID()); - if (process->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { + if (m_async_listener_sp->GetEvent(event_sp, llvm::None)) { const uint32_t event_type = event_sp->GetType(); - if (event_sp->BroadcasterIs(&process->m_async_broadcaster)) { + if (event_sp->BroadcasterIs(&m_async_broadcaster)) { LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") Got an event of type: %d...", - __FUNCTION__, arg, process->GetID(), event_type); + __FUNCTION__, GetID(), event_type); switch (event_type) { case eBroadcastBitAsyncContinue: { @@ -3628,39 +3536,39 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { (const char *)continue_packet->GetBytes(); const size_t continue_cstr_len = continue_packet->GetByteSize(); LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", - __FUNCTION__, arg, process->GetID(), continue_cstr); + __FUNCTION__, GetID(), continue_cstr); if (::strstr(continue_cstr, "vAttach") == nullptr) - process->SetPrivateState(eStateRunning); + SetPrivateState(eStateRunning); StringExtractorGDBRemote response; StateType stop_state = - process->GetGDBRemote().SendContinuePacketAndWaitForResponse( - *process, *process->GetUnixSignals(), + GetGDBRemote().SendContinuePacketAndWaitForResponse( + *this, *GetUnixSignals(), llvm::StringRef(continue_cstr, continue_cstr_len), - process->GetInterruptTimeout(), response); + GetInterruptTimeout(), 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(); + // SetLastStopPacket()... + ClearThreadIDList(); switch (stop_state) { case eStateStopped: case eStateCrashed: case eStateSuspended: - process->SetLastStopPacket(response); - process->SetPrivateState(stop_state); + SetLastStopPacket(response); + SetPrivateState(stop_state); break; case eStateExited: { - process->SetLastStopPacket(response); - process->ClearThreadIDList(); + SetLastStopPacket(response); + ClearThreadIDList(); response.SetFilePos(1); int exit_status = response.GetHexU8(); @@ -3675,7 +3583,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { extractor.GetHexByteString(desc_string); } } - process->SetExitStatus(exit_status, desc_string.c_str()); + SetExitStatus(exit_status, desc_string.c_str()); done = true; break; } @@ -3686,20 +3594,20 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { // helpful error message about why the attach failed. if (::strstr(continue_cstr, "vAttach") != nullptr && response.GetError() == 0x87) { - process->SetExitStatus(-1, "cannot attach to process due to " - "System Integrity Protection"); + SetExitStatus(-1, "cannot attach to process due to " + "System Integrity Protection"); } else if (::strstr(continue_cstr, "vAttach") != nullptr && response.GetStatus().Fail()) { - process->SetExitStatus(-1, response.GetStatus().AsCString()); + SetExitStatus(-1, response.GetStatus().AsCString()); } else { - process->SetExitStatus(-1, "lost connection"); + SetExitStatus(-1, "lost connection"); } done = true; break; } default: - process->SetPrivateState(stop_state); + SetPrivateState(stop_state); break; } // switch(stop_state) } // if (continue_packet) @@ -3708,49 +3616,47 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { case eBroadcastBitAsyncThreadShouldExit: LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", - __FUNCTION__, arg, process->GetID()); + __FUNCTION__, GetID()); done = true; break; default: LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") got unknown event 0x%8.8x", - __FUNCTION__, arg, process->GetID(), event_type); + __FUNCTION__, GetID(), event_type); done = true; break; } - } else if (event_sp->BroadcasterIs(&process->m_gdb_comm)) { + } else if (event_sp->BroadcasterIs(&m_gdb_comm)) { switch (event_type) { case Communication::eBroadcastBitReadThreadDidExit: - process->SetExitStatus(-1, "lost connection"); + SetExitStatus(-1, "lost connection"); done = true; break; default: LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") got unknown event 0x%8.8x", - __FUNCTION__, arg, process->GetID(), event_type); + __FUNCTION__, GetID(), event_type); done = true; break; } } } else { LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 + "ProcessGDBRemote::%s(pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", - __FUNCTION__, arg, process->GetID()); + __FUNCTION__, GetID()); done = true; } } - LLDB_LOGF(log, - "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 - ") thread exiting...", - __FUNCTION__, arg, process->GetID()); + LLDB_LOGF(log, "ProcessGDBRemote::%s(pid = %" PRIu64 ") thread exiting...", + __FUNCTION__, GetID()); return {}; } @@ -3781,7 +3687,7 @@ bool ProcessGDBRemote::NewThreadNotifyBreakpointHit( // I don't think I have to do anything here, just make sure I notice the new // thread when it starts to // run so I can stop it if that's what I want to do. - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); LLDB_LOGF(log, "Hit New Thread Notification breakpoint."); return false; } @@ -3824,7 +3730,7 @@ Status ProcessGDBRemote::UpdateAutomaticSignalFiltering() { } bool ProcessGDBRemote::StartNoticingNewThreads() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (m_thread_create_bp_sp) { if (log && log->GetVerbose()) LLDB_LOGF(log, "Enabled noticing new thread breakpoint."); @@ -3850,7 +3756,7 @@ bool ProcessGDBRemote::StartNoticingNewThreads() { } bool ProcessGDBRemote::StopNoticingNewThreads() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF(log, "Disabling new thread notification breakpoint."); @@ -4116,7 +4022,7 @@ void ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize( bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch, ModuleSpec &module_spec) { - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + Log *log = GetLog(LLDBLog::Platform); const ModuleCacheKey key(module_file_spec.GetPath(), arch.GetTriple().getTriple()); @@ -4495,7 +4401,7 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() { return llvm::createStringError(llvm::inconvertibleErrorCode(), "XML parsing not available"); - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS); + Log *log = GetLog(LLDBLog::Process); LLDB_LOGF(log, "ProcessGDBRemote::%s", __FUNCTION__); LoadedModuleInfoList list; @@ -5102,19 +5008,12 @@ public: ~CommandObjectProcessGDBRemotePacketHistory() override = default; bool DoExecute(Args &command, CommandReturnObject &result) override { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) { - ProcessGDBRemote *process = - (ProcessGDBRemote *)m_interpreter.GetExecutionContext() - .GetProcessPtr(); - if (process) { - process->GetGDBRemote().DumpHistory(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } - } else { - result.AppendErrorWithFormat("'%s' takes no arguments", - m_cmd_name.c_str()); + ProcessGDBRemote *process = + (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + process->GetGDBRemote().DumpHistory(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; } result.SetStatus(eReturnStatusFailed); return false; @@ -5128,7 +5027,10 @@ public: : CommandObjectParsed( interpreter, "process plugin packet xfer-size", "Maximum size that lldb will try to read/write one one chunk.", - nullptr) {} + nullptr) { + CommandArgumentData max_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; + m_arguments.push_back({max_arg}); + } ~CommandObjectProcessGDBRemotePacketXferSize() override = default; @@ -5169,7 +5071,10 @@ public: "The packet header and footer will automatically " "be added to the packet prior to sending and " "stripped from the result.", - nullptr) {} + nullptr) { + CommandArgumentData packet_arg{eArgTypeNone, eArgRepeatStar}; + m_arguments.push_back({packet_arg}); + } ~CommandObjectProcessGDBRemotePacketSend() override = default; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index bdf130e3ec11..50cef8e499dc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -70,6 +70,8 @@ public: static std::chrono::seconds GetPacketTimeout(); + ArchSpec GetSystemArchitecture() override; + // Check if a given Process bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; @@ -143,9 +145,6 @@ public: lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, Status &error) override; - Status GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo ®ion_info) override; - Status DoDeallocateMemory(lldb::addr_t ptr) override; // Process STDIO @@ -284,7 +283,6 @@ protected: MMapMap m_addr_to_mmap_size; lldb::BreakpointSP m_thread_create_bp_sp; bool m_waiting_for_attach; - bool m_destroy_tried_resuming; lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach @@ -345,12 +343,11 @@ protected: void StopAsyncThread(); - static lldb::thread_result_t AsyncThread(void *arg); + lldb::thread_result_t AsyncThread(); - static bool + static void MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp, - lldb::pid_t pid, bool exited, int signo, - int exit_status); + lldb::pid_t pid, int signo, int exit_status); lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet); @@ -415,6 +412,9 @@ protected: Status DoWriteMemoryTags(lldb::addr_t addr, size_t len, int32_t type, const std::vector<uint8_t> &tags) override; + Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion_info) override; + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index 730384204393..66b2f00f1ea9 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -10,6 +10,7 @@ #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H #include "lldb/Utility/Log.h" +#include "llvm/ADT/BitmaskEnum.h" namespace lldb_private { namespace process_gdb_remote { @@ -28,6 +29,7 @@ enum class GDBRLog : Log::MaskType { Watchpoints = Log::ChannelFlag<10>, LLVM_MARK_AS_BITMASK_ENUM(Watchpoints) }; +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); class ProcessGDBRemoteLog { public: |
