diff --git a/lldb/bindings/interface/SBThread.i b/lldb/bindings/interface/SBThread.i --- a/lldb/bindings/interface/SBThread.i +++ b/lldb/bindings/interface/SBThread.i @@ -104,6 +104,9 @@ eStopReasonSignal 1 unix signal number eStopReasonException N exception data eStopReasonExec 0 + eStopReasonFork 1 pid of the child process + eStopReasonVFork 1 pid of the child process + eStopReasonVForkDone 0 eStopReasonPlanComplete 0") GetStopReasonDataAtIndex; uint64_t GetStopReasonDataAtIndex(uint32_t idx); diff --git a/lldb/bindings/interface/SBThreadPlan.i b/lldb/bindings/interface/SBThreadPlan.i --- a/lldb/bindings/interface/SBThreadPlan.i +++ b/lldb/bindings/interface/SBThreadPlan.i @@ -73,6 +73,9 @@ eStopReasonSignal 1 unix signal number eStopReasonException N exception data eStopReasonExec 0 + eStopReasonFork 1 pid of the child process + eStopReasonVFork 1 pid of the child process + eStopReasonVForkDone 0 eStopReasonPlanComplete 0") GetStopReasonDataAtIndex; uint64_t GetStopReasonDataAtIndex(uint32_t idx); diff --git a/lldb/docs/python_api_enums.rst b/lldb/docs/python_api_enums.rst --- a/lldb/docs/python_api_enums.rst +++ b/lldb/docs/python_api_enums.rst @@ -342,6 +342,9 @@ .. py:data:: eStopReasonSignal .. py:data:: eStopReasonException .. py:data:: eStopReasonExec +.. py:data:: eStopReasonFork +.. py:data:: eStopReasonVFork +.. py:data:: eStopReasonVForkDone .. py:data:: eStopReasonPlanComplete .. py:data:: eStopReasonThreadExiting .. py:data:: eStopReasonInstrumentation diff --git a/lldb/examples/python/performance.py b/lldb/examples/python/performance.py --- a/lldb/examples/python/performance.py +++ b/lldb/examples/python/performance.py @@ -255,6 +255,15 @@ select_thread = True if self.verbose: print("signal %d" % (thread.GetStopReasonDataAtIndex(0))) + elif stop_reason == lldb.eStopReasonFork: + if self.verbose: + print("fork pid = %d" % (thread.GetStopReasonDataAtIndex(0))) + elif stop_reason == lldb.eStopReasonVFork: + if self.verbose: + print("vfork pid = %d" % (thread.GetStopReasonDataAtIndex(0))) + elif stop_reason == lldb.eStopReasonVForkDone: + if self.verbose: + print("vfork done") if select_thread and not selected_thread: self.thread = thread diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -66,6 +66,9 @@ /// eStopReasonSignal 1 unix signal number /// eStopReasonException N exception data /// eStopReasonExec 0 + /// eStopReasonFork 1 pid of the child process + /// eStopReasonVFork 1 pid of the child process + /// eStopReasonVForkDone 0 /// eStopReasonPlanComplete 0 uint64_t GetStopReasonDataAtIndex(uint32_t idx); diff --git a/lldb/include/lldb/API/SBThreadPlan.h b/lldb/include/lldb/API/SBThreadPlan.h --- a/lldb/include/lldb/API/SBThreadPlan.h +++ b/lldb/include/lldb/API/SBThreadPlan.h @@ -58,6 +58,9 @@ /// eStopReasonSignal 1 unix signal number /// eStopReasonException N exception data /// eStopReasonExec 0 + /// eStopReasonFork 1 pid of the child process + /// eStopReasonVFork 1 pid of the child process + /// eStopReasonVForkDone 0 /// eStopReasonPlanComplete 0 uint64_t GetStopReasonDataAtIndex(uint32_t idx); diff --git a/lldb/include/lldb/Host/Debug.h b/lldb/include/lldb/Host/Debug.h --- a/lldb/include/lldb/Host/Debug.h +++ b/lldb/include/lldb/Host/Debug.h @@ -144,6 +144,12 @@ uint32_t data_count; lldb::addr_t data[8]; } exception; + + // eStopReasonFork / eStopReasonVFork + struct { + lldb::pid_t child_pid; + lldb::tid_t child_tid; + } fork; } details; }; } diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -249,6 +249,9 @@ eStopReasonThreadExiting, eStopReasonInstrumentation, eStopReasonProcessorTrace, + eStopReasonFork, + eStopReasonVFork, + eStopReasonVForkDone, }; /// Command Return Status Types. diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -252,6 +252,12 @@ return "watchpoint" elif enum == lldb.eStopReasonExec: return "exec" + elif enum == lldb.eStopReasonFork: + return "fork" + elif enum == lldb.eStopReasonVFork: + return "vfork" + elif enum == lldb.eStopReasonVForkDone: + return "vforkdone" elif enum == lldb.eStopReasonSignal: return "signal" elif enum == lldb.eStopReasonException: diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -173,6 +173,7 @@ case eStopReasonThreadExiting: case eStopReasonInstrumentation: case eStopReasonProcessorTrace: + case eStopReasonVForkDone: // There is no data for these stop reasons. return 0; @@ -195,6 +196,12 @@ case eStopReasonException: return 1; + + case eStopReasonFork: + return 1; + + case eStopReasonVFork: + return 1; } } } @@ -225,6 +232,7 @@ case eStopReasonThreadExiting: case eStopReasonInstrumentation: case eStopReasonProcessorTrace: + case eStopReasonVForkDone: // There is no data for these stop reasons. return 0; @@ -258,6 +266,12 @@ case eStopReasonException: return stop_info_sp->GetValue(); + + case eStopReasonFork: + return stop_info_sp->GetValue(); + + case eStopReasonVFork: + return stop_info_sp->GetValue(); } } } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -659,6 +659,12 @@ return "exec"; case eStopReasonProcessorTrace: return "processor trace"; + case eStopReasonFork: + return "fork"; + case eStopReasonVFork: + return "vfork"; + case eStopReasonVForkDone: + return "vforkdone"; case eStopReasonInstrumentation: case eStopReasonInvalid: case eStopReasonPlanComplete: @@ -934,6 +940,22 @@ } } + // Include child process PID/TID for forks. + if (tid_stop_info.reason == eStopReasonFork || + tid_stop_info.reason == eStopReasonVFork) { + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::multiprocess)); + if (tid_stop_info.reason == eStopReasonFork) + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::fork)); + if (tid_stop_info.reason == eStopReasonVFork) + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::vfork)); + response.Printf("%s:p%" PRIx64 ".%" PRIx64 ";", reason_str, + tid_stop_info.details.fork.child_pid, + tid_stop_info.details.fork.child_tid); + } + return SendPacketNoLock(response.GetString()); } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -822,6 +822,9 @@ case eStopReasonWatchpoint: case eStopReasonException: case eStopReasonExec: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: case eStopReasonThreadExiting: case eStopReasonInstrumentation: case eStopReasonProcessorTrace: diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -131,6 +131,9 @@ case eStopReasonWatchpoint: case eStopReasonException: case eStopReasonExec: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: case eStopReasonSignal: // In all these cases we want to stop in the deepest frame. m_current_inlined_pc = curr_pc; diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1679,6 +1679,12 @@ return "exception"; case eStopReasonExec: return "exec"; + case eStopReasonFork: + return "fork"; + case eStopReasonVFork: + return "vfork"; + case eStopReasonVForkDone: + return "vfork done"; case eStopReasonPlanComplete: return "plan complete"; case eStopReasonThreadExiting: diff --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp --- a/lldb/tools/lldb-vscode/JSONUtils.cpp +++ b/lldb/tools/lldb-vscode/JSONUtils.cpp @@ -878,6 +878,15 @@ case lldb::eStopReasonExec: body.try_emplace("reason", "entry"); break; + case lldb::eStopReasonFork: + body.try_emplace("reason", "fork"); + break; + case lldb::eStopReasonVFork: + body.try_emplace("reason", "vfork"); + break; + case lldb::eStopReasonVForkDone: + body.try_emplace("reason", "vforkdone"); + break; case lldb::eStopReasonThreadExiting: case lldb::eStopReasonInvalid: case lldb::eStopReasonNone: diff --git a/lldb/tools/lldb-vscode/LLDBUtils.cpp b/lldb/tools/lldb-vscode/LLDBUtils.cpp --- a/lldb/tools/lldb-vscode/LLDBUtils.cpp +++ b/lldb/tools/lldb-vscode/LLDBUtils.cpp @@ -56,6 +56,9 @@ case lldb::eStopReasonException: case lldb::eStopReasonExec: case lldb::eStopReasonProcessorTrace: + case lldb::eStopReasonFork: + case lldb::eStopReasonVFork: + case lldb::eStopReasonVForkDone: return true; case lldb::eStopReasonThreadExiting: case lldb::eStopReasonInvalid: