Repository: llvm/llvm-project
Pull request #134354: [lldb][AIX] get host info for AIX
Author: login: HemangGadhavi
Labels: name: lldb
Created: 2025-04-04T07:50:26Z | Merged: 2025-04-29T05:53:04Z

This PR is in reference to porting LLDB on AIX.

Link to discussions on llvm discourse and github:

1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640
2. https://github.com/llvm/llvm-project/issues/101657
The complete changes for porting are present in this draft PR:
https://github.com/llvm/llvm-project/pull/102601

- Added changes to make the common host support functions under `Host/posix` for unix-like system. 
Also, created the `unittests/Host/posix/` to test the hostInfo & support functions for unix-like system.
- Added changes to get the host information for AIX. (GetProcessInfo()) 
(Information like : executable path, arch, process status etc.)
[@DavidSpickett](https://github.com/DavidSpickett) [@labath](https://github.com/labath) [@DhruvSrivastavaX](https://github.com/DhruvSrivastavaX)


Diff:
diff --git a/lldb/include/lldb/Host/linux/Support.h b/lldb/include/lldb/Host/linux/Support.h
index d1eb7f83d4916..1b8e1e2c26fa7 100644
--- a/lldb/include/lldb/Host/linux/Support.h
+++ b/lldb/include/lldb/Host/linux/Support.h
@@ -18,12 +18,6 @@ namespace lldb_private {
 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
 getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file);
 
-llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
-getProcFile(::pid_t pid, const llvm::Twine &file);
-
-llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
-getProcFile(const llvm::Twine &file);
-
 } // namespace lldb_private
 
 #endif // #ifndef LLDB_HOST_LINUX_SUPPORT_H
diff --git a/lldb/include/lldb/Host/posix/Support.h b/lldb/include/lldb/Host/posix/Support.h
new file mode 100644
index 0000000000000..4e779b6485ff4
--- /dev/null
+++ b/lldb/include/lldb/Host/posix/Support.h
@@ -0,0 +1,27 @@
+//===-- Support.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_POSIX_SUPPORT_H
+#define LLDB_HOST_POSIX_SUPPORT_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace lldb_private {
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(::pid_t pid, const llvm::Twine &file);
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(const llvm::Twine &file);
+
+} // namespace lldb_private
+
+#endif // #ifndef LLDB_HOST_POSIX_SUPPORT_H
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index a2ae6f1430c38..90814b1bed4c8 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -87,6 +87,7 @@ else()
     posix/MainLoopPosix.cpp
     posix/PipePosix.cpp
     posix/ProcessLauncherPosixFork.cpp
+    posix/Support.cpp
     )
 
   if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp
index 751c4fbcc9368..a812e061ccae2 100644
--- a/lldb/source/Host/aix/Host.cpp
+++ b/lldb/source/Host/aix/Host.cpp
@@ -7,17 +7,138 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/Host.h"
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include <sys/proc.h>
+#include <sys/procfs.h>
 
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {
+  ProcessInstanceInfo::timespec ts;
+  ts.tv_sec = t.tv_sec;
+  ts.tv_usec = t.tv_nsec / 1000; // nanos to micros
+  return ts;
+}
+
+static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo,
+                          ProcessState &State) {
+  struct pstatus pstatusData;
+  auto BufferOrError = getProcFile(pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  std::unique_ptr<llvm::MemoryBuffer> StatusBuffer = std::move(*BufferOrError);
+  // Ensure there's enough data for psinfoData
+  if (StatusBuffer->getBufferSize() < sizeof(pstatusData))
+    return false;
+
+  std::memcpy(&pstatusData, StatusBuffer->getBufferStart(),
+              sizeof(pstatusData));
+  switch (pstatusData.pr_stat) {
+  case SIDL:
+    State = ProcessState::Idle;
+    break;
+  case SACTIVE:
+    State = ProcessState::Running;
+    break;
+  case SSTOP:
+    State = ProcessState::TracedOrStopped;
+    break;
+  case SZOMB:
+    State = ProcessState::Zombie;
+    break;
+  default:
+    State = ProcessState::Unknown;
+    break;
+  }
+  processInfo.SetIsZombie(State == ProcessState::Zombie);
+  processInfo.SetUserTime(convert(pstatusData.pr_utime));
+  processInfo.SetSystemTime(convert(pstatusData.pr_stime));
+  processInfo.SetCumulativeUserTime(convert(pstatusData.pr_cutime));
+  processInfo.SetCumulativeSystemTime(convert(pstatusData.pr_cstime));
+  return true;
+}
+
+static bool GetExePathAndIds(::pid_t pid, ProcessInstanceInfo &process_info) {
+  struct psinfo psinfoData;
+  auto BufferOrError = getProcFile(pid, "psinfo");
+  if (!BufferOrError)
+    return false;
+
+  std::unique_ptr<llvm::MemoryBuffer> PsinfoBuffer = std::move(*BufferOrError);
+  // Ensure there's enough data for psinfoData
+  if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData))
+    return false;
+
+  std::memcpy(&psinfoData, PsinfoBuffer->getBufferStart(), sizeof(psinfoData));
+  llvm::StringRef PathRef(
+      psinfoData.pr_psargs,
+      strnlen(psinfoData.pr_psargs, sizeof(psinfoData.pr_psargs)));
+  if (PathRef.empty())
+    return false;
+
+  process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
+  ArchSpec arch_spec = ArchSpec();
+  arch_spec.SetArchitecture(eArchTypeXCOFF, llvm::XCOFF::TCPU_PPC64,
+                            LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);
+  process_info.SetArchitecture(arch_spec);
+  process_info.SetParentProcessID(psinfoData.pr_ppid);
+  process_info.SetGroupID(psinfoData.pr_gid);
+  process_info.SetEffectiveGroupID(psinfoData.pr_egid);
+  process_info.SetUserID(psinfoData.pr_uid);
+  process_info.SetEffectiveUserID(psinfoData.pr_euid);
+  process_info.SetProcessGroupID(psinfoData.pr_pgid);
+  process_info.SetProcessSessionID(psinfoData.pr_sid);
+  return true;
+}
+
+static bool GetProcessAndStatInfo(::pid_t pid,
+                                  ProcessInstanceInfo &process_info,
+                                  ProcessState &State) {
+  process_info.Clear();
+  process_info.SetProcessID(pid);
+
+  if (pid == LLDB_INVALID_PROCESS_ID)
+    return false;
+  // Get Executable path/Arch and Get User and Group IDs.
+  if (!GetExePathAndIds(pid, process_info))
+    return false;
+  // Get process status and timing info.
+  if (!GetStatusInfo(pid, process_info, State))
+    return false;
+
+  return true;
+}
+
 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
                                  ProcessInstanceInfoList &process_infos) {
   return 0;
 }
 
 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
-  return false;
+  ProcessState State;
+  return GetProcessAndStatInfo(pid, process_info, State);
 }
 
 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp
index 25bef9b0e7151..8b475a7ab5003 100644
--- a/lldb/source/Host/linux/Host.cpp
+++ b/lldb/source/Host/linux/Host.cpp
@@ -30,7 +30,7 @@
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Host/linux/Host.h"
-#include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "lldb/Utility/DataExtractor.h"
 
 using namespace lldb;
diff --git a/lldb/source/Host/linux/Support.cpp b/lldb/source/Host/linux/Support.cpp
index 8b0decc48c038..c6321e93f4dfa 100644
--- a/lldb/source/Host/linux/Support.cpp
+++ b/lldb/source/Host/linux/Support.cpp
@@ -22,23 +22,3 @@ lldb_private::getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file) {
     LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
   return Ret;
 }
-
-llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
-lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) {
-  Log *log = GetLog(LLDBLog::Host);
-  std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str();
-  auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
-  if (!Ret)
-    LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
-  return Ret;
-}
-
-llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
-lldb_private::getProcFile(const llvm::Twine &file) {
-  Log *log = GetLog(LLDBLog::Host);
-  std::string File = ("/proc/" + file).str();
-  auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
-  if (!Ret)
-    LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
-  return Ret;
-}
diff --git a/lldb/source/Host/posix/Support.cpp b/lldb/source/Host/posix/Support.cpp
new file mode 100644
index 0000000000000..abfcc8ddb2d7f
--- /dev/null
+++ b/lldb/source/Host/posix/Support.cpp
@@ -0,0 +1,32 @@
+//===-- Support.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+lldb_private::getProcFile(::pid_t pid, const llvm::Twine &file) {
+  Log *log = GetLog(LLDBLog::Host);
+  std::string File = ("/proc/" + llvm::Twine(pid) + "/" + file).str();
+  auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
+  if (!Ret)
+    LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
+  return Ret;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+lldb_private::getProcFile(const llvm::Twine &file) {
+  Log *log = GetLog(LLDBLog::Host);
+  std::string File = ("/proc/" + file).str();
+  auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
+  if (!Ret)
+    LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
+  return Ret;
+}
diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
index 0fd7ff2785123..bc44f2b02af98 100644
--- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
@@ -12,7 +12,7 @@
 #include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
 #include "lldb/Host/Debug.h"
 #include "lldb/Host/common/NativeProcessProtocol.h"
-#include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/FileSpec.h"
diff --git a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
index a38b75c9e615f..06551a4ff5a00 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -10,7 +10,6 @@
 #include "Perf.h"
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 #include "Procfs.h"
-#include "lldb/Host/linux/Support.h"
 #include "lldb/Utility/StreamString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
index 2af6c646332c9..d345f165a75d8 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -15,6 +15,7 @@
 #include "lldb/Host/Debug.h"
 #include "lldb/Host/HostThread.h"
 #include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/FileSpec.h"
diff --git a/lldb/source/Plugins/Process/Linux/Perf.cpp b/lldb/source/Plugins/Process/Linux/Perf.cpp
index 097c719b9c1d2..4207364812110 100644
--- a/lldb/source/Plugins/Process/Linux/Perf.cpp
+++ b/lldb/source/Plugins/Process/Linux/Perf.cpp
@@ -9,7 +9,6 @@
 #include "Perf.h"
 
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
-#include "lldb/Host/linux/Support.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
diff --git a/lldb/source/Plugins/Process/Linux/Procfs.cpp b/lldb/source/Plugins/Process/Linux/Procfs.cpp
index 8c279c7ab6533..d3bd396fbaeab 100644
--- a/lldb/source/Plugins/Process/Linux/Procfs.cpp
+++ b/lldb/source/Plugins/Process/Linux/Procfs.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Procfs.h"
-#include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
diff --git a/lldb/unittests/Host/CMakeLists.txt b/lldb/unittests/Host/CMakeLists.txt
index c959478970d18..5b8deed00af88 100644
--- a/lldb/unittests/Host/CMakeLists.txt
+++ b/lldb/unittests/Host/CMakeLists.txt
@@ -15,10 +15,10 @@ set (FILES
   XMLTest.cpp
 )
 
-if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
+if (UNIX)
   list(APPEND FILES
-    linux/HostTest.cpp
-    linux/SupportTest.cpp
+    posix/HostTest.cpp
+    posix/SupportTest.cpp
   )
 endif()
 
diff --git a/lldb/unittests/Host/linux/HostTest.cpp b/lldb/unittests/Host/posix/HostTest.cpp
similarity index 97%
rename from lldb/unittests/Host/linux/HostTest.cpp
rename to lldb/unittests/Host/posix/HostTest.cpp
index d6aefcc7faa25..b4b3a33e7ddc1 100644
--- a/lldb/unittests/Host/linux/HostTest.cpp
+++ b/lldb/unittests/Host/posix/HostTest.cpp
@@ -40,7 +40,8 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
-  ASSERT_FALSE(Host::GetProcessInfo(0, Info));
+
+  ASSERT_FALSE(Host::GetProcessInfo(LLDB_INVALID_PROCESS_ID, Info));
 
   ASSERT_TRUE(Host::GetProcessInfo(getpid(), Info));
 
@@ -90,6 +91,7 @@ TEST_F(HostTest, GetProcessInfo) {
   ASSERT_TRUE(user_time.tv_sec <= next_user_time.tv_sec ||
               user_time.tv_usec <= next_user_time.tv_usec);
 
+#ifndef _AIX
   struct rlimit rlim;
   EXPECT_EQ(getrlimit(RLIMIT_NICE, &rlim), 0);
   // getpriority can return -1 so we zero errno first
@@ -108,4 +110,5 @@ TEST_F(HostTest, GetProcessInfo) {
   }
   ASSERT_TRUE(Info.IsZombie().has_value());
   ASSERT_FALSE(Info.IsZombie().value());
+#endif /* ifndef _AIX */
 }
diff --git a/lldb/unittests/Host/linux/SupportTest.cpp b/lldb/unittests/Host/posix/SupportTest.cpp
similarity index 62%
rename from lldb/unittests/Host/linux/SupportTest.cpp
rename to lldb/unittests/Host/posix/SupportTest.cpp
index 6d1d28cd4caad..f3976db755943 100644
--- a/lldb/unittests/Host/linux/SupportTest.cpp
+++ b/lldb/unittests/Host/posix/SupportTest.cpp
@@ -6,22 +6,16 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "llvm/Support/Threading.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
 
+#ifndef __APPLE__
 TEST(Support, getProcFile_Pid) {
-  auto BufferOrError = getProcFile(getpid(), "maps");
+  auto BufferOrError = getProcFile(getpid(), "status");
   ASSERT_TRUE(BufferOrError);
   ASSERT_TRUE(*BufferOrError);
 }
-
-#ifdef LLVM_ENABLE_THREADING
-TEST(Support, getProcFile_Tid) {
-  auto BufferOrError = getProcFile(getpid(), llvm::get_threadid(), "comm");
-  ASSERT_TRUE(BufferOrError);
-  ASSERT_TRUE(*BufferOrError);
-}
-#endif /*ifdef LLVM_ENABLE_THREADING */
+#endif // #ifndef __APPLE__
diff --git a/lldb/unittests/Process/Linux/ProcfsTests.cpp b/lldb/unittests/Process/Linux/ProcfsTests.cpp
index d95de649ed578..e7af1f469c2bf 100644
--- a/lldb/unittests/Process/Linux/ProcfsTests.cpp
+++ b/lldb/unittests/Process/Linux/ProcfsTests.cpp
@@ -9,6 +9,7 @@
 #include "Procfs.h"
 
 #include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -118,3 +119,11 @@ TEST(Perf, RealPtraceScope) {
   ASSERT_LE(*ptrace_scope, 3)
       << "Sensible values of ptrace_scope are between 0 and 3";
 }
+
+#ifdef LLVM_ENABLE_THREADING
+TEST(Support, getProcFile_Tid) {
+  auto BufferOrError = getProcFile(getpid(), llvm::get_threadid(), "comm");
+  ASSERT_TRUE(BufferOrError);
+  ASSERT_TRUE(*BufferOrError);
+}
+#endif /*ifdef LLVM_ENABLE_THREADING */


Reviews:
user: login: DhruvSrivastavaX
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T08:02:56Z
user: login: DhruvSrivastavaX
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T08:05:59Z
user: login: DhruvSrivastavaX
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T08:09:21Z
user: login: labath
body: We have a tests for this function in `unittests/Host/linux/HostTest.cpp` and it looks like at least some of it should apply to other systems as well. We could move it to the "posix" folder so that it applies to your code as well. Depending on the size of linux-specific parts, we could either keep them in the "linux" folder, or `#ifdef` them out
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-04T08:45:50Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:40:24Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:40:33Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:41:41Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:43:01Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:47:43Z
user: login: labath
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-10T12:53:19Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:07:07Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:19:24Z
user: login: labath
body: Looks pretty good. Just a couple of details.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T08:55:09Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:22:17Z
user: login: labath
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T09:32:51Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:49:40Z
user: login: labath
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-22T10:31:54Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T10:43:49Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T06:05:11Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T06:05:40Z
user: login: labath
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-23T11:05:37Z
user: login: HemangGadhavi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T12:07:27Z
user: login: labath
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-24T11:16:56Z
user: login: DhruvSrivastavaX
body: LGTM
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-29T05:52:14Z

