Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h =================================================================== --- lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -220,6 +220,10 @@ lldb::StateType state) = 0; virtual void DidExec(NativeProcessProtocol *process) = 0; + + virtual void + NewSubprocess(NativeProcessProtocol *parent_process, + std::unique_ptr &child_process) = 0; }; virtual Status GetLoadedModuleFileSpec(const char *module_path, Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -78,6 +78,10 @@ void DidExec(NativeProcessProtocol *process) override; + void + NewSubprocess(NativeProcessProtocol *parent_process, + std::unique_ptr &child_process) override; + Status InitializeConnection(std::unique_ptr connection); protected: @@ -89,7 +93,8 @@ NativeProcessProtocol *m_current_process; NativeProcessProtocol *m_continue_process; std::recursive_mutex m_debugged_process_mutex; - std::unique_ptr m_debugged_process_up; + std::unordered_map> + m_debugged_processes; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -243,14 +243,14 @@ { std::lock_guard guard(m_debugged_process_mutex); - assert(!m_debugged_process_up && "lldb-server creating debugged " - "process but one already exists"); + assert(m_debugged_processes.empty() && "lldb-server creating debugged " + "process but one already exists"); auto process_or = m_process_factory.Launch(m_process_launch_info, *this, m_mainloop); if (!process_or) return Status(process_or.takeError()); - m_debugged_process_up = std::move(*process_or); - m_continue_process = m_current_process = m_debugged_process_up.get(); + m_continue_process = m_current_process = process_or->get(); + m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); } // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as @@ -265,10 +265,10 @@ LLDB_LOG(log, "pid = {0}: setting up stdout/stderr redirection via $O " "gdb-remote commands", - m_debugged_process_up->GetID()); + m_current_process->GetID()); // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); + auto terminal_fd = m_current_process->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { LLDB_LOGF(log, "ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -287,12 +287,12 @@ LLDB_LOG(log, "pid = {0} skipping stdout/stderr redirection via $O: inferior " "will communicate over client-provided file descriptors", - m_debugged_process_up->GetID()); + m_current_process->GetID()); } printf("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments().GetArgumentAtIndex(0), - m_debugged_process_up->GetID()); + m_current_process->GetID()); return Status(); } @@ -304,12 +304,11 @@ // Before we try to attach, make sure we aren't already monitoring something // else. - if (m_debugged_process_up && - m_debugged_process_up->GetID() != LLDB_INVALID_PROCESS_ID) + if (!m_debugged_processes.empty()) return Status("cannot attach to process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", - pid, m_debugged_process_up->GetID()); + pid, m_current_process->GetID()); // Try to attach. auto process_or = m_process_factory.Attach(pid, *this, m_mainloop); @@ -319,11 +318,11 @@ status); return status; } - m_debugged_process_up = std::move(*process_or); - m_continue_process = m_current_process = m_debugged_process_up.get(); + m_continue_process = m_current_process = process_or->get(); + m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); + auto terminal_fd = m_current_process->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { LLDB_LOGF(log, "ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -1029,6 +1028,18 @@ ClearProcessSpecificData(); } +void GDBRemoteCommunicationServerLLGS::NewSubprocess( + NativeProcessProtocol *parent_process, + std::unique_ptr &child_process) { + // Apparently the process has been dealt with by another delegate. + if (!child_process) + return; + lldb::pid_t child_pid = child_process->GetID(); + assert(child_pid != LLDB_INVALID_PROCESS_ID); + assert(m_debugged_processes.find(child_pid) == m_debugged_processes.end()); + m_debugged_processes[child_pid] = std::move(child_process); +} + void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); @@ -3211,19 +3222,32 @@ return SendIllFormedResponse(packet, "D failed to parse the process id"); } - if (pid != LLDB_INVALID_PROCESS_ID && m_current_process->GetID() != pid) { - return SendIllFormedResponse(packet, "Invalid pid"); - } - - const Status error = m_current_process->Detach(); - if (error.Fail()) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to detach from " - "pid %" PRIu64 ": %s\n", - __FUNCTION__, m_current_process->GetID(), error.AsCString()); - return SendErrorResponse(0x01); + // Detach forked children if their PID was specified *or* no PID was requested + // (i.e. detach-all packet). + bool detached = false; + for (auto it = m_debugged_processes.begin(); + it != m_debugged_processes.end();) { + if (pid == LLDB_INVALID_PROCESS_ID || pid == it->first) { + const Status error = it->second->Detach(); + if (error.Fail()) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s failed to detach from " + "pid %" PRIu64 ": %s\n", + __FUNCTION__, it->first, error.AsCString()); + return SendErrorResponse(0x01); + } + if (it->second == m_current_process) + m_current_process = nullptr; + if (it->second == m_continue_process) + m_continue_process = nullptr; + it = m_debugged_processes.erase(it); + detached = true; + } else + ++it; } + if (!detached) + return SendErrorResponse(Status("PID %" PRIu64 " not traced", pid)); return SendOKResponse(); } Index: lldb/source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- lldb/source/Utility/StringExtractorGDBRemote.cpp +++ lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -378,9 +378,7 @@ return eServerPacketType_C; case 'D': - if (packet_size == 1) - return eServerPacketType_D; - break; + return eServerPacketType_D; case 'g': return eServerPacketType_g; Index: lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h =================================================================== --- lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h +++ lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h @@ -25,6 +25,9 @@ MOCK_METHOD2(ProcessStateChanged, void(NativeProcessProtocol *Process, StateType State)); MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process)); + MOCK_METHOD2(NewSubprocess, + void(NativeProcessProtocol *parent_process, + std::unique_ptr &child_process)); }; // NB: This class doesn't use the override keyword to avoid