mgorny updated this revision to Diff 336668.
mgorny retitled this revision from "[lldb] Introduce new stop reasons: fork and
vfork" to "[lldb] Introduce new stop reasons for fork and vfork".
mgorny edited the summary of this revision.
mgorny added a comment.
Add 'vforkdone' stop reason. Move overrideable actions to this patch.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D100196/new/
https://reviews.llvm.org/D100196
Files:
lldb/bindings/interface/SBThread.i
lldb/bindings/interface/SBThreadPlan.i
lldb/docs/python_api_enums.rst
lldb/examples/python/performance.py
lldb/include/lldb/API/SBThread.h
lldb/include/lldb/API/SBThreadPlan.h
lldb/include/lldb/Host/Debug.h
lldb/include/lldb/Target/Process.h
lldb/include/lldb/Target/StopInfo.h
lldb/include/lldb/lldb-enumerations.h
lldb/packages/Python/lldbsuite/test/lldbutil.py
lldb/source/API/SBThread.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Target/Process.cpp
lldb/source/Target/StackFrameList.cpp
lldb/source/Target/StopInfo.cpp
lldb/source/Target/Thread.cpp
lldb/tools/lldb-vscode/JSONUtils.cpp
lldb/tools/lldb-vscode/LLDBUtils.cpp
Index: lldb/tools/lldb-vscode/LLDBUtils.cpp
===================================================================
--- lldb/tools/lldb-vscode/LLDBUtils.cpp
+++ 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:
Index: lldb/tools/lldb-vscode/JSONUtils.cpp
===================================================================
--- lldb/tools/lldb-vscode/JSONUtils.cpp
+++ lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -877,6 +877,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:
Index: lldb/source/Target/Thread.cpp
===================================================================
--- lldb/source/Target/Thread.cpp
+++ 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:
Index: lldb/source/Target/StopInfo.cpp
===================================================================
--- lldb/source/Target/StopInfo.cpp
+++ lldb/source/Target/StopInfo.cpp
@@ -1145,6 +1145,103 @@
bool m_performed_action;
};
+// StopInfoFork
+
+class StopInfoFork : public StopInfo {
+public:
+ StopInfoFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid)
+ : StopInfo(thread, child_pid), m_performed_action(false),
+ m_child_pid(child_pid), m_child_tid(child_tid) {}
+
+ ~StopInfoFork() override = default;
+
+ bool ShouldStop(Event *event_ptr) override { return false; }
+
+ StopReason GetStopReason() const override { return eStopReasonFork; }
+
+ const char *GetDescription() override { return "fork"; }
+
+protected:
+ void PerformAction(Event *event_ptr) override {
+ // Only perform the action once
+ if (m_performed_action)
+ return;
+ m_performed_action = true;
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ thread_sp->GetProcess()->DidFork(m_child_pid, m_child_tid);
+ }
+
+ bool m_performed_action;
+
+private:
+ lldb::pid_t m_child_pid;
+ lldb::tid_t m_child_tid;
+};
+
+// StopInfoVFork
+
+class StopInfoVFork : public StopInfo {
+public:
+ StopInfoVFork(Thread &thread, lldb::pid_t child_pid, lldb::tid_t child_tid)
+ : StopInfo(thread, child_pid), m_performed_action(false),
+ m_child_pid(child_pid), m_child_tid(child_tid) {}
+
+ ~StopInfoVFork() override = default;
+
+ bool ShouldStop(Event *event_ptr) override { return false; }
+
+ StopReason GetStopReason() const override { return eStopReasonVFork; }
+
+ const char *GetDescription() override { return "vfork"; }
+
+protected:
+ void PerformAction(Event *event_ptr) override {
+ // Only perform the action once
+ if (m_performed_action)
+ return;
+ m_performed_action = true;
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ thread_sp->GetProcess()->DidVFork(m_child_pid, m_child_tid);
+ }
+
+ bool m_performed_action;
+
+private:
+ lldb::pid_t m_child_pid;
+ lldb::tid_t m_child_tid;
+};
+
+// StopInfoVForkDone
+
+class StopInfoVForkDone : public StopInfo {
+public:
+ StopInfoVForkDone(Thread &thread)
+ : StopInfo(thread, 0), m_performed_action(false) {}
+
+ ~StopInfoVForkDone() override = default;
+
+ bool ShouldStop(Event *event_ptr) override { return false; }
+
+ StopReason GetStopReason() const override { return eStopReasonVForkDone; }
+
+ const char *GetDescription() override { return "vforkdone"; }
+
+protected:
+ void PerformAction(Event *event_ptr) override {
+ // Only perform the action once
+ if (m_performed_action)
+ return;
+ m_performed_action = true;
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ thread_sp->GetProcess()->DidVForkDone();
+ }
+
+ bool m_performed_action;
+};
+
} // namespace lldb_private
StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
@@ -1194,6 +1291,23 @@
return StopInfoSP(new StopInfoExec(thread));
}
+StopInfoSP StopInfo::CreateStopReasonFork(Thread &thread,
+ lldb::pid_t child_pid,
+ lldb::tid_t child_tid) {
+ return StopInfoSP(new StopInfoFork(thread, child_pid, child_tid));
+}
+
+
+StopInfoSP StopInfo::CreateStopReasonVFork(Thread &thread,
+ lldb::pid_t child_pid,
+ lldb::tid_t child_tid) {
+ return StopInfoSP(new StopInfoVFork(thread, child_pid, child_tid));
+}
+
+StopInfoSP StopInfo::CreateStopReasonVForkDone(Thread &thread) {
+ return StopInfoSP(new StopInfoVForkDone(thread));
+}
+
ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) {
if (stop_info_sp &&
stop_info_sp->GetStopReason() == eStopReasonPlanComplete) {
Index: lldb/source/Target/StackFrameList.cpp
===================================================================
--- lldb/source/Target/StackFrameList.cpp
+++ 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;
Index: lldb/source/Target/Process.cpp
===================================================================
--- lldb/source/Target/Process.cpp
+++ lldb/source/Target/Process.cpp
@@ -812,6 +812,9 @@
case eStopReasonWatchpoint:
case eStopReasonException:
case eStopReasonExec:
+ case eStopReasonFork:
+ case eStopReasonVFork:
+ case eStopReasonVForkDone:
case eStopReasonThreadExiting:
case eStopReasonInstrumentation:
case eStopReasonProcessorTrace:
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
@@ -1901,6 +1901,28 @@
} else if (reason == "processor trace") {
thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace(
*thread_sp, description.c_str()));
+ } else if (reason == "fork") {
+ StringExtractor desc_extractor(description.c_str());
+ lldb::pid_t child_pid = desc_extractor.GetU64(
+ LLDB_INVALID_PROCESS_ID);
+ lldb::tid_t child_tid = desc_extractor.GetU64(
+ LLDB_INVALID_THREAD_ID);
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonFork(
+ *thread_sp, child_pid, child_tid));
+ handled = true;
+ } else if (reason == "vfork") {
+ StringExtractor desc_extractor(description.c_str());
+ lldb::pid_t child_pid = desc_extractor.GetU64(
+ LLDB_INVALID_PROCESS_ID);
+ lldb::tid_t child_tid = desc_extractor.GetU64(
+ LLDB_INVALID_THREAD_ID);
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonVFork(
+ *thread_sp, child_pid, child_tid));
+ handled = true;
+ } else if (reason == "vforkdone") {
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonVForkDone(*thread_sp));
+ handled = true;
}
} else if (!signo) {
addr_t pc = thread_sp->GetRegisterContext()->GetPC();
@@ -2307,6 +2329,21 @@
ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
LLDB_LOG_ERROR(log, std::move(error), "Failed to load modules: {0}");
}
+ } else if (key.compare("fork") == 0 || key.compare("vfork") == 0) {
+ // fork includes child pid/tid in thread-id format
+ StringExtractorGDBRemote thread_id{value};
+ auto pid_tid = thread_id.GetPidTid(LLDB_INVALID_PROCESS_ID);
+ if (!pid_tid) {
+ Log *log(
+ ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ LLDB_LOG(log, "Invalid PID/TID to fork: {0}", value);
+ pid_tid = {{LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID}};
+ }
+
+ reason = key.str();
+ StreamString ostr;
+ ostr.Printf("%" PRIu64 " %" PRIu64, pid_tid->first, pid_tid->second);
+ description = std::string(ostr.GetString());
} else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) {
uint32_t reg = UINT32_MAX;
if (!key.getAsInteger(16, reg))
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
@@ -650,6 +650,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:
@@ -926,6 +932,14 @@
}
}
+ // Include child process PID/TID for forks.
+ if (tid_stop_info.reason == eStopReasonFork ||
+ tid_stop_info.reason == eStopReasonVFork) {
+ 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());
}
Index: lldb/source/API/SBThread.cpp
===================================================================
--- lldb/source/API/SBThread.cpp
+++ 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();
}
}
}
Index: lldb/packages/Python/lldbsuite/test/lldbutil.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/lldbutil.py
+++ lldb/packages/Python/lldbsuite/test/lldbutil.py
@@ -247,6 +247,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:
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -249,6 +249,9 @@
eStopReasonThreadExiting,
eStopReasonInstrumentation,
eStopReasonProcessorTrace,
+ eStopReasonFork,
+ eStopReasonVFork,
+ eStopReasonVForkDone,
};
/// Command Return Status Types.
Index: lldb/include/lldb/Target/StopInfo.h
===================================================================
--- lldb/include/lldb/Target/StopInfo.h
+++ lldb/include/lldb/Target/StopInfo.h
@@ -132,6 +132,16 @@
static lldb::StopInfoSP
CreateStopReasonProcessorTrace(Thread &thread, const char *description);
+ static lldb::StopInfoSP CreateStopReasonFork(Thread &thread,
+ lldb::pid_t child_pid,
+ lldb::tid_t child_tid);
+
+ static lldb::StopInfoSP CreateStopReasonVFork(Thread &thread,
+ lldb::pid_t child_pid,
+ lldb::tid_t child_tid);
+
+ static lldb::StopInfoSP CreateStopReasonVForkDone(Thread &thread);
+
static lldb::ValueObjectSP
GetReturnValueObject(lldb::StopInfoSP &stop_info_sp);
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -980,6 +980,15 @@
/// anything after a process exec's itself.
virtual void DoDidExec() {}
+ /// Called after a reported fork.
+ virtual void DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {}
+
+ /// Called after a reported vfork.
+ virtual void DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {}
+
+ /// Called after reported vfork completion.
+ virtual void DidVForkDone() {}
+
/// Called before launching to a process.
///
/// Allow Process plug-ins to execute some code before launching a process.
Index: lldb/include/lldb/Host/Debug.h
===================================================================
--- lldb/include/lldb/Host/Debug.h
+++ 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;
};
}
Index: lldb/include/lldb/API/SBThreadPlan.h
===================================================================
--- lldb/include/lldb/API/SBThreadPlan.h
+++ 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);
Index: lldb/include/lldb/API/SBThread.h
===================================================================
--- lldb/include/lldb/API/SBThread.h
+++ 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);
Index: lldb/examples/python/performance.py
===================================================================
--- lldb/examples/python/performance.py
+++ 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
Index: lldb/docs/python_api_enums.rst
===================================================================
--- lldb/docs/python_api_enums.rst
+++ 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
Index: lldb/bindings/interface/SBThreadPlan.i
===================================================================
--- lldb/bindings/interface/SBThreadPlan.i
+++ 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);
Index: lldb/bindings/interface/SBThread.i
===================================================================
--- lldb/bindings/interface/SBThread.i
+++ 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);
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits