[Lldb-commits] [lldb] [lldb][AIX] Implement read/write handling for GPR and SPR registers (PR #193205)

Hemang Gadhavi via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 24 03:40:46 PDT 2026


https://github.com/HemangGadhavi updated https://github.com/llvm/llvm-project/pull/193205

>From 4f2de03941db5c3d12cd95c880a2c1b1d7de56bd Mon Sep 17 00:00:00 2001
From: HemangGadhavi <hemang.gadhavi at ibm.com>
Date: Tue, 21 Apr 2026 06:35:38 -0500
Subject: [PATCH 1/3] [lldb][AIX] Implement read/write handling for GPR and SPR
 registers

---
 .../Plugins/Process/AIX/NativeProcessAIX.cpp  | 83 ++++++++++++++++++-
 .../Process/AIX/NativeRegisterContextAIX.cpp  | 20 ++++-
 .../Process/AIX/NativeRegisterContextAIX.h    | 16 +++-
 .../AIX/NativeRegisterContextAIX_ppc64.cpp    | 77 ++++++++++++++++-
 .../AIX/NativeRegisterContextAIX_ppc64.h      | 19 +++++
 .../Plugins/Process/AIX/NativeThreadAIX.cpp   |  5 +-
 .../Plugins/Process/AIX/NativeThreadAIX.h     |  2 +
 .../Utility/RegisterInfoPOSIX_ppc64.cpp       | 21 ++++-
 .../Process/Utility/RegisterInfoPOSIX_ppc64.h |  1 +
 .../Process/Utility/RegisterInfos_ppc64.h     | 52 ++++++++++++
 10 files changed, 285 insertions(+), 11 deletions(-)

diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
index af54b043cc44c..24f91704272b8 100644
--- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
@@ -22,10 +22,14 @@
 #include <cerrno>
 #include <cstdint>
 #include <cstring>
+#include <dirent.h>
 #include <sstream>
 #include <string>
 #include <sys/ptrace.h>
 #include <unistd.h>
+#define DECLARE_REGISTER_INFOS_PPC64_STRUCT
+#include "Plugins/Process/Utility/RegisterInfos_ppc64.h"
+#undef DECLARE_REGISTER_INFOS_PPC64_STRUCT
 
 using namespace lldb;
 using namespace lldb_private;
@@ -279,13 +283,90 @@ llvm::Error NativeProcessAIX::Detach(lldb::tid_t tid) {
   return PtraceWrapper(PT_DETACH, tid).takeError();
 }
 
+template <typename GPR_T, typename PTSPRS_T>
+llvm::Expected<int> GetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
+  PTSPRS_T sprs;
+
+  int ret = ptrace64(req, tid, (long long)&sprs, 0, 0);
+
+  if (ret != -1) {
+    gpr->cr = sprs.pt_cr;
+    gpr->msr = sprs.pt_msr;
+    gpr->xer = sprs.pt_xer;
+    gpr->lr = sprs.pt_lr;
+    gpr->ctr = sprs.pt_ctr;
+    gpr->pc = sprs.pt_iar;
+  }
+  return ret;
+}
+
+template <typename GPR_T, typename PTSPRS_T>
+llvm::Expected<int> SetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
+  PTSPRS_T sprs;
+
+  sprs.pt_cr = gpr->cr;
+  sprs.pt_msr = gpr->msr;
+  sprs.pt_xer = gpr->xer;
+  sprs.pt_lr = gpr->lr;
+  sprs.pt_ctr = gpr->ctr;
+  sprs.pt_iar = gpr->pc;
+
+  return (ptrace64(req, tid, (long long)&sprs, 0, 0));
+}
+
 llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
                                                     void *addr, void *data,
                                                     size_t data_size) {
   int ret;
-
   Log *log = GetLog(POSIXLog::Ptrace);
+  // for PTT_*
+  const char procdir[] = "/proc/";
+  const char lwpdir[] = "/lwp/";
+  std::string process_task_dir = procdir + std::to_string(pid) + lwpdir;
+  DIR *dirproc = opendir(process_task_dir.c_str());
+
+  lldb::tid_t tid = 0;
+  if (dirproc) {
+    struct dirent *direntry = nullptr;
+    while ((direntry = readdir(dirproc)) != nullptr) {
+      if (strcmp(direntry->d_name, ".") == 0 ||
+          strcmp(direntry->d_name, "..") == 0) {
+        continue;
+      }
+      tid = atoi(direntry->d_name);
+      break;
+    }
+    closedir(dirproc);
+  }
+
   switch (req) {
+  case PTT_READ_GPRS:
+    if (data_size == sizeof(GPR_PPC)) // 32bit SPRs read
+      ret = GetSPRs<GPR_PPC, ptsprs>(PTT_READ_SPRS, tid,
+                                     static_cast<GPR_PPC *>(data))
+                .get();
+    else if (data_size == sizeof(GPR_PPC64)) // 64bit SPRs read
+      ret = GetSPRs<GPR_PPC64, ptxsprs>(PTT_READ_SPRS, tid,
+                                        static_cast<GPR_PPC64 *>(data))
+                .get();
+
+    if (ret != -1)
+      ret = ptrace64(req, tid, (long long)data, 0, 0); // read GPRs
+    break;
+
+  case PTT_WRITE_GPRS:
+    if (data_size == sizeof(GPR_PPC)) // 32bit SPRs write
+      ret = SetSPRs<GPR_PPC, ptsprs>(PTT_WRITE_SPRS, tid,
+                                     static_cast<GPR_PPC *>(data))
+                .get();
+    else if (data_size == sizeof(GPR_PPC64)) // 64bit SPRS write
+      ret = SetSPRs<GPR_PPC64, ptxsprs>(PTT_WRITE_SPRS, tid,
+                                        static_cast<GPR_PPC64 *>(data))
+                .get();
+
+    if (ret != -1)
+      ret = ptrace64(req, tid, (long long)data, 0, 0); // write GPRs
+    break;
   case PT_ATTACH:
   case PT_DETACH:
   case PT_KILL:
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
index e44cd7b5a30f5..7c3f538e93b11 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
@@ -27,9 +27,25 @@ NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index,
   return Status("unimplemented");
 }
 
-Status NativeRegisterContextAIX::ReadGPR() { return Status("unimplemented"); }
+Status NativeRegisterContextAIX::ReadGPR() {
+  auto result = NativeProcessAIX::PtraceWrapper(
+      PTT_READ_GPRS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize());
 
-Status NativeRegisterContextAIX::WriteGPR() { return Status("unimplemented"); }
+  if (!result)
+    return Status::FromError(result.takeError());
+
+  return Status();
+}
+
+Status NativeRegisterContextAIX::WriteGPR() {
+  auto result = NativeProcessAIX::PtraceWrapper(
+      PTT_WRITE_GPRS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize());
+
+  if (!result)
+    return Status::FromError(result.takeError());
+
+  return Status();
+}
 
 Status NativeRegisterContextAIX::ReadFPR() { return Status("unimplemented"); }
 
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
index e78483a7670f6..5f80c9d90fed4 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
@@ -13,8 +13,20 @@
 
 namespace lldb_private::process_aix {
 
+class NativeThreadAIX;
+
 class NativeRegisterContextAIX
     : public virtual NativeRegisterContextRegisterInfo {
+public:
+  // This function is implemented in the NativeRegisterContextAIX_ppc64
+  // subclasses to create a new instance of the host specific
+  // NativeRegisterContextAIX. The implementations can't collide as only one
+  // NativeRegisterContextAIX_ppc64 variant should be compiled into the final
+  // executable.
+  static std::unique_ptr<NativeRegisterContextAIX>
+  CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch,
+                                     NativeThreadAIX &native_thread);
+
 protected:
   NativeRegisterContextAIX(NativeThreadProtocol &thread)
       : NativeRegisterContextRegisterInfo(thread, nullptr) {}
@@ -50,7 +62,9 @@ class NativeRegisterContextAIX
 
   virtual void *GetGPRBuffer() = 0;
 
-  virtual size_t GetGPRSize() = 0;
+  virtual size_t GetGPRSize() const {
+    return GetRegisterInfoInterface().GetGPRSize();
+  }
 
   virtual void *GetFPRBuffer() = 0;
 
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
index aba785753055c..2096641dd272e 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
@@ -9,6 +9,9 @@
 #if defined(__powerpc64__)
 
 #include "NativeRegisterContextAIX_ppc64.h"
+#include "NativeThreadAIX.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.h"
+#include "lldb/Utility/RegisterValue.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -87,11 +90,34 @@ static const RegisterSet g_reg_sets_ppc64[k_num_register_sets] = {
     {"VSX Registers", "vsx", k_num_vsx_registers_ppc64, g_vsx_regnums_ppc64},
 };
 
+std::unique_ptr<NativeRegisterContextAIX>
+NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX(
+    const ArchSpec &target_arch, NativeThreadAIX &native_thread) {
+  switch (target_arch.GetMachine()) {
+  case llvm::Triple::ppc:
+  case llvm::Triple::ppc64:
+    return std::make_unique<NativeRegisterContextAIX_ppc64>(target_arch,
+                                                            native_thread);
+  default:
+    llvm_unreachable("have no register context for architecture");
+  }
+}
+
 NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64(
     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
-    : NativeRegisterContextAIX(native_thread) {
-  if (target_arch.GetMachine() != llvm::Triple::ppc64)
+    : NativeRegisterContextRegisterInfo(
+          native_thread, new RegisterInfoPOSIX_ppc64(target_arch)),
+      NativeRegisterContextAIX(native_thread) {
+  switch (target_arch.GetMachine()) {
+  case llvm::Triple::ppc:
+    m_gpr = &m_gpr_storage.gpr32;
+    break;
+  case llvm::Triple::ppc64:
+    m_gpr = &m_gpr_storage.gpr64;
+    break;
+  default:
     llvm_unreachable("Unhandled target architecture.");
+  }
 }
 
 uint32_t NativeRegisterContextAIX_ppc64::GetRegisterSetCount() const {
@@ -116,13 +142,56 @@ uint32_t NativeRegisterContextAIX_ppc64::GetUserRegisterCount() const {
 Status
 NativeRegisterContextAIX_ppc64::ReadRegister(const RegisterInfo *reg_info,
                                              RegisterValue &reg_value) {
-  return Status("unimplemented");
+  Status error;
+  if (!reg_info)
+    return Status::FromErrorString("reg_info NULL");
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (IsGPR(reg)) {
+    error = ReadGPR();
+    if (error.Fail())
+      return error;
+
+    const uint8_t *src = reinterpret_cast<const uint8_t *>(GetGPRBuffer()) +
+                         reg_info->byte_offset;
+    reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
+                                eByteOrderBig, error);
+
+    return error;
+  } else if (IsFPR(reg) || IsVSX(reg) || IsVMX(reg)) {
+    return Status::FromErrorString("unimplemented");
+  }
+
+  return Status::FromErrorString("failed - register wasn't recognized to be a "
+                                 "GPR, FPR, VSX or VMX, read strategy unknown");
 }
 
 Status
 NativeRegisterContextAIX_ppc64::WriteRegister(const RegisterInfo *reg_info,
                                               const RegisterValue &reg_value) {
-  return Status("unimplemented");
+  Status error;
+  if (!reg_info)
+    return Status::FromErrorString("reg_info NULL");
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (IsGPR(reg)) {
+    error = ReadGPR();
+    if (error.Fail())
+      return error;
+
+    uint8_t *dst =
+        reinterpret_cast<uint8_t *>(GetGPRBuffer()) + reg_info->byte_offset;
+    ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
+
+    return (WriteGPR());
+  } else if (IsFPR(reg) || IsVMX(reg) || IsVSX(reg)) {
+    return Status::FromErrorString("unimplemented");
+  }
+
+  return Status::FromErrorString("failed - register wasn't recognized to be a "
+                                 "GPR, FPR, VSX or VMX, read strategy unknown");
 }
 
 Status NativeRegisterContextAIX_ppc64::ReadAllRegisterValues(
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
index 77f75777737d1..b86d9f887f4e5 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
@@ -14,6 +14,10 @@
 #include "Plugins/Process/AIX/NativeRegisterContextAIX.h"
 #include "Plugins/Process/Utility/lldb-ppc64-register-enums.h"
 
+#define DECLARE_REGISTER_INFOS_PPC64_STRUCT
+#include "Plugins/Process/Utility/RegisterInfos_ppc64.h"
+#undef DECLARE_REGISTER_INFOS_PPC64_STRUCT
+
 namespace lldb_private {
 namespace process_aix {
 
@@ -40,6 +44,13 @@ class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX {
 
   Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
 
+protected:
+  void *GetGPRBuffer() override { return m_gpr; }
+
+  void *GetFPRBuffer() override { return nullptr; }
+
+  size_t GetFPRSize() override { return 0; }
+
 private:
   bool IsGPR(unsigned reg) const;
 
@@ -54,6 +65,14 @@ class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX {
   uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const;
 
   uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const;
+
+  union GPRStorage {
+    GPR_PPC gpr32;   // 32-bit general purpose registers.
+    GPR_PPC64 gpr64; // 64-bit general purpose registers.
+  };
+
+  GPRStorage m_gpr_storage;
+  void *m_gpr = nullptr;
 };
 
 } // namespace process_aix
diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
index 3bb608168ce30..264106fe56d92 100644
--- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp
@@ -15,7 +15,10 @@ using namespace lldb_private;
 using namespace lldb_private::process_aix;
 
 NativeThreadAIX::NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid)
-    : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid) {}
+    : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+      m_reg_context_up(
+          NativeRegisterContextAIX::CreateHostNativeRegisterContextAIX(
+              process.GetArchitecture(), *this)) {}
 
 std::string NativeThreadAIX::GetName() { return ""; }
 
diff --git a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
index e32d3db2c5fa2..5c374b399c5c3 100644
--- a/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
+++ b/lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_
 #define LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVETHREADAIX_H_
 
+#include "Plugins/Process/AIX/NativeRegisterContextAIX.h"
 #include "lldb/Host/common/NativeThreadProtocol.h"
 
 namespace lldb_private::process_aix {
@@ -47,6 +48,7 @@ class NativeThreadAIX : public NativeThreadProtocol {
 
 private:
   lldb::StateType m_state;
+  std::unique_ptr<NativeRegisterContextAIX> m_reg_context_up;
 };
 } // namespace lldb_private::process_aix
 
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.cpp
index 1550f00bea28e..e4969d4b306b7 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.cpp
@@ -23,6 +23,8 @@
 static const lldb_private::RegisterInfo *
 GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
   switch (target_arch.GetMachine()) {
+  case llvm::Triple::ppc:
+    return g_register_infos_ppc;
   case llvm::Triple::ppc64:
     return g_register_infos_ppc64;
   default:
@@ -34,6 +36,9 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
 static uint32_t
 GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
   switch (target_arch.GetMachine()) {
+  case llvm::Triple::ppc:
+    return static_cast<uint32_t>(sizeof(g_register_infos_ppc) /
+                                 sizeof(g_register_infos_ppc[0]));
   case llvm::Triple::ppc64:
     return static_cast<uint32_t>(sizeof(g_register_infos_ppc64) /
                                  sizeof(g_register_infos_ppc64[0]));
@@ -47,9 +52,21 @@ RegisterInfoPOSIX_ppc64::RegisterInfoPOSIX_ppc64(
     const lldb_private::ArchSpec &target_arch)
     : lldb_private::RegisterInfoInterface(target_arch),
       m_register_info_p(GetRegisterInfoPtr(target_arch)),
-      m_register_info_count(GetRegisterInfoCount(target_arch)) {}
+      m_register_info_count(GetRegisterInfoCount(target_arch)), m_gpr_size(0) {
+  switch (target_arch.GetMachine()) {
+  case llvm::Triple::ppc:
+    m_gpr_size = sizeof(GPR_PPC);
+    break;
+  case llvm::Triple::ppc64:
+    m_gpr_size = sizeof(GPR_PPC64);
+    break;
+  default:
+    assert(false && "Unhandled target architecture.");
+    break;
+  }
+}
 
-size_t RegisterInfoPOSIX_ppc64::GetGPRSize() const { return sizeof(GPR_PPC64); }
+size_t RegisterInfoPOSIX_ppc64::GetGPRSize() const { return m_gpr_size; }
 
 const lldb_private::RegisterInfo *
 RegisterInfoPOSIX_ppc64::GetRegisterInfo() const {
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.h
index 177ff439828e8..e33d32ae98ad3 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64.h
@@ -26,6 +26,7 @@ class RegisterInfoPOSIX_ppc64 : public lldb_private::RegisterInfoInterface {
 private:
   const lldb_private::RegisterInfo *m_register_info_p;
   uint32_t m_register_info_count;
+  size_t m_gpr_size;
 };
 
 #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_PPC64_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h
index 5ea561fe22b42..ba0b6d45d95ba 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h
@@ -334,6 +334,48 @@ typedef struct _GPR_PPC64 {
   uint64_t pad[3];
 } GPR_PPC64;
 
+typedef struct _GPR_PPC {
+  uint32_t r0;
+  uint32_t r1;
+  uint32_t r2;
+  uint32_t r3;
+  uint32_t r4;
+  uint32_t r5;
+  uint32_t r6;
+  uint32_t r7;
+  uint32_t r8;
+  uint32_t r9;
+  uint32_t r10;
+  uint32_t r11;
+  uint32_t r12;
+  uint32_t r13;
+  uint32_t r14;
+  uint32_t r15;
+  uint32_t r16;
+  uint32_t r17;
+  uint32_t r18;
+  uint32_t r19;
+  uint32_t r20;
+  uint32_t r21;
+  uint32_t r22;
+  uint32_t r23;
+  uint32_t r24;
+  uint32_t r25;
+  uint32_t r26;
+  uint32_t r27;
+  uint32_t r28;
+  uint32_t r29;
+  uint32_t r30;
+  uint32_t r31;
+  uint32_t cr;
+  uint32_t msr;
+  uint32_t xer;
+  uint32_t lr;
+  uint32_t ctr;
+  uint32_t pc;
+  uint32_t pad[3];
+} GPR_PPC;
+
 typedef struct _FPR_PPC64 {
   uint64_t f0;
   uint64_t f1;
@@ -481,6 +523,16 @@ static_assert((sizeof(g_register_infos_ppc64) /
                sizeof(g_register_infos_ppc64[0])) == k_num_registers_ppc64,
               "g_register_infos_powerpc64 has wrong number of register infos");
 
+static lldb_private::RegisterInfo g_register_infos_ppc[] = {
+#define GPR_PPC64 GPR_PPC
+    PPC64_REGS
+#undef GPR_PPC64
+};
+
+static_assert((sizeof(g_register_infos_ppc) /
+               sizeof(g_register_infos_ppc[0])) == k_num_registers_ppc64,
+              "g_register_infos_powerpc has wrong number of register infos");
+
 #undef DEFINE_FPR_PPC64
 #undef DEFINE_GPR_PPC64
 #undef DEFINE_VMX_PPC64

>From 328f75ec3d250e7712547ac330f5f41907a2c01c Mon Sep 17 00:00:00 2001
From: HemangGadhavi <hemang.gadhavi at ibm.com>
Date: Fri, 24 Apr 2026 02:23:08 -0500
Subject: [PATCH 2/3] Addressed review comments

---
 .../Plugins/Process/AIX/NativeProcessAIX.cpp  | 38 +++++++++++--------
 .../Process/AIX/NativeRegisterContextAIX.h    |  8 ++--
 .../AIX/NativeRegisterContextAIX_ppc64.cpp    |  2 +
 .../AIX/NativeRegisterContextAIX_ppc64.h      |  3 +-
 4 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
index 24f91704272b8..c42f30a495c3d 100644
--- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
@@ -284,10 +284,10 @@ llvm::Error NativeProcessAIX::Detach(lldb::tid_t tid) {
 }
 
 template <typename GPR_T, typename PTSPRS_T>
-llvm::Expected<int> GetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
+int GetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
   PTSPRS_T sprs;
 
-  int ret = ptrace64(req, tid, (long long)&sprs, 0, 0);
+  int ret = ptrace64(req, tid, reinterpret_cast<long long>(&sprs), 0, 0);
 
   if (ret != -1) {
     gpr->cr = sprs.pt_cr;
@@ -301,7 +301,7 @@ llvm::Expected<int> GetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
 }
 
 template <typename GPR_T, typename PTSPRS_T>
-llvm::Expected<int> SetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
+int SetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
   PTSPRS_T sprs;
 
   sprs.pt_cr = gpr->cr;
@@ -311,13 +311,13 @@ llvm::Expected<int> SetSPRs(int req, lldb::tid_t tid, GPR_T *gpr) {
   sprs.pt_ctr = gpr->ctr;
   sprs.pt_iar = gpr->pc;
 
-  return (ptrace64(req, tid, (long long)&sprs, 0, 0));
+  return ptrace64(req, tid, reinterpret_cast<long long>(&sprs), 0, 0);
 }
 
 llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
                                                     void *addr, void *data,
                                                     size_t data_size) {
-  int ret;
+  int ret = 0;
   Log *log = GetLog(POSIXLog::Ptrace);
   // for PTT_*
   const char procdir[] = "/proc/";
@@ -325,6 +325,12 @@ llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
   std::string process_task_dir = procdir + std::to_string(pid) + lwpdir;
   DIR *dirproc = opendir(process_task_dir.c_str());
 
+  // PTT_* requests require a thread ID (TID).
+  // Each entry under /proc/<pid>/lwp/ represents a thread,
+  // and the directory name corresponds to its thread ID (TID).
+  // A process may contain multiple threads.
+  // TODO: With multi-threading support, iterate over all entries to enumerate
+  // available TIDs and retrieve the target debugging thread ID.
   lldb::tid_t tid = 0;
   if (dirproc) {
     struct dirent *direntry = nullptr;
@@ -340,32 +346,34 @@ llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
   }
 
   switch (req) {
+  // On AIX, ptrace exposes differently. GPRs and SPRs are handled via separate
+  // requests: PTT_READ_GPRS reads only GPRs & PTT_READ_SPRS is required to
+  // fetch SPRs. Similarly, writes are also split across:
+  // PTT_WRITE_GPRS & PTT_WRITE_SPRS.
   case PTT_READ_GPRS:
     if (data_size == sizeof(GPR_PPC)) // 32bit SPRs read
       ret = GetSPRs<GPR_PPC, ptsprs>(PTT_READ_SPRS, tid,
-                                     static_cast<GPR_PPC *>(data))
-                .get();
+                                     static_cast<GPR_PPC *>(data));
     else if (data_size == sizeof(GPR_PPC64)) // 64bit SPRs read
       ret = GetSPRs<GPR_PPC64, ptxsprs>(PTT_READ_SPRS, tid,
-                                        static_cast<GPR_PPC64 *>(data))
-                .get();
+                                        static_cast<GPR_PPC64 *>(data));
 
     if (ret != -1)
-      ret = ptrace64(req, tid, (long long)data, 0, 0); // read GPRs
+      ret = ptrace64(req, tid, reinterpret_cast<long long>(data), 0,
+                     0); // read GPRs
     break;
 
   case PTT_WRITE_GPRS:
     if (data_size == sizeof(GPR_PPC)) // 32bit SPRs write
       ret = SetSPRs<GPR_PPC, ptsprs>(PTT_WRITE_SPRS, tid,
-                                     static_cast<GPR_PPC *>(data))
-                .get();
+                                     static_cast<GPR_PPC *>(data));
     else if (data_size == sizeof(GPR_PPC64)) // 64bit SPRS write
       ret = SetSPRs<GPR_PPC64, ptxsprs>(PTT_WRITE_SPRS, tid,
-                                        static_cast<GPR_PPC64 *>(data))
-                .get();
+                                        static_cast<GPR_PPC64 *>(data));
 
     if (ret != -1)
-      ret = ptrace64(req, tid, (long long)data, 0, 0); // write GPRs
+      ret = ptrace64(req, tid, reinterpret_cast<long long>(data), 0,
+                     0); // write GPRs
     break;
   case PT_ATTACH:
   case PT_DETACH:
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
index 5f80c9d90fed4..1372affd0044a 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
@@ -19,10 +19,10 @@ class NativeRegisterContextAIX
     : public virtual NativeRegisterContextRegisterInfo {
 public:
   // This function is implemented in the NativeRegisterContextAIX_ppc64
-  // subclasses to create a new instance of the host specific
-  // NativeRegisterContextAIX. The implementations can't collide as only one
-  // NativeRegisterContextAIX_ppc64 variant should be compiled into the final
-  // executable.
+  // subclasses to create a new instance (for both 32-bit or 64-bit) of the host
+  // specific NativeRegisterContextAIX. Only one variant (e.g., 32-bit or
+  // 64-bit) is
+  // compiled into the final executable, so there is no conflict between them.
   static std::unique_ptr<NativeRegisterContextAIX>
   CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch,
                                      NativeThreadAIX &native_thread);
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
index 2096641dd272e..847a1b486a998 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp
@@ -110,9 +110,11 @@ NativeRegisterContextAIX_ppc64::NativeRegisterContextAIX_ppc64(
       NativeRegisterContextAIX(native_thread) {
   switch (target_arch.GetMachine()) {
   case llvm::Triple::ppc:
+    new (&m_gpr_storage.gpr32) GPR_PPC{};
     m_gpr = &m_gpr_storage.gpr32;
     break;
   case llvm::Triple::ppc64:
+    new (&m_gpr_storage.gpr32) GPR_PPC64{};
     m_gpr = &m_gpr_storage.gpr64;
     break;
   default:
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
index b86d9f887f4e5..aa0a6b8549900 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
@@ -69,9 +69,8 @@ class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX {
   union GPRStorage {
     GPR_PPC gpr32;   // 32-bit general purpose registers.
     GPR_PPC64 gpr64; // 64-bit general purpose registers.
-  };
+  } m_gpr_storage;
 
-  GPRStorage m_gpr_storage;
   void *m_gpr = nullptr;
 };
 

>From d7e5c4e07d1aa5b4e7768ce151f07f92313bcf85 Mon Sep 17 00:00:00 2001
From: HemangGadhavi <hemang.gadhavi at ibm.com>
Date: Fri, 24 Apr 2026 05:15:39 -0500
Subject: [PATCH 3/3] Use llvm code style for get TID

---
 .../Plugins/Process/AIX/NativeProcessAIX.cpp  | 29 +++++++++----------
 .../Process/AIX/NativeRegisterContextAIX.h    |  6 ++--
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
index c42f30a495c3d..9c7e66cb79028 100644
--- a/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
+++ b/lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
@@ -22,7 +22,6 @@
 #include <cerrno>
 #include <cstdint>
 #include <cstring>
-#include <dirent.h>
 #include <sstream>
 #include <string>
 #include <sys/ptrace.h>
@@ -319,30 +318,30 @@ llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
                                                     size_t data_size) {
   int ret = 0;
   Log *log = GetLog(POSIXLog::Ptrace);
-  // for PTT_*
-  const char procdir[] = "/proc/";
-  const char lwpdir[] = "/lwp/";
-  std::string process_task_dir = procdir + std::to_string(pid) + lwpdir;
-  DIR *dirproc = opendir(process_task_dir.c_str());
-
   // PTT_* requests require a thread ID (TID).
   // Each entry under /proc/<pid>/lwp/ represents a thread,
   // and the directory name corresponds to its thread ID (TID).
   // A process may contain multiple threads.
   // TODO: With multi-threading support, iterate over all entries to enumerate
   // available TIDs and retrieve the target debugging thread ID.
+  llvm::SmallString<128> proc_lwp_dir;
+  llvm::sys::path::append(proc_lwp_dir, "/proc/", std::to_string(pid), "/lwp/");
+
   lldb::tid_t tid = 0;
-  if (dirproc) {
-    struct dirent *direntry = nullptr;
-    while ((direntry = readdir(dirproc)) != nullptr) {
-      if (strcmp(direntry->d_name, ".") == 0 ||
-          strcmp(direntry->d_name, "..") == 0) {
+  std::error_code ec;
+  bool result;
+  if (!llvm::sys::fs::is_directory(proc_lwp_dir, result) && result) {
+    for (sys::fs::directory_iterator it(proc_lwp_dir, ec), end;
+         it != end && !ec; it.increment(ec)) {
+      llvm::StringRef name = llvm::sys::path::filename(it->path());
+
+      if (name == "." || name == "..")
         continue;
+
+      if (!name.getAsInteger(10, tid)) {
+        break;
       }
-      tid = atoi(direntry->d_name);
-      break;
     }
-    closedir(dirproc);
   }
 
   switch (req) {
diff --git a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
index 1372affd0044a..1f4f79627db41 100644
--- a/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
+++ b/lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
@@ -20,9 +20,9 @@ class NativeRegisterContextAIX
 public:
   // This function is implemented in the NativeRegisterContextAIX_ppc64
   // subclasses to create a new instance (for both 32-bit or 64-bit) of the host
-  // specific NativeRegisterContextAIX. Only one variant (e.g., 32-bit or
-  // 64-bit) is
-  // compiled into the final executable, so there is no conflict between them.
+  // specific NativeRegisterContextAIX.
+  // The appropriate implementation is selected at runtime based on the
+  // target process architecture, so only the relevant code path is used.
   static std::unique_ptr<NativeRegisterContextAIX>
   CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch,
                                      NativeThreadAIX &native_thread);



More information about the lldb-commits mailing list