Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -232,6 +232,7 @@ void DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) override; void DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) override; + void DidVForkDone() override; protected: friend class ThreadGDBRemote; @@ -294,6 +295,8 @@ using FlashRange = FlashRangeVector::Entry; FlashRangeVector m_erased_flash_ranges; + bool m_vfork_in_progress; + // Accessors bool IsRunning(lldb::StateType state) { return state == lldb::eStateRunning || IsStepping(state); Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -265,7 +265,8 @@ m_waiting_for_attach(false), m_destroy_tried_resuming(false), m_command_sp(), m_breakpoint_pc_offset(0), m_initial_tid(LLDB_INVALID_THREAD_ID), m_replay_mode(false), - m_allow_flash_writes(false), m_erased_flash_ranges() { + m_allow_flash_writes(false), m_erased_flash_ranges(), + m_vfork_in_progress(false) { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -5479,6 +5480,22 @@ void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + assert(!m_vfork_in_progress); + m_vfork_in_progress = true; + + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { + // Disable all software breakpoints for the time of vfork + GetBreakpointSiteList().ForEach([this](BreakpointSite *bp_site) { + if (bp_site->IsEnabled() && + (bp_site->GetType() == BreakpointSite::eSoftware || + bp_site->GetType() == BreakpointSite::eExternal)) { + m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointSoftware, false, bp_site->GetLoadAddress(), + bp_site->GetTrapOpcodeMaxByteSize()); + } + }); + } + LLDB_LOG(log, "Detaching forked child {0}", child_pid); Status error = m_gdb_comm.Detach(false, child_pid); if (error.Fail()) { @@ -5488,3 +5505,21 @@ return; } } + +void ProcessGDBRemote::DidVForkDone() { + assert(m_vfork_in_progress); + m_vfork_in_progress = false; + + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { + // Reenable all software breakpoints that were enabled before vfork + GetBreakpointSiteList().ForEach([this](BreakpointSite *bp_site) { + if (bp_site->IsEnabled() && + (bp_site->GetType() == BreakpointSite::eSoftware || + bp_site->GetType() == BreakpointSite::eExternal)) { + m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointSoftware, true, bp_site->GetLoadAddress(), + bp_site->GetTrapOpcodeMaxByteSize()); + } + }); + } +} Index: lldb/test/Shell/Subprocess/vfork-follow-parent-softbp.test =================================================================== --- /dev/null +++ lldb/test/Shell/Subprocess/vfork-follow-parent-softbp.test @@ -0,0 +1,12 @@ +# REQUIRES: native +# UNSUPPORTED: system-windows +# RUN: %clangxx_host %p/Inputs/fork.cpp -DTEST_FORK=vfork -o %t +# RUN: %lldb -b -s %s %t | FileCheck %s +b parent_func +b child_func +process launch +# CHECK-NOT: function run in parent +# CHECK: stop reason = breakpoint +continue +# CHECK: function run in parent +# CHECK: child exited: 0