[Lldb-commits] [lldb] adds additional information to the ProcessInfo object for elf processes (PR #88995)
Fred Grim via lldb-commits
lldb-commits at lists.llvm.org
Tue Apr 16 14:55:07 PDT 2024
https://github.com/feg208 created https://github.com/llvm/llvm-project/pull/88995
This adds some additional bits into a ProcessInfo structure that will be of use in filling structs in an elf core file. This is a demand for implementing process save-core
>From 9b8ec4d0c31ad1b228add56bc27cd79457e515c7 Mon Sep 17 00:00:00 2001
From: Fred Grim <fgrim at apple.com>
Date: Tue, 16 Apr 2024 14:46:37 -0700
Subject: [PATCH] adds additional information to the ProcessInfo object for elf
processes
---
lldb/include/lldb/Utility/ProcessInfo.h | 71 ++++++++++++++
lldb/source/Host/linux/Host.cpp | 125 ++++++++++++++++++++----
lldb/unittests/Host/linux/HostTest.cpp | 6 ++
3 files changed, 182 insertions(+), 20 deletions(-)
diff --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h
index 7fb5b37be0f48f..e9fe71e1b851d1 100644
--- a/lldb/include/lldb/Utility/ProcessInfo.h
+++ b/lldb/include/lldb/Utility/ProcessInfo.h
@@ -139,6 +139,11 @@ class ProcessInfo {
// to that process.
class ProcessInstanceInfo : public ProcessInfo {
public:
+ struct timespec {
+ time_t tv_sec = 0;
+ long int tv_usec = 0;
+ };
+
ProcessInstanceInfo() = default;
ProcessInstanceInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid)
@@ -172,6 +177,66 @@ class ProcessInstanceInfo : public ProcessInfo {
return m_parent_pid != LLDB_INVALID_PROCESS_ID;
}
+ lldb::pid_t GetProcessGroupID() const { return m_process_group_id; }
+
+ void SetProcessGroupID(lldb::pid_t pgrp) { m_process_group_id = pgrp; }
+
+ bool ProcessGroupIDIsValid() const {
+ return m_process_group_id != LLDB_INVALID_PROCESS_ID;
+ }
+
+ lldb::pid_t GetProcessSessionID() const { return m_process_session_id; }
+
+ void SetProcessSessionID(lldb::pid_t session) {
+ m_process_session_id = session;
+ }
+
+ bool ProcessSessionIDIsValid() const {
+ return m_process_session_id != LLDB_INVALID_PROCESS_ID;
+ }
+
+ struct timespec GetUserTime() const { return m_user_time; }
+
+ 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;
+ }
+
+ struct timespec GetSystemTime() const { return m_system_time; }
+
+ 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;
+ }
+
+ struct timespec GetCumulativeUserTime() const {
+ return m_cumulative_user_time;
+ }
+
+ void SetCumulativeUserTime(struct timespec cutime) {
+ m_cumulative_user_time = cutime;
+ }
+
+ bool CumulativeUserTimeIsValid() const {
+ return m_cumulative_user_time.tv_sec > 0 ||
+ m_cumulative_user_time.tv_usec > 0;
+ }
+
+ struct timespec GetCumulativeSystemTime() const {
+ return m_cumulative_system_time;
+ }
+
+ void SetCumulativeSystemTime(struct timespec cstime) {
+ m_cumulative_system_time = cstime;
+ }
+
+ bool CumulativeSystemTimeIsValid() const {
+ return m_cumulative_system_time.tv_sec > 0 ||
+ m_cumulative_system_time.tv_sec > 0;
+ }
+
void Dump(Stream &s, UserIDResolver &resolver) const;
static void DumpTableHeader(Stream &s, bool show_args, bool verbose);
@@ -183,6 +248,12 @@ class ProcessInstanceInfo : public ProcessInfo {
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 {};
};
typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList;
diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp
index 6c57384aa38a13..c6490f2fc9e2f5 100644
--- a/lldb/source/Host/linux/Host.cpp
+++ b/lldb/source/Host/linux/Host.cpp
@@ -49,6 +49,29 @@ enum class ProcessState {
TracedOrStopped,
Zombie,
};
+
+constexpr int task_comm_len = 16;
+
+struct StatFields {
+ ::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ char comm[task_comm_len];
+ char state;
+ ::pid_t ppid = LLDB_INVALID_PROCESS_ID;
+ ::pid_t pgrp = LLDB_INVALID_PROCESS_ID;
+ ::pid_t session = LLDB_INVALID_PROCESS_ID;
+ int tty_nr;
+ int tpgid;
+ unsigned flags;
+ long unsigned minflt;
+ long unsigned cminflt;
+ long unsigned majflt;
+ long unsigned cmajflt;
+ long unsigned utime;
+ long unsigned stime;
+ long cutime;
+ long cstime;
+ // .... other things. We don't need them below
+};
}
namespace lldb_private {
@@ -60,11 +83,92 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
::pid_t &Tgid) {
Log *log = GetLog(LLDBLog::Host);
- auto BufferOrError = getProcFile(Pid, "status");
+ auto BufferOrError = getProcFile(Pid, "stat");
if (!BufferOrError)
return false;
llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+ 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) {
+ return false;
+ }
+
+ auto convert = [sc_clk_ticks = sysconf(_SC_CLK_TCK)](auto time_in_ticks) {
+ ProcessInstanceInfo::timespec ts;
+ if (sc_clk_ticks <= 0) {
+ return ts;
+ }
+ ts.tv_sec = time_in_ticks / sc_clk_ticks;
+ double remainder =
+ (static_cast<double>(time_in_ticks) / sc_clk_ticks) - ts.tv_sec;
+ ts.tv_usec =
+ std::chrono::microseconds{std::lround(1e+6 * remainder)}.count();
+ return ts;
+ };
+
+ ProcessInfo.SetParentProcessID(stat_fields.ppid);
+ ProcessInfo.SetProcessGroupID(stat_fields.pgrp);
+ ProcessInfo.SetProcessSessionID(stat_fields.session);
+ ProcessInfo.SetUserTime(convert(stat_fields.utime));
+ ProcessInfo.SetSystemTime(convert(stat_fields.stime));
+ ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
+ ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
+ switch (stat_fields.state) {
+ case 'R':
+ State = ProcessState::Running;
+ break;
+ case 'S':
+ State = ProcessState::Sleeping;
+ break;
+ case 'D':
+ State = ProcessState::DiskSleep;
+ break;
+ case 'Z':
+ State = ProcessState::Zombie;
+ break;
+ case 'X':
+ State = ProcessState::Dead;
+ break;
+ case 'P':
+ State = ProcessState::Parked;
+ break;
+ case 'W':
+ State = ProcessState::Paging;
+ break;
+ case 'I':
+ State = ProcessState::Idle;
+ break;
+ case 'T': // Stopped on a signal or (before Linux 2.6.33) trace stopped
+ [[fallthrough]];
+ case 't':
+ State = ProcessState::TracedOrStopped;
+ break;
+ default:
+ State = ProcessState::Unknown;
+ break;
+ }
+
+ if (State == ProcessState::Unknown) {
+ LLDB_LOG(log, "Unknown process state {0}", stat_fields.state);
+ }
+
+ BufferOrError = getProcFile(Pid, "status");
+ if (!BufferOrError)
+ return false;
+
+ Rest = BufferOrError.get()->getBuffer();
+ if (Rest.empty())
+ return false;
+
while (!Rest.empty()) {
llvm::StringRef Line;
std::tie(Line, Rest) = Rest.split('\n');
@@ -89,25 +193,6 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
ProcessInfo.SetUserID(RUid);
ProcessInfo.SetEffectiveUserID(EUid);
- } else if (Line.consume_front("PPid:")) {
- ::pid_t PPid;
- Line.ltrim().consumeInteger(10, PPid);
- ProcessInfo.SetParentProcessID(PPid);
- } else if (Line.consume_front("State:")) {
- State = llvm::StringSwitch<ProcessState>(Line.ltrim().take_front(1))
- .Case("D", ProcessState::DiskSleep)
- .Case("I", ProcessState::Idle)
- .Case("R", ProcessState::Running)
- .Case("S", ProcessState::Sleeping)
- .CaseLower("T", ProcessState::TracedOrStopped)
- .Case("W", ProcessState::Paging)
- .Case("P", ProcessState::Parked)
- .Case("X", ProcessState::Dead)
- .Case("Z", ProcessState::Zombie)
- .Default(ProcessState::Unknown);
- if (State == ProcessState::Unknown) {
- LLDB_LOG(log, "Unknown process state {0}", Line);
- }
} else if (Line.consume_front("TracerPid:")) {
Line = Line.ltrim();
Line.consumeInteger(10, TracerPid);
diff --git a/lldb/unittests/Host/linux/HostTest.cpp b/lldb/unittests/Host/linux/HostTest.cpp
index 78bbe470d69531..32b1a3678e1fa4 100644
--- a/lldb/unittests/Host/linux/HostTest.cpp
+++ b/lldb/unittests/Host/linux/HostTest.cpp
@@ -40,6 +40,12 @@ TEST_F(HostTest, GetProcessInfo) {
ASSERT_TRUE(Info.ParentProcessIDIsValid());
EXPECT_EQ(lldb::pid_t(getppid()), Info.GetParentProcessID());
+ ASSERT_TRUE(Info.ProcessGroupIDIsValid());
+ EXPECT_EQ(lldb::pid_t(getpgrp()), Info.GetProcessGroupID());
+
+ ASSERT_TRUE(Info.ProcessSessionIDIsValid());
+ EXPECT_EQ(lldb::pid_t(getsid(getpid())), Info.GetProcessSessionID());
+
ASSERT_TRUE(Info.EffectiveUserIDIsValid());
EXPECT_EQ(geteuid(), Info.GetEffectiveUserID());
More information about the lldb-commits
mailing list