Review comments:
diff_hunk: @@ -141,6 +141,7 @@ else()
     add_host_subdirectory(aix
       aix/Host.cpp
       aix/HostInfoAIX.cpp
+      linux/Support.cpp
path: lldb/source/Host/CMakeLists.txt
user: login: DhruvSrivastavaX
body: In the original draft PR, we have a copy file from linux for aix as well. 
Shall we use the linux version to avoid redundant code, or create a new one for aix? 
For the NativeProcessAIX, we are using the linux/Support.cpp as of now.
created_at: 2025-04-04T08:02:56Z
author_association: MEMBER
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
path: lldb/source/Host/aix/Host.cpp
user: login: DhruvSrivastavaX
body: You can remove this blank line and run clang format once to keep all the includes together in order.
created_at: 2025-04-04T08:05:59Z
author_association: MEMBER
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
+
+  ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
+  if (len > 0) {
+    ExePath.resize(len);
+
+    struct stat statData;
+
path: lldb/source/Host/aix/Host.cpp
user: login: DhruvSrivastavaX
body: Delete the extra blank lines.
created_at: 2025-04-04T08:09:20Z
author_association: MEMBER
diff_hunk: @@ -141,6 +141,7 @@ else()
     add_host_subdirectory(aix
       aix/Host.cpp
       aix/HostInfoAIX.cpp
+      linux/Support.cpp
path: lldb/source/Host/CMakeLists.txt
user: login: labath
body: I'd move those functions into the `posix` folder given that other systems have similar functionality (besides AIX, freebsd also seems to have something similar, albeit deprecated). The functions don't do anything unless they are called, and they're quite simple, so it shouldn't hurt having them even if not all OSes have that functionality.

We might want to keep the three-arg overload (with pid+tid) linux specific -- I don't know if any other system has that.
created_at: 2025-04-04T08:36:48Z
author_association: COLLABORATOR
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
path: lldb/source/Host/aix/Host.cpp
user: login: labath
body: cwd??
created_at: 2025-04-04T08:38:42Z
author_association: COLLABORATOR
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
+
+  ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
+  if (len > 0) {
+    ExePath.resize(len);
+
+    struct stat statData;
+
+    std::ostringstream oss;
+
+    oss << "/proc/" << std::dec << pid << "/psinfo";
+    assert(stat(oss.str().c_str(), &statData) == 0);
+
+    const int fd = open(oss.str().c_str(), O_RDONLY);
+    assert(fd >= 0);
+
+    ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData));
+    assert(readNum >= 0);
+
+    close(fd);
path: lldb/source/Host/aix/Host.cpp
user: login: labath
body: This could be done with `getProcFile`, right?
created_at: 2025-04-04T08:40:08Z
author_association: COLLABORATOR
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
path: lldb/source/Host/aix/Host.cpp
user: login: HemangGadhavi
body: Removed. 
created_at: 2025-04-10T11:40:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
+
+  ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
+  if (len > 0) {
+    ExePath.resize(len);
+
+    struct stat statData;
+
path: lldb/source/Host/aix/Host.cpp
user: login: HemangGadhavi
body: Removed. 
created_at: 2025-04-10T11:40:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
path: lldb/source/Host/aix/Host.cpp
user: login: HemangGadhavi
body: This was extra check we added, but now we removed and changed the design
created_at: 2025-04-10T11:41:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
+
+  ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
+  if (len > 0) {
+    ExePath.resize(len);
+
+    struct stat statData;
+
+    std::ostringstream oss;
+
+    oss << "/proc/" << std::dec << pid << "/psinfo";
+    assert(stat(oss.str().c_str(), &statData) == 0);
+
+    const int fd = open(oss.str().c_str(), O_RDONLY);
+    assert(fd >= 0);
+
+    ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData));
+    assert(readNum >= 0);
+
+    close(fd);
path: lldb/source/Host/aix/Host.cpp
user: login: HemangGadhavi
body: Yes, We changed it and used the `getProcFile`. Please check once.
created_at: 2025-04-10T11:43:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -141,6 +141,7 @@ else()
     add_host_subdirectory(aix
       aix/Host.cpp
       aix/HostInfoAIX.cpp
+      linux/Support.cpp
path: lldb/source/Host/CMakeLists.txt
user: login: HemangGadhavi
body: @labath This is a great suggestion. Thanks for suggestion.
we will create the new PR for the same and create the common Support.cpp under `posix` .

created_at: 2025-04-10T11:47:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -141,6 +141,7 @@ else()
     add_host_subdirectory(aix
       aix/Host.cpp
       aix/HostInfoAIX.cpp
+      linux/Support.cpp
path: lldb/source/Host/CMakeLists.txt
user: login: labath
body: This PR is small enough, so I think you can just do it here. At least it will have context for why you're doing this.
created_at: 2025-04-10T12:52:55Z
author_association: COLLABORATOR
diff_hunk: @@ -141,6 +141,7 @@ else()
     add_host_subdirectory(aix
       aix/Host.cpp
       aix/HostInfoAIX.cpp
+      linux/Support.cpp
path: lldb/source/Host/CMakeLists.txt
user: login: HemangGadhavi
body: Hey @labath 
Made the changes as per the discussion, I have added the common `posix/Support.cpp` for unix-like system,  And kept as it as for three-arg overload linux specific and changed wherever it requires for getProcFile()
Please review once and give your comments. 
Thanks

created_at: 2025-04-14T13:07:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,21 +7,24 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "llvm/Support/Threading.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
 
 TEST(Support, getProcFile_Pid) {
-  auto BufferOrError = getProcFile(getpid(), "maps");
+  auto BufferOrError = getProcFile(getpid(), "status");
path: lldb/unittests/Host/posix/SupportTest.cpp
user: login: HemangGadhavi
body: I have changed from `maps` to `status` to test `getProcFile()`, because `/proc/pid/status` is there in all the Linux, AIX and Android.
and here its only testing the `getProcFile()` functions so it will not impact any other things. 
created_at: 2025-04-14T13:19:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,17 +7,135 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/Host.h"
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include <sys/proc.h>
+#include <sys/procfs.h>
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {
+  ProcessInstanceInfo::timespec ts;
+  ts.tv_sec = t.tv_sec;
+  ts.tv_usec = t.tv_nsec / 1000; // nanos to micros
+  return ts;
+}
+
+static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo,
+                          ProcessState &State) {
+  struct pstatus pstatusData;
+  auto BufferOrError = getProcFile(pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  std::unique_ptr<llvm::MemoryBuffer> StatusBuffer = std::move(*BufferOrError);
+  // Ensure there's enough data for psinfoData
+  if (StatusBuffer->getBufferSize() < sizeof(pstatusData))
+    return false;
+
+  std::memcpy(&pstatusData, StatusBuffer->getBufferStart(),
+              sizeof(pstatusData));
+  switch (pstatusData.pr_stat) {
+  case SIDL:
+    State = ProcessState::Idle;
+    break;
+  case SACTIVE:
+    State = ProcessState::Running;
+    break;
+  case SSTOP:
+    State = ProcessState::TracedOrStopped;
+    break;
+  case SZOMB:
+    State = ProcessState::Zombie;
+    break;
+  default:
+    State = ProcessState::Unknown;
+    break;
+  }
+  processInfo.SetIsZombie(State == ProcessState::Zombie);
+  processInfo.SetUserTime(convert(pstatusData.pr_utime));
+  processInfo.SetSystemTime(convert(pstatusData.pr_stime));
+  processInfo.SetCumulativeUserTime(convert(pstatusData.pr_cutime));
+  processInfo.SetCumulativeSystemTime(convert(pstatusData.pr_cstime));
+  return true;
+}
+
+static bool GetExePathAndIds(::pid_t pid, ProcessInstanceInfo &process_info) {
+  struct psinfo psinfoData;
+  auto BufferOrError = getProcFile(pid, "psinfo");
+  if (!BufferOrError)
+    return false;
+
+  std::unique_ptr<llvm::MemoryBuffer> PsinfoBuffer = std::move(*BufferOrError);
+  // Ensure there's enough data for psinfoData
+  if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData))
+    return false;
+
+  std::memcpy(&psinfoData, PsinfoBuffer->getBufferStart(), sizeof(psinfoData));
+  llvm::StringRef PathRef(&(psinfoData.pr_psargs[0]));
path: lldb/source/Host/aix/Host.cpp
user: login: labath
body: Is this guaranteed to be null-terminated (at least on linux, these kinds of fields do not get null-terminated when they're truncated). If it isn't, you may want to do something like `StringRef(psinfoData.pr_psargs, strnlen(psinfoData.pr_psargs, sizeof(psinfoData.pr_psargs))`
created_at: 2025-04-22T08:36:13Z
author_association: COLLABORATOR
diff_hunk: @@ -15,10 +15,10 @@ set (FILES
   XMLTest.cpp
 )
 
-if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
+if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android|AIX")
path: lldb/unittests/Host/CMakeLists.txt
user: login: labath
body: ```suggestion
if (UNIX)
```

If individual tests fail on some systems. We can disable them there.
created_at: 2025-04-22T08:41:22Z
author_association: COLLABORATOR
diff_hunk: @@ -40,8 +40,9 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
+#ifndef _AIX
path: lldb/unittests/Host/posix/HostTest.cpp
user: login: labath
body: Why is that? Does process zero exist on AIX?
created_at: 2025-04-22T08:41:39Z
author_association: COLLABORATOR
diff_hunk: @@ -7,21 +7,24 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "llvm/Support/Threading.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
 
 TEST(Support, getProcFile_Pid) {
-  auto BufferOrError = getProcFile(getpid(), "maps");
+  auto BufferOrError = getProcFile(getpid(), "status");
   ASSERT_TRUE(BufferOrError);
   ASSERT_TRUE(*BufferOrError);
 }
 
+#ifndef _AIX
 #ifdef LLVM_ENABLE_THREADING
 TEST(Support, getProcFile_Tid) {
   auto BufferOrError = getProcFile(getpid(), llvm::get_threadid(), "comm");
   ASSERT_TRUE(BufferOrError);
   ASSERT_TRUE(*BufferOrError);
 }
 #endif /*ifdef LLVM_ENABLE_THREADING */
+#endif /*ifndef _AIX */
path: lldb/unittests/Host/posix/SupportTest.cpp
user: login: labath
body: Let's move this into lldb/unittests/Process/Linux/ProcfsTests.cpp since the function it's testing is also linux-specific.
created_at: 2025-04-22T08:48:19Z
author_association: COLLABORATOR
diff_hunk: @@ -7,21 +7,24 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "llvm/Support/Threading.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
 
 TEST(Support, getProcFile_Pid) {
path: lldb/unittests/Host/posix/SupportTest.cpp
user: login: labath
body: And then make this `#ifndef __APPLE__`, as that's the only OS which definitely doesn't have proc. It looks like the BSD should mostly have them. If it turns out to be  a problem, we opt them out as well.
created_at: 2025-04-22T08:54:45Z
author_association: COLLABORATOR
diff_hunk: @@ -40,8 +40,9 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
+#ifndef _AIX
path: lldb/unittests/Host/posix/HostTest.cpp
user: login: HemangGadhavi
body: Yes process zero exist on AIX. That is the reason disabled for AIX
created_at: 2025-04-22T09:22:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,8 +40,9 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
+#ifndef _AIX
path: lldb/unittests/Host/posix/HostTest.cpp
user: login: labath
body: I see... Well, that could be a bit tricky (not just for this test, but in general), because lldb defines `LLDB_INVALID_PROCESS_ID` to be zero.

What can you tell me about this process? Is it some system/kernel process that runs before `init`? Can it even be debugged/attached to?
created_at: 2025-04-22T09:32:50Z
author_association: COLLABORATOR
diff_hunk: @@ -40,8 +40,9 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
+#ifndef _AIX
path: lldb/unittests/Host/posix/HostTest.cpp
user: login: HemangGadhavi
body: This process is basically for swapper/scheduling work. And yes its kernel process which is start after `init` only.
But that is sure we can not debugged/attached that process. 
created_at: 2025-04-22T09:49:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,8 +40,9 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
+#ifndef _AIX
path: lldb/unittests/Host/posix/HostTest.cpp
user: login: labath
body: In that case, what would say to filtering this process out inside the AIX implementation? (basically add something like `if (pid == 0) return false;`)

In theory, I suppose that someone may want to get the process information of the process zero, but i doubt it's an important use case since we normally call this while attaching to a process. And it would ensure that `GetProcessInfo(LLDB_INVALID_PROCESS_ID)` behaves the same way everywhere (we could also change this test to use the LLDB_INVALID_PROCESS_ID macro to make it clear that it's checking for an "invalid" process).
created_at: 2025-04-22T10:31:54Z
author_association: COLLABORATOR
diff_hunk: @@ -40,8 +40,9 @@ TEST_F(HostTest, GetProcessInfo) {
        triple.getEnvironment() == llvm::Triple::EnvironmentType::Android));
 
   ProcessInstanceInfo Info;
+#ifndef _AIX
path: lldb/unittests/Host/posix/HostTest.cpp
user: login: HemangGadhavi
body: Make sense. 
Thanks for the suggestion let me make the changes. 
created_at: 2025-04-22T10:43:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,17 +7,135 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/Host.h"
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include <sys/proc.h>
+#include <sys/procfs.h>
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {
+  ProcessInstanceInfo::timespec ts;
+  ts.tv_sec = t.tv_sec;
+  ts.tv_usec = t.tv_nsec / 1000; // nanos to micros
+  return ts;
+}
+
+static bool GetStatusInfo(::pid_t pid, ProcessInstanceInfo &processInfo,
+                          ProcessState &State) {
+  struct pstatus pstatusData;
+  auto BufferOrError = getProcFile(pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  std::unique_ptr<llvm::MemoryBuffer> StatusBuffer = std::move(*BufferOrError);
+  // Ensure there's enough data for psinfoData
+  if (StatusBuffer->getBufferSize() < sizeof(pstatusData))
+    return false;
+
+  std::memcpy(&pstatusData, StatusBuffer->getBufferStart(),
+              sizeof(pstatusData));
+  switch (pstatusData.pr_stat) {
+  case SIDL:
+    State = ProcessState::Idle;
+    break;
+  case SACTIVE:
+    State = ProcessState::Running;
+    break;
+  case SSTOP:
+    State = ProcessState::TracedOrStopped;
+    break;
+  case SZOMB:
+    State = ProcessState::Zombie;
+    break;
+  default:
+    State = ProcessState::Unknown;
+    break;
+  }
+  processInfo.SetIsZombie(State == ProcessState::Zombie);
+  processInfo.SetUserTime(convert(pstatusData.pr_utime));
+  processInfo.SetSystemTime(convert(pstatusData.pr_stime));
+  processInfo.SetCumulativeUserTime(convert(pstatusData.pr_cutime));
+  processInfo.SetCumulativeSystemTime(convert(pstatusData.pr_cstime));
+  return true;
+}
+
+static bool GetExePathAndIds(::pid_t pid, ProcessInstanceInfo &process_info) {
+  struct psinfo psinfoData;
+  auto BufferOrError = getProcFile(pid, "psinfo");
+  if (!BufferOrError)
+    return false;
+
+  std::unique_ptr<llvm::MemoryBuffer> PsinfoBuffer = std::move(*BufferOrError);
+  // Ensure there's enough data for psinfoData
+  if (PsinfoBuffer->getBufferSize() < sizeof(psinfoData))
+    return false;
+
+  std::memcpy(&psinfoData, PsinfoBuffer->getBufferStart(), sizeof(psinfoData));
+  llvm::StringRef PathRef(&(psinfoData.pr_psargs[0]));
path: lldb/source/Host/aix/Host.cpp
user: login: HemangGadhavi
body: Yes it is always NULL-terminated, But this is more safest way. 
Addressed.
created_at: 2025-04-23T06:05:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,21 +7,24 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/linux/Support.h"
+#include "lldb/Host/posix/Support.h"
 #include "llvm/Support/Threading.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
 
 TEST(Support, getProcFile_Pid) {
-  auto BufferOrError = getProcFile(getpid(), "maps");
+  auto BufferOrError = getProcFile(getpid(), "status");
   ASSERT_TRUE(BufferOrError);
   ASSERT_TRUE(*BufferOrError);
 }
 
+#ifndef _AIX
 #ifdef LLVM_ENABLE_THREADING
 TEST(Support, getProcFile_Tid) {
   auto BufferOrError = getProcFile(getpid(), llvm::get_threadid(), "comm");
   ASSERT_TRUE(BufferOrError);
   ASSERT_TRUE(*BufferOrError);
 }
 #endif /*ifdef LLVM_ENABLE_THREADING */
+#endif /*ifndef _AIX */
path: lldb/unittests/Host/posix/SupportTest.cpp
user: login: HemangGadhavi
body: Moved.
created_at: 2025-04-23T06:05:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,26 @@
+//===-- Support.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_POSIX_SUPPORT_H
+#define LLDB_HOST_POSIX_SUPPORT_H
+
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
path: lldb/include/lldb/Host/posix/Support.h
user: login: labath
body: ```suggestion
#include "llvm/ADT/Twine.h"
#include <memory>
```
created_at: 2025-04-23T10:57:27Z
author_association: COLLABORATOR
diff_hunk: @@ -7,17 +7,139 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/Host.h"
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include <sys/proc.h>
+#include <sys/procfs.h>
 
+using namespace llvm;
path: lldb/source/Host/aix/Host.cpp
user: login: labath
body: I'd recommend not getting into the habit of including the whole llvm namespace. It may be fine if you have code that's heavily using some llvm objects, but in general I think it's more trouble than it's worth -- `llvm` is a big namespace and it includes names (e.g. `Module`) which conflict with lldb entities.

I don't think that's the case here, but if you find yourself using a particular function/class very often, then I it'd be better to just include that single class.
created_at: 2025-04-23T11:01:46Z
author_association: COLLABORATOR
diff_hunk: @@ -7,17 +7,139 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/Host.h"
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include <sys/proc.h>
+#include <sys/procfs.h>
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {
path: lldb/source/Host/aix/Host.cpp
user: login: labath
body: ```suggestion
static ProcessInstanceInfo::timespec convert(pr_timestruc64_t t) {
```
created_at: 2025-04-23T11:02:09Z
author_association: COLLABORATOR
diff_hunk: @@ -7,17 +7,139 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/Host.h"
+#include "lldb/Host/posix/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include <sys/proc.h>
+#include <sys/procfs.h>
 
+using namespace llvm;
path: lldb/source/Host/aix/Host.cpp
user: login: HemangGadhavi
body: Modified 
created_at: 2025-04-23T12:07:27Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-04T07:50:46Z
body: <!--LLVM NEW CONTRIBUTOR COMMENT-->

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using `@` followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the [LLVM GitHub User Guide](https://llvm.org/docs/GitHub.html).

You can also ask questions in a comment on this PR, on the [LLVM Discord](https://discord.com/invite/xS7Z362) or on the [forums](https://discourse.llvm.org/).
author_association: NONE
user: login: llvmbot
created_at: 2025-04-04T07:51:20Z
body: 
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Hemang Gadhavi (HemangGadhavi)

<details>
<summary>Changes</summary>

This PR is in reference to porting LLDB on AIX.

Link to discussions on llvm discourse and github:

1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640
2. https://github.com/llvm/llvm-project/issues/101657
The complete changes for porting are present in this draft PR:
https://github.com/llvm/llvm-project/pull/102601

Added changes to get the host information for AIX. (GetProcessInfo()) 
(Information like : executable path, arch, process status etc.)
[@<!-- -->DavidSpickett](https://github.com/DavidSpickett) [@<!-- -->labath](https://github.com/labath) [@<!-- -->DhruvSrivastavaX](https://github.com/DhruvSrivastavaX)

---
Full diff: https://github.com/llvm/llvm-project/pull/134354.diff


2 Files Affected:

- (modified) lldb/source/Host/CMakeLists.txt (+1) 
- (modified) lldb/source/Host/aix/Host.cpp (+155-1) 


``````````diff
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index a2ae6f1430c38..a02b1c104396e 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -141,6 +141,7 @@ else()
     add_host_subdirectory(aix
       aix/Host.cpp
       aix/HostInfoAIX.cpp
+      linux/Support.cpp
       )
   endif()
 endif()
diff --git a/lldb/source/Host/aix/Host.cpp b/lldb/source/Host/aix/Host.cpp
index 751c4fbcc9368..6ba3e05348df1 100644
--- a/lldb/source/Host/aix/Host.cpp
+++ b/lldb/source/Host/aix/Host.cpp
@@ -6,18 +6,172 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <fcntl.h>
+#include <sstream>
+#include <sys/procfs.h>
+
 #include "lldb/Host/Host.h"
+#include "lldb/Host/linux/Support.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 
+using namespace llvm;
+using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+enum class ProcessState {
+  Unknown,
+  Dead,
+  DiskSleep,
+  Idle,
+  Paging,
+  Parked,
+  Running,
+  Sleeping,
+  TracedOrStopped,
+  Zombie,
+};
+}
+
+static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo,
+                          ProcessState &State, ::pid_t &TracerPid,
+                          ::pid_t &Tgid) {
+  Log *log = GetLog(LLDBLog::Host);
+
+  auto BufferOrError = getProcFile(Pid, "status");
+  if (!BufferOrError)
+    return false;
+
+  llvm::StringRef Rest = BufferOrError.get()->getBuffer();
+  while (!Rest.empty()) {
+    llvm::StringRef Line;
+    std::tie(Line, Rest) = Rest.split('\n');
+
+    if (Line.consume_front("Gid:")) {
+      // Real, effective, saved set, and file system GIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RGid, EGid;
+      Line.consumeInteger(10, RGid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EGid);
+
+      ProcessInfo.SetGroupID(RGid);
+      ProcessInfo.SetEffectiveGroupID(EGid);
+    } else if (Line.consume_front("Uid:")) {
+      // Real, effective, saved set, and file system UIDs. Read the first two.
+      Line = Line.ltrim();
+      uint32_t RUid, EUid;
+      Line.consumeInteger(10, RUid);
+      Line = Line.ltrim();
+      Line.consumeInteger(10, EUid);
+
+      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);
+    } else if (Line.consume_front("Tgid:")) {
+      Line = Line.ltrim();
+      Line.consumeInteger(10, Tgid);
+    }
+  }
+  return true;
+}
+
+static void GetExePathAndArch(::pid_t pid, ProcessInstanceInfo &process_info) {
+  Log *log = GetLog(LLDBLog::Process);
+  std::string ExePath(PATH_MAX, '\0');
+  struct psinfo psinfoData;
+
+  // We can't use getProcFile here because proc/[pid]/exe is a symbolic link.
+  llvm::SmallString<64> ProcExe;
+  (llvm::Twine("/proc/") + llvm::Twine(pid) + "/cwd").toVector(ProcExe);
+
+  ssize_t len = readlink(ProcExe.c_str(), &ExePath[0], PATH_MAX);
+  if (len > 0) {
+    ExePath.resize(len);
+
+    struct stat statData;
+
+    std::ostringstream oss;
+
+    oss << "/proc/" << std::dec << pid << "/psinfo";
+    assert(stat(oss.str().c_str(), &statData) == 0);
+
+    const int fd = open(oss.str().c_str(), O_RDONLY);
+    assert(fd >= 0);
+
+    ssize_t readNum = read(fd, &psinfoData, sizeof(psinfoData));
+    assert(readNum >= 0);
+
+    close(fd);
+  } else {
+    LLDB_LOG(log, "failed to read link exe link for {0}: {1}", pid,
+             Status(errno, eErrorTypePOSIX));
+    ExePath.resize(0);
+  }
+
+  llvm::StringRef PathRef(&(psinfoData.pr_psargs[0]));
+
+  if (!PathRef.empty()) {
+    process_info.GetExecutableFile().SetFile(PathRef, FileSpec::Style::native);
+    ArchSpec arch_spec = ArchSpec();
+    arch_spec.SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64,
+                              LLDB_INVALID_CPUTYPE, llvm::Triple::AIX);
+    process_info.SetArchitecture(arch_spec);
+  }
+}
+
+static bool GetProcessAndStatInfo(::pid_t pid,
+                                  ProcessInstanceInfo &process_info,
+                                  ProcessState &State, ::pid_t &tracerpid) {
+  ::pid_t tgid;
+  tracerpid = 0;
+  process_info.Clear();
+
+  process_info.SetProcessID(pid);
+
+  GetExePathAndArch(pid, process_info);
+
+  // Get User and Group IDs and get tracer pid.
+  if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid))
+    return false;
+
+  return true;
+}
+
 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
                                  ProcessInstanceInfoList &process_infos) {
   return 0;
 }
 
 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
-  return false;
+  ::pid_t tracerpid;
+  ProcessState State;
+  return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
 }
 
 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {

``````````

</details>

author_association: MEMBER
user: login: DhruvSrivastavaX
created_at: 2025-04-04T07:58:31Z
body: Hi Team, 

@HemangGadhavi from our ibm aix team will be helping me out in some of the merging process, as per our decided guidelines. Please provide your review.

Thanks!
Dhruv Srivastava
author_association: MEMBER
user: login: github-actions[bot]
created_at: 2025-04-10T11:51:26Z
body: <!--LLVM CODE FORMAT COMMENT: {clang-format}-->

:white_check_mark: With the latest revision this PR passed the C/C++ code formatter.
author_association: NONE
user: login: HemangGadhavi
created_at: 2025-04-10T11:52:50Z
body: > We have a tests for this function in `unittests/Host/linux/HostTest.cpp` and it looks like at least some of it should apply to other systems as well. We could move it to the "posix" folder so that it applies to your code as well. Depending on the size of linux-specific parts, we could either keep them in the "linux" folder, or `#ifdef` them out

Okay, we will create new PR to either move it to posix or we can create `HostTest.cpp` for aix separately.  
@labath or you want me to drop the testcase changes in same PR ?
author_association: CONTRIBUTOR
user: login: DhruvSrivastavaX
created_at: 2025-04-10T11:53:33Z
body: Please re-run clang-format on the changes.
author_association: MEMBER
user: login: labath
created_at: 2025-04-10T12:54:19Z
body: > > We have a tests for this function in `unittests/Host/linux/HostTest.cpp` and it looks like at least some of it should apply to other systems as well. We could move it to the "posix" folder so that it applies to your code as well. Depending on the size of linux-specific parts, we could either keep them in the "linux" folder, or `#ifdef` them out
> 
> Okay, we will create new PR to either move it to posix or we can create `HostTest.cpp` for aix separately. @labath or you want me to drop the testcase changes in same PR ?

Let's do that here. The PR is small (as it should be) and it's good to have tests together with the code being tested.
author_association: COLLABORATOR
user: login: HemangGadhavi
created_at: 2025-04-14T13:13:49Z
body: > > > We have a tests for this function in `unittests/Host/linux/HostTest.cpp` and it looks like at least some of it should apply to other systems as well. We could move it to the "posix" folder so that it applies to your code as well. Depending on the size of linux-specific parts, we could either keep them in the "linux" folder, or `#ifdef` them out
> > 
> > 
> > Okay, we will create new PR to either move it to posix or we can create `HostTest.cpp` for aix separately. @labath or you want me to drop the testcase changes in same PR ?
> 
> Let's do that here. The PR is small (as it should be) and it's good to have tests together with the code being tested.

Hi @labath 
I moved the `unittests/Host/linux/HostTest.cpp` &  `SupportTest.cpp` under the `unittests/Host/posix/`, so that unix-like system can used it. 
Also I have `#ifdef` out some of the tests, which are not applicable for AIX and tested on Linux/AIX all testcases are passed .
Please review it and give you comments.
Thanks

author_association: CONTRIBUTOR
user: login: HemangGadhavi
created_at: 2025-04-23T06:11:42Z
body: @labath Addressed all your comments, Please have a look once and give your comments if any.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-29T05:53:22Z
body: <!--LLVM BUILDBOT INFORMATION COMMENT-->

@HemangGadhavi Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr).

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

author_association: NONE
user: login: felipepiovezan
created_at: 2025-04-29T14:26:56Z
body: Hi, this test is _still_ failing on the macOS bots: https://ci.swift.org/view/all/job/llvm.org/job/lldb-cmake/11728/execution/node/111/log/

```
/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/unittests/Host/./HostTests --gtest_filter=HostTest.GetProcessInfo
--
/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/llvm-project/lldb/unittests/Host/posix/HostTest.cpp:72: Failure
Expected equality of these values:
  HostInfo::GetArchitecture(HostInfo::eArchKindDefault)
    Which is: 64-byte object <28-78 38-36 5F-36 34-68 2D-61 70-70 6C-65 2D-6D 61-63 6F-73 78-00 00-00 26-00 00-00 00-00 00-00 01-00 00-00 09-00 00-00 00-00 00-00 05-00 00-00 51-00 00-00 04-00 00-00 00-00 00-00 00-00 00-00>
  Info.GetArchitecture()
    Which is: 64-byte object <26-78 38-36 5F-36 34-2D 61-70 70-6C 65-2D 6D-61 63-6F 73-78 00-00 00-00 26-00 00-00 00-00 00-00 01-00 00-00 09-00 00-00 00-00 00-00 05-00 00-00 50-00 00-00 04-00 00-00 00-00 00-00 F8-7F 00-00>


/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/llvm-project/lldb/unittests/Host/posix/HostTest.cpp:72
Expected equality of these values:
  HostInfo::GetArchitecture(HostInfo::eArchKindDefault)
    Which is: 64-byte object <28-78 38-36 5F-36 34-68 2D-61 70-70 6C-65 2D-6D 61-63 6F-73 78-00 00-00 26-00 00-00 00-00 00-00 01-00 00-00 09-00 00-00 00-00 00-00 05-00 00-00 51-00 00-00 04-00 00-00 00-00 00-00 00-00 00-00>
  Info.GetArchitecture()
    Which is: 64-byte object <26-78 38-36 5F-36 34-2D 61-70 70-6C 65-2D 6D-61 63-6F 73-78 00-00 00-00 26-00 00-00 00-00 00-00 01-00 00-00 09-00 00-00 00-00 00-00 05-00 00-00 50-00 00-00 04-00 00-00 00-00 00-00 F8-7F 00-00>
```
author_association: CONTRIBUTOR
user: login: felipepiovezan
created_at: 2025-04-29T14:27:16Z
body: Could you please disable/revert if the fix is not easy?
author_association: CONTRIBUTOR
user: login: HemangGadhavi
created_at: 2025-04-30T06:16:59Z
body: > Could you please disable/revert if the fix is not easy?

@felipepiovezan Done through the commit ID cf7301aeb808a13fe882a4b0bf7f1bfe4051c301 by labath 
author_association: CONTRIBUTOR