Author: Michał Górny Date: 2021-08-31T13:41:35+02:00 New Revision: 8307869a224633d3516d98071b45fdec7314f8a3
URL: https://github.com/llvm/llvm-project/commit/8307869a224633d3516d98071b45fdec7314f8a3 DIFF: https://github.com/llvm/llvm-project/commit/8307869a224633d3516d98071b45fdec7314f8a3.diff LOG: [lldb] [gdb-remote client] Remove breakpoints in forked processes Remove software breakpoints from forked processes in order to restore the original program code before detaching it. Differential Revision: https://reviews.llvm.org/D100263 Added: lldb/test/Shell/Subprocess/clone-follow-parent-softbp.test lldb/test/Shell/Subprocess/fork-follow-parent-softbp.test Modified: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py Removed: ################################################################################ diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index f135f8975cec7..f81e2acf3e17a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5485,16 +5485,49 @@ CommandObject *ProcessGDBRemote::GetPluginCommandObject() { return m_command_sp.get(); } +void ProcessGDBRemote::DidForkSwitchSoftwareBreakpoints(bool enable) { + GetBreakpointSiteList().ForEach([this, enable](BreakpointSite *bp_site) { + if (bp_site->IsEnabled() && + (bp_site->GetType() == BreakpointSite::eSoftware || + bp_site->GetType() == BreakpointSite::eExternal)) { + m_gdb_comm.SendGDBStoppointTypePacket( + eBreakpointSoftware, enable, bp_site->GetLoadAddress(), + bp_site->GetTrapOpcodeMaxByteSize(), GetInterruptTimeout()); + } + }); +} + void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + lldb::pid_t parent_pid = m_gdb_comm.GetCurrentProcessID(); + // Any valid TID will suffice, thread-relevant actions will set a proper TID + // anyway. + lldb::tid_t parent_tid = m_thread_ids.front(); + + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { + // Switch to the new process to clear breakpoints there. + if (!m_gdb_comm.SetCurrentThread(child_tid, child_pid)) { + LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to set pid/tid"); + return; + } + + // Disable all software breakpoints in the forked process. + DidForkSwitchSoftwareBreakpoints(false); + + // Reset gdb-remote to the original process. + if (!m_gdb_comm.SetCurrentThread(parent_tid, parent_pid)) { + LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to reset pid/tid"); + return; + } + } + LLDB_LOG(log, "Detaching forked child {0}", child_pid); Status error = m_gdb_comm.Detach(false, child_pid); if (error.Fail()) { - LLDB_LOG(log, - "ProcessGDBRemote::DidFork() detach packet send failed: {0}", - error.AsCString() ? error.AsCString() : "<unknown error>"); - return; + LLDB_LOG(log, "ProcessGDBRemote::DidFork() detach packet send failed: {0}", + error.AsCString() ? error.AsCString() : "<unknown error>"); + return; } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index e86f697439500..70b3ca1ca3a22 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -462,6 +462,9 @@ class ProcessGDBRemote : public Process, ProcessGDBRemote(const ProcessGDBRemote &) = delete; const ProcessGDBRemote &operator=(const ProcessGDBRemote &) = delete; + + // fork helpers + void DidForkSwitchSoftwareBreakpoints(bool enable); }; } // namespace process_gdb_remote diff --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py index 5bbee0b33de81..0222e8453f7a0 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py +++ b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py @@ -147,7 +147,12 @@ def respond(self, packet): if packet == "s": return self.haltReason() if packet[0] == "H": - return self.selectThread(packet[1], int(packet[2:], 16)) + tid = packet[2:] + if "." in tid: + assert tid.startswith("p") + # TODO: do we want to do anything with PID? + tid = tid.split(".", 1)[1] + return self.selectThread(packet[1], int(tid, 16)) if packet[0:6] == "qXfer:": obj, read, annex, location = packet[6:].split(":") offset, length = [int(x, 16) for x in location.split(',')] diff --git a/lldb/test/Shell/Subprocess/clone-follow-parent-softbp.test b/lldb/test/Shell/Subprocess/clone-follow-parent-softbp.test new file mode 100644 index 0000000000000..852ed9dcbce25 --- /dev/null +++ b/lldb/test/Shell/Subprocess/clone-follow-parent-softbp.test @@ -0,0 +1,13 @@ +# REQUIRES: native && (system-linux || system-netbsd) +# clone() tests fails on arm64 Linux, PR #49899 +# UNSUPPORTED: system-linux && target-aarch64 +# RUN: %clangxx_host %p/Inputs/fork.cpp -DTEST_CLONE -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 diff --git a/lldb/test/Shell/Subprocess/fork-follow-parent-softbp.test b/lldb/test/Shell/Subprocess/fork-follow-parent-softbp.test new file mode 100644 index 0000000000000..6618834ae4055 --- /dev/null +++ b/lldb/test/Shell/Subprocess/fork-follow-parent-softbp.test @@ -0,0 +1,12 @@ +# REQUIRES: native +# UNSUPPORTED: system-windows +# RUN: %clangxx_host %p/Inputs/fork.cpp -DTEST_FORK=fork -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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits