Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h =================================================================== --- lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -222,6 +222,10 @@ lldb::StateType state) = 0; virtual void DidExec(NativeProcessProtocol *process) = 0; + + virtual void + NewSubprocess(NativeProcessProtocol *parent_process, + std::unique_ptr &child_process) = 0; }; /// Register a native delegate. 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: @@ -88,6 +92,8 @@ lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID; std::recursive_mutex m_debugged_process_mutex; std::unique_ptr m_debugged_process_up; + std::unordered_map> + m_additional_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 @@ -1030,6 +1030,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_additional_processes.find(child_pid) == m_additional_processes.end()); + m_additional_processes[child_pid] = std::move(child_process); +} + void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); @@ -3213,19 +3225,43 @@ return SendIllFormedResponse(packet, "D failed to parse the process id"); } - if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_up->GetID() != pid) { - return SendIllFormedResponse(packet, "Invalid pid"); + // 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_additional_processes.begin(); it != m_additional_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__, m_debugged_process_up->GetID(), error.AsCString()); + return SendErrorResponse(0x01); + } + it = m_additional_processes.erase(it); + detached = true; + } else + ++it; } - const Status error = m_debugged_process_up->Detach(); - if (error.Fail()) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to detach from " - "pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_up->GetID(), error.AsCString()); - return SendErrorResponse(0x01); + // Detach the main process if PID matches or no PID was requested. + if (pid == LLDB_INVALID_PROCESS_ID || m_debugged_process_up->GetID() == pid) { + if (!m_additional_processes.empty()) + return SendErrorResponse(Status("Unable to detach the main process while children are still traced")); + + const Status error = m_debugged_process_up->Detach(); + if (error.Fail()) { + LLDB_LOGF(log, + "GDBRemoteCommunicationServerLLGS::%s failed to detach from " + "pid %" PRIu64 ": %s\n", + __FUNCTION__, m_debugged_process_up->GetID(), error.AsCString()); + return SendErrorResponse(0x01); + } + detached = true; } + 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