mgorny created this revision.
mgorny added reviewers: labath, emaste, krytarowski.
mgorny requested review of this revision.

Introduce two new stop reasons for fork and vfork events.  This includes
server support for serializing fork/vfork events into gdb-remote
protocol, and client support for deserializing them.  The stop infos
for both events take a pair of PID and TID for the newly forked process.


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/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,8 @@
   case lldb::eStopReasonException:
   case lldb::eStopReasonExec:
   case lldb::eStopReasonProcessorTrace:
+  case lldb::eStopReasonFork:
+  case lldb::eStopReasonVFork:
     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,12 @@
   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::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,10 @@
     return "exception";
   case eStopReasonExec:
     return "exec";
+  case eStopReasonFork:
+    return "fork";
+  case eStopReasonVFork:
+    return "vfork";
   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,48 @@
   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_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"; }
+
+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_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"; }
+
+private:
+  lldb::pid_t m_child_pid;
+  lldb::tid_t m_child_tid;
+};
+
 } // namespace lldb_private
 
 StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
@@ -1194,6 +1236,19 @@
   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));
+}
+
 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,8 @@
   case eStopReasonWatchpoint:
   case eStopReasonException:
   case eStopReasonExec:
+  case eStopReasonFork:
+  case eStopReasonVFork:
   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
@@ -800,6 +800,8 @@
             case eStopReasonWatchpoint:
             case eStopReasonException:
             case eStopReasonExec:
+            case eStopReasonFork:
+            case eStopReasonVFork:
             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,24 @@
             } 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 (!signo) {
             addr_t pc = thread_sp->GetRegisterContext()->GetPC();
@@ -2307,6 +2325,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,10 @@
     return "exec";
   case eStopReasonProcessorTrace:
     return "processor trace";
+  case eStopReasonFork:
+    return "fork";
+  case eStopReasonVFork:
+    return "vfork";
   case eStopReasonInstrumentation:
   case eStopReasonInvalid:
   case eStopReasonPlanComplete:
@@ -926,6 +930,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
@@ -195,6 +195,12 @@
 
         case eStopReasonException:
           return 1;
+
+        case eStopReasonFork:
+          return 1;
+
+        case eStopReasonVFork:
+          return 1;
         }
       }
     }
@@ -258,6 +264,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,10 @@
         return "watchpoint"
     elif enum == lldb.eStopReasonExec:
         return "exec"
+    elif enum == lldb.eStopReasonFork:
+        return "fork"
+    elif enum == lldb.eStopReasonVFork:
+        return "vfork"
     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,8 @@
   eStopReasonThreadExiting,
   eStopReasonInstrumentation,
   eStopReasonProcessorTrace,
+  eStopReasonFork,
+  eStopReasonVFork,
 };
 
 /// 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,14 @@
   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::ValueObjectSP
   GetReturnValueObject(lldb::StopInfoSP &stop_info_sp);
 
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,8 @@
   /// 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
   /// 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,8 @@
   /// 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
   /// 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,12 @@
                                 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)))
 
                             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,8 @@
 .. py:data:: eStopReasonSignal
 .. py:data:: eStopReasonException
 .. py:data:: eStopReasonExec
+.. py:data:: eStopReasonFork
+.. py:data:: eStopReasonVFork
 .. 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,8 @@
     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
     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,8 @@
     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
     eStopReasonPlanComplete  0") GetStopReasonDataAtIndex;
     uint64_t
     GetStopReasonDataAtIndex(uint32_t idx);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to