mgorny created this revision. mgorny added reviewers: labath, emaste, krytarowski. mgorny requested review of this revision.
Temporarily remove breakpoints for the duration of vfork, in order to prevent them from triggering in the child process. Restore them once the server reports that vfork has finished and it is ready to resume execution. https://reviews.llvm.org/D100267 Files: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h lldb/test/Shell/Subprocess/vfork-follow-parent-softbp.test 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 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 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()); + } + }); + } +}
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits