https://github.com/feg208 updated 
https://github.com/llvm/llvm-project/pull/91544

>From d01efd10f8a4b7d908acaa3237541bf6a83b4c7c Mon Sep 17 00:00:00 2001
From: Fred Grim <fg...@apple.com>
Date: Wed, 8 May 2024 15:36:16 -0700
Subject: [PATCH] [lldb] Adds additional fields to ProcessInfo

To implement SaveCore for elf binaries we need to populate some
additional fields in the prpsinfo struct. Those fields are the nice
value of the process whose core is to be taken as well as a boolean
flag indicating whether or not that process is a zombie. This commit
adds those as well as tests to ensure that the values are consistent
with expectations
---
 lldb/include/lldb/Utility/ProcessInfo.h | 94 +++++++++++++++----------
 lldb/source/Host/linux/Host.cpp         | 32 ++++++---
 lldb/source/Utility/ProcessInfo.cpp     | 11 ++-
 lldb/unittests/Host/linux/HostTest.cpp  | 21 ++++++
 4 files changed, 109 insertions(+), 49 deletions(-)

diff --git a/lldb/include/lldb/Utility/ProcessInfo.h 
b/lldb/include/lldb/Utility/ProcessInfo.h
index 54ac000dc7fc2..995873a6869e0 100644
--- a/lldb/include/lldb/Utility/ProcessInfo.h
+++ b/lldb/include/lldb/Utility/ProcessInfo.h
@@ -15,6 +15,7 @@
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/NameMatches.h"
 #include "lldb/Utility/StructuredData.h"
+#include <optional>
 #include <vector>
 
 namespace lldb_private {
@@ -147,72 +148,71 @@ class ProcessInstanceInfo : public ProcessInfo {
   ProcessInstanceInfo() = default;
 
   ProcessInstanceInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid)
-      : ProcessInfo(name, arch, pid), m_euid(UINT32_MAX), m_egid(UINT32_MAX),
-        m_parent_pid(LLDB_INVALID_PROCESS_ID) {}
+      : ProcessInfo(name, arch, pid) {}
 
   void Clear() {
     ProcessInfo::Clear();
-    m_euid = UINT32_MAX;
-    m_egid = UINT32_MAX;
-    m_parent_pid = LLDB_INVALID_PROCESS_ID;
+    m_euid = std::nullopt;
+    m_egid = std::nullopt;
+    m_parent_pid = std::nullopt;
   }
 
-  uint32_t GetEffectiveUserID() const { return m_euid; }
+  uint32_t GetEffectiveUserID() const { return m_euid.value(); }
 
-  uint32_t GetEffectiveGroupID() const { return m_egid; }
+  uint32_t GetEffectiveGroupID() const { return m_egid.value(); }
 
-  bool EffectiveUserIDIsValid() const { return m_euid != UINT32_MAX; }
+  bool EffectiveUserIDIsValid() const { return m_euid.has_value(); }
 
-  bool EffectiveGroupIDIsValid() const { return m_egid != UINT32_MAX; }
+  bool EffectiveGroupIDIsValid() const { return m_egid.has_value(); }
 
   void SetEffectiveUserID(uint32_t uid) { m_euid = uid; }
 
   void SetEffectiveGroupID(uint32_t gid) { m_egid = gid; }
 
-  lldb::pid_t GetParentProcessID() const { return m_parent_pid; }
+  lldb::pid_t GetParentProcessID() const { return m_parent_pid.value(); }
 
   void SetParentProcessID(lldb::pid_t pid) { m_parent_pid = pid; }
 
-  bool ParentProcessIDIsValid() const {
-    return m_parent_pid != LLDB_INVALID_PROCESS_ID;
-  }
+  bool ParentProcessIDIsValid() const { return m_parent_pid.has_value(); }
 
-  lldb::pid_t GetProcessGroupID() const { return m_process_group_id; }
+  lldb::pid_t GetProcessGroupID() const { return m_process_group_id.value(); }
 
   void SetProcessGroupID(lldb::pid_t pgrp) { m_process_group_id = pgrp; }
 
-  bool ProcessGroupIDIsValid() const {
-    return m_process_group_id != LLDB_INVALID_PROCESS_ID;
-  }
+  bool ProcessGroupIDIsValid() const { return m_process_group_id.has_value(); }
 
-  lldb::pid_t GetProcessSessionID() const { return m_process_session_id; }
+  lldb::pid_t GetProcessSessionID() const {
+    return m_process_session_id.value();
+  }
 
   void SetProcessSessionID(lldb::pid_t session) {
     m_process_session_id = session;
   }
 
   bool ProcessSessionIDIsValid() const {
-    return m_process_session_id != LLDB_INVALID_PROCESS_ID;
+    return m_process_session_id.has_value();
   }
 
-  struct timespec GetUserTime() const { return m_user_time; }
+  struct timespec GetUserTime() const { return m_user_time.value(); }
 
   void SetUserTime(struct timespec utime) { m_user_time = utime; }
 
   bool UserTimeIsValid() const {
-    return m_user_time.tv_sec > 0 || m_user_time.tv_usec > 0;
+    return m_user_time.has_value() &&
+           (m_user_time->tv_sec > 0 || m_user_time->tv_usec > 0);
   }
 
-  struct timespec GetSystemTime() const { return m_system_time; }
+  struct timespec GetSystemTime() const { return m_system_time.value(); }
 
   void SetSystemTime(struct timespec stime) { m_system_time = stime; }
 
   bool SystemTimeIsValid() const {
-    return m_system_time.tv_sec > 0 || m_system_time.tv_usec > 0;
+    return m_system_time.has_value() &&
+           (m_system_time->tv_sec > 0 || m_system_time->tv_usec > 0);
   }
 
   struct timespec GetCumulativeUserTime() const {
-    return m_cumulative_user_time;
+    return m_cumulative_user_time.value();
   }
 
   void SetCumulativeUserTime(struct timespec cutime) {
@@ -220,12 +220,13 @@ class ProcessInstanceInfo : public ProcessInfo {
   }
 
   bool CumulativeUserTimeIsValid() const {
-    return m_cumulative_user_time.tv_sec > 0 ||
-           m_cumulative_user_time.tv_usec > 0;
+    return m_cumulative_user_time.has_value() &&
+           (m_cumulative_user_time->tv_sec > 0 ||
+            m_cumulative_user_time->tv_usec > 0);
   }
 
   struct timespec GetCumulativeSystemTime() const {
-    return m_cumulative_system_time;
+    return m_cumulative_system_time.value();
   }
 
   void SetCumulativeSystemTime(struct timespec cstime) {
@@ -233,10 +234,25 @@ class ProcessInstanceInfo : public ProcessInfo {
   }
 
   bool CumulativeSystemTimeIsValid() const {
-    return m_cumulative_system_time.tv_sec > 0 ||
-           m_cumulative_system_time.tv_usec > 0;
+    return m_cumulative_system_time.has_value() &&
+           (m_cumulative_system_time->tv_sec > 0 ||
+            m_cumulative_system_time->tv_usec > 0);
+  }
+
+  int8_t GetPriorityValue() const { return m_priority_value.value(); }
+
+  void SetPriorityValue(int8_t priority_value) {
+    m_priority_value = priority_value;
   }
 
+  bool PriorityValueIsValid() const;
+
+  void SetIsZombie(bool is_zombie) { m_zombie = is_zombie; }
+
+  bool IsZombieValid() const { return m_zombie.has_value(); }
+
+  bool IsZombie() const { return m_zombie.value(); }
+
   void Dump(Stream &s, UserIDResolver &resolver) const;
 
   static void DumpTableHeader(Stream &s, bool show_args, bool verbose);
@@ -245,15 +261,17 @@ class ProcessInstanceInfo : public ProcessInfo {
                       bool verbose) const;
 
 protected:
-  uint32_t m_euid = UINT32_MAX;
-  uint32_t m_egid = UINT32_MAX;
-  lldb::pid_t m_parent_pid = LLDB_INVALID_PROCESS_ID;
-  lldb::pid_t m_process_group_id = LLDB_INVALID_PROCESS_ID;
-  lldb::pid_t m_process_session_id = LLDB_INVALID_PROCESS_ID;
-  struct timespec m_user_time {};
-  struct timespec m_system_time {};
-  struct timespec m_cumulative_user_time {};
-  struct timespec m_cumulative_system_time {};
+  std::optional<uint32_t> m_euid = std::nullopt;
+  std::optional<uint32_t> m_egid = std::nullopt;
+  std::optional<lldb::pid_t> m_parent_pid = std::nullopt;
+  std::optional<lldb::pid_t> m_process_group_id = std::nullopt;
+  std::optional<lldb::pid_t> m_process_session_id = std::nullopt;
+  std::optional<struct timespec> m_user_time = std::nullopt;
+  std::optional<struct timespec> m_system_time = std::nullopt;
+  std::optional<struct timespec> m_cumulative_user_time = std::nullopt;
+  std::optional<struct timespec> m_cumulative_system_time = std::nullopt;
+  std::optional<int8_t> m_priority_value = std::nullopt;
+  std::optional<bool> m_zombie = std::nullopt;
 };
 
 typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList;
diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp
index c6490f2fc9e2f..5545f9ef4d70e 100644
--- a/lldb/source/Host/linux/Host.cpp
+++ b/lldb/source/Host/linux/Host.cpp
@@ -37,6 +37,7 @@ using namespace lldb;
 using namespace lldb_private;
 
 namespace {
+
 enum class ProcessState {
   Unknown,
   Dead,
@@ -70,6 +71,12 @@ struct StatFields {
   long unsigned stime;
   long cutime;
   long cstime;
+  // In proc_pid_stat(5) this field is specified as priority
+  // but documented as realtime priority. To keep with the adopted
+  // nomenclature in ProcessInstanceInfo, we adopt the documented
+  // naming here.
+  long realtime_priority;
+  long priority;
   // .... other things. We don't need them below
 };
 }
@@ -91,14 +98,16 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
   if (Rest.empty())
     return false;
   StatFields stat_fields;
-  if (sscanf(Rest.data(),
-             "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld",
-             &stat_fields.pid, stat_fields.comm, &stat_fields.state,
-             &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
-             &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
-             &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
-             &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
-             &stat_fields.cutime, &stat_fields.cstime) < 0) {
+  if (sscanf(
+          Rest.data(),
+          "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld",
+          &stat_fields.pid, stat_fields.comm, &stat_fields.state,
+          &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
+          &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
+          &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
+          &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
+          &stat_fields.cutime, &stat_fields.cstime,
+          &stat_fields.realtime_priority, &stat_fields.priority) < 0) {
     return false;
   }
 
@@ -115,6 +124,11 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
     return ts;
   };
 
+  // Priority (nice) values run from 19 to -20 inclusive (in linux). In the
+  // prpsinfo struct pr_nice is a char.
+  auto priority_value = static_cast<int8_t>(
+      (stat_fields.priority < 0 ? 0x80 : 0x00) | (stat_fields.priority & 
0x7f));
+
   ProcessInfo.SetParentProcessID(stat_fields.ppid);
   ProcessInfo.SetProcessGroupID(stat_fields.pgrp);
   ProcessInfo.SetProcessSessionID(stat_fields.session);
@@ -122,6 +136,7 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
   ProcessInfo.SetSystemTime(convert(stat_fields.stime));
   ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
   ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
+  ProcessInfo.SetPriorityValue(priority_value);
   switch (stat_fields.state) {
   case 'R':
     State = ProcessState::Running;
@@ -156,6 +171,7 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
     State = ProcessState::Unknown;
     break;
   }
+  ProcessInfo.SetIsZombie(State == ProcessState::Zombie);
 
   if (State == ProcessState::Unknown) {
     LLDB_LOG(log, "Unknown process state {0}", stat_fields.state);
diff --git a/lldb/source/Utility/ProcessInfo.cpp 
b/lldb/source/Utility/ProcessInfo.cpp
index 6b2a7114dfb4c..a5574931bcb23 100644
--- a/lldb/source/Utility/ProcessInfo.cpp
+++ b/lldb/source/Utility/ProcessInfo.cpp
@@ -117,12 +117,16 @@ bool ProcessInfo::IsScriptedProcess() const {
   return m_scripted_metadata_sp && *m_scripted_metadata_sp;
 }
 
+bool ProcessInstanceInfo::PriorityValueIsValid() const {
+  return m_priority_value.has_value();
+}
+
 void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
   if (m_pid != LLDB_INVALID_PROCESS_ID)
     s.Printf("    pid = %" PRIu64 "\n", m_pid);
 
-  if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
-    s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
+  if (ParentProcessIDIsValid())
+    s.Printf(" parent = %" PRIu64 "\n", GetParentProcessID());
 
   if (m_executable) {
     s.Printf("   name = %s\n", m_executable.GetFilename().GetCString());
@@ -193,7 +197,8 @@ void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool 
show_args,
 void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver,
                                          bool show_args, bool verbose) const {
   if (m_pid != LLDB_INVALID_PROCESS_ID) {
-    s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
+    s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid,
+             (ParentProcessIDIsValid()) ? GetParentProcessID() : 0);
 
     StreamString arch_strm;
     if (m_arch.IsValid())
diff --git a/lldb/unittests/Host/linux/HostTest.cpp 
b/lldb/unittests/Host/linux/HostTest.cpp
index 8ecaf3ec0decb..b2c42c0c42d40 100644
--- a/lldb/unittests/Host/linux/HostTest.cpp
+++ b/lldb/unittests/Host/linux/HostTest.cpp
@@ -12,6 +12,9 @@
 #include "lldb/Utility/ProcessInfo.h"
 #include "gtest/gtest.h"
 
+#include <cerrno>
+#include <sys/resource.h>
+
 using namespace lldb_private;
 
 namespace {
@@ -86,4 +89,22 @@ TEST_F(HostTest, GetProcessInfo) {
   ProcessInstanceInfo::timespec next_user_time = Info.GetUserTime();
   ASSERT_TRUE(user_time.tv_sec <= next_user_time.tv_sec ||
               user_time.tv_usec <= next_user_time.tv_usec);
+
+  struct rlimit rlim;
+  EXPECT_EQ(getrlimit(RLIMIT_NICE, &rlim), 0);
+  // getpriority can return -1 so we zero errno first
+  errno = 0;
+  int prio = getpriority(PRIO_PROCESS, PRIO_PROCESS);
+  ASSERT_TRUE((prio < 0 && errno == 0) || prio >= 0);
+  ASSERT_EQ(Info.GetPriorityValue(), prio);
+  // If we can't raise our nice level then this test can't be performed.
+  int max_incr = PRIO_MAX - rlim.rlim_cur;
+  if (max_incr < prio) {
+    EXPECT_EQ(setpriority(PRIO_PROCESS, PRIO_PROCESS, prio - 1), 0);
+    ASSERT_TRUE(Host::GetProcessInfo(getpid(), Info));
+    ASSERT_EQ(Info.GetPriorityValue(), prio - 1);
+    EXPECT_EQ(setpriority(PRIO_PROCESS, PRIO_PROCESS, prio), 0);
+  }
+  ASSERT_TRUE(Info.IsZombieValid());
+  ASSERT_FALSE(Info.IsZombie());
 }

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